This assignment will be closed on February 13, 2026 (23:59:59).
You must be authenticated to submit your files

Pale Machine CSE101

SJBerkemer

Objectives

What we will evaluate today: Everything!

Setup: Before you start

Launch Spyder (from the Applications/Programming menu). If you see a “Spyder update” message, just click OK and ignore it.

Before you start: create a new project, called PracticalExam_2 (using “New Project” from the “Projects” menu). This will ensure that files from last week (and future weeks) do not get mixed up together.

Now download the following files located in the same moodle folder as the exam and save them in your PracticalExam_2 folder. You can use save as, and choose your PracticalExam_2 folder.

Check and make sure that they have all appeared in your PracticalExam_2 project in Spyder.

Now open the file named hoover.py. This is the file in which you will be writing your code today. We already provide a code basis, you have to fill in the missing parts.

Upload form is only available when connected
# Introduction

Before the holidays, you have to clean your room. To save some time, you want to automatize the vacuum cleaning by using a vacuum cleaning robot. The image below shows an example.

Your room will be divided into square tiles with coordinates (x,y). Your robot will start at its base (B). The base is currently located at position (1,1) but it can be anywhere in the room. Then the vacuum cleaning robot will go through the room and clean every tile it passes. The robot will have to go around the furniture (X) and make sure to not fall down the stairs (S). The robot can only continue as long as it has enough energy. The image below gives an example of the room where # shows the dirty and . the clean tiles. The arrow shows the robot position and its orientation. The numbers show the x and y coordinates of the room tiles.

We will implement the robot as its own class (Robot) as well as the single tiles (Tile) and the room in another class (Room).

Example

Exercises

Exercise 1: Directions

Look at the three lists in the beginning of the file hoover.py: Directions, Direction_steps and Direction_chars. They will be used to turn and move the robot to the right positions.

Directions = ["north", "east", "south", "west"]
Direction_chars = ["^", ">", "v", "<"]
Direction_steps = [(0,1), (1,0), (0,-1), (-1,0)]

Run the following examples in order to see how these lists will be used.

In [1]: myorientation = "south"
In [2]: myindex = Directions.index(myorientation)
In [3]: myindex
Out[4]: 2
In [5]: mychar = Direction_chars[myindex]
In [6]: mychar
Out[7]: 'v'
In [8]: mystep = Direction_steps[myindex]
In [9]: mystep
Out[10]: (0, -1)
In [11]: myposition = (3,2)
In [12]: newposition = (myposition[0]+mystep[0],myposition[1]+mystep[1])
In [13]: newposition
Out[14]: (3, 1)

We will need these directions in the next exercises in order to change the robot’s orientation to the left or right and to move one step in the direction of the orientation.

Exercise 2: Robot

We first look at the class Robot to represent the vacuum cleaning robot. The robot is defined by its position in the room, its energy level, and its orientation. Additionally, it stores the position of its base which is also the starting point of the robot, thus the __init__ function will set the robot’s position to it’s base in the beginning.

Note that the coordinates of the room tiles are always given as (x,y) where x is the column number and y the row number as shown in the image above.

Your class Robot begins as follows:

class Robot:
    """
    Encapsulates the robot and its properties
    
    Data Attributes:
    position     -- the current position of the robot in the room (x,y), initialized with base_pos
    energy   	 -- the energy level of the robot
    orientation	 -- the orientation of the robot (north, east, south, west)
    base_pos	 -- position of the base
    """

    def __init__(self, posx, posy, energy, orientation):
		self.base_pos = (posx,posy)
		pass  # remove this line and replace with your own code

    def __str__(self):
		pass  # remove this line and replace with your own code

Complete the two methods __init__ and __str__.

Testing

Test your class Robot in the console, for example as follows:

In [15]: robo = Robot(1, 1, 100, "north")

In [16]: print(robo)
Vacuum cleaning robot:
Position (1, 1)
Energy 100
Orientation north
Base (1, 1)

In [17]: robo.position = (4,3) 

In [18]: print(robo)
Vacuum cleaning robot:
Position (4, 3)
Energy 100
Orientation north
Base (1, 1)

In [19]: robo.energy = 42

In [20]: print(robo)
Vacuum cleaning robot:
Position (4, 3)
Energy 42
Orientation north
Base (1, 1)

Exercise 3: Robot Moves

