Today: infinite loops, style tactics, variables 3x, parameters, top-down decomposition
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.
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()
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
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:
... 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
Suppose we want to fill the world with alternating rows painted blue, green, blue, green ... like this:
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()
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()
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.
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')
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')
Our standard picture - program made up of functions
> Hurdles
while not bit.left_clear(): bit.move()
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)
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()
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')
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.
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.
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.
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.