Skip to content

PA1: Robot Vacuum

Robot vacuums look clever, but they are not. They cannot see the whole room; they just follow orders. Drive forward, stop, vacuum. Drive the other way, bonk into the wall, bounce off, vacuum again. And that crumb pile under the couch? That takes more than one pass.

In this PA, you are writing the robot's brain. Your code builds a hallway full of dirt, drives the robot one move at a time (bonks included), and runs a whole list of moves to find out when the hall is finally clean. Every spot, and every bit of dirt on it, lives in one Python list.

This is one of the two PA1 options; do this one or Chutes and Ladders, not both.

What you'll practice

  • Using a for loop over a range to build a list, and index assignment to change it.
  • Looping over the indexes of two lists at once, when spots[i] goes with amounts[i].
  • Writing a function with several cases, and checking them in the right order.
  • Remembering what happened across the moves of a loop, and returning two results as a tuple.

Get set up

Download vacuum.py and save it in the Week06 folder inside ~/CS149. That one file is the whole PA.

Open it and look around. All three functions are already there, each with a docstring that says exactly what it takes and what it returns, and each body is just pass. Your job is to replace those pass lines with real code. Read each docstring all the way through, example included, before you start that function. The main block at the bottom is written for you; leave it alone, and it will run a whole cleaning job for you at the end.

Put your name and today's date in place of YOUR NAME and THE DATE at the top of the file. Gradescope checks.

Submit early to Gradescope

If you don't submit to Gradescope and get a nonzero score, you will receive a reflection grade of no higher than 15/30 points.

How the hallway works

Here is the trick that makes the whole PA simple: the hall is a list, and the index is the spot. Spot 0 is one end, where the robot's dock is, and the last index is the other end. So a hall of 10 spots has indexes 0 to 9, with a wall just past each end.

The value stored at each spot is how much dirt is there, and 0 means spotless. Here is a 10-spot hall with 1 unit of dirt on spot 2, a 2-unit mess on spot 6, and 1 unit on spot 9:

Spot 0 1 2 3 4 5 6 7 8 9
Dirt 0 0 1 0 0 0 2 0 0 1
>>> hall = [0, 0, 1, 0, 0, 0, 2, 0, 0, 1]
>>> hall[6]
2
>>> len(hall)
10
>>> hall[len(hall) - 1]
1

Each time the robot stops on a spot with dirt, it vacuums up one unit of it.

Quick check: at least how many stops does this hall need before it is clean?

Four: one each for spots 2 and 9, and two for spot 6. Add up all the dirt in the list and you have the answer, which will come in handy in Part C.

Part A: build the hall with make_hall

make_hall(length, spots, amounts) builds a hall like the one above. length is the number of spots, and the two lists say which spots are dirty and how dirty: spots[0] goes with amounts[0], spots[1] with amounts[1], and so on.

>>> make_hall(10, [2, 6, 9], [1, 2, 1])
[0, 0, 1, 0, 0, 0, 2, 0, 0, 1]
Predict it: what does make_hall(6, [0, 5], [3, 1]) return?

[3, 0, 0, 0, 0, 1]. Six spots, a 3-unit disaster right by the dock, and a little dust at the far end. Check it in the Shell once your function works.

Two loops, one after the other

First build a clean hall, with a 0 on every spot. Then add the dirt. The second loop is not over the hall; think about which list it should go through, and why it needs the indexes rather than the values.

Part B: drive once with step

step(position, distance, length) drives the robot once and returns the spot it stops on. A positive distance drives right, toward the last spot, and a negative one drives left, toward spot 0. There are three cases:

  1. A drive that stays inside the hall just stops where it ends. Easy.
  2. A drive that would go past the right wall bonks and bounces back by the spots left over. In the hall above, a robot on spot 7 that drives 4 counts 8, 9, bonk, then back to 8 and 7, and stops on 7.
  3. A drive that would go past the left wall bounces back the same way. A robot on spot 1 that drives -3 counts 0, bonk, then back to 1 and 2, and stops on 2.