Now complete the method move in the Robot class: The method move(self) moves the robot one step in the direction of its orientation by updating the position and reduce energy by -1. If the energy is 0, the robot will stay on its position.

Hint: use the examples from the first exercise (e.g. Direction_steps) in order to get the steps right.

def move(self):
    """
    Checks if energy > 0, then updates the position by 1 corresponding to the 
    robot's orientation and decreases the energy by 1.
    """
    pass  # remove this line and replace with your own code

Testing

Test your class Robot in the console, for example as follows:

In [21]: robo = Robot(1, 1, 100, "north")
In [22]: print(robo)
Vacuum cleaning robot:
Position (1, 1)
Energy 100
Orientation north
Base (1, 1)

In [23]: robo.move()
In [24]: print(robo)
Vacuum cleaning robot:
Position (1, 2)
Energy 99    
Orientation north
Base (1, 1)

In [25]: robo2 = Robot(3, 4, 100, "west")
In [26]: print(robo2)
Vacuum cleaning robot:
Position (3, 4)
Energy 100
Orientation west
Base (3, 4)

In [27]: robo2.move()
In [28]: print(robo2)
Vacuum cleaning robot:
Position (2, 4)
Energy 99    
Orientation west
Base (3, 4)

In [29]: robo3 = Robot(2, 6, 1, "south")
In [30]: print(robo3)
Vacuum cleaning robot:
Position (2, 6)
Energy 1
Orientation south
Base (2, 6)

In [31]: robo3.move()
In [32]: print(robo3)
Vacuum cleaning robot:
Position (2, 5)
Energy 0    
Orientation south
Base (2, 6)

In [33]: robo3.move()
In [34]: print(robo3)
Vacuum cleaning robot:
Position (2, 5)
Energy 0    
Orientation south
Base (2, 6)

Note: It is important to test your function in the console as there is no grader feedback.

Exercise 4: Robot Turns

Now, complete the class Robot with two other methods: 1. turn_left(self) and 2. turn_right(self) that will update the orientation of the robot in the corresponding direction.

Hint: use the examples from the first exercise in order to get the directions right.

def turn_left(self):
    """
    Change orientation of the robot to the left 
    """
    pass  # remove this line and replace with your own code

def turn_right(self):
    """
    Change orientation of the robot to the right
    """
    pass  # remove this line and replace with your own code

Testing

Test your class Robot in the console, for example as follows:

In [35]: robo = Robot(1, 1, 100, "north")
In [36]: print(robo)
Vacuum cleaning robot:
Position (1, 1)
Energy 100
Orientation north
Base (1, 1)

In [37]: robo.turn_right()
In [38]: print(robo)
Vacuum cleaning robot:
Position (1, 1)
Energy 100
Orientation east
Base (1, 1)

In [39]: robo2 = Robot(3, 4, 100, "west")
In [40]: print(robo2)
Vacuum cleaning robot:
Position (3, 4)
Energy 100
Orientation west
Base (3, 4)

In [41]: robo2.turn_left()
In [42]: print(robo2)
Vacuum cleaning robot:
Position (3, 4)
Energy 100  
Orientation south
Base (3, 4)

Note: It is important to test your function in the console as there is no grader feedback.

Upload

Now take a moment to upload your hoover.py file to the moodle assignment corresponding to this exam.

(You can upload hoover.py several times, but only your final upload will be graded - don’t wait until the last moment to upload a preliminary version, in case you miss the cut-off!)

Exercise 5: Tiles

We imagine our room is organized by a grid of tiles each with a unique position. We now implement the class Tile with the following attributes:

  • coordinates: the x and y integer coordinates of the tile on the grid
  • state: a string that can be “clean” or “dirty”
  • kind: a string that can be “plain”, “base”, “furniture”, “stairs”

Our class Tile will therefore work as follows: Each object will get coordinates (x,y) and a kind which can be plain, base, stairs and furniture. As the room is really messy, each plain tile’sstate is set to dirty in the beginning. It will be set to clean as soon as the robot entered the tile. All the non-plain tiles will be clean from the beginning.

Look for the class in your python file and complete the methods __init__ and __str__.

class Tile:
    """
    Data Attributes:
    coordinates -- integer coordinates (x,y) of the tile
    state	-- a string: clean or dirty
    kind	-- a string: plain, base, furniture or stairs

    In the beginning, set all the plain tiles to dirty, all the others to clean.
    """

    def __init__(self, x, y, kind):
        pass  # remove this line and replace with your own code

    def __str__(self):
        pass  # remove this line and replace with your own code

