Today: infinite loops, style tactics, variables 3x, parameters, top-down decomposition

Lecture Example Code Strategy

We run through lecture examples for the important ideas, but it's pretty fast. It's hard to know in the moment if you've gotten the idea or not. Later you'll see a homework problem on the same topic. If you are stuck, a good use of time is to go back to the lecture notes, and see if you can work the lecture problem yourself, peeking at the solution here and there as you go. Ultimately, you want to be able to write the solution without peeking at a similar problem, but to learn the material it's fine.

Infinite Loops

Nick demo:

while bit.front_clear():
    bit.left()
    bit.right()

Here's a more subtle version of the bug. What is the problem here?

while bit.front_clear():
    bit.move

A: Easy typo to make - without parenthesis, the move function does not happen! Correct is bit.move()

Coding Style 1.0 - Tactics

CS106A doe not just teach coding. It has always taught how to write clean code with good style. Your section leader will talk with you about the correctness of code, but also pointers for good style.

All the code we show you will follow PEP8, so just picking up the style tactic that way is the easiest.

Python Style1 guide - scan through this today quickly

Variables - 3 Things To Know

See also: Python Variables

A variable stores a value for the code. (1) Variables are set up with a single equal sign =. (2) Later appearances of that variable retrieve the stored value. Here's a little example:

alt: variable color points to 'red'

...
color = 'red'
bit.paint(color)
bit.move()
bit.paint(color)

This paints 2 squares 'red', or whatever value was assigned to color on the first line. (3) Variable name is just a label. If we change color to xyz throughout the above code .. the code will still work perfectly. The name of the variable is just a for-human label to tie a few lines together. Code needs to use a consistent variable name; The actual word does not matter. (Which is unintuitive, since writing for humans, the word used is very important!)


Stripes Problem

> Stripes

Suppose we want to fill the world with alternating rows painted blue, green, blue, green ... like this:

alt:world has blue green blue ...horizontal stripes

We want a function to color one row. When solving a problem, it's natural look at some working code we have laying around as a starting point. Here is our fill_row_blue() code from last time:

def fill_row_blue(bit):
    bit.left()
    bit.paint('blue')
    while bit.front_clear():
        bit.move()
        bit.paint('blue')
    bit.right()
    bit.right()
    while bit.front_clear():
        bit.move()
    bit.left()

Parameterize: fill_row_color(bit, color)

Parameterized fill_row_blue() - fill_row_color()

def fill_row_color(bit, color):
    bit.left()
    bit.paint(color)   # key line: use parameter
    while bit.front_clear():
        bit.move()
        bit.paint(color)
    bit.right()
    bit.right()
    while bit.front_clear():
        bit.move()
    bit.left()

Caller Syntax With Parameter

What does the "caller" code that calls this function look like? Call fill_row_color() with 'green':

   ....
   fill_row_color(bit, 'green')
   ...

1. Parameters match up by position within the parenthesis, separated by commas

2. Look at the Cases Menu w/ Run button .. shows this in action. Call this function a few times, see the output vs. the passed in parameter.

Write Code For - stripe_world()

This is our partway-correct solution - shows calling the helper function, passing in a color parameter.

def stripe_world(filename):
    bit = Bit(filename)
    fill_row_color(bit, 'blue')
    while bit.front_clear():
        bit.move()
        fill_row_color(bit, 'green')
        bit.move()
        fill_row_color(bit, 'blue')

stripe_world() - Issue With Even World

What if there are an odd number of rows available in the loop? Solution: add if-logic for the second move within the loop.

Pattern: every move() needs to be "guarded" by if logic. What guards the first move() below? We add an if-test to guard the second move()

def stripe_world(filename):
    bit = Bit(filename)
    fill_row_color(bit, 'blue')
    while bit.front_clear():
        bit.move()
        fill_row_color(bit, 'green')
        if bit.front_clear():   # Need this if
            bit.move()
            fill_row_color(bit, 'blue')

Program Made of Functions

Our standard picture - program made up of functions

alt: program is made of functions, each with def

Decomposition Strategy - Divide and Conquer

Big Picture - Browser Example

Top-Down Decomposition Strategy


Hurdles Decomposition Example

> Hurdles

alt: bit runs series of hurdles

   while not bit.left_clear():
       bit.move()

Top-Down Decomposition - Hurdles

solve_hurdles()

def solve_hurdles(filename):
    """
    Solve the sequence of hurdles.
    Start facing north at the first hurdle.
    Finish facing north at the end.
    (provided)
    """
    # Un-comment the loop when the helpers
    # are done
    while bit.front_clear():
        solve_1_hurdle(bit)

solve_1_hurdle()

Here is the solve_1_hurdle() code - write this one first, just imagine that that the helpers exist. Think about pre/post for each.

def solve_1_hurdle(bit):
    """
    Solve one hurdle, painting all squares green.
    Start facing up at the hurdle's left edge.
    End facing up at the start of the next hurdle.
    """
    go_wall_right(bit)
    bit.right()
    bit.move()
    go_wall_right(bit)
    bit.right()
    go_until_blocked(bit)
    bit.left()
    go_until_blocked(bit)
    bit.left()

Power Move: Delegation and Knowing Things

Write Two More Helpers

Now write two more helpers. Here we see the importance of the pre/post to mesh the functions together.

def go_wall_right(bit):
    """
    Move bit forward so long as there
    is a wall to the right. Paint
    all squares green. Leave bit with the
    original facing.
    """
    bit.paint('green')
    while not bit.right_clear():
        bit.move()
        bit.paint('green')


def go_until_blocked(bit):
    """
    Move bit forward until blocked.
    Painting all squares green.
    Leave bit with the original facing.
    """
    bit.paint('green')
    while bit.front_clear():
        bit.move()
        bit.paint('green')

Run It

When all the helpers are built, we can try running it on a few worlds. Switch to a small font so you can see all the code at once, watch the run jump around. Go, Bit go!


Some other points to clean up.

Helpers At Top - Convention

There is a convention to put the smallest, helper functions first in a file. The larger functions that call them down below. This is just a habit; Python code will work with the functions in any order. Placing the helpers first does have a kind of logic — looking at solve_1_hurdle(), the functions it uses are defined above it, not after.

solve_1_hurdle() Helpers + Triple Quote

At the top of each function is a description of what the function does within triple-quote marks - we'll start writing these from now on. This is a Python convention known as "Pydoc" for each function. The description is just a summary of the pre/post in words.

Run vs. Helper Tests

Previously we had separate testing for each helper which is ideal, and we will do that again in CS106A. In this case, we just run the whole thing and see if it works without the benefit of helper tests.