Comet has Pip on the workbench, wheels spinning in the air. "It is time Pip drove," she says. "One cell forward. How hard can it be?"
Wren holds up the field sketch. "What does the evidence say?" he asks. "Forward means a different direction for each heading. And some cells are rocks."
Nova projects four small arrows labeled N, E, S and W, each with a pair of numbers. "How can I help?" she asks. "Turn each heading into a row change and a column change."
Comet nods slowly. "So the rover adds the numbers, then asks the grid first. Lead programmer, trace one step that works and one that does not."
STEPS is a dict from each heading to a pair: the change in row and the change in column. North is one row up, so its row change is -1.
Wednesday these lines go into rover.py. Today you read them, trace them and try the idea in a small program of your own.
HEADINGS = ["N", "E", "S", "W"]
STEPS = {"N": (-1, 0), "E": (0, 1), "S": (1, 0), "W": (0, -1)} move() is a mutator: it changes Pip's row, column, battery and log. It also returns True or False so the caller knows what happened.
It checks the cell ahead first, then the battery. Only when both checks pass does Pip step.
def move(self, grid):
"""Step forward one cell if it is open. Gives back True or False."""
d_row, d_col = STEPS[self._heading]
new_row = self._row + d_row
new_col = self._col + d_col
if not grid.is_open(new_row, new_col):
self._log.append(f"blocked at ({new_row}, {new_col})")
return False
if self._battery < self.step_use():
self._log.append("battery low")
return False
self._row = new_row
self._col = new_col
self._battery -= self.step_use()
self._log.append(f"moved to ({new_row}, {new_col})")
return True | Line | Pip at (0, 0) facing E | Pip at (0, 1) facing S |
|---|---|---|
| d_row, d_col | (0, 1) | (1, 0) |
| new_row, new_col | (0, 1) | (1, 1) |
| grid.is_open(...) | True: open ground | False: a rock |
| log line added | moved to (0, 1) | blocked at (1, 1) |
| returns | True | False |
# one_move.py
from field_data import FIELD
from grid import FieldGrid
from rover import Rover
grid = FieldGrid(FIELD)
pip = Rover("Pip")
print(pip.move(grid))
print(pip.status())
pip.turn_right()
print(pip.move(grid))
print(pip.get_log()) True Pip at (0, 1) facing E, battery 95 False ['moved to (0, 1)', 'blocked at (1, 1)']
# step_test.py
from field_data import FIELD
from grid import FieldGrid
STEPS = {"N": (-1, 0), "E": (0, 1), "S": (1, 0), "W": (0, -1)}
grid = FieldGrid(FIELD)
row = 0
col = 0
for heading in ["E", "S"]:
d_row, d_col = STEPS[heading]
new_row = row + d_row
new_col = col + d_col
if grid.is_open(new_row, new_col):
row = new_row
col = new_col
print(heading, "moved to", (row, col))
else:
print(heading, "blocked at", (new_row, new_col)) | Statement | True or false? |
|---|---|
| STEPS["N"] is (-1, 0) because north is one row up. | ? |
| move() changes Pip's position before it checks the grid. | ? |
| A blocked move adds a line to the log. | ? |
| move() returns True or False to its caller. | ? |
One step, traced both ways. Tomorrow Pip follows a whole string of commands.