Problem Set 3: Robot Simulation
Please Log In for full access to the web site.
Note that this link will take you to an external site (https://shimmer.mit.edu) to authenticate, and then you will be redirected back to this page.
Download Files
Introduction
In this problem set, you will design a simulation and implement a program that uses classes to simulate robot movement. We recommend testing your code incrementally to see if your code is not working as expected. To test your code, run test_ps3.py
.
As always, please do not change any given function signatures. Remember to follow the 6.0002 Style Guide.
A) Simulation Overview
iRobot is a company (started by MIT alumni and faculty) that sells the Roomba vacuuming robot (watch one of the product videos to see these robots in action). Roomba robots move around the floor, cleaning the area they pass over.
You will code a simulation to compare how much time a group of Roomba-like robots will take to clean the floor of a room. The following simplified model of a single robot moving in a square 5x5 room should give you some intuition about the system we are simulating. A description and sample illustrations are below.
The robot starts out at some random position in the room. Its direction is specified by the angle of motion measured in degrees clockwise from “north.” Its position is specified from the lower left corner of the room, which is considered the origin (0.0, 0.0). The illustrations below show the robot's position (indicated by a black dot) as well as its direction (indicated by the direction of the red arrowhead).
t0
The robot starts at the position (2.1, 2.2) with an angle of 205 degrees (measured clockwise from "north"). The tile that it is on is now clean.
t1
The robot has moved 1 unit in the direction it was facing, to the position (1.7, 1.3), cleaning another tile.
t2
The robot has moved 1 unit in the same direction (205 degrees from north), to the position (1.2, 0.4), cleaning another tile.
t3
The robot could not have moved another unit in the same direction without hitting the wall, so instead it turns to face in a new, random direction, 287 degrees.
t4
The robot moves along its new direction to the position (0.3, 0.7), cleaning another tile.
B) Simulation Components:
Here are the components of the simulation model.
-
Room: Rooms are rectangles, divided into square tiles. At the start of the simulation, each tile is covered in some amount of dirt, which is the same across all the tiles. You will first implement the class BasicRoom in Problem 1.
-
Robot: Multiple robots can exist in the room. iRobot has invested in technology that allows the robots to exist in the same position as another robot without causing a collision. You will implement the abstract class Robot in Problem 1. You will then implement the subclasses ClassicRobot, MalfunctioningRobot and BetterRobot in Problems 2, 3, and 4.
More details about the properties of these components will be described later in the problem set.
C) Helper Code
We have provided an additional file: ps3_visualize.py
. This Python file contains helper code for visualizing your robot simulation. More information about this visualizer is located at the bottom of this pset. To test your code, run test_ps3.py
. You can comment out test suites at the bottom of test_ps3.py
to test just one part.
Note that any test containing the word Simulation (e.g. ps3_P5_Simple.testSimulation1
) will produce an error until you implement Problem 5 of the pset.
Read ps3.py
carefully before starting, so that you understand the provided code and its capabilities. Remember to carefully read the docstrings for each function to understand what it should do and what it needs to return.
The first task is to implement the class BasicRoom
and the abstract class Robot
.
In the skeleton code provided, the abstract class contains some methods which should only be implemented in the subclasses. If the comment for the method says “do not change,” please do not change it. You can test your code as you go along by running the provided tests in test_ps3.py
.
In ps3.py
, we've provided skeletons for these classes, which you will fill in for Problem 1. We've also provided for you a complete implementation of the class Position
. Do not change the Position
class.
Class Descriptions:
- BasicRoom - Represents the space to be cleaned and keeps track of which tiles have been cleaned.
- Robot - Stores the position, direction, and cleaning capacity of a robot.
- Position - Represents a location in x- and y-coordinates. x and y are floats satisfying 0 \leq x < w and 0 \leq y < h, where w and h are the room’s width and height.
BasicRoom Implementation Details:
- Representation:
- You will need to keep track of which parts of the floor have been cleaned by the robot(s). When a robot's location is anywhere inside a particular tile, we will consider the dirt on that entire tile to be reduced by some amount determined by the robot. We consider the tile to be "clean" when the amount of dirt on the tile is 0. We will refer to the tiles using ordered pairs of integers: (0, 0), (0, 1), …, (0, h-1), (1, 0), (1, 1), …, (w-1, h-1).
- Tiles can never have a negative amount of dirt.
- Starting Conditions:
- Initially, the entire floor is uniformly dirty. Each tile should start with an integer amount of dirt, specified by
dirt_amount
.
- Initially, the entire floor is uniformly dirty. Each tile should start with an integer amount of dirt, specified by
Robot Implementation Details:
- Representation
- Each robot has a position inside the room. We'll represent the position using an instance of the
Position
class. Remember thePosition
coordinates are floats. - A robot has a direction of motion. We'll represent the direction using a float
direction
satisfying 0 \leq direction < 360, which gives an angle in degrees from north. - A robot has a cleaning capacity, capacity, which describes how much dirt is cleaned on each tile at each time.
- A robot has a speed. We’ll represent the speed using a positive float.
- Each robot has a position inside the room. We'll represent the position using an instance of the
- Starting Conditions
- Each robot should start at a random position in the room (hint: the
Robot’s
room
attribute has a method you can use)
- Each robot should start at a random position in the room (hint: the
- Movement Strategy
- A robot moves according to its movement strategy, which you will implement in
update_position_and_clean
.
- A robot moves according to its movement strategy, which you will implement in
If you find any places above where the specification of the simulation dynamics seems ambiguous, it is up to you to make a reasonable decision about how your program/model will behave, and document that decision in your code.
Complete the BasicRoom class and Robot abstract class by implementing their methods according to the specifications in ps3.py. You should now be passing all tests under ps3_1A
and ps3_1B
. Remember that the Robot class will never be instantiated; we will only instantiate its subclasses.
Hints:
- Make sure to think carefully about what kind of data type you want to use to store information about the floor tiles in the
BasicRoom
class. - A majority of the methods should require only one line of code.
- In the final implementation of the
Robot
abstract class, not all methods will be implemented. Not to worry — their subclass(es) will implement them (e.g.,Robot’s
subclasses will implement the methodupdate_position_and_clean
). - Remember that tiles are represented using ordered pairs of integers (0, 0), (0, 1), …, (0, h-1), (1, 0), (1, 1), …, (w-1, h-1). But a robot’s
Position
is specified as floats (x, y). Be careful converting between the two! We recommend usingmath.floor(x)
to always round down when converting to ensure thatPosition
s are always in the room. - Remember to give the robot an initial random position and direction. The robot’s position should be an instance of the
Position
class and should be a valid position in the room. Note that the classBasicRoom
has aget_random_position
method that may be useful for this. - Your implementation may occasionally fail a few simulation tests. This is ok, and will not be counted against you as long as all of the tests pass most of the time.
Each robot must also have some code that tells it how to move about a room, which will go in a method called update_position_and_clean
.
We have already refactored the robot code for you into two classes: the abstract Robot
class you completed above (which contains general robot code), and a ClassicRobot
class inheriting from it (which contains its own movement strategy).
The movement strategy for ClassicRobot
is as follows. In each time-step:
- Calculate what the new position for the robot would be if it moved straight in its current direction at its given speed.
- If that is a valid position, move there and then clean the tile corresponding to that position by the robot’s capacity. The position is valid if it is in the room. Do not worry about the robot’s path in between the old position and the new position.
- Otherwise, rotate the robot to be pointing in a random new direction. Don’t clean the current tile or move to a different tile.
We have provided the get_new_position
method of the Position
class, which you may find helpful in implementing this. It computes and returns the new Position
for the current Position
object after a single clock-tick has passed with the given angle and speed parameters. Read the docstring for this method for more information.
Complete the update_position_and_clean method of ClassicRobot to simulate the motion of the robot during a single time-step (as described above in the time-step dynamics). You should now be passing ps3_P3
.
Testing Your Code:
Before moving on to Problem 3, check that your implementation of ClassicRobot
works by uncommenting the following line under your implementation of ClassicRobot
:
test_robot_movement(ClassicRobot, BasicRoom)
The test file will display a 5 by 5 room as implemented in BasicRoom
and a robot as implemented in ClassicRobot
. Initially, all dirty tiles are marked as black. As the robot visits each tile and cleans the tile according to its given capacity, the color of the tile changes from black to gray to white, with white meaning the tile is completely clean.
Make sure that as your robot moves around the room, the tiles get lighter (from black to gray to white as shown below on page 10) each time when your robot traverses. The simulation terminates when the robot finishes cleaning the entire room. Make sure your robot doesn’t violate any of the simulation specifications (e.g., your robot should never move to a position outside of the room, it should never clean the tile if it also had to choose a new direction, etc.)
Do not worry if it appears your robot is "cutting corners" as it cleans, as long as its final position in each time step is never outside of the room. When you've checked that your robot moves correctly, make sure to comment out the test_robot_movement
line.
iRobot’s roombas have become quite the hit sensation. And the company wants more people to be able to take advantage of their product. iRobot has made a cheaper version of the roomba, but it doesn’t hold the dirt as securely as the ClassicRobot. Therefore, sometimes, the MalfunctioningRobot will drop some dirt on a tile instead of cleaning it. You wonder how badly this affects the time it takes a robot to clean a room and decide to design a simulation.
Note: Whether the robot drops dirt or not is determined for each timestep. If your robot drops dirt at one timestep, it may or may drop dirt again at the next timestep.
Complete the class MalfunctioningRobot that inherits from Robot (just as ClassicRobot inherits) but factors in the dropped dirt behavior. MalfunctioningRobot should have its own implementation of update_position_and_clean.
The behavior for a MalfunctioningRobot
is outlined in the docstring.
We have written a method dropping_dirt
inside MalfunctioningRobot
for you that you should use in order to determine if your robot drops dirt on a tile. Initially the robot drops dirt with probability p = 0.05. If the robot does drop dirt, the amount of dirt that will be dropped is a random decimal value between 0 (inclusive) and 0.5 (exclusive). (think about what this means in terms of how ‘clean’ a tile becomes). As with ClassicRobot
, you may find the provided get_new_position
method of Position
helpful.
Testing Your Code
Test out your new class. Perform a single trial with the new MalfunctioningRobot
implementation and watch the visualization to make sure it behaves as expected.
test_robot_movement(MalfunctioningRobot, BasicRoom)
To accommodate impatient customers, iRobot churned out a batch of BetterRobots. These robots are able to clean two tiles in one timestep by using super boosters. However, if they hit a wall, they might knock dust off the wall and dirty a tile.
You must also design a simulation to determine how badly this affects the time it takes a robot to clean a room.
Complete the class BetterRobot
that inherits from Robot
(just as ClassicRobot
inherits) but implements a new movement strategy. BetterRobot
should have its own implementation of update_position_and_clean
.
If the BetterRobot
hits a wall when it attempts to move in its current direction, it may dirty the tile adjacent to the wall because it moves very fast and can knock dust off of the wall. This will increase the dirtiness of the tile by 1.
There are three possible cases:
- The robot tries to move. If it immediately hits the wall, it does not move forward, turns to face a random direction, and stops for this timestep. It does not dirty the tile with any probability, because it was not traveling fast when it hit the wall. An example of this case is shown below.

- If the robot can move, it moves and cleans the tile it moves to. Then, it tries to move a second time. If it hits the wall, it dirties the tile it is on by one unit with probability p. After hitting the wall, regardless of whether it dirties the tile, the robot turns to a random direction and then stops. An example of this case is shown below.

- If the robot can move, it moves and cleans the tile it moves to. Then, it tries to move a second time. If it does not hit the wall, it moves and cleans the tile it moves to.
We have written a method dropping_dirt
inside BetterRobot
for you that you should use in order to determine if the robot coughs up dust. Initially the robot dirties the tiles adjacent to the wall with probability p = 0.15. As with ClassicRobot
, you may find the provided get_new_position
method of Position
helpful.
Testing Your Code
Test out your new class. Perform a single trial with the new BetterRobot
implementation and watch the visualization to make sure it behaves as expected.
test_robot_movement(BetterRobot, BasicRoom)
In this problem you will write code that:
- Simulates the robot(s) cleaning the room up to a specified fraction of the room; and
- Returns the mean number of time-steps needed to clean the room.
Once you have written this code, you’ll comment on the results of your simulation in Problem 6.
Implement run_simulation(num_robots, speed, capacity, width, height, dirt_amount, min_coverage, num_trials, robot_type)
according to its specification.
Simulation Starting Conditions:
- Each simulation should begin with a new room.
- Each robot in that simulation should start at a random position in that room.
- Each room should start with a uniform amount of dirt on each tile, given by
dirt_amount
.
The simulation terminates when a specified fraction of the room tiles have been fully cleaned (i.e., the amount of dirt on those tiles is 0).
Simulation Animation:
If you want to see a visualization of your simulation, similar to the visualization that pops up when you call test_robot_movement
, check the end of this pset for instructions!
The first six parameters of run_simulation
should be self-explanatory. If you are confused, check the docstrings. For the time being, you should pass in ClassicRobot
for the robot_type
parameter, like so:
avg = run_simulation(10, 1.0, 1, 15, 20, 5, 0.8, 30, ClassicRobot)
Then, in run_simulation
you should use robot_type(…)
instead of ClassicRobot(...)
whenever you wish to instantiate a robot. (This will allow us to easily adapt the simulation to run with different robot implementations, which you'll encounter in Problem 6.) Feel free to write whatever helper functions you wish. You should now be passing all of the test cases.
Now, use your simulation to answer some questions about the robots' performance. In order to do this problem, you will be using a Python package called pylab
(aka matplotlib
). If you want to learn more about pylab
, please read this tutorial.
For the questions below, uncomment the function calls provided (at the very end of the problem set) and run the code to generate a plot using pylab, and then answer the corresponding questions underneath the function calls in ps3.py
.
-
Examine
show_plot_compare_strategies
inps3.py
, which takes in the parameters title,x_label
, andy_label
. It outputs a plot comparing the performance of all types of robots in a 20x20BasicRoom
with 3 units of dirt on each tile and 80% minimum coverage, with a varying number of robots with speed of 1.0 and cleaning capacity of 1. Uncomment the call toshow_plot_compare_strategies
, and answer question #1. Depending on your computer, it may take a few minutes for the plot to show up. Remember to comment this out when submitting your pset. -
Examine
show_plot_room_shape
inps3.py
, which takes in the same parameters asshow_plot_compare_strategies
. This figure compares how long it takes two of each type of robot to clean 80% ofBasicRooms
with dimensions 10x30, 20x15, 25x12, and 50x6 (notice that the rooms have the same area.) Uncomment the call toshow_plot_room_shape
, and answer question #2. Depending on your computer, it may take a few minutes for the plot to show up. Remember to comment this out when submitting your pset.
Visualizing Robot Simulation
We've provided some code to generate animations of your robots as they go about cleaning a room. These animations can also help you debug your simulation by helping you to visually determine when things are going wrong.
Running the Visualization:
- In your simulation, at the beginning of a trial, do the following to start an animation:
anim = ps3_visualize.RobotVisualization(num_robots, width, height, delay)
- Pass in parameters appropriate to the trial, of course.
delay
is an optional parameter that is discussed below. This will open a new window to display the animation and draw a picture of the room. - Then, during each time-step, after the robot(s) move, do the following to draw a new frame of the animation:
anim.update(room, robots)
whereroom
is aBasicRoom
object and robots is a list of Robot objects representing the current state of the room and the robots in the room. - When the trial is over, call the following method:
anim.done()
The resulting animation will look like this:

Initially, all dirty tiles are marked as black. As the robot cleans each tile by its given capacity, the color of the tile transits from black to gray to white, with white means completely clean.
The visualization code slows down your simulation so that the animation doesn't zip by too fast (by default, it shows 5 time-steps every second). Naturally, you will want to avoid running the animation code if you are trying to run many trials at once.
Delay:
For purposes of debugging your simulation, you can slow down the animation even further. You can do this by changing the call to RobotVisualization
, as follows:
anim = ps3_visualize.RobotVisualization(num_robots, width, height, delay)
The parameter delay specifies how many seconds the program should pause between frames. The default is 0.2 (5 frames/second). You can raise this value to make the animation slower.
For problem 6, we will make calls to run_simulation()
to get simulation data and plot it. However, you don't want the visualization getting in the way. If you choose to do this visualization exercise, before you get started on problem 6 and before you turn your problem set in, make sure to comment out the visualization code out of run_simulation().
1. Save
Save your solution as ps3.py
2. Test
Run your file to make sure it has no syntax errors. Test your run_simulation
to make sure that it still works with all of the ClassicRobot
, MalfunctioningRobot
and BetterRobot
classes. Make sure that plots are produced when you run the two functions in problem 6 and verify that the results make sense. Make sure all the tests run.
3. Time and Collaboration Info
At the start of ps3.py, in a comment, write down the number of hours (roughly) you spent on the problems in that part, and the names of the people you collaborated with. For example:
# Problem Set 3
# Name: Jane Lee
# Collaborators: John Doe
# Time: x hours
Note: Passing all of the tests in the local tester does not necessarily mean you will receive a perfect score. The staff will run additional tests on your code to check for correctness.
4. Submission
The tester file contains a subset of the tests that will be run to determine the problem set grade.
You may upload new versions of each file until the 9PM deadline, but anything uploaded after that time will be counted towards your late days, if you have any remaining. If you have no remaining late days, you will receive no credit for a late submission.
When you upload a new file with the same name, your old one will be overwritten.