← Back to course
Python 11-12 / Week 12 / Wednesday
3/6
Week 12 · Reading Java II and Ship

Wednesday

Sim Lab: Ship FieldSim
// ArrayList, sorting, searching and recursion in Java; then a code review and the FieldSim release
⏱ about 30 min

Wednesday: Sim Lab: Ship FieldSim

Today is release day. Comet has her bomber jacket on and Pip parked at the edge of the Larkspur test field.

"Let us finish fieldsim.py and send Pip out!" she says.

Wren holds up a hand. "What does the evidence say? First the simulation runs the whole route. Then the tests pass. Then we save a release copy."

Nova projects a checklist with three empty boxes. "How can I help?" she asks. "Programmers test with many conditions to make a program reliable. Each box is one check."

Comet laughs and sits down at the keyboard. "Fine. Simulation first, lead programmer."

The main program

fieldsim.py brings every file together: field_data.py, grid.py, rover.py, sample.py and sorts.py. The field and samples are made-up data from the FieldSim story.

Pip follows the command string one letter at a time. After each letter, collect_here picks up a sample if Pip is on a sample spot.

  1. Open a new file and save it in your fieldsim folder as fieldsim.py.
  2. Type the program below. Check every import name against your own files.
  3. Answer the prediction questions before you run it.
  4. Run fieldsim.py with F5 and compare with the output on this page.
  5. Open test_fieldsim.py from week 6 and run it.
  6. Back in fieldsim.py, use File, Save Copy As, and save fieldsim_v1.py in the same folder. That copy is your release.
# fieldsim.py
# FieldSim: drive a rover across the test field and report what it found.
from field_data import FIELD, FIELD_SAMPLES
from grid import FieldGrid
from rover import Rover
from sample import Sample
from sorts import sort_by_grams


def collect_here(rover, grid, samples_by_spot):
    """Pick up the sample under the rover, if there is one."""
    spot = (rover.get_row(), rover.get_col())
    if grid.cell(spot[0], spot[1]) == "*" and spot in samples_by_spot:
        if rover.pick_up(samples_by_spot[spot]):
            grid.set_cell(spot[0], spot[1], ".")


def main():
    grid = FieldGrid(FIELD)
    samples_by_spot = {}
    for label, kind, grams, row, col in FIELD_SAMPLES:
        samples_by_spot[(row, col)] = Sample(label, kind, grams, row, col)
    pip = Rover("Pip")
    for c in "FFRFFFLFFLFRRFFLF":
        pip.run(c, grid)
        collect_here(pip, grid, samples_by_spot)
    grid.show(pip)
    print(pip.status())
    found = pip.get_samples()
    sort_by_grams(found)
    for s in found:
        print(s.describe())
    print(f"Total: {pip.total_grams()} g")


main()
PREDICT BEFORE YOU RUN
  • Read the question.
  • Tap your answer.
The route crosses three sample spots: (0, 2), (2, 4) and (4, 5). How many sample lines print before the Total line?
found is sorted with sort_by_grams. Which sample prints first?
Each step forward uses 5 battery, and Pip makes 11 steps. What battery is left?
.....#
.#....
...#..
*.....
..#..R
Pip at (4, 5) facing E, battery 45
S04 mica 7 g at (4, 5)
S02 quartz 18 g at (2, 4)
S01 basalt 42 g at (0, 2)
Total: 67 g
READ THE FINAL GRID
  • Read the question.
  • Tap your answer.
Which sample spot is still marked * on the final grid?

Then the tests from week 6. One line means every assert held:

All FieldSim tests passed

Change once, then break once

Never experiment in a release. Save Copy As again, this time as fieldsim_try.py, and open that copy. Change its first comment line to match the program below.

Change one thing: add a line after print(pip.status()) that prints the last log entry. Predict it, then run it.

# fieldsim_try.py (a copy to experiment in)
# FieldSim: drive a rover across the test field and report what it found.
from field_data import FIELD, FIELD_SAMPLES
from grid import FieldGrid
from rover import Rover
from sample import Sample
from sorts import sort_by_grams