Complete the method called clean(self) to the class Tile that changes the state of a tile from dirty to clean.

   def clean(self):
       pass  # remove this line and replace with your own code

Testing

You should be able to reproduce the following behavior:

In [43]: t1 = Tile(2,3,"plain")
In [44]: print(t1)
Coordinates (2, 3)
Kind plain
State dirty

In [45]: t1.clean()
In [46]: print(t1)
Coordinates (2, 3)
Kind plain
State clean

In [47]: t2 = Tile(5,6,"base")
In [48]: print(t2)
Coordinates (5, 6)
Kind base
State clean

Upload

Now take a moment to upload your hoover.py file to the moodle assignment corresponding to this exam.

(Remember, you can upload hoover.py several times, but only your final upload will be graded - don’t wait until the last moment to upload a preliminary version, in case you miss the cut-off!)

Exercise 6: The Room

Objects from the class Room have the following data attributes:

  • xsize which is the number of squares in x direction of the grid,
  • ysize which is the number of squares in y direction of the grid,
  • a dictionary tiles, whose keys are tuples of coordinates on the grid, with the corresponding values being Tile objects at those positions,
  • the position of the tile with the robot base
  • a list of coordinates that specify the furniture
  • the position of the stairs

Note: The coordinates of the grid are always between 1 and xsize or ysize!

Note 2 : To initialize a room object, you need xsize, ysize, the furniture list, the position of the stairs and the base position. If a robot, base or stairs position is set to (-1,-1) it means that they are not in the room! If the furniture list is empty, there is no furniture in the room!

Now, complete the __str__ method of your Room class and test your class Room and the already implemented method draw.

Note 3: The room.draw(position,orientation) will get the position and orientation of the robot as arguments in order to draw also the robot. However, if the robot position is (-1,-1), there is no robot in the room!

Testing

In [49]: b = Room(3,2,[],(-1,-1),(1,1))
In [50]: print(b)
Room of size 3x2
In [51]: b.draw((-1,-1), "north")
###
B##

In [52]: b2 = Room(4, 5, [(4,4),(1,5),(3,4)], (2,3), (1,1))
In [53]: print(b2)
Room of size 4x5
In [54]: b2.draw((-1,-1), "north")
X###
##XX
#S##
####
B###

In [55]: b3 = Room(4, 5, [(4,4),(1,5),(3,4)], (2,3), (1,1)) 
In [56]: print(b3)
Room of size 4x5
In [57]: robo = Robot(4,2,100,"east")
In [58]: print(robo)
Vacuum cleaning robot:
Position (4, 2)
Energy 100
Orientation east
Base (4, 2)

In [59]: b3.draw(robo.position,robo.orientation)
X###
##XX
#S##
###>
B###

Exercise 7: The RoboRun class

In order to control the behaviour of the robot, we create the class RoboRun that will combine all the classes so far.

Objects from the class RoboRun have the following data attributes:

  • room which is an instance of the room class
  • robot which is an instance of the robot class

The __init__ function of the class will initialize the robot object and get the room object as argument. For the robot, we will calculate its energy rounded to the next integer as int(xsize*ysize*1.5) and set the orientation as a default to north.

Write the __init__ and __str__ functions. Both should use the corresponding functions from the Robot and Room classes.

Note: The starting position of the robot will be the base.

Implement the __init__ and __str__ methods using the corresponding methods from the classes for Robot and Room.

class RoboRun:
        """
        The class RoboRun which organizes the course of the robot through the room
 	Data Attributes:
            room -- Room object
            robot -- Robot object
        """
    
	def __init__(self, room):
	    pass  # remove this line and replace with your own code


	def __str__(self):
	    pass  # remove this line and replace with your own code

Testing

In [60]: b3 = Room(4, 5, [(4,4),(1,5),(3,4)], (2,3), (1,1)) 
In [61]: print(b3)
Room of size 4x5

In [62]: rr = RoboRun(b3)
In [63]: print(rr)
RoboRun with
Vacuum cleaning robot:
Position (1, 1)
Energy 30
Orientation north
Base (1, 1)

and Room of size 4x5

In [64]: rr.room.draw(rr.robot.position, rr.robot.orientation)
X###
##XX
#S##
####
^###

Note If the robot is located on the base, only the robot is drawn.

Exercise 8: The allowed directions for the next step