A drive is never longer than the hall, so the robot never bonks twice in one move.

>>> step(3, 3, 10)
6
>>> step(7, 4, 10)
7
>>> step(1, -3, 10)
2
>>> step(4, -4, 10)
0
Your turn: in a 10-spot hall, one robot on spot 8 drives 5, and another on spot 2 drives -7. Where does each stop?

Both stop on spot 5. The first counts 9, bonk, and back 8, 7, 6, 5. The second counts 1, 0, bonk, and back 1, 2, 3, 4, 5. Opposite walls, same spot.

The bounce is subtraction, twice

Work out where the drive would end if there were no wall, even if that is past the end or below 0. Then work out how far past the wall that is, and go back from the wall by that much. Try both walls on paper before you write the code. A drive that ends exactly on spot 0 or on the last spot is not a bounce.

Part C: run the job with clean

clean(hall, moves) runs the robot through a list of moves. The robot starts on spot 0 and makes every move in order, using your step. Each time it stops on a spot with dirt, it vacuums up one unit. It returns a tuple of two things:

  • a new list of how much dirt is left on each spot, and
  • the move number, counting from 1, on which the last of the dirt was vacuumed, or -1 if there is dirt left after the final move. A hall with no dirt at all returns 0, since there was nothing to do.

The robot makes every move, even after the hall is clean; it does not know it is done. Here is a run in the hall above with the moves [2, 4, 3, -3, 5]:

Move Distance From Stops on Vacuums Dirt left in the hall
1 2 0 2 yes 3
2 4 2 6 yes 2
3 3 6 9 yes 1
4 -3 9 6 yes 0, so the answer is 4
5 5 6 7 (bounce) no 0
>>> clean(hall, [2, 4, 3, -3, 5])
([0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 4)
>>> clean(hall, [2, 4, 3, 5])
([0, 0, 0, 0, 0, 0, 1, 0, 0, 0], -1)
Trace it: what does clean(hall, [6, 3, -3]) return?

([0, 0, 1, 0, 0, 0, 0, 0, 0, 0], -1). The robot stops on 6, 9, and 6 again, so spot 6's mess gets both of its passes, but it never goes back for spot 2.

Do not vacuum the hall you were given

clean must not change the hall list passed into it; Gradescope checks. Build a new list of the dirt that is left, one item at a time, before the robot starts, and vacuum that one instead. While you build it, you can add up how much dirt there is in total.

Test it before you submit

Press Run. Until clean works, the main block stops with a TypeError, and that is expected, not a sign you broke something. Your functions are still defined, so you can call each one in the Shell as you finish it, using the examples on this page and in the docstrings. Then try to break your own code: a hall with no dirt, a run with no moves, a drive that ends exactly on a wall.

When all three work, the main block runs the robot in a 12-spot hall, and you get to see the result:

Before: [0, 0, 0, 1, 0, 0, 2, 0, 0, 0, 1, 1]
After:  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Clean after move 6 of 8

The moves are [3, 3, 7, 1, 1, -5, -8, 4]. Before you submit, work out on paper where the robot stops after moves 3 and 7, both of which bonk a wall, and check your step agrees.

Rules

Only what we have covered

Gradescope rejects a submission that uses any of these:

  • a while loop (Week 9)
  • in or not in as a test, like if spot in spots: (Week 8); a for loop's in is fine
  • slicing, like hall[2:5] (Week 10)
  • a list comprehension (Week 11)
  • copy(), list(), count(), index(), extend(), sum(), max(), min(), or abs()

Each of these would do a loop's job for you, and writing the loop yourself is what this PA is for.

Do not change the lists you are given

None of the functions may change a list passed into it: make_hall leaves spots and amounts alone, and clean leaves hall and moves alone. Gradescope checks.

Submission

Submit vacuum.py to the Gradescope assignment PA1b Robot Vacuum, then commit and push your Week06 folder (how).

Gradescope also checks that your name and the date are in the docstring, and that ruff check is clean.