Comet writes a route on a sticky note: FFRFX. "F is forward, L and R are turns," she says. "X was a typo. Pip should just stop, right?"
Wren shakes his head. "What does the evidence say we want?" he asks. "A rover that crashes on one bad letter is not ready for the field."
Nova projects the route one letter at a time, with a log growing beside it. "How can I help?" she asks. "Try logging anything Pip does not know, and keep going."
"Lead programmer," Comet says, "trace my route. Where does Pip end up, and what does the log say about X?"
run() walks a command string one letter at a time. F calls move(), L and R turn, and anything else is logged as an unknown command.
Common security issues in programs include missing bounds checks and poor input validation. run() validates every letter instead of trusting it.
def run(self, commands, grid):
"""Follow a command string: F forward, L left, R right."""
for c in commands:
if c == "F":
self.move(grid)
elif c == "L":
self.turn_left()
elif c == "R":
self.turn_right()
else:
self._log.append(f"unknown command {c}") # route.py
from field_data import FIELD
from grid import FieldGrid
from rover import Rover
grid = FieldGrid(FIELD)
pip = Rover("Pip")
pip.run("FFRFX", grid)
print(pip.status())
for line in pip.get_log():
print(line) | Letter | What run() does | Pip after it |
|---|---|---|
| F | move() | (0, 1) facing E |
| F | move() | (0, 2) facing E |
| R | turn_right() | (0, 2) facing S |
| F | move() | (1, 2) facing S |
| X | logs unknown command X | (1, 2) facing S |
Pip at (1, 2) facing S, battery 85 moved to (0, 1) moved to (0, 2) moved to (1, 2) unknown command X
Now the commands come from input(). The program asks only for simulation commands. Watch two runs: one typed in capitals, one in lowercase.
# drive_input.py
from field_data import FIELD
from grid import FieldGrid
from rover import Rover
grid = FieldGrid(FIELD)
pip = Rover("Pip")
commands = input("Commands (F, L, R): ")
pip.run(commands, grid)
print(pip.status())
print(pip.get_log()) Run 1, typed FFRF:
Commands (F, L, R): FFRF Pip at (1, 2) facing S, battery 85 ['moved to (0, 1)', 'moved to (0, 2)', 'moved to (1, 2)']
Run 2, typed ffrf:
Commands (F, L, R): ffrf Pip at (0, 0) facing E, battery 100 ['unknown command f', 'unknown command f', 'unknown command r', 'unknown command f']
One change fixes it: add .upper() after input(...). The run below shows typed ffrf now drives like FFRF.
# drive_upper.py
from field_data import FIELD
from grid import FieldGrid
from rover import Rover
grid = FieldGrid(FIELD)
pip = Rover("Pip")
commands = input("Commands (F, L, R): ").upper()
pip.run(commands, grid)
print(pip.status()) # command_test.py
HEADINGS = ["N", "E", "S", "W"]
heading = "E"
log = []
for c in "RRLXF":
if c == "L":
i = HEADINGS.index(heading)
heading = HEADINGS[(i - 1) % 4]
elif c == "R":
i = HEADINGS.index(heading)
heading = HEADINGS[(i + 1) % 4]
elif c == "F":
log.append(f"forward facing {heading}")
else:
log.append(f"unknown command {c}")
print(heading)
print(log) Pip can follow orders and stay calm about typos. Tomorrow you build the final rover.py.