Comet wants Pip to turn. "Left and right," she says. "N, E, S, W, round and round. That is just a list!"
Wren writes the four headings in a circle on his graph paper. "What does the evidence say happens after W?" he asks. "The list ends, but the circle keeps going."
Nova projects the list with an arrow that jumps from the end back to the start. "How can I help?" she asks. "Try the remainder operator, %, in the shell first."
Comet hands you the keyboard. "Lead programmer, stage one. Then we turn."
rover.py is the second real FieldSim file. drive_test.py is a short driver that imports Rover and tries it out. Save both in your fieldsim folder.
# rover.py
# A Rover drives on the test field, one cell at a time.
HEADINGS = ["N", "E", "S", "W"]
class Rover:
"""A survey rover on the Larkspur test field."""
def __init__(self, name, row=0, col=0):
self.name = name
self._row = row
self._col = col
self._heading = "E"
self._battery = 100
def get_row(self):
return self._row
def get_col(self):
return self._col
def get_heading(self):
return self._heading
def get_battery(self):
return self._battery
def status(self):
return (f"{self.name} at ({self._row}, {self._col}) facing "
f"{self._heading}, battery {self._battery}") # drive_test.py
from rover import Rover
pip = Rover("Pip")
print(pip.status())
print(pip.get_row(), pip.get_col(), pip.get_heading()) >>> HEADINGS = ["N", "E", "S", "W"]
>>> HEADINGS.index("E")
1
>>> HEADINGS[(1 + 1) % 4]
'S'
>>> HEADINGS.index("W")
3
>>> (3 + 1) % 4
0
>>> (0 - 1) % 4
3 index() gives the zero-based position of the first matching item. The shell shows % 4 turns 4 back into 0, and -1 into 3, so the list wraps like a circle.
turn_left() and turn_right() are mutators: they change _heading and give nothing back. HEADINGS sits at the top of rover.py from stage 1 on.
def turn_left(self):
i = HEADINGS.index(self._heading)
self._heading = HEADINGS[(i - 1) % 4]
def turn_right(self):
i = HEADINGS.index(self._heading)
self._heading = HEADINGS[(i + 1) % 4] # rover.py
# A Rover drives on the test field, one cell at a time.
HEADINGS = ["N", "E", "S", "W"]
class Rover:
"""A survey rover on the Larkspur test field."""
rovers_built = 0
def __init__(self, name, row=0, col=0):
self.name = name
self._row = row
self._col = col
self._heading = "E"
self._battery = 100
Rover.rovers_built += 1
def get_row(self):
return self._row
def get_col(self):
return self._col
def get_heading(self):
return self._heading
def get_battery(self):
return self._battery
def turn_left(self):
i = HEADINGS.index(self._heading)
self._heading = HEADINGS[(i - 1) % 4]
def turn_right(self):
i = HEADINGS.index(self._heading)
self._heading = HEADINGS[(i + 1) % 4]
def status(self):
return (f"{self.name} at ({self._row}, {self._col}) facing "
f"{self._heading}, battery {self._battery}") # drive_test.py
from rover import Rover
pip = Rover("Pip")
print(pip.status())
pip.turn_right()
print(pip.get_heading())
pip.turn_right()
pip.turn_right()
pip.turn_right()
print(pip.get_heading())
pip.turn_left()
print(pip.status())
print(Rover.rovers_built) Pip at (0, 0) facing E, battery 100 S E Pip at (0, 0) facing N, battery 100 1
In rover.py, change the last line of turn_right() to self._heading = HEADINGS[i + 1]. Save it and run drive_test.py.
# drive_test.py
from rover import Rover
pip = Rover("Pip")
print(pip.status())
pip.turn_right()
print(pip.get_heading())
pip.turn_right()
pip.turn_right()
pip.turn_right()
print(pip.get_heading())
pip.turn_left()
print(pip.status())
print(Rover.rovers_built) Pip at (0, 0) facing E, battery 100
S
Traceback (most recent call last):
File "drive_test.py", line 9, in <module>
pip.turn_right()
~~~~~~~~~~~~~~^^
File "rover.py", line 38, in turn_right
self._heading = HEADINGS[i + 1]
~~~~~~~~^^^^^^^
IndexError: list index out of range rover.py now turns and guards its state. Tomorrow: the one variable that every rover shares.