def collect_here(rover, grid, samples_by_spot):
    """Pick up the sample under the rover, if there is one."""
    spot = (rover.get_row(), rover.get_col())
    if grid.cell(spot[0], spot[1]) == "*" and spot in samples_by_spot:
        if rover.pick_up(samples_by_spot[spot]):
            grid.set_cell(spot[0], spot[1], ".")


def main():
    grid = FieldGrid(FIELD)
    samples_by_spot = {}
    for label, kind, grams, row, col in FIELD_SAMPLES:
        samples_by_spot[(row, col)] = Sample(label, kind, grams, row, col)
    pip = Rover("Pip")
    for c in "FFRFFFLFFLFRRFFLF":
        pip.run(c, grid)
        collect_here(pip, grid, samples_by_spot)
    grid.show(pip)
    print(pip.status())
    print("Last log:", pip.get_log()[-1])
    found = pip.get_samples()
    sort_by_grams(found)
    for s in found:
        print(s.describe())
    print(f"Total: {pip.total_grams()} g")


main()
PREDICT THE LOG LINE
  • Read the question.
  • Tap your answer.
What is the last entry in Pip's log?

Now break it on purpose: in fieldsim_try.py, change total_grams to total_gram on the last line of main. Run it and read the traceback calmly.

# fieldsim_try.py (a copy to experiment in)
# FieldSim: drive a rover across the test field and report what it found.
from field_data import FIELD, FIELD_SAMPLES
from grid import FieldGrid
from rover import Rover
from sample import Sample
from sorts import sort_by_grams


def collect_here(rover, grid, samples_by_spot):
    """Pick up the sample under the rover, if there is one."""
    spot = (rover.get_row(), rover.get_col())
    if grid.cell(spot[0], spot[1]) == "*" and spot in samples_by_spot:
        if rover.pick_up(samples_by_spot[spot]):
            grid.set_cell(spot[0], spot[1], ".")


def main():
    grid = FieldGrid(FIELD)
    samples_by_spot = {}
    for label, kind, grams, row, col in FIELD_SAMPLES:
        samples_by_spot[(row, col)] = Sample(label, kind, grams, row, col)
    pip = Rover("Pip")
    for c in "FFRFFFLFFLFRRFFLF":
        pip.run(c, grid)
        collect_here(pip, grid, samples_by_spot)
    grid.show(pip)
    print(pip.status())
    print("Last log:", pip.get_log()[-1])
    found = pip.get_samples()
    sort_by_grams(found)
    for s in found:
        print(s.describe())
    print(f"Total: {pip.total_gram()} g")


main()
.....#
.#....
...#..
*.....
..#..R
Pip at (4, 5) facing E, battery 45
Last log: moved to (4, 5)
S04 mica 7 g at (4, 5)
S02 quartz 18 g at (2, 4)
S01 basalt 42 g at (0, 2)
Traceback (most recent call last):
  File "fieldsim_try.py", line 37, in <module>
    main()
    ~~~~^^
  File "fieldsim_try.py", line 34, in main
    print(f"Total: {pip.total_gram()} g")
                    ^^^^^^^^^^^^^^
AttributeError: 'Rover' object has no attribute 'total_gram'. Did you mean: 'total_grams'?
What is the name of this error?

Now fix it: change total_gram back to total_grams in fieldsim_try.py, save it and run it again. Keep this working copy; you will use it on Saturday.

StatementTrue or false?
The release copy fieldsim_v1.py is where you try new changes.?
Running the tests after the program runs is part of checking reliability.?
Everything before the error still printed in the broken copy.?
Testing compares what a program does with what it should do.?
WHY THIS EXERCISEA release stays as it was shipped. Experiments go in a separate copy, and tests compare actual results with intended ones.

FieldSim version 1 is shipped, lead programmer. The whole crew is proud of you. Tomorrow comes the code review.

← Tuesday