Today: idiomatic range index loop, reversed, grid, grid testing, work on one function at a time
Also: office hours after class,
How are the things numbered individually? It's always the zero based scheme: 0, 1, 2, .. 9
The idiomatic way to loop over them by their index numbers is with the for/i/range loop.
for i in range(10): # i in here: 0 1 2 .. 9 # e.g. use s[i]"Idiomatic" here meaning a phrase that is used frequently, becomes familiar and easy to use correctly.
The reversed() function: reverses a sequence such as from range(). Splices into the regular for/i/range idiom to go through the same numbers in reverse order:
for i in reversed(range(10)):
# i in here: 9 8 7 .. 0
For more detail, see guide Python range()
Download movie.zip
grid = Grid(3, 2) grid.width # returns 3 grid.set(2, 0, 'a') grid.set(2, 1, 'b')
Implement set_edges() (in movie.py)
def set_edges(grid):
"""
Set all the squares along the left edge (x=0) to 'a'.
Do the same for the right edge.
Return the changed grid.
"""
pass
Solution code:
def set_edges(grid):
"""
Set all the squares along the left edge (x=0) to 'a'.
Do the same for the right edge.
Return the changed grid.
"""
for y in range(grid.height):
grid.set(0, y, 'a')
grid.set(grid.width - 1, y, 'a')
return grid
Is that code right? How can we tell if that code works? With our image examples, at least you could look at the output, although that was not a perfect solution either. Really we want to be able to write test for a small case with visible data.
A "literal" in code is when you can type a value directly in the code, like 6 or 'Hello'
There is a syntax to write a Grid literal in Python code. It's a little funny looking, but it's fine for small grids. Suppose we have this 3 by 2 grid
Here is the nested-list "literal" representation of that grid:
[['a', None, 'a'], ['b', None, 'b']]
The grid is shown as a series of rows, row-0, row-1, .... Each row within square brackets. The special value None is in the empty squares. So the first thing you see is the top row, Then the next row and so on.
The Grid code understands how to build a grid from a literal. This lets us throw together a grid in one line. This will be handy for testing!
grid = Grid.build([['a', None, 'a'], ['b', None, 'b']])
Here are the key 3 lines added to set_edges() that make the Doctest: (1) create a grid, (2) call fn, (3) write out the expected result of the function call
>>> grid = Grid.build([['b', 'b', 'b'], ['x', 'x', 'x']])
>>> set_edges(grid)
[['a', 'b', 'a'], ['a', 'x', 'a']]
Note: Doctests are super picky - if we had an extra space after the last ], the test will fail.
A computer program is "deterministic" - each time you run the lines with the same input, they do exactly the same thing. Creating random numbers is a challenge, so we settle for "pseudo-random" which are random looking, but generated by a computer program.
>>> import random # starter code has this already
>>> random.randrange(10)
1
>>> random.randrange(10)
3
>>> random.randrange(10)
9
>>> random.randrange(10)
1
>>> random.randrange(10)
8
>>> random.choice('doofus')
'o'
>>> random.choice('doofus')
'u'
>>> random.choice('doofus')
'o'
>>> random.choice('doofus')
'o'
>>> random.choice('doofus')
's'
>>> random.choice('doofus')
's'
>>> random.choice('doofus')
'o'
>>> random.choice('doofus')
's'
Provided to fill in letters at right 10% of the time to a random char from 'doofus'
def random_right(grid):
"""
Set the right edge of the grid to some
random letters from 'doofus'.
(provided)
"""
for y in range(grid.height):
if random.randrange(10) == 0:
char = random.choice('doofus')
grid.set(grid.width - 1, y, char)
return grid
Before:
NNd NNN
After:
NdN NNN
def scroll_left(grid):
"""
Implement scroll_left as in lecture notes.
"""
# v1 - has bugs
for y in range(grid.height):
for x in range(grid.width):
# Move letter at x,y leftwards
val = grid.get(x, y)
if x > 0 and val != None:
grid.set(x - 1, y, val)
return grid
How about this input case:
[['a', 'b', 'c'], ['d', None, None]]
What should result look like for that input case? You should be able to write out the "after" case for an algorithm you are building.
After:
[['b', 'c', None], [None, None, None]]
def scroll_left(grid):
"""
Implement scroll_left as in lecture notes.
>>> grid = Grid.build([['a', 'b', 'c'], ['d', None, None]])
>>> scroll_left(grid)
[['b', 'c', None], [None, None, None]]
"""
def scroll_left(grid):
"""
Implement scroll_left as in lecture notes.
>>> grid = Grid.build([['a', 'b', 'c'], ['d', None, None]])
>>> scroll_left(grid)
[['b', 'c', None], [None, None, None]]
"""
for y in range(grid.height):
for x in range(grid.width):
# Move letter at x,y leftwards
val = grid.get(x, y)
if x > 0 and val != None:
grid.set(x - 1, y, val)
grid.set(x, y, None)
return grid