Pale Machine CSE101
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.
- hoover.py
- room1.txt
- room2.txt
- room3.txt
- robot_example.svg
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.
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).
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 codeComplete 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 codeTesting
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 codeTesting
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 gridstate: 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 codeComplete 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 codeTesting
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:
xsizewhich is the number of squares in x direction of the grid,ysizewhich 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 beingTileobjects 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:
roomwhich is an instance of the room classrobotwhich 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 codeTesting
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 codeTest 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 codeTest 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 codeTest 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!)