Complete the method get_allowed_directions in the RoboRun class.

The method get_allowed_directions returns a list of possible directions the robot can move to (as defined in the Directions list in the first exercise). The robot can move by one tile north, east, south or west but it cannot move outside of the room, hence the coordinates cannot go below 1 or above xsize or ysize. The robot cannot move to a tile occupied by furniture but it can move onto the stairs which will result in the robot falling down such that it won’t be able to continue. If the robot can’t move, return an empty list.

Reminder Use the lists Directions and Direction_steps at the beginning of the file and the examples in exercise 1 to get the directions right.

    def get_allowed_directions(self):
        """
        Return a list of allowed Directions the robot could move to.
        The output list should contain the directions as defined in the 
        Directions list above and only if 
        - the next tile in the direction is not occupied by furniture 
        - and still inside the room
        """
        pass  # remove this line and replace with your own code

Test your methods in the console, for example as follows.

In [65]: room = Room(9, 6, [(4,4),(1,5),(3,4)], (2,3), (1,1))
In [66]: rr = RoboRun(room)
In [67]: print(rr)
RoboRun with
Vacuum cleaning robot:
Position (1, 1)
Energy 81
Orientation north
Base (1, 1)

and Room of size 9x6

In [68]: rr.room.draw(rr.robot.position,rr.robot.orientation)
#########
X########
##XX#####
#S#######
#########
^########

In [69]: npos = rr.get_allowed_directions()
In [70]: print(npos)
Out[71]: ['north', 'east']

In [72]: rr.robot.move()
In [73]: print(rr)
RoboRun with
Vacuum cleaning robot:
Position (1, 2)
Energy 80
Orientation north
Base (1, 1)

and Room of size 9x6

In [74]: rr.room.draw(rr.robot.position,rr.robot.orientation)
#########
X########
##XX#####
#S#######
^########
B########

In [75]: npos = rr.get_allowed_directions()
In [76]: print(npos)
Out[77]: ['north', 'east', 'south']

We allow printing the allowed directions in any order, so the output does not have to have exactly the same order.

Upload

Now take a moment to upload your hoover.py file to the moodle assignment corresponding to this exam.

(Remember, you can upload hoover.py several times, but only your final upload will be graded - don’t wait until the last moment to upload a preliminary version, in case you miss the cut-off!)

Exercise 9: One step

Our robot vacuum cleaner will run in rounds. It will be able to do one step per round which includes:

  • getting the allowed directions,
  • choosing one of the directions,
  • cleaning the tile the robot is on,
  • setting the new direction,
  • moving to the next position according to the direction.

As our robot doesn’t have a good strategy, we will use random.choice to choose one of the next possible positions. Hence random.choice(inputlist) will return an element of the inputlist.

Hint: We recommend to use already implemented functions (e.g. robot.move, tile.clean).

Note 1: As we choose the next position randomly, your output may look different!

Note 2: The robot is able to move onto the stairs currently, we will implement this in the next step!

Complete the method one_round(self) in the RoboRun class.

    def one_round(self):
        """
        Get allowed directions,
        choose one direction randomly,
        clean the tile the robot is on,
        set the new direction,
        move to the next tile accordingly.
	"""
        pass  # remove this line and replace with your own code

Test your methods in the console, for example as follows.

In [78]: room = Room(9, 6, [(4,4),(1,5),(3,4),(9,2),(9,3)], (-1,-1), (1,1))
In [79]: rr = RoboRun(room)
In [80]: print(rr)
RoboRun with
Vacuum cleaning robot:
Position (1, 1)
Energy 81
Orientation north
Base (1, 1)

and Room of size 9x6

In [81]: rr.one_round()
In [82]: rr.room.draw(rr.robot.position,rr.robot.orientation)
#########
X########
##XX#####
########X
^#######X
B########

In [83]: rr.one_round()
In [84]: rr.room.draw(rr.robot.position,rr.robot.orientation)
#########
X########
##XX#####
########X
.>######X
B########

In [85]: rr.one_round()
In [86]: rr.room.draw(rr.robot.position,rr.robot.orientation)
#########
X########
##XX#####
#^######X
..######X
B########

Exercise 10: Robo run!

We now have everything to let the robot run automatically through the room as long as it has enough energy and doesn’t fall down the stairs (if any). Write a method run(self) into the class RoboRun which lets the robot run as long as it did not hit the stairs and still has energy.

