Today: if statement, ==, function call, decomposition
Recall from last time, go-green demo:
> go-green
While loop is power. If-statement is control, controlling if lines are run or not
Problem statement: Move bit forward until blocked. For each moved-to square, if the square is blue, change it to green. (Demo: this code is complete.).
> If Demo
For reference here is the code:
def if_demo(filename):
bit = Bit(filename)
while bit.front_clear():
bit.move()
if bit.get_color() == 'blue':
bit.paint('green')
Syntax 4 parts (similar to "while"): if, boolean test-expression, colon, indented body lines
if test-expr:
body lines
Here are the key lines of code:
....
if bit.get_color() == 'blue':
bit.paint('green')
....
Suppose bit is on a squared painted 'blue'. Here is diagram - visualizing that bit.get_color() is called and it returns the value'blue' to be used by the calling code.
== Compares Two Values - Boolean
if bit.get_color() == 'red':
# run this if color is 'red'
if bit.get_color() == None:
# run this if square is not painted
if bit.get_color() != 'red':
# run this if square is anything but 'red'
# e.g. 'green' 'blue' or None
In with Wizard of EarthSea novels by Ursula Le Guin .. each thing in the world has its true name. A magician calls a thing's true name, invoking that thing's power. Function calls work like this - a function has a name, you invoke the function by its name, getting its power.
We've seen def many times - defines a function. Note that
each function has a name and body lines of code, like this "go_west" function:
def go_west(bit):
bit.left()
bit.paint('blue')
...
To "call" a function means to go run its code. One way to call a function in Python is the "object oriented" form, aka noun.verb. The bit functions look like that, e.g. bit.left(), here "left" is the name of the function.
The other way to call a function is just by using its name with parenthesis. For the above function named "go_west", code to call it looks like:
...
go_west(bit)
...
Both of these function-call styles are widely used in Python code.
Say the program is running through some lines, which we'll call the "caller" lines. Then the run gets to the following function call line; what happens?
# caller lines
bit = Bit('5x5.world')
go_west(bit)
bit.left()
...
What this means simply is: (a) go run the lines inside the "go_west" function, suspend running here in the caller. (b) When go_west() is done, return to these caller lines and continue running with the next line. In other words, the program runs one function at a time, and function-call jumps over to run that function.
The whole program does this: bit starts at the upper left facing down. We want to fill the whole world with blue, like this
Program Before:
Program After:
> Fill
First we'll decompose out a fill_row_blue() function that just does 1 row. Work on that function first.
This is a "helper" function - solves a smaller sub-problem.
fill_row_blue() Before (pre)
fill_row_blue After (post):
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()
bit.left_clear() + not
if bit.left_clear():
# run here if left is clear
if not bit.left_clear():
# run here if left is blocked, aka not-clear
Bit starts next to a block of solid squares (these are not "clear" for moving). Bit goes around the 4 sides clockwise, painting everything green.
Cover Before (pre):
cover_row() After (post):
cover_square() After (post):
cover_row(bit): Move bit forward until the right side is clear. Color every square green. (demonstrates not left-clear test).
Run this code with case-1, see what it does. Study the code to see how it works, think about its pre/post (make a little drawing).
cover_square(bit): Bit begins atop the upper left corner, facing right. Paint all 4 sides green. End to the left of the original position, facing up.
Start by calling cover_row() once. How can we solve the whole thing? How to address the pre/post conditions of cover_side()? Key ideas:
Boolean Examples..
Q1: when is the following if-test True?
if bit.left_clear() and bit.right_clear():
# when does this happen?
Q2: when is the following if-test True? (just changing and to or)?
if bit.left_clear() or bit.right_clear():
# when does this happen?
Q3: when is the following if-test True?
if not bit.left_clear():
# when does this happen?
Answers.. A1: When either both left and right are clear A2: When either left or right are clear (or both) A3: When the left is blocked (i.e. lear_clear() returns False)
First 3 are demos - walk through them
Then last 3 are little exercises to try .. see how many we get through today
Nick demo:
while bit.front_clear():
bit.left()
bit.right()
Here's a more subtle 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()