The method should:

  • count the rounds
  • print START as well as the room and robot at the beginning
  • print the round number every round
  • print the room every 10 rounds
  • print END as well as the room and robot after the run ended

Complete the method run(self) in the class RoboRun.

    def run(self):
        """
        Let the robot run as long as the robot still has energy and did not fall down the stairs
        Print START as well as the room and robot at the beginning
        Print the round number every round
        Print the room every 10 rounds
        Print END as well as the room and robot after the run ended
        """
	
        pass  # remove this line and replace with your own code

Test your methods in the console, for example as follows.

In [87]: room = Room(2, 3, [], (-1,-1), (1,1))
In [88]: rr = RoboRun(room)
In [89]: rr.run()
START
##
##
^#

Vacuum cleaning robot:
Position (1, 1)
Energy 9
Orientation north
Base (1, 1)

ROUND 1
ROUND 2
ROUND 3
ROUND 4
ROUND 5
ROUND 6
ROUND 7
ROUND 8
ROUND 9
END
..
..
Bv

Vacuum cleaning robot:
Position (2, 1)
Energy 0
Orientation south
Base (1, 1)

In [90]: room2 = Room(3, 4, [(2,2),(2,3)], (-1,-1), (1,1))
In [91]: rr2 = RoboRun(room2)
In [92]: rr2.run()
START
###
#X#
#X#
^##

Vacuum cleaning robot:
Position (1, 1)
Energy 18
Orientation north
Base (1, 1)

ROUND 1
ROUND 2
ROUND 3
ROUND 4
ROUND 5
ROUND 6
ROUND 7
ROUND 8
ROUND 9
ROUND 10
###
#X^
.X.
B..

ROUND 11
ROUND 12
ROUND 13
ROUND 14
ROUND 15
ROUND 16
ROUND 17
ROUND 18
END
.>.
#X.
.X.
B..

Vacuum cleaning robot:
Position (2, 4)
Energy 0
Orientation east
Base (1, 1)

In [93]: room3 = Room(3, 4, [(2,2),(2,3)], (2,4), (1,1))
In [94]: rr3 = RoboRun(room3)
In [95]: rr3.run()
START
#S#
#X#
#X#
^##

Vacuum cleaning robot:
Position (1, 1)
Energy 18
Orientation north
Base (1, 1)

ROUND 1
ROUND 2
ROUND 3
ROUND 4
ROUND 5
ROUND 6
ROUND 7
ROUND 8
END
.>#
.X#
.X#
B##

Vacuum cleaning robot:
Position (2, 4)
Energy 10
Orientation east
Base (1, 1)

Upload

Now take a moment to upload your hoover.py file to the moodle assignment corresponding to this exam.

(Remember, you can upload hoover.py several times, but only your final upload will be graded - don’t wait until the last moment to upload a preliminary version, in case you miss the cut-off!)

Exercise 11: Reading from a file

To test your function, it will be convenient to use pre-defined rooms. The three files (room1.txt, room2.txt and room3.txt) given at the top of this page contain the rooms we will have to clean.

We strongly encourage you to open the files room1.txt, room2.txt and room3.txt to see how they look like.

Write the function load_from_file(filename) (in hoover.py, outside the Robot, Tile, Room and RoboRun classes). The function should return a room object that can be used to initiate a RoboRun.

Hints:

  • The room coordinates are between 1 and xsize and 1 and ysize!
  • There are no spaces within the tuples!
  • The elements (ysize, xsize, stairs, base and furniture) can be in any order!
  • base and stairs do not have to be present, then they should be initialized with (-1,-1)
  • if no furniture is present, it should be initialized with []

Test your function, for example as follows:

In [95]: room1 = load_from_file('room1.txt')
In [96]: room1.draw((-1,-1),"north")
###B####
#XX##XX#
#XX##XX#
#XX##XX#
########
####S###


In [96]: room2 = load_from_file('room2.txt')
In [97]: room2.draw((-1,-1),"north")
XXX
###
###
##X
S#B
##X
###
###
XXX

In [97]: room3 = load_from_file('room3.txt')
In [98]: room3.draw((-1,-1),"north")
########
##X##X##
##X##X##
##XXXX##
####B###

Upload

Now take a moment to upload your hoover.py file to the moodle assignment corresponding to this exam.

(Remember, you can upload hoover.py several times, but only your final upload will be graded - don’t wait until the last moment to upload a preliminary version, in case you miss the cut-off!)