Learn faster and stay on-track by joining this free class with other self-learners.
Register for MIT OpenCourseWare 6.00 Introduction to Computer Science and Programming now.
|
MIT OpenCourseWare 6.00 Introduction to Computer Science and ProgrammingClass length: 24 weeks. Start anytime. Creator: duallain Status: Established |
Join this class! |
|
Lesson 19: Assignment 1: PS 11Homework Submissions8 total# Problem Set 11: Simulating robots
# Name:
# Collaborators:
# Time:
import math, random, pylab
import ps11_visualize
# === Provided classes
class Position(object):
"""
A Position represents a location in a two-dimensional room.
"""
def __init__(self, x, y):
"""
Initializes a position with coordinates (x, y).
x: a real number indicating the x-coordinate
y: a real number indicating the y-coordinate
"""
self.x = x
self.y = y
def getX(self):
return self.x
def getY(self):
return self.y
def getNewPosition(self, angle, speed):
"""
Computes and returns the new Position after a single clock-tick has
passed, with this object as the current position, and with the
specified angle and speed.
Does NOT test whether the returned position fits inside the room.
angle: integer representing angle in degrees, 0 <= angle < 360
speed: positive float representing speed
Returns: a Position object representing the new position.
"""
old_x, old_y = self.getX(), self.getY()
# Compute the change in position
delta_y = speed * math.cos(math.radians(angle))
delta_x = speed * math.sin(math.radians(angle))
# Add that to the existing position
new_x = old_x + delta_x
new_y = old_y + delta_y
return Position(new_x, new_y)
# === Problems 1 and 2
class RectangularRoom(object):
"""
A RectangularRoom represents a rectangular region containing clean or dirty
tiles.
A room has a width and a height and contains (width * height) tiles. At any
particular time, each of these tiles is either clean or dirty.
"""
def __init__(self, width, height):
"""
Initializes a rectangular room with the specified width and height.
Initially, no tiles in the room have been cleaned.
width: an integer > 0
height: an integer > 0
"""
self.width = int(width)
self.height = int(height)
self.tiles = []
self.cleaned = []
for h in range(0,height):
for w in range(0,width):
self.tiles.append((w,h))
def cleanTileAtPosition(self, pos):
"""
Mark the tile under the position POS as cleaned.
Assumes that POS represents a valid position inside this room.
pos: a Position
"""
self.cleaned.append((int(pos.getX()),int(pos.getY())))
def isTileCleaned(self, m, n):
"""
Return True if the tile (m, n) has been cleaned.
Assumes that (m, n) represents a valid tile inside the room.
m: an integer
n: an integer
returns: True if (m, n) is cleaned, False otherwise
"""
return (m,n) in self.cleaned
def getNumTiles(self):
"""
Return the total number of tiles in the room.
returns: an integer
"""
return len(self.tiles)
def getNumCleanedTiles(self):
"""
Return the total number of clean tiles in the room.
returns: an integer
"""
return len(self.cleaned)
def getRandomPosition(self):
"""
Return a random position inside the room.
returns: a Position object.
"""
return Position(random.randint(0,self.width),random.randint(0,self.height))
def isPositionInRoom(self, pos):
"""
Return True if POS is inside the room.
pos: a Position object.
returns: True if POS is in the room, False otherwise.
"""
return 0 <= pos.getX() < self.width and 0 <= pos.getY() < self.height
class BaseRobot(object):
"""
Represents a robot cleaning a particular room.
At all times the robot has a particular position and direction in
the room. The robot also has a fixed speed.
Subclasses of BaseRobot should provide movement strategies by
implementing updatePositionAndClean(), which simulates a single
time-step.
"""
def __init__(self, room, speed):
"""
Initializes a Robot with the given speed in the specified
room. The robot initially has a random direction d and a
random position p in the room.
The direction d is an integer satisfying 0 <= d < 360; it
specifies an angle in degrees.
p is a Position object giving the robot's position.
room: a RectangularRoom object.
speed: a float (speed > 0)
"""
self.room = room
self.speed = float(speed)
self.p = self.room.getRandomPosition()
self.d = random.randint(0,359)
def getRobotPosition(self):
"""
Return the position of the robot.
returns: a Position object giving the robot's position.
"""
return self.p
def getRobotDirection(self):
"""
Return the direction of the robot.
returns: an integer d giving the direction of the robot as an angle in
degrees, 0 <= d < 360.
"""
return self.d
def setRobotPosition(self, position):
"""
Set the position of the robot to POSITION.
position: a Position object.
"""
self.p = position
def setRobotDirection(self, direction):
"""
Set the direction of the robot to DIRECTION.
direction: integer representing an angle in degrees
"""
self.d = direction
class Robot(BaseRobot):
"""
A Robot is a BaseRobot with the standard movement strategy.
At each time-step, a Robot attempts to move in its current
direction; when it hits a wall, it chooses a new direction
randomly.
"""
def updatePositionAndClean(self):
"""
Simulate the passage of a single time-step.
Move the robot to a new position and mark the tile it is on as having
been cleaned.
"""
moving = True
while moving:
new_p = self.p.getNewPosition(self.d,self.speed)
if self.room.isPositionInRoom(new_p):
self.setRobotPosition(new_p)
#print new_p.getX(), new_p.getY()
if not self.room.isTileCleaned(int(new_p.getX()),int(new_p.getY())):
self.room.cleanTileAtPosition(new_p)
#print 'cleaned'
moving = False
else:
#print 'new direction'
self.setRobotDirection(random.randint(0,359))
continue
# Testing Problem 1 and 2
##room = RectangularRoom(5,5)
##robby = Robot(room,1)
##robby.updatePositionAndClean()
##robby.updatePositionAndClean()
##robby.updatePositionAndClean()
##print room.getNumCleanedTiles()/float(room.getNumTiles())
# === Problem 3
def runSimulation(num_robots, speed, width, height, min_coverage, num_trials,
robot_type, visualize):
"""
Runs NUM_TRIALS trials of the simulation and returns a list of
lists, one per trial. The list for a trial has an element for each
timestep of that trial, the value of which is the percentage of
the room that is clean after that timestep. Each trial stops when
MIN_COVERAGE of the room is clean.
The simulation is run with NUM_ROBOTS robots of type ROBOT_TYPE,
each with speed SPEED, in a room of dimensions WIDTH x HEIGHT.
Visualization is turned on when boolean VISUALIZE is set to True.
num_robots: an int (num_robots > 0)
speed: a float (speed > 0)
width: an int (width > 0)
height: an int (height > 0)
min_coverage: a float (0 <= min_coverage <= 1.0)
num_trials: an int (num_trials > 0)
robot_type: class of robot to be instantiated (e.g. Robot or
RandomWalkRobot)
visualize: a boolean (True to turn on visualization)
"""
results = []
for i in xrange(0,num_trials):
coverage = 0
trial = []
robots = []
room = RectangularRoom(width,height)
for n in xrange(0,num_robots):
robots.append(robot_type(room, speed))
if visualize:
anim = ps11_visualize.RobotVisualization(num_robots, width, height)
# Simulate a trial
while coverage < min_coverage:
for robot in robots:
robot.updatePositionAndClean()
if visualize:
anim.update(room, robots)
coverage = room.getNumCleanedTiles()/float(room.getNumTiles())
trial.append(coverage)
if visualize:
anim.done()
results.append(trial)
return results
# Testing Problem 3
#avg = runSimulation(1, 1.0, 5, 5, 1.0, 5, Robot, True)
# === Provided function
def computeMeans(list_of_lists):
"""
Returns a list as long as the longest list in LIST_OF_LISTS, where
the value at index i is the average of the values at index i in
all of LIST_OF_LISTS' lists.
Lists shorter than the longest list are padded with their final
value to be the same length.
"""
# Find length of longest list
longest = 0
for lst in list_of_lists:
if len(lst) > longest:
longest = len(lst)
# Get totals
tots = [0]*(longest)
for lst in list_of_lists:
for i in range(longest):
if i < len(lst):
tots[i] += lst[i]
else:
tots[i] += lst[-1]
# Convert tots to an array to make averaging across each index easier
tots = pylab.array(tots)
# Compute means
means = tots/float(len(list_of_lists))
return means
# === Problem 4
def showPlot1():
"""
Produces a plot showing dependence of cleaning time on room size.
"""
num_robots = 1
speed = 1.0
min_coverage = 0.75
num_trials = 100
robot_type = Robot
visualize = False
rooms = [5,10,15,20,25]
means = []
area = []
for i in range(len(rooms)):
width = rooms[i]
height = rooms[i]
sim = runSimulation(num_robots, speed, width, height, min_coverage, num_trials, robot_type, visualize)
avg = plotHelper(sim)
area.append(width*height)
means.append(avg)
pylab.figure()
pylab.plot(area, means)
pylab.ylabel('Timesteps')
pylab.xlabel('Room area')
pylab.title('Time to clean %d percent of a square room of various areas with %d robots (%d trials)' % (min_coverage*100, num_robots, num_trials))
def showPlot2():
"""
Produces a plot showing dependence of cleaning time on number of robots.
"""
num_robots = range(1,11)
speed = 1.0
min_coverage = 0.75
num_trials = 100
robot_type = Robot
visualize = False
width, height = (25, 25)
means = []
for bot in num_robots:
sim = runSimulation(bot, speed, width, height, min_coverage, num_trials, robot_type, visualize)
avg = plotHelper(sim)
means.append(avg)
pylab.figure()
pylab.plot(num_robots, means)
pylab.ylabel('Timesteps')
pylab.xlabel('Number of Robots')
pylab.title('Time to clean %d percent of a 25x25 room with multiple robots (%d trials)' % (min_coverage*100, num_trials))
def showPlot3():
"""
Produces a plot showing dependence of cleaning time on room shape.
"""
num_robots = 2
speed = 1.0
min_coverage = 0.75
num_trials = 100
robot_type = Robot
visualize = False
rooms = [(20,20),(25,16),(40,10),(50,8),(80,5),(100,4)]
means = []
ratio = []
for i in range(len(rooms)):
width, height = rooms[i]
sim = runSimulation(num_robots, speed, width, height, min_coverage, num_trials, robot_type, visualize)
avg = plotHelper(sim)
ratio.append(width/float(height))
means.append(avg)
pylab.figure()
pylab.plot(ratio, means)
pylab.axis([0,25,0, 400])
pylab.ylabel('Timesteps')
pylab.xlabel('Ratio of Width to Height')
pylab.title('Time to clean %d percent of a rectangular room with %d robots (%d trials)' % (min_coverage*100, num_robots, num_trials))
def showPlot4():
"""
Produces a plot showing cleaning time vs. percentage cleaned, for
each of 1-5 robots.
"""
num_robots = range(1,6)
speed = 1.0
min_coverage = [0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0]
num_trials = 10
robot_type = Robot
visualize = False
width, height = (25, 25)
pylab.figure()
for bot in num_robots:
means = []
for percent in min_coverage:
sim = runSimulation(bot, speed, width, height, percent, num_trials, robot_type, visualize)
avg = plotHelper(sim)
means.append(avg)
pylab.plot(min_coverage, means, label='%d robots' % bot)
pylab.legend(loc=2)
pylab.ylabel('Timesteps')
pylab.xlabel('Minimum Coverage')
pylab.title('Time to clean a 25x25 room with 1 to 5 robots (%d trials)' % num_trials)
# Testing Problem 4
def plotHelper(list_of_lists):
"""
Returns the average length of all the lists of lists.
"""
listCounter = 0
for list in list_of_lists:
listCounter += len(list)
return listCounter/float(len(list_of_lists))
showPlot1()
showPlot2()
showPlot3()
showPlot4()
pylab.show()
# === Problem 5
class RandomWalkRobot(BaseRobot):
"""
A RandomWalkRobot is a robot with the "random walk" movement
strategy: it chooses a new direction at random after each
time-step.
"""
def updatePositionAndClean(self):
"""
Simulate the passage of a single time-step.
Move the robot to a new position and mark the tile it is on as having
been cleaned.
"""
moving = True
while moving:
new_p = self.p.getNewPosition(self.d,self.speed)
if self.room.isPositionInRoom(new_p):
self.setRobotPosition(new_p)
if not self.room.isTileCleaned(int(new_p.getX()),int(new_p.getY())):
self.room.cleanTileAtPosition(new_p)
moving = False
self.setRobotDirection(random.randint(0,359))
# Testing Problem 5
#avg = runSimulation(3, 1.0, 5, 5, 0.8, 1, RandomWalkRobot, True)
# === Problem 6
def showPlot5():
"""
Produces a plot comparing the two robot strategies.
"""
num_robots = 3
speed = 1.0
min_coverage = 0.75
num_trials = 100
robot_type = [Robot, RandomWalkRobot]
visualize = False
rooms = [5,10,15,20,25]
pylab.figure()
for botType in robot_type:
means = []
area = []
for i in range(len(rooms)):
width = rooms[i]
height = rooms[i]
sim = runSimulation(num_robots, speed, width, height, min_coverage, num_trials, botType, visualize)
avg = plotHelper(sim)
area.append(width*height)
means.append(avg)
if botType is Robot:
label = 'Robot'
else: label = 'RandomWalkRobot'
pylab.plot(area, means, label=label)
pylab.legend(loc=2)
pylab.ylabel('Timesteps')
pylab.xlabel('Area')
pylab.title('Performance comparison of Robot and RandomWalkRobot clearing %d percent of various size rooms (%d trials)' % (min_coverage*100, num_trials))
pylab.show()
#Testing Problem 6
#showPlot5()
# Observations for Problem 6:
# RobotWalkRandom() is always slower than Robot(), the difference in performance is more obvious
# with 1 robot and a large room and high minimum coverage.
# Problem Set 11: Simulating robots
# Name:
# Collaborators:
# Time:
import math, random, pylab
import ps11_visualize
# === Provided classes
class Position(object):
"""
A Position represents a location in a two-dimensional room.
"""
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
return "x-coord=" + str(self.x) + " & y-coord=" + str(self.y)
def getX(self):
return self.x
def getY(self):
return self.y
def convertPosToTile(self):
tileX = int(self.x)
tileY = int(self.y)
self.tile = (tileX, tileY)
return self.tile
def getNewPosition(self, angle, speed):
old_x, old_y = self.getX(), self.getY()
# Compute the change in position
delta_y = speed * math.cos(math.radians(angle))
delta_x = speed * math.sin(math.radians(angle))
# Add that to the existing position
new_x = old_x + delta_x
new_y = old_y + delta_y
return Position(new_x, new_y)
# === Problems 1 and 2
class RectangularRoom(object):
def __init__(self, width, height):
self.w = width
self.h = height
self.cleantiles = []
self.dirtytiles = []
for w in range (width):
for h in range (height):
self.dirtytiles.append ((w,h))
def __str__(self):
return "This RectangularRoom contains the following dirty tiles: \n" + str(self.dirtytiles) + "\n And also the following clean tiles: \n" + str(self.cleantiles)
def cleanTileAtPosition(self, tile):
if tile[0] >= self.w or tile[1] >= self.h:
raise ValueError ("RectangularRoom.cleanTileAtPosition called with a position not in the room.")
self.cleantiles.append (tile)
self.dirtytiles.remove (tile)
def isTileCleaned(self, m,n):
tile = (m,n)
return tile in self.cleantiles
def getNumTiles(self):
return int(self.w*self.h)
def getNumCleanedTiles(self):
return len(self.cleantiles)
def getRandomPosition(self):
return Position(random.triangular(0, self.w), random.triangular(0, self.h))
def isPositionInRoom(self, pos):
return (0 <= pos.x < (self.w)) and (0<= pos.y < (self.h))
class BaseRobot(object):
def __init__(self, room, speed):
self.speed = speed
self.room = room
self.d = random.randint(0,359)
self.p = self.room.getRandomPosition()
def getRobotPosition(self):
return self.p
def getRobotDirection(self):
return self.d
def setRobotPosition(self, position):
self.p = position
def setRobotDirection(self, direction):
self.d = direction
class Robot(BaseRobot):
def updatePositionAndClean(self):
thinking = True
while thinking:
self.testp = self.p.getNewPosition(self.d, self.speed)
if self.room.isPositionInRoom(self.testp) == True:
thinking = False
else:
self.d = random.randint(0,359)
self.p = self.testp
tile = self.testp.convertPosToTile()
if not self.room.isTileCleaned(tile[0], tile[1]):
self.room.cleanTileAtPosition(tile)
# === Problem 5
class RandomWalkRobot(BaseRobot):
def updatePositionAndClean(self):
thinking = True
while thinking:
self.d = random.randint(0,359)
self.testp = self.p.getNewPosition(self.d, self.speed)
if self.room.isPositionInRoom(self.testp) == True:
thinking = False
self.p = self.testp
tile = self.testp.convertPosToTile()
if not self.room.isTileCleaned(tile[0], tile[1]):
self.room.cleanTileAtPosition(tile)
# === Problem 3
def runSimulation(num_robots, speed, width, height, min_coverage, num_trials,robot_type, visualize):
iTrial = 0 #index of active trial, starts at 0
trialsList = []
incomplete = True
while incomplete:
trialsList.append (runTrial (num_robots, speed, width, height, min_coverage, robot_type, visualize))
if iTrial+1 == num_trials:
incomplete = False
else:
iTrial += 1
return trialsList
def runTrial (num_robots, speed, width, height, min_coverage, robot_type, visualize):
trialRoom = RectangularRoom(width, height)
trialRoomSize = trialRoom.getNumTiles()
trialSteps = []
allRobots = []
for i in range(num_robots):
allRobots.append(robot_type(trialRoom, speed))
dirty = True
# Visualization Code:
if visualize:
anim = ps11_visualize.RobotVisualization(num_robots, width, height, .01)
while dirty:
iRobot = 0
while iRobot != len(allRobots):
allRobots[iRobot].updatePositionAndClean()
iRobot += 1
if visualize:
anim.update(trialRoom, allRobots)
numCleaned = trialRoom.getNumCleanedTiles()
pctCleaned = float(numCleaned)/float(trialRoomSize)
trialSteps.append(pctCleaned)
if pctCleaned >= min_coverage:
dirty = False
if visualize:
anim.done()
return trialSteps
# === Provided function ===
def computeMeans(list_of_lists):
"""
Returns a list as long as the longest list in LIST_OF_LISTS, where
the value at index i is the average of the values at index i in
all of LIST_OF_LISTS' lists.
Lists shorter than the longest list are padded with their final
value to be the same length.
"""
# Find length of longest list
longest = 0
for lst in list_of_lists:
if len(lst) > longest:
longest = len(lst)
# Get totals
tots = [0]*(longest)
for lst in list_of_lists:
for i in range(longest):
if i < len(lst):
tots[i] += lst[i]
else:
tots[i] += lst[-1]
# Convert tots to an array to make averaging across each index easier
tots = pylab.array(tots)
# Compute means
means = tots/float(len(list_of_lists))
return means
# === My Own Helper Function ===
def computeAvgLens(listList):
"""Given a list of lists, returns the average length of the lists (as a proxy for time elapsed)"""
tot = 0
for i in range(len(listList)):
tot += len(listList[i])
avg = tot/len(listList)
return avg
# === Problem 4
def showPlot1():
"""
Produces a plot showing dependence of cleaning time on room size.
"""
widths = [5, 10, 15, 20, 25]
areas = [5**2, 10**2, 15**2, 20**2, 25**2]
times = []
for i in widths:
times.append(computeAvgLens(runSimulation (1, 1.0, i, i, 0.75, 30, RandomWalkRobot, False)))
pylab.figure()
pylab.plot(areas, times, '-ro')
pylab.axis([0, 650, 0, 3000]) #RandomWalkRobot needs 3 times as long
pylab.ylabel ('time to clean')
pylab.xlabel ('areas of room')
pylab.title ('Room Area vs. 1 Robot Time To Clean')
pylab.show()
# showPlot1()
def showPlot2():
"""
Produces a plot showing dependence of cleaning time on number of robots.
"""
number = [1,2,3,4,5,6,7,8,9,10]
times = []
for i in number:
times.append(computeAvgLens(runSimulation (i, 1.0, 25, 25, 0.75, 30, Robot, False)))
pylab.figure()
pylab.plot(number, times, '-ro')
pylab.axis([0, 11, 0, 1000])
pylab.ylabel ('time to clean')
pylab.xlabel ('number of robots')
pylab.title ('# of Robots vs. Time To Clean 75% of 25x25 rm')
pylab.show()
# showPlot2()
def showPlot3():
"""
Produces a plot showing dependence of cleaning time on room shape.
"""
widths = [20, 25, 40, 50, 80, 100]
heights = [20, 16, 10, 8, 5, 4]
ratios = [float(widths[i])/float(heights[i]) for i in range(len(widths))]
times = []
for i in range (len(widths)):
times.append(computeAvgLens(runSimulation (1, 1.0, widths[i], heights[i], 0.75, 30, Robot, False)))
pylab.figure()
pylab.plot(ratios, times, '-ro')
pylab.axis([0, 30, 580, 800])
pylab.ylabel ('time to clean')
pylab.xlabel ('ratio')
pylab.title ('ratio of width to height vs. Time To Clean 75% of rm')
pylab.show()
# showPlot3()
def showPlot4A():
"""
Produces a plot showing dependence of cleaning time on required coverage.
"""
coverages = [.50, .60, .70, .80, .90, .97, .98, .99, 1.0]
times = []
for i in coverages:
times.append(computeAvgLens(runSimulation (5, 1.0, 25,25, i, 30, Robot, False)))
pylab.figure()
pylab.plot(coverages, times, '-ro')
pylab.axis([0.45, 1.05, 0, 6000])
pylab.ylabel ('time to clean (ticks)')
pylab.xlabel ('required coverage (%)')
pylab.title ('Coverage Requirements vs. Time To Clean for 1 robot')
pylab.show()
# showPlot4A()
def showPlot4():
"""
Produces a plot showing cleaning time vs. percentage cleaned, for
each of 1-5 robots.
"""
numRobots = [1,2,3,4,5]
pcts = []
for i in range (1,6):
pcts.append (computeMeans(runSimulation (i, 1.0, 25, 25, 1.0, 10, Robot, False)))
pylab.figure()
pylab.plot(pcts[0], '-r', label='1 Robot')
pylab.plot(pcts[1], '-b', label='2 Robots')
pylab.plot(pcts[2], '-g', label='3 Robots')
pylab.plot(pcts[3], '-c', label='4 Robots')
pylab.plot(pcts[4], '-m', label='5 Robots')
pylab.axis ([0, 6300, 0, 1.05])
pylab.xlabel ('time to clean (ticks)')
pylab.ylabel ('% of floor cleaned')
pylab.title ('Completed Coverage vs. Time for 1-5 robots')
pylab.legend()
pylab.show()
showPlot4()
# === Problem 6
def showPlot5():
"""
Produces a plot comparing the two robot strategies.
"""
pcts = computeMeans(runSimulation (1, 1.0, 15, 15, 1.0, 30, Robot, False))
randomWalkPcts = computeMeans(runSimulation (1, 1.0, 15, 15, 1.0, 30, RandomWalkRobot, False))
pylab.figure()
pylab.plot(pcts, '-r')
pylab.plot(randomWalkPcts, '-b')
pylab.axis ([0, 7500, 0, 1.05])
pylab.xlabel ('time to clean (ticks)')
pylab.ylabel ('% of floor cleaned')
pylab.title ('Coverage vs. Time, for Regular (red) vs RandomWalk (blue) robots')
pylab.show()
# showPlot5()
### Final Comments: RandomWalk Robot averages about 2.5-3 times longer for most tasks, with high volatility between trials.
No comments. Sign up or log in to comment This was more fun that the previous problems. # Problem Set 11: Simulating robots
# Name:conwayblue
import math
import pylab
import random
import ps11_visualize
# === Provided classes
class Position(object):
"""
A Position represents a location in a two-dimensional room.
"""
def __init__(self, x, y):
"""
Initializes a position with coordinates (x, y).
x: a real number indicating the x-coordinate
y: a real number indicating the y-coordinate
"""
self.x = x
self.y = y
def getX(self):
return self.x
def getY(self):
return self.y
def getNewPosition(self, angle, speed):
"""
Computes and returns the new Position after a single clock-tick has
passed, with this object as the current position, and with the
specified angle and speed.
Does NOT test whether the returned position fits inside the room.
angle: integer representing angle in degrees, 0 <= angle < 360
speed: positive float representing speed
Returns: a Position object representing the new position.
"""
old_x, old_y = self.getX(), self.getY()
# Compute the change in position
delta_y = speed * math.cos(math.radians(angle))
delta_x = speed * math.sin(math.radians(angle))
# Add that to the existing position
new_x = old_x + delta_x
new_y = old_y + delta_y
return Position(new_x,new_y)
def __eq__(self, other):
return self.getX() == other.getX() and self.getY() == other.getY()
# === Problems 1 and 2
class RectangularRoom(object):
"""
A RectangularRoom represents a rectangular region containing clean or dirty
tiles.
A room has a width and a height and contains (width * height) tiles. At any
particular time, each of these tiles is either clean or dirty.
"""
def __init__(self, width, height):
"""
Initializes a rectangular room with the specified width and height.
Initially, no tiles in the room have been cleaned.
width: an integer > 0
height: an integer > 0
"""
self.width = width
self.height = height
self.clean = []
def cleanTileAtPosition(self, pos):
"""
Mark the tile under the position POS as cleaned.
Assumes that POS represents a valid position inside this room.
pos: a Position
"""
point = (int(pos.getX()), int(pos.getY()))
if point not in self.clean:
self.clean.append(point)
def isTileCleaned(self, m, n):
"""
Return True if the tile (m, n) has been cleaned.
Assumes that (m, n) represents a valid tile inside the room.
m: an integer
n: an integer
returns: True if (m, n) is cleaned, False otherwise
"""
return (m,n) in self.clean
def getNumTiles(self):
"""
Return the total number of tiles in the room.
returns: an integer
"""
return self.width * self.height
def getNumCleanedTiles(self):
"""
Return the total number of clean tiles in the room.
returns: an integer
"""
return len(self.clean)
def getRandomPosition(self):
"""
Return a random position inside the room.
returns: a Position object.
"""
return Position(random.randint(0,self.width),
random.randint(0,self.height))
def isPositionInRoom(self, pos):
"""
Return True if POS is inside the room.
pos: a Position object.
returns: True if POS is in the room, False otherwise.
"""
return (pos.getX() <= self.width and
pos.getX() >- 0 and
pos.getY() <= self.height and
pos.getY() >= 0)
class BaseRobot(object):
"""
Represents a robot cleaning a particular room.
At all times the robot has a particular position and direction in
the room. The robot also has a fixed speed.
Subclasses of BaseRobot should provide movement strategies by
implementing updatePositionAndClean(), which simulates a single
time-step.
"""
def __init__(self, room, speed):
"""
Initializes a Robot with the given speed in the specified
room. The robot initially has a random direction d and a
random position p in the room.
The direction d is an integer satisfying 0 <= d < 360; it
specifies an angle in degrees.
p is a Position object giving the robot's position.
room: a RectangularRoom object.
speed: a float (speed > 0)
"""
# TODO: Your code goes here
self.room = room
self.speed = speed
self.d = random.randint(0,360)
self.p = room.getRandomPosition()
def getRobotPosition(self):
"""
Return the position of the robot.
returns: a Position object giving the robot's position.
"""
# TODO: Your code goes here
return self.p
def getRobotDirection(self):
"""
Return the direction of the robot.
returns: an integer d giving the direction of the robot as an angle in
degrees, 0 <= d < 360.
"""
# TODO: Your code goes here
return self.d
def setRobotPosition(self, position):
"""
Set the position of the robot to POSITION.
position: a Position object.
"""
# TODO: Your code goes here
self.p = position
def setRobotDirection(self, direction):
"""
Set the direction of the robot to DIRECTION.
direction: integer representing an angle in degrees
"""
# TODO: Your code goes here
self.d = direction
class Robot(BaseRobot):
"""
A Robot is a BaseRobot with the standard movement strategy.
At each time-step, a Robot attempts to move in its current
direction; when it hits a wall, it chooses a new direction
randomly.
"""
def updatePositionAndClean(self):
"""
Simulate the passage of a single time-step.
Move the robot to a new position and mark the tile it is on as having
been cleaned.
"""
# TODO: Your code goes here
inroom = False
while not inroom:
newpos = self.p.getNewPosition(self.d,self.speed)
if self.room.isPositionInRoom(newpos):
inroom = True
else:
self.setRobotDirection(random.randint(0,360))
self.setRobotPosition(newpos)
self.setRobotDirection(self.d)
self.room.cleanTileAtPosition(newpos)
# === Problem 3
def runSimulation(num_robots, speed, width, height, min_coverage, num_trials,
robot_type=Robot, visualize=False):
"""
Runs NUM_TRIALS trials of the simulation and returns a list of
lists, one per trial. The list for a trial has an element for each
timestep of that trial, the value of which is the percentage of
the room that is clean after that timestep. Each trial stops when
MIN_COVERAGE of the room is clean.
The simulation is run with NUM_ROBOTS robots of type ROBOT_TYPE,
each with speed SPEED, in a room of dimensions WIDTH x HEIGHT.
Visualization is turned on when boolean VISUALIZE is set to True.
num_robots: an int (num_robots > 0)
speed: a float (speed > 0)
width: an int (width > 0)
height: an int (height > 0)
min_coverage: a float (0 <= min_coverage <= 1.0)
num_trials: an int (num_trials > 0)
robot_type: class of robot to be instantiated (e.g. Robot or
RandomWalkRobot)
visualize: a boolean (True to turn on visualization)
"""
# TODO: Your code goes
results = []
for i in range(num_trials):
room = RectangularRoom(width, height)
robots = [robot_type(room,speed) for i in range(num_robots)]
clean = 0
tick = 0
trial = []
if visualize:
anim = ps11_visualize.RobotVisualization(num_robots,width,height)
while clean < min_coverage:
clean = float(room.getNumCleanedTiles()) / float(room.getNumTiles())
trial.append(clean)
for bot in robots:
tick += 1
bot.updatePositionAndClean()
if visualize:
anim.update(room,robots)
#print tick
if visualize:
anim.done()
results.append(trial)
return results
# === Provided function
def computeMeans(list_of_lists):
"""
Returns a list as long as the longest list in LIST_OF_LISTS, where
the value at index i is the average of the values at index i in
all of LIST_OF_LISTS' lists.
Lists shorter than the longest list are padded with their final
value to be the same length.
"""
# Find length of longest list
longest = 0
for lst in list_of_lists:
if len(lst) > longest:
longest = len(lst)
# Get totals
tots = [0]*(longest)
for lst in list_of_lists:
for i in range(longest):
if i < len(lst):
tots[i] += lst[i]
else:
tots[i] += lst[-1]
# Convert tots to an array to make averaging across each index easier
tots = pylab.array(tots)
# Compute means
means = tots/float(len(list_of_lists))
return means
def avgTime(list_of_lists):
total = 0
for i in list_of_lists:
total += len(i)
avg = float(total) / float(len(list_of_lists))
return avg
# === Problem 4
def showPlot1(typebot=Robot):
"""
Produces a plot showing dependence of cleaning time on room size.
"""
# TODO: Your code goes here
avgTimes = []
sizes = [5,10,15,20,25]
areas = [25,100,225,400,625]
clean = 0.75
sims = 1
bots = 1
speed = 1
#typebot = Robot
#typebot = RandomWalkRobot
visualize = False
for side in sizes:
avgTimes.append(int(avgTime(runSimulation(
bots,speed,side,side,
clean,sims,typebot,visualize))))
pylab.figure()
pylab.plot(areas,avgTimes)
pylab.ylabel('Number of steps')
pylab.xlabel('Room Area')
pylab.title('Avg time to clean 75% of given area with 1 robot at speed 1')
pylab.show()
def showPlot2(typebot=Robot):
"""
Produces a plot showing dependence of cleaning time on number of robots.
"""
# TODO: Your code goes here
avgTimes = []
side = 25
clean = 0.75
sims = 30
speed = 1
#typebot = Robot
#typebot = RandomWalkRobot
visualize = False
for i in range(1,11):
avgTimes.append(avgTime(runSimulation(i,speed,side,side,clean,
sims,typebot,visualize)))
pylab.figure()
pylab.plot(range(1,11),avgTimes)
pylab.xlabel('Number of robots')
pylab.ylabel('Number of steps')
pylab.title('Avg time for x number of robots to clean 75% of 25 x 25 room')
pylab.show()
def showPlot3(typebot=Robot):
"""
Produces a plot showing dependence of cleaning time on room shape.
"""
# TODO: Your code goes here
rooms = [(20,20),(25,16),(40,10),(50,8),(80,5),(100,4)]
clean = 0.75
sims = 30
speed = 1
bots = 2
#typebot = Robot
#typebot = RandomWalkRobot
visualize = False
avgTimes = []
ratios = []
for room in rooms:
ratios.append(float(room[0]) / room[1])
avgTimes.append(avgTime(runSimulation(bots,speed,room[0],room[1],
clean,sims,typebot,visualize)))
pylab.figure()
pylab.plot(ratios,avgTimes)
pylab.xlabel('Ratio of room width / height')
pylab.ylabel('Number of steps')
pylab.title('Avg time for 2 robots to clean 75% of x-ratio room')
pylab.show()
def showPlot4(typebot=Robot):
"""
Produces a plot showing cleaning time vs. percentage cleaned, for
each of 1-5 robots.
"""
# TODO: Your code goes here
sims = 3
speed = 1
side = 25
#typebot = Robot
#typebot = RandomWalkRobot
visualize = False
labels = []
pylab.figure()
for bots in range(1,6):
run = runSimulation(bots,speed,side,side,1,sims,typebot,visualize)
meanRun = computeMeans(run)
label = '%d bots' % bots
labels.append(label)
pylab.plot(meanRun*100,range(len(meanRun)), label=label)
pylab.legend(labels)
pylab.xlabel('Percent cleaned')
pylab.ylabel('Number of steps')
pylab.title('Time for x robots to clean x percent of room')
pylab.show()
# === Problem 5
class RandomWalkRobot(BaseRobot):
"""
A RandomWalkRobot is a robot with the "random walk" movement
strategy: it chooses a new direction at random after each
time-step.
"""
# TODO: Your code goes here
def updatePositionAndClean(self):
"""
Simulate the passage of a single time-step.
Move the robot to a new position and mark the tile it is on as having
been cleaned.
"""
# TODO: Your code goes here
inroom = False
while not inroom:
self.setRobotDirection(random.randint(0,360))
newpos = self.p.getNewPosition(self.d,self.speed)
if self.room.isPositionInRoom(newpos):
inroom = True
else:
self.setRobotDirection(random.randint(0,360))
self.setRobotPosition(newpos)
self.setRobotDirection(self.d)
self.room.cleanTileAtPosition(newpos)
# === Problem 6
def showPlot5():
"""
Produces a plot comparing the two robot strategies.
"""
# TODO: Your code goes here
sims = 10
speed = 1
side = 20
visualize = False
types = (Robot,RandomWalkRobot)
labels = []
totalbots = 3
pylab.figure()
for bots in range(1,totalbots+1):
for bot_type in types:
run = runSimulation(bots,speed,side,side,0.75,sims,bot_type,visualize)
meanRun = computeMeans(run)
if bot_type == Robot:
label = '%d Robot type' % (bots)
else:
label = '%d RandomWalkRobot' % (bots)
labels.append(label)
pylab.plot(meanRun*100,range(len(meanRun)),label=label)
pylab.legend(labels)
pylab.xlabel('Percent cleaned')
pylab.ylabel('Number of steps')
pylab.title('Time for x robots of x type to clean 75 percent of room')
pylab.show()
No comments. Sign up or log in to comment Designed my robot classes so RandomWalkRobot could inherit from Robot rather than BaseRobot, and avoid duplicate code in updatePositionAndClean # Problem Set 11: Simulating robots
# Name:
# Collaborators:
# Time:
import math
import random
import ps11_visualize
import pylab
# === Provided classes
class Position(object):
"""
A Position represents a location in a two-dimensional room.
"""
def __init__(self, x, y):
"""
Initializes a position with coordinates (x, y).
x: a real number indicating the x-coordinate
y: a real number indicating the y-coordinate
"""
self.x = x
self.y = y
def getX(self):
return self.x
def getY(self):
return self.y
def getNewPosition(self, angle, speed):
"""
Computes and returns the new Position after a single clock-tick has
passed, with this object as the current position, and with the
specified angle and speed.
Does NOT test whether the returned position fits inside the room.
angle: integer representing angle in degrees, 0 <= angle < 360
speed: positive float representing speed
Returns: a Position object representing the new position.
"""
old_x, old_y = self.getX(), self.getY()
# Compute the change in position
delta_y = speed * math.cos(math.radians(angle))
delta_x = speed * math.sin(math.radians(angle))
# Add that to the existing position
new_x = old_x + delta_x
new_y = old_y + delta_y
return Position(new_x, new_y)
# === Problems 1 and 2
class RectangularRoom(object):
"""
A RectangularRoom represents a rectangular region containing clean or dirty
tiles.
A room has a width and a height and contains (width * height) tiles. At any
particular time, each of these tiles is either clean or dirty.
"""
def __init__(self, width, height):
"""
Initializes a rectangular room with the specified width and height.
Initially, no tiles in the room have been cleaned.
width: an integer > 0
height: an integer > 0
"""
if width < 0: raise ValueException('Width cannot be less than 0')
if height < 0: raise ValueException('Height cannot be less than 0')
self.width = width
self.height = height
self.cleanedTiles = []
def cleanTileAtPosition(self, pos):
"""
Mark the tile under the position POS as cleaned.
Assumes that POS represents a valid position inside this room.
pos: a Position
"""
coords = int(pos.getX()), int(pos.getY())
if coords in self.cleanedTiles:
return
self.cleanedTiles.append(coords)
def isTileCleaned(self, m, n):
"""
Return True if the tile (m, n) has been cleaned.
Assumes that (m, n) represents a valid tile inside the room.
m: an integer
n: an integer
returns: True if (m, n) is cleaned, False otherwise
"""
return (int(m), int(n)) in self.cleanedTiles
def getNumTiles(self):
"""
Return the total number of tiles in the room.
returns: an integer
"""
return self.width * self.height
def getNumCleanedTiles(self):
"""
Return the total number of clean tiles in the room.
returns: an integer
"""
return len(self.cleanedTiles)
def getRandomPosition(self):
"""
Return a random position inside the room.
returns: a Position object.
"""
return Position(random.randrange(0, self.width), random.randrange(0, self.height))
def isPositionInRoom(self, pos):
"""
Return True if POS is inside the room.
pos: a Position object.
returns: True if POS is in the room, False otherwise.
"""
return 0 <= pos.getX() <= self.width and 0 <= pos.getY() <= self.height
class BaseRobot(object):
"""
Represents a robot cleaning a particular room.
At all times the robot has a particular position and direction in
the room. The robot also has a fixed speed.
Subclasses of BaseRobot should provide movement strategies by
implementing updatePositionAndClean(), which simulates a single
time-step.
"""
def __init__(self, room, speed):
"""
Initializes a Robot with the given speed in the specified
room. The robot initially has a random direction d and a
random position p in the room.
The direction d is an integer satisfying 0 <= d < 360; it
specifies an angle in degrees.
p is a Position object giving the robot's position.
room: a RectangularRoom object.
speed: a float (speed > 0)
"""
self.room = room
self.speed = speed
self.direction = random.randrange(0, 360)
self.position = room.getRandomPosition()
def getRobotPosition(self):
"""
Return the position of the robot.
returns: a Position object giving the robot's position.
"""
return self.position
def getRobotDirection(self):
"""
Return the direction of the robot.
returns: an integer d giving the direction of the robot as an angle in
degrees, 0 <= d < 360.
"""
return self.direction
def setRobotPosition(self, position):
"""
Set the position of the robot to POSITION.
position: a Position object.
"""
self.position = position
def setRobotDirection(self, direction):
"""
Set the direction of the robot to DIRECTION.
direction: integer representing an angle in degrees
"""
self.direction = direction
class Robot(BaseRobot):
"""
A Robot is a BaseRobot with the standard movement strategy.
At each time-step, a Robot attempts to move in its current
direction; when it hits a wall, it chooses a new direction
randomly.
"""
def updatePositionAndClean(self):
"""
Simulate the passage of a single time-step.
Move the robot to a new position and mark the tile it is on as having
been cleaned.
"""
newPosition = self.position.getNewPosition(self.direction, self.speed)
while not self.room.isPositionInRoom(newPosition):
self.direction = random.randrange(0, 360)
newPosition = self.position.getNewPosition(self.direction, self.speed)
self.room.cleanTileAtPosition(newPosition)
self.position = newPosition
# === Problem 3
def runSimulation(num_robots, speed, width, height, minCoverage, numTrials,
robotType, visualize = False):
"""
Runs NUM_TRIALS trials of the simulation and returns a list of
lists, one per trial. The list for a trial has an element for each
timestep of that trial, the value of which is the percentage of
the room that is clean after that timestep. Each trial stops when
MIN_COVERAGE of the room is clean.
The simulation is run with NUM_ROBOTS robots of type ROBOT_TYPE,
each with speed SPEED, in a room of dimensions WIDTH x HEIGHT.
Visualization is turned on when boolean VISUALIZE is set to True.
num_robots: an int (num_robots > 0)
speed: a float (speed > 0)
width: an int (width > 0)
height: an int (height > 0)
minCoverage: a float (0 <= minCoverage <= 1.0)
num_trials: an int (num_trials > 0)
robotType: class of robot to be instantiated (e.g. Robot or
RandomWalkRobot)
visualize: a boolean (True to turn on visualization)
"""
def percentageOfRoomCleaned(room):
return float(room.getNumCleanedTiles()) / room.getNumTiles()
results = []
for trialNum in range(1, numTrials + 1):
if visualize:
anim = ps11_visualize.RobotVisualization(num_robots, width, height)
trialResults = []
room = RectangularRoom(width, height)
robots = []
for robotNum in range(0, num_robots):
robots.append(robotType(room, speed))
while percentageOfRoomCleaned(room) < minCoverage:
if visualize:
anim.update(room, robots)
trialResults.append(percentageOfRoomCleaned(room))
for robo in robots:
robo.updatePositionAndClean()
if visualize:
anim.done()
results.append(trialResults)
return results
#print(runSimulation(1, 1, 15, 15, 1.0, 100, Robot, True))
# === Provided function
def computeMeans(list_of_lists):
"""
Returns a list as long as the longest list in LIST_OF_LISTS, where
the value at index i is the average of the values at index i in
all of LIST_OF_LISTS' lists.
Lists shorter than the longest list are padded with their final
value to be the same length.
"""
# Find length of longest list
longest = 0
for lst in list_of_lists:
if len(lst) > longest:
longest = len(lst)
# Get totals
tots = [0]*(longest)
for lst in list_of_lists:
for i in range(longest):
if i < len(lst):
tots[i] += lst[i]
else:
tots[i] += lst[-1]
# Convert tots to an array to make averaging across each index easier
tots = pylab.array(tots)
# Compute means
means = tots/float(len(list_of_lists))
return means
def computeAverageTime(listOfLists):
totalTime = 0
for l in listOfLists:
totalTime += len(l)
return float(totalTime) / len(listOfLists)
# === Problem 4
def showPlot1():
"""
Produces a plot showing dependence of cleaning time on room size.
"""
numTrials = 50
averageTimes = []
roomSideSizes = (5, 10, 15, 20, 25)
roomAreas = []
for size in roomSideSizes:
roomAreas.append(size**2)
averageTimes.append(computeAverageTime(runSimulation(1, 1.0, size, size, .75, numTrials, Robot)))
pylab.figure()
pylab.plot(roomAreas, averageTimes)
pylab.ylabel('Timesteps')
pylab.xlabel('Room area')
pylab.title('Time to clean 75%% of a square room with 1 robot (%d trials)' % numTrials)
def showPlot2():
"""
Produces a plot showing dependence of cleaning time on number of robots.
"""
numTrials = 50
averageTimes = []
for numRobots in range(1, 11):
averageTimes.append(computeAverageTime(runSimulation(numRobots, 1.0, 25, 25, .75, numTrials, Robot)))
pylab.figure()
pylab.plot(range(1, 11), averageTimes)
pylab.ylabel('Timesteps')
pylab.xlabel('Number of robots')
pylab.title('Time to clean 75%% of a 25x25 room (%d trials)' % numTrials)
def showPlot3():
"""
Produces a plot showing dependence of cleaning time on room shape.
"""
numTrials = 50
averageTimes = []
widthHeightRatios = []
for width, height in ((20, 20), (25, 16), (40, 10), (50, 8), (80, 5), (100, 4)):
widthHeightRatios.append(float(width) / height)
averageTimes.append(computeAverageTime(runSimulation(2, 1.0, width, height, .75, numTrials, Robot)))
pylab.figure()
pylab.plot(widthHeightRatios, averageTimes)
pylab.ylabel('Timesteps')
pylab.xlabel('Width to height ratio for room size')
pylab.title('Time to clean 75%% of a room with the same area, but varying widths/heights using 2 robots (%d trials)' % numTrials)
def showPlot4():
"""
Produces a plot showing cleaning time vs. percentage cleaned, for
each of 1-5 robots.
"""
numTrials = 15
pylab.figure()
labels = []
for numRobots in range(1, 6):
label = "%d robot(s)" % numRobots
labels.append(label)
results = computeMeans(runSimulation(numRobots, 1.0, 25, 25, 1, numTrials, Robot))
pylab.plot(results * 100, range(0, len(results)), label=label)
pylab.legend(labels)
pylab.ylabel('Timesteps')
pylab.xlabel('Minimum coverage %')
pylab.title('Time to clean vs Minimum coverage %% with 1-5 robots (%d trials)' % numTrials)
#showPlot1()
#showPlot2()
#showPlot3()
#showPlot4()
#pylab.show()
# === Problem 5
class RandomWalkRobot(Robot):
"""
A RandomWalkRobot is a robot with the "random walk" movement
strategy: it chooses a new direction at random after each
time-step.
"""
def updatePositionAndClean(self):
self.direction = random.randrange(0, 360)
Robot.updatePositionAndClean(self)
#runSimulation(1, 1.0, 25, 25, 1, 1, RandomWalkRobot, True)
# === Problem 6
def showPlot5():
"""
Produces a plot comparing the two robot strategies.
"""
numTrials = 10
pylab.figure()
labels = []
robotTypes = (Robot, RandomWalkRobot)
for numRobots in range(1, 3):
for robotType in robotTypes:
label = "%d %s robot(s)" % (numRobots, robotType.__name__)
labels.append(label)
results = computeMeans(runSimulation(numRobots, 1.0, 25, 25, 1, numTrials, robotType))
pylab.plot(results * 100, range(0, len(results)), label=label)
pylab.legend(labels)
pylab.ylabel('Timesteps')
pylab.xlabel('Minimum coverage %')
pylab.title('Time to clean vs Minimum coverage %% with 1-5 robots of type Robot and RandomWalkRobot (%d trials)' % numTrials)
showPlot5()
pylab.show()
No comments. Sign up or log in to comment Took a while but was able to include legends on some of the graphs. # Problem Set 11: Simulating robots
# Name: gwb
# Collaborators:
# Time: 2.5 hrs
import math
import random
import pylab
##import ps11_visualize
# === Provided classes
class Position(object):
"""
A Position represents a location in a two-dimensional room.
"""
def __init__(self, x, y):
"""
Initializes a position with coordinates (x, y).
x: a real number indicating the x-coordinate
y: a real number indicating the y-coordinate
"""
self.x = x
self.y = y
def getX(self):
return self.x
def getY(self):
return self.y
def getNewPosition(self, angle, speed):
"""
Computes and returns the new Position after a single clock-tick has
passed, with this object as the current position, and with the
specified angle and speed.
Does NOT test whether the returned position fits inside the room.
angle: integer representing angle in degrees, 0 <= angle < 360
speed: positive float representing speed
Returns: a Position object representing the new position.
"""
old_x, old_y = self.getX(), self.getY()
# Compute the change in position
delta_y = speed * math.cos(math.radians(angle))
delta_x = speed * math.sin(math.radians(angle))
# Add that to the existing position
new_x = old_x + delta_x
new_y = old_y + delta_y
return Position(new_x, new_y)
# === Problems 1 and 2
class RectangularRoom(object):
"""
A RectangularRoom represents a rectangular region containing clean or dirty
tiles.
A room has a width and a height and contains (width * height) tiles. At any
particular time, each of these tiles is either clean or dirty.
"""
def __init__(self, width, height):
"""
Initializes a rectangular room with the specified width and height.
Initially, no tiles in the room have been cleaned.
width: an integer > 0
height: an integer > 0
"""
# TODO: Your code goes here
self.width = int(width)
self.height = int(height)
# cleaned is a list of cleaned tile tuples
self.cleaned = []
def cleanTileAtPosition(self, pos):
"""
Mark the tile under the position POS as cleaned.
Assumes that POS represents a valid position inside this room.
pos: a Position
"""
# TODO: Your code goes here
tile = (int(pos.x), int(pos.y))
self.cleaned += [tile]
def isTileCleaned(self, m, n):
"""
Return True if the tile (m, n) has been cleaned.
Assumes that (m, n) represents a valid tile inside the room.
m: an integer
n: an integer
returns: True if (m, n) is cleaned, False otherwise
"""
# TODO: Your code goes here
if (m, n) not in self.cleaned: return False
else: return True
def getNumTiles(self):
"""
Return the total number of tiles in the room.
returns: an integer
"""
# TODO: Your code goes here
return self.width * self.height
def getNumCleanedTiles(self):
"""
Return the total number of clean tiles in the room.
returns: an integer
"""
# TODO: Your code goes here
return len(self.cleaned)
def getRandomPosition(self):
"""
Return a random position inside the room.
returns: a Position object.
"""
# TODO: Your code goes here
p_x = random.uniform(0,self.width)
p_y = random.uniform(0,self.height)
return Position(p_x, p_y)
def isPositionInRoom(self, pos):
"""
Return True if POS is inside the room.
pos: a Position object.
returns: True if POS is in the room, False otherwise.
"""
# TODO: Your code goes here
if pos.x < 0 or pos.x > self.width or pos.y < 0 or pos.y > self.height:
return False
else:
return True
class BaseRobot(object):
"""
Represents a robot cleaning a particular room.
At all times the robot has a particular position and direction in
the room. The robot also has a fixed speed.
Subclasses of BaseRobot should provide movement strategies by
implementing updatePositionAndClean(), which simulates a single
time-step.
"""
def __init__(self, room, speed):
"""
Initializes a Robot with the given speed in the specified
room. The robot initially has a random direction d and a
random position p in the room.
The direction d is an integer satisfying 0 <= d < 360; it
specifies an angle in degrees.
p is a Position object giving the robot's position.
room: a RectangularRoom object.
speed: a float (speed > 0)
"""
# TODO: Your code goes here
self.room = room
self.speed = float(speed)
self.direction = int(random.uniform(0,360))
self.pos = self.room.getRandomPosition()
# clean tile at initial position!
self.room.cleanTileAtPosition(self.pos)
def getRobotPosition(self):
"""
Return the position of the robot.
returns: a Position object giving the robot's position.
"""
# TODO: Your code goes here
return self.pos
def getRobotDirection(self):
"""
Return the direction of the robot.
returns: an integer d giving the direction of the robot as an angle in
degrees, 0 <= d < 360.
"""
# TODO: Your code goes here
return self.direction
def setRobotPosition(self, position):
"""
Set the position of the robot to POSITION.
position: a Position object.
"""
# TODO: Your code goes here
self.pos = position
def setRobotDirection(self, direction):
"""
Set the direction of the robot to DIRECTION.
direction: integer representing an angle in degrees
"""
# TODO: Your code goes here
self.direction = direction
def getRobotTile(self):
"""
Returns the tile tuple for the current robot position
"""
return (int(self.pos.x), int(self.pos.y))
class Robot(BaseRobot):
"""
A Robot is a BaseRobot with the standard movement strategy.
At each time-step, a Robot attempts to move in its current
direction; when it hits a wall, it chooses a new direction
randomly.
"""
def updatePositionAndClean(self):
"""
Simulate the passage of a single time-step.
Move the robot to a new position and mark the tile it is on as having
been cleaned.
"""
# TODO: Your code goes here
newLocation = self.pos.getNewPosition(self.direction, self.speed)
# make sure new position is in room!
while self.room.isPositionInRoom(newLocation) is False:
# try a different direction
self.setRobotDirection(int(random.uniform(0,360)))
newLocation = self.pos.getNewPosition(self.direction, self.speed)
self.setRobotPosition(newLocation)
tile = self.getRobotTile()
if self.room.isTileCleaned(tile[0], tile[1]) == False:
self.room.cleanTileAtPosition(newLocation)
# === Problem 3
def runSimulation(num_robots, speed, width, height, min_coverage, num_trials,
robot_type, visualize):
"""
Runs NUM_TRIALS trials of the simulation and returns a list of
lists, one per trial. The list for a trial has an element for each
timestep of that trial, the value of which is the percentage of
the room that is clean after that timestep. Each trial stops when
MIN_COVERAGE of the room is clean.
The simulation is run with NUM_ROBOTS robots of type ROBOT_TYPE,
each with speed SPEED, in a room of dimensions WIDTH x HEIGHT.
Visualization is turned on when boolean VISUALIZE is set to True.
num_robots: an int (num_robots > 0)
speed: a float (speed > 0)
width: an int (width > 0)
height: an int (height > 0)
min_coverage: a float (0 <= min_coverage <= 1.0)
num_trials: an int (num_trials > 0)
robot_type: class of robot to be instantiated (e.g. Robot or
RandomWalkRobot)
visualize: a boolean (True to turn on visualization)
"""
# TODO: Your code goes here
## print 'Robots: ' + str(num_robots) + '; Trials: ' + str(num_trials) + '; Room: ' + str(width) + 'x' + str(height) \
## + '; Speed: ' + str(speed) + '; Coverage: ' + str(min_coverage)
# a container for list of lists
output = []
for i in range(num_trials):
# a container for trial list
## anim = ps11_visualize.RobotVisualization(num_robots, width, height)
room = RectangularRoom(width, height)
totalTiles = float(width * height)
# set of robots
robots = []
for j in range(num_robots):
robots += [robot_type(room, speed)]
# initialize cleaned tiles
cleaned = float(room.getNumCleanedTiles())
pctCleaned = cleaned/totalTiles
result = [pctCleaned]
# work until min_coverage is clean
while pctCleaned < min_coverage:
for j in range(num_robots):
robots[j].updatePositionAndClean()
cleaned = float(room.getNumCleanedTiles())
pctCleaned = cleaned/totalTiles
result.append(pctCleaned)
## anim.update(room, robots)
output.append(result)
return output
def avgLength(listOfLists):
"""
computes average length of list for list of lists
"""
n = len(listOfLists)
total = 0
for i in range(n - 1):
total += len(listOfLists[i])
return float(total)/float(n)
# === Provided function
def computeMeans(list_of_lists):
"""
Returns a list as long as the longest list in LIST_OF_LISTS, where
the value at index i is the average of the values at index i in
all of LIST_OF_LISTS' lists.
Lists shorter than the longest list are padded with their final
value to be the same length.
"""
# Find length of longest list
longest = 0
for lst in list_of_lists:
if len(lst) > longest:
longest = len(lst)
# Get totals
tots = [0]*(longest)
for lst in list_of_lists:
for i in range(longest):
if i < len(lst):
tots[i] += lst[i]
else:
tots[i] += lst[-1]
# Convert tots to an array to make averaging across each index easier
tots = pylab.array(tots)
# Compute means
means = tots/float(len(list_of_lists))
return means
# === Problem 4
def showPlot1():
"""
Produces a plot showing dependence of cleaning time on room size.
Single robot, 75% clean, 5x5, 10x10, 15x15, 20x20, 25x25 rooms
"""
# TODO: Your code goes here
num_robots = 1
speed = 1
min_coverage = 0.75
num_trials = 30
robot_type = Robot
visualize = False
x_values = []
y_values = []
initial_dim = 5
for i in range(1,6):
run = runSimulation(num_robots, speed, i*initial_dim, i*initial_dim, min_coverage, num_trials, robot_type, visualize)
x_values.append((i*initial_dim)**2)
y_values.append(avgLength(run))
pylab.plot(x_values, y_values)
pylab.xlabel('Area')
pylab.ylabel('Time')
pylab.title('Mean time vs. Area; single robot')
pylab.show()
def showPlot2():
"""
Produces a plot showing dependence of cleaning time on number of robots.
"""
# TODO: Your code goes here
num_robots = 1
speed = 1
min_coverage = 0.75
num_trials = 30
robot_type = Robot
visualize = False
x_values = []
y_values = []
initial_dim = 25
for i in range(1,11):
run = runSimulation(i*num_robots, speed, initial_dim, initial_dim, min_coverage, num_trials, robot_type, visualize)
x_values.append(i)
y_values.append(avgLength(run))
pylab.plot(x_values, y_values)
pylab.xlabel('No. Robots')
pylab.ylabel('Time')
pylab.title('Mean time vs. Number of Robots')
pylab.show()
def showPlot3():
"""
Produces a plot showing dependence of cleaning time on room shape.
"""
# TODO: Your code goes here
num_robots = 2
speed = 1
min_coverage = 0.75
num_trials = 60
robot_type = Robot
visualize = False
x_values = []
y_values = []
width = [20, 25, 40, 50, 80, 100]
height = [20, 16, 10, 8, 5, 4]
for i in range(6):
run = runSimulation(num_robots, speed, width[i], height[i], min_coverage, num_trials, robot_type, visualize)
ratio = float(width[i])/float(height[i])
x_values.append(ratio)
y_values.append(avgLength(run))
pylab.plot(x_values, y_values)
pylab.xlabel('Ratio')
pylab.ylabel('Time')
pylab.title('Mean time vs. Width/Height')
pylab.show()
def showPlot4():
"""
Produces a plot showing cleaning time vs. percentage cleaned, for
each of 1-5 robots.
"""
# TODO: Your code goes here
speed = 1
min_coverage = 0.9
num_trials = 30
robot_type = Robot
visualize = False
width = 25
height = 25
for r in range(1,6):
run = runSimulation(r, speed, width, height, min_coverage, num_trials, robot_type, visualize)
means = computeMeans(run)
pylab.plot(means, range(len(means)), label = str(r) + ' robots')
pylab.xlabel('Pct Cleaned')
pylab.ylabel('Time')
pylab.title('Mean time vs.Pct Cleaned\n1 - 5 robots')
pylab.legend(loc='upper left')
pylab.show()
# === Problem 5
class RandomWalkRobot(BaseRobot):
"""
A RandomWalkRobot is a robot with the "random walk" movement
strategy: it chooses a new direction at random after each
time-step.
"""
# TODO: Your code goes here
def updatePositionAndClean(self):
"""
Simulate the passage of a single time-step.
Move the robot to a new position at each time increment and mark the tile it is on as having
been cleaned.
"""
# TODO: Your code goes here
# only difference: get a new direction every update
self.setRobotDirection(int(random.uniform(0,360)))
newLocation = self.pos.getNewPosition(self.direction, self.speed)
# make sure new position is in room!
while self.room.isPositionInRoom(newLocation) is False:
# try a different direction
self.setRobotDirection(int(random.uniform(0,360)))
newLocation = self.pos.getNewPosition(self.direction, self.speed)
self.setRobotPosition(newLocation)
tile = self.getRobotTile()
if self.room.isTileCleaned(tile[0], tile[1]) == False:
self.room.cleanTileAtPosition(newLocation)
# === Problem 6
def showPlot5():
"""
Produces a plot comparing the two robot strategies.
"""
# TODO: Your code goes here
num_robots = 1
speed = 1
min_coverage = 0.75
num_trials = 30
robot_type = Robot
visualize = False
x_values = []
y_values = []
initial_dim = 5
for i in range(1,6):
run = runSimulation(num_robots, speed, i*initial_dim, i*initial_dim, min_coverage, num_trials, robot_type, visualize)
x_values.append((i*initial_dim)**2)
y_values.append(avgLength(run))
pylab.plot(x_values, y_values, label = 'Standard robot')
robot_type = RandomWalkRobot
visualize = False
x_values = []
y_values = []
initial_dim = 5
for i in range(1,6):
run = runSimulation(num_robots, speed, i*initial_dim, i*initial_dim, min_coverage, num_trials, robot_type, visualize)
x_values.append((i*initial_dim)**2)
y_values.append(avgLength(run))
pylab.plot(x_values, y_values, label = 'Random walk robot')
pylab.xlabel('Area')
pylab.ylabel('Time')
pylab.title('Mean time vs. Area')
pylab.legend(loc = 'upper left')
pylab.show()
No comments. Sign up or log in to comment This one is really fun. # 6.00 Problem Set 12
#
# Name: Joe Li
# Collaborators:
# Time: 7:00
import numpy
import random
import pylab
class NoChildException(Exception):
"""
NoChildException is raised by the reproduce() method in the SimpleVirus
and ResistantVirus classes to indicate that a virus particle does not
reproduce. You can use NoChildException as is, you do not need to
modify/add any code.
"""
#
# PROBLEM 1
#
class SimpleVirus(object):
"""
Representation of a simple virus (does not model drug effects/resistance).
"""
def __init__(self, maxBirthProb, clearProb):
"""
Initialize a SimpleVirus instance, saves all parameters as attributes
of the instance.
maxBirthProb: Maximum reproduction probability (a float between 0-1)
clearProb: Maximum clearance probability (a float between 0-1).
"""
self.maxBirthProb = maxBirthProb
self.clearProb = clearProb
def doesClear(self):
"""
Stochastically determines whether this virus is cleared from the
patient's body at a time step.
returns: Using a random number generator (random.random()), this method
returns True with probability self.clearProb and otherwise returns
False.
"""
prob = random.random()
if prob < self.clearProb:
return True
else:
return False
def reproduce(self, popDensity):
"""
Stochastically determines whether this virus particle reproduces at a
time step. Called by the update() method in the SimplePatient and
Patient classes. The virus particle reproduces with probability
self.maxBirthProb * (1 - popDensity).
If this virus particle reproduces, then reproduce() creates and returns
the instance of the offspring SimpleVirus (which has the same
maxBirthProb and clearProb values as its parent).
popDensity: the population density (a float), defined as the current
virus population divided by the maximum population.
returns: a new instance of the SimpleVirus class representing the
offspring of this virus particle. The child should have the same
maxBirthProb and clearProb values as this virus. Raises a
NoChildException if this virus particle does not reproduce.
"""
chance = self.maxBirthProb * (1 - popDensity)
prob = random.random()
if prob < chance:
offspring = SimpleVirus(self.maxBirthProb, self.clearProb)
return offspring
raise NoChildException
class SimplePatient(object):
"""
Representation of a simplified patient. The patient does not take any drugs
and his/her virus populations have no drug resistance.
"""
def __init__(self, viruses, maxPop):
"""
Initialization function, saves the viruses and maxPop parameters as
attributes.
viruses: the list representing the virus population (a list of
SimpleVirus instances)
maxPop: the maximum virus population for this patient (an integer)
"""
self.viruses = viruses
self.maxPop = maxPop
def getTotalPop(self):
"""
Gets the current total virus population.
returns: The total virus population (an integer)
"""
return len(self.viruses)
def update(self):
"""
Update the state of the virus population in this patient for a single
time step. update() should execute the following steps in this order:
- Determine whether each virus particle survives and updates the list
of virus particles accordingly.
- The current population density is calculated. This population density
value is used until the next call to update()
- Determine whether each virus particle should reproduce and add
offspring virus particles to the list of viruses in this patient.
returns: the total virus population at the end of the update (an
integer)
"""
health = []
# the list of viruses isn't cleared
offsprings = []
for v in self.viruses:
# append the virus which is able to reproduce to health
if not v.doesClear():
health.append(v)
popDensity = float(len(health))/float(self.maxPop)
assert 0 <= popDensity <=1,'wrong popDensity'
for v in health:
# append the offsprings the viruses reproduce to a list
try:
offsprings.append(v.reproduce(popDensity))
except NoChildException: pass
self.viruses = health + offsprings
# the new viruses list is both list health and list offspring
return len(self.viruses)
#
# PROBLEM 2
#
def problem2():
"""
Run the simulation and plot the graph for problem 2 (no drugs are used,
viruses do not have any drug resistance).
Instantiates a patient, runs a simulation for 300 timesteps, and plots the
total virus population as a function of time.
"""
v = []
pop = []
for i in range(100):
v.append(SimpleVirus(0.1, 0.05))
poorguy = SimplePatient(v, 1000)
for i in range(300):
pop.append(poorguy.update())
pylab.plot(pop)
pylab.xlabel('Time')
pylab.ylabel('Total virus population')
pylab.title('Simulation of viruses reproduction without drug')
pylab.show()
#
# PROBLEM 3
#
class ResistantVirus(SimpleVirus):
"""
Representation of a virus which can have drug resistance.
"""
def __init__(self, maxBirthProb, clearProb, resistances, mutProb):
"""
Initialize a ResistantVirus instance, saves all parameters as attributes
of the instance.
maxBirthProb: Maximum reproduction probability (a float between 0-1)
clearProb: Maximum clearance probability (a float between 0-1).
resistances: A dictionary of drug names (strings) mapping to the state
of this virus particle's resistance (either True or False) to each drug.
e.g. {'guttagonol':False, 'grimpex',False}, means that this virus
particle is resistant to neither guttagonol nor grimpex.
mutProb: Mutation probability for this virus particle (a float). This is
the probability of the offspring acquiring or losing resistance to a drug.
"""
assert type(maxBirthProb) == type(clearProb) == type(mutProb) == float, 'wrong input type'
assert 0 <= maxBirthProb <= 1, 'maxBirthProb should be in [0,1]'
assert 0 <= clearProb <= 1, 'clearProb should be in [0,1]'
assert 0 <= mutProb <= 1, 'mutProb should be in [0,1]'
self.maxBirthProb = maxBirthProb
self.clearProb = clearProb
self.resistances = resistances
self.mutProb = mutProb
def getResistance(self, drug):
"""
Get the state of this virus particle's resistance to a drug. This method
is called by getResistPop() in Patient to determine how many virus
particles have resistance to a drug.
drug: the drug (a string).
returns: True if this virus instance is resistant to the drug, False
otherwise.
"""
return self.resistances[drug]
def reproduce(self, popDensity, activeDrugs):
"""
Stochastically determines whether this virus particle reproduces at a
time step. Called by the update() method in the Patient class.
If the virus particle is not resistant to any drug in activeDrugs,
then it does not reproduce. Otherwise, the virus particle reproduces
with probability:
self.maxBirthProb * (1 - popDensity).
If this virus particle reproduces, then reproduce() creates and returns
the instance of the offspring ResistantVirus (which has the same
maxBirthProb and clearProb values as its parent).
For each drug resistance trait of the virus (i.e. each key of
self.resistances), the offspring has probability 1-mutProb of
inheriting that resistance trait from the parent, and probability
mutProb of switching that resistance trait in the offspring.
For example, if a virus particle is resistant to guttagonol but not
grimpex, and `self.mutProb` is 0.1, then there is a 10% chance that
that the offspring will lose resistance to guttagonol and a 90%
chance that the offspring will be resistant to guttagonol.
There is also a 10% chance that the offspring will gain resistance to
grimpex and a 90% chance that the offspring will not be resistant to
grimpex.
popDensity: the population density (a float), defined as the current
virus population divided by the maximum population
activeDrugs: a list of the drug names acting on this virus particle
(a list of strings).
returns: a new instance of the ResistantVirus class representing the
offspring of this virus particle. The child should have the same
maxBirthProb and clearProb values as this virus. Raises a
NoChildException if this virus particle does not reproduce.
"""
for drug in activeDrugs:
if not self.resistances[drug]:
raise NoChildException
chance = self.maxBirthProb * (1 - popDensity)
prob = random.random()
if prob < chance:
# reproduce
child_resistances = {}
for drug in self.resistances:
switch = random.random()
if switch < self.mutProb:
# mutate
child_resistances[drug] = not self.resistances[drug]
else:
# inherit
child_resistances[drug] = self.resistances[drug]
offspring = ResistantVirus(self.maxBirthProb, self.clearProb, child_resistances, self.mutProb)
return offspring
raise NoChildException
class Patient(SimplePatient):
"""
Representation of a patient. The patient is able to take drugs and his/her
virus population can acquire resistance to the drugs he/she takes.
"""
def __init__(self, viruses, maxPop):
"""
Initialization function, saves the viruses and maxPop parameters as
attributes. Also initializes the list of drugs being administered
(which should initially include no drugs).
viruses: the list representing the virus population (a list of
SimpleVirus instances)
maxPop: the maximum virus population for this patient (an integer)
"""
self.viruses = viruses
self.maxPop = maxPop
self.prescription = []
def addPrescription(self, newDrug):
"""
Administer a drug to this patient. After a prescription is added, the
drug acts on the virus population for all subsequent time steps. If the
newDrug is already prescribed to this patient, the method has no effect.
newDrug: The name of the drug to administer to the patient (a string).
postcondition: list of drugs being administered to a patient is updated
"""
if newDrug not in self.prescription:
self.prescription.append(newDrug)
def getPrescriptions(self):
"""
Returns the drugs that are being administered to this patient.
returns: The list of drug names (strings) being administered to this
patient.
"""
return self.prescription
def getResistPop(self, drugResist):
"""
Get the population of virus particles resistant to the drugs listed in
drugResist.
drugResist: Which drug resistances to include in the population (a list
of strings - e.g. ['guttagonol'] or ['guttagonol', 'grimpex'])
returns: the population of viruses (an integer) with resistances to all
drugs in the drugResist list.
"""
resistpop = 0
for v in self.viruses:
resist_all = True
for drug in drugResist:
if not v.resistances[drug]:
resist_all = False
if resist_all == True:
resistpop += 1
return resistpop
def update(self):
"""
Update the state of the virus population in this patient for a single
time step. update() should execute these actions in order:
- Determine whether each virus particle survives and update the list of
virus particles accordingly
- The current population density is calculated. This population density
value is used until the next call to update().
- Determine whether each virus particle should reproduce and add
offspring virus particles to the list of viruses in this patient.
The list of drugs being administered should be accounted for in the
determination of whether each virus particle reproduces.
returns: the total virus population at the end of the update (an
integer)
"""
health = []
# the list of viruses isn't cleared
offsprings = []
for v in self.viruses:
# append the virus which is able to reproduce to health
if not v.doesClear():
health.append(v)
popDensity = float(len(health))/float(self.maxPop)
assert 0 <= popDensity <=1,'wrong popDensity'
for v in health:
# append the offsprings the viruses reproduce to a list
try:
offsprings.append(v.reproduce(popDensity, self.prescription))
except NoChildException: pass
self.viruses = health + offsprings
# the new viruses list is both list health and list offspring
return len(self.viruses)
#
# PROBLEM 4
#
def problem4():
"""
Runs simulations and plots graphs for problem 4.
Instantiates a patient, runs a simulation for 150 timesteps, adds
guttagonol, and runs the simulation for an additional 150 timesteps.
total virus population vs. time and guttagonol-resistant virus population
vs. time are plotted
"""
v = []
pop = []
for i in range(100):
v.append(ResistantVirus(0.1, 0.05, {'guttagonol':False}, 0.005))
poorguy = Patient(v, 1000)
poorguy.addPrescription('guttagonol')
for i in range(150):
pop.append(poorguy.update())
pylab.plot(pop)
pylab.xlabel('Time')
pylab.ylabel('Total virus population')
pylab.title('Simulation of viruses reproduction with drug')
pylab.show()
#
# PROBLEM 5
#
def problem5():
"""
Runs simulations and make histograms for problem 5.
Runs multiple simulations to show the relationship between delayed treatment
and patient outcome.
Histograms of final total virus populations are displayed for delays of 300,
150, 75, 0 timesteps (followed by an additional 150 timesteps of
simulation).
"""
tot_trial = 100
delay = [300, 150, 75, 0]
for s in delay:
trial = 0
record = []
for test in range(tot_trial):
trial += 1
v = []
pop = []
for i in range(100):
v.append(ResistantVirus(0.1, 0.05, {'guttagonol':False}, 0.005))
poorguy = Patient(v, 1000)
# instiate patient
for i in range(s):
poorguy.update()
poorguy.addPrescription('guttagonol')
# take meds
for i in range(150):
poorguy.update()
record.append(poorguy.getTotalPop())
# record the final virus population
print 'delay: '+str(s)+' timesteps, Tiral: '+str(trial)
cured = 0
for result in record:
if result <= 50:
cured +=1
curerate = str(float(cured) / len(record) * 100.0) + '%'
pylab.figure()
pylab.hist(record, bins=20, label='Cure rate: '+curerate, facecolor='g')
pylab.legend()
pylab.title('Simulation of viruses reproduction with drug delay '+str(s)+' timesteps')
pylab.xlabel('Total virus population')
pylab.ylabel('Number of patients')
pylab.show()
#
# PROBLEM 6
#
def problem6():
"""
Runs simulations and make histograms for problem 6.
Runs multiple simulations to show the relationship between administration
of multiple drugs and patient outcome.
Histograms of final total virus populations are displayed for lag times of
150, 75, 0 timesteps between adding drugs (followed by an additional 150
timesteps of simulation).
"""
delay = [300, 150, 75, 0]
for s in delay:
trial = 0
record = []
for test in range(30):
trial += 1
v = []
pop = []
for i in range(100):
v.append(ResistantVirus(0.1, 0.05, {'guttagonol':False,'grimpex':False}, 0.005))
poorguy = Patient(v, 1000)
# initiate patient
for i in range(150):
poorguy.update()
poorguy.addPrescription('guttagonol')
# take meds 1
for i in range(s):
poorguy.update()
poorguy.addPrescription('grimpex')
# take meds 2
for i in range(150):
poorguy.update()
record.append(poorguy.getTotalPop())
# record the final virus population
print 'delay: '+str(s)+' timesteps, Tiral: '+str(trial)
cured = 0
for result in record:
if result <= 50:
cured +=1
curerate = str(float(cured) / len(record) * 100.0) + '%'
pylab.figure()
pylab.hist(record, bins=20, label='Cure rate: '+curerate, facecolor='g')
pylab.legend()
pylab.title('Simulation of viruses reproduction with delay '+str(s)+' timesteps between 2 drugs')
pylab.xlabel('Total virus population')
pylab.ylabel('Number of patients')
pylab.show()
#
# PROBLEM 7
#
def problem7():
"""
Run simulations and plot graphs examining the relationship between
administration of multiple drugs and patient outcome.
Plots of total and drug-resistant viruses vs. time are made for a
simulation with a 300 time step delay between administering the 2 drugs and
a simulations for which drugs are administered simultaneously.
"""
delay = [300, 0]
t = {300:'Simulation of viruses population agianst time \n with a 300 time step delay between administering the 2 drugs',0:'Simulation of viruses population agianst time \n with drugs administered simultaneously'}
for s in delay:
v = []
pop = [] # total virus population
pop1 = [] # the population of guttagonol-resistant virus
pop2 = [] # the population of grimpex- resistant virus
popb = [] # the population of viruses that are resistant to both drugs
for i in range(100):
v.append(ResistantVirus(0.1, 0.05, {'guttagonol':False,'grimpex':False}, 0.005))
poorguy = Patient(v, 1000)
# initiate patient
for i in range(150):
pop.append(poorguy.update())
p1 = 0
p2 = 0
pb = 0
for v in poorguy.viruses:
if v.resistances['guttagonol']: p1 += 1
if v.resistances['grimpex']: p2 += 1
if v.resistances['guttagonol'] and v.resistances['grimpex']: pb += 1
pop1.append(p1)
pop2.append(p2)
popb.append(pb)
poorguy.addPrescription('guttagonol')
# take meds 1
for i in range(s):
pop.append(poorguy.update())
p1 = 0
p2 = 0
pb = 0
for v in poorguy.viruses:
if v.resistances['guttagonol']: p1 += 1
if v.resistances['grimpex']: p2 += 1
if v.resistances['guttagonol'] and v.resistances['grimpex']: pb += 1
pop1.append(p1)
pop2.append(p2)
popb.append(pb)
poorguy.addPrescription('grimpex')
# take meds 2
for i in range(150):
pop.append(poorguy.update())
p1 = 0
p2 = 0
pb = 0
for v in poorguy.viruses:
if v.resistances['guttagonol']: p1 += 1
if v.resistances['grimpex']: p2 += 1
if v.resistances['guttagonol'] and v.resistances['grimpex']: pb += 1
pop1.append(p1)
pop2.append(p2)
popb.append(pb)
pylab.figure()
pylab.plot(pop, label='total')
pylab.plot(pop1, label='guttagonol-resistant virus')
pylab.plot(pop2, label='grimpex- resistant virus')
pylab.plot(popb, label='resistant to both drugs')
pylab.legend(loc=0)
pylab.xlabel('Time')
pylab.ylabel('Virus population')
pylab.title(t[s])
pylab.show()
No comments. Sign up or log in to comment # Problem Set 11: Simulating robots
# Name:
# Collaborators:
# Time:
import math
import random
import pylab
##import time
##import ps11_visualize_amended
# === Provided classes
class Position(object):
"""
A Position represents a location in a two-dimensional room.
"""
def __init__(self, x, y):
"""
Initializes a position with coordinates (x, y).
x: a real number indicating the x-coordinate
y: a real number indicating the y-coordinate
"""
self.x = x
self.y = y
def getX(self):
return self.x
def getY(self):
return self.y
def getNewPosition(self, angle, speed):
"""
Computes and returns the new Position after a single clock-tick has
passed, with this object as the current position, and with the
specified angle and speed.
Does NOT test whether the returned position fits inside the room.
angle: integer representing angle in degrees, 0 <= angle < 360
speed: positive float representing speed
Returns: a Position object representing the new position.
"""
old_x, old_y = self.getX(), self.getY()
# Compute the change in position
delta_y = speed * math.sin(math.radians(angle))
delta_x = speed * math.cos(math.radians(angle))
# Add that to the existing position
new_x = old_x + delta_x
new_y = old_y + delta_y
# returns two floats
return new_x, new_y
# === Problems 1 and 2
class RectangularRoom(object):
"""
A RectangularRoom represents a rectangular region containing clean or dirty
tiles.
A room has a width and a height and contains (width * height) tiles. At any
particular time, each of these tiles is either clean or dirty.
"""
def __init__(self, width, height):
"""
Initializes a rectangular room with the specified width and height.
Initially, no tiles in the room have been cleaned.
width: an integer > 0
height: an integer > 0
"""
self.width = width
self.height = height
# represent the state of the floor using a dictionary. If dirty value = 0, clean = 1
self.cleanDict = {}
for fat in range(width):
for tall in range(height):
self.cleanDict[fat, tall] = 0
def cleanTileAtPosition(self, pos):
"""
Mark the tile under the position POS as cleaned.
Assumes that POS represents a valid position inside this room.
pos: a Position object
"""
self.cleanDict[pos] = 1
def isTileCleaned(self, m, n):
"""
Return True if the tile (m, n) has been cleaned.
Assumes that (m, n) represents a valid tile inside the room.
m: an integer
n: an integer
returns: True if (m, n) is cleaned, False otherwise
"""
return self.cleanDict[int(m), int(n)] == 1
def getNumTiles(self):
"""
Return the total number of tiles in the room.
returns: an integer
"""
return self.width*self.height
def getNumCleanedTiles(self):
"""
Return the total number of clean tiles in the room.
returns: an integer
"""
return sum(self.cleanDict.values())
def getRandomPosition(self):
"""
Return a random position inside the room.
returns: a Position object.
"""
return random.choice(self.cleanDict.keys())
def isPositionInRoom(self, pos):
"""
Return True if POS is inside the room.
pos: a Position object.
returns: True if POS is in the room, False otherwise.
"""
return pos in self.cleanDict
##a = RectangularRoom(5,5)
class BaseRobot(object):
"""
Represents a robot cleaning a particular room.
At all times the robot has a particular position and direction in
the room. The robot also has a fixed speed.
Subclasses of BaseRobot should provide movement strategies by
implementing updatePositionAndClean(), which simulates a single
time-step.
"""
def __init__(self, room, speed):
"""
Initializes a Robot with the given speed in the specified
room. The robot initially has a random direction d and a
random position p in the room.
The direction d is an integer satisfying 0 <= d < 360; it
specifies an angle in degrees.
p is a Position object giving the robot's position.
room: a RectangularRoom object.
speed: a float (speed > 0)
"""
self.room = room
self.speed = float(speed)
self.direction = random.randint(0, 359)
self.position = self.room.getRandomPosition()
def getRobotPosition(self):
"""
Return the position of the robot.
returns: a Position object giving the robot's position.
"""
return self.position
def getRobotDirection(self):
"""
Return the direction of the robot.
returns: an integer d giving the direction of the robot as an angle in
degrees, 0 <= d < 360.
"""
return self.direction
def setRobotPosition(self, position):
"""
Set the position of the robot to POSITION.
position: a Position object.
"""
self.position = position
def setRobotDirection(self, direction):
"""
Set the direction of the robot to DIRECTION.
direction: integer representing an angle in degrees
"""
self.direction = direction
##b = BaseRobot(a, 1)
class Robot(BaseRobot):
"""
A Robot is a BaseRobot with the standard movement strategy.
At each time-step, a Robot attempts to move in its current
direction; when it hits a wall, it chooses a new direction
randomly.
"""
def updatePositionAndClean(self):
"""
Simulate the passage of a single time-step.
Move the robot to a new position and mark the tile it is on as having
been cleaned.
"""
# get new position
self.new_x, self.new_y = Position(self.getRobotPosition()[0], self.getRobotPosition()[1]).getNewPosition(self.getRobotDirection(), self.speed)
# checking for negative establishes left and bottom boundaries
if self.new_x < 0 or self.new_y < 0:
# if the new position is out of the room, change direction and do it again
self.direction = random.randint(0, 359)
self.updatePositionAndClean()
# if it's in the room clean it. int rounds down to whole number.
elif self.room.isPositionInRoom((int(self.new_x), int(self.new_y))):
self.setRobotPosition((self.new_x, self.new_y)) # position must be kept as float, otherwise distance will keep being reset
self.room.cleanTileAtPosition((int(self.new_x), int(self.new_y))) # coordinates are integers. must keep with convention.
else:
# if the new position is out of the room, change direction and do it again
self.direction = random.randint(0, 359)
self.updatePositionAndClean()
##c = Robot(a, 1)
# === Problem 3
def runSimulation(num_robots, width, height, speed, min_coverage, num_trials,
robot_type, visualize):
"""
Runs NUM_TRIALS trials of the simulation and returns a list of
lists, one per trial. The list for a trial has an element for each
timestep of that trial, the value of which is the percentage of
the room that is clean after that timestep. Each trial stops when
MIN_COVERAGE of the room is clean.
The simulation is run with NUM_ROBOTS robots of type ROBOT_TYPE,
each with speed SPEED, in a room of dimensions WIDTH x HEIGHT.
Visualization is turned on when boolean VISUALIZE is set to True.
num_robots: an int (num_robots > 0)
speed: a float (speed > 0)
width: an int (width > 0)
height: an int (height > 0)
min_coverage: a float (0 <= min_coverage <= 1.0)
num_trials: an int (num_trials > 0)
robot_type: class of robot to be instantiated (e.g. Robot or
RandomWalkRobot)
visualize: a boolean (True to turn on visualization)
"""
anim = None
robotDict = {}
simlist = []
trial = 0
while trial < num_trials:
room = RectangularRoom(width, height)
# create a dictionary of numbered robots of length num_robots.
# a list of variables would not work for this task. The variables were
# cleared when passed to runtrial
for ronum in range(num_robots):
robotDict[ronum] = robot_type(room, speed)
if visualize:
anim = ps11_visualize_amended.RobotVisualization(num_robots, width, height)
# append the trial's resultant list to simlist
simlist.append(runtrial(room, robotDict, min_coverage, anim, visualize))
trial += 1 # go to next trial
if visualize:
anim.done()
return simlist
def runtrial(room, robotDict, min_coverage, anim, visualize):
"""Returns the list for one trial run"""
triallist = []
percentclean = 0
totaltiles = room.getNumTiles()
while percentclean < min_coverage:
# run num_robots simultaneously in time step
for robot in robotDict:
robotDict[robot].updatePositionAndClean()
percentclean = round(float(room.getNumCleanedTiles())/totaltiles, 2)
triallist.append(percentclean)
robots = robotDict.values()
if visualize:
anim.update(room, robots)
return triallist
##d = runSimulation(5, 20, 20, 1, .9, 1, Robot, True)
# === Provided function
def computeMeans(list_of_lists):
"""
Returns a list as long as the longest list in LIST_OF_LISTS, where
the value at index i is the average of the values at index i in
all of LIST_OF_LISTS' lists.
Lists shorter than the longest list are padded with their final
value to be the same length.
"""
# Find length of longest list
longest = 0
for lst in list_of_lists:
if len(lst) > longest:
longest = len(lst)
# Get totals
tots = [0]*(longest)
for lst in list_of_lists:
for i in range(longest):
if i < len(lst):
tots[i] += lst[i]
else:
tots[i] += lst[-1]
# Convert tots to an array to make averaging across each index easier
tots = pylab.array(tots)
# Compute means
means = tots/float(len(list_of_lists))
return means
##q = [[ 0.11, 0.22, 0.33],[ 0.11, 0.198, 0.308, 0.396, 0.44 ],[ 0.11, 0.22, 0.33, 0.418, 0.488, 0.536, 0.536, 0.536, 0.536, 0.56 ]]
##p = computeMeans(q)
# === Helper Function
def avgTrialTime(simulation):
"""Returns the average number of time steps (an integer) for a simulation"""
# get the number of trials run
num_lists = float(len(simulation))
total_length = 0
# get the total number of time steps from one trial
for result in simulation:
total_length += len(result)
# return the average number of time steps per trial
return round(total_length/num_lists, 2)
# === Problem 4
def showPlot1():
"""
Produces a plot showing dependence of cleaning time on room size.
"""
roomside = [5, 10, 15, 20, 25]
lengthlist = []
roomarea = []
for side in roomside:
tempsim = runSimulation(3, side, side, 1, .75, 20, Robot, False)
roomarea.append(side*side)
lengthlist.append(avgTrialTime(tempsim))
pylab.figure()
pylab.plot(roomarea, lengthlist)
pylab.axis([25, 650, 0, 350])
pylab.ylabel('Cleaning Time')
pylab.xlabel('Room Area')
pylab.title('Average Time to Clean 75% of Various Room Sizes with 3 Robots')
pylab.show()
##showPlot1()
def showPlot2():
"""
Produces a plot showing dependence of cleaning time on number of robots.
"""
robotlist = list(range(1, 11))
lengthlist = []
for robot in robotlist:
tempsim = runSimulation(robot, 25, 25, 1, .75, 20, Robot, False)
lengthlist.append(avgTrialTime(tempsim))
pylab.figure()
pylab.plot(robotlist,lengthlist, 'ro')
pylab.axis([1, 10, 0, 1000])
pylab.ylabel('Cleaning Time')
pylab.xlabel('Number of Robots')
pylab.title('Average Time to Clean 75% of a 25x25 Room with 1-10 Robots')
pylab.show()
##showPlot2()
def showPlot3():
"""
Produces a plot showing dependence of cleaning time on room shape.
"""
widthlist = [20, 25, 40, 50, 80, 100]
roomlist = []
lengthlist = []
for width in widthlist:
roomlist.append((width, 400/width))
for room in roomlist:
tempsim = runSimulation(2, room[0], room[1], 1, .75, 50, Robot, False)
lengthlist.append(avgTrialTime(tempsim))
pylab.figure()
pylab.plot(widthlist,lengthlist)
pylab.axis([20, 100, 250, 400])
pylab.ylabel('Cleaning Time')
pylab.xlabel('Room Width')
pylab.title('Average Time to Clean 75% of a Various Room Shapes with Same Area using 2 Robots')
pylab.show()
##showPlot3()
def showPlot4():
"""
Produces a plot showing cleaning time vs. percentage cleaned, for
each of 1-5 robots.
"""
lengthDict = {}
x = [25, 40, 55, 70, 85]
for robot in range(1, 6):
templength = []
for coverage in x:
tempsim = runSimulation(robot, 25, 25, 1, coverage/100.0, 20, Robot, False)
templength.append(avgTrialTime(tempsim))
lengthDict[robot] = templength
pylab.figure()
pylab.plot(x, lengthDict[1], 'r', x, lengthDict[2], 'b', x, lengthDict[3], 'g', \
x, lengthDict[4], 'k', x, lengthDict[5], 'y')
pylab.legend(('1 robot', '2 robots', '3 robots', '4 robots', '5 robots'), loc = 2)
pylab.axis([20, 90, 0, 1275])
pylab.ylabel('Mean Cleaning Time')
pylab.xlabel('Percent Cleaned')
pylab.title('Average Time to Clean Various Percentages of a 25x25 Room with 1-5 Robots')
pylab.show()
##showPlot4()
# === Problem 5
class RandomWalkRobot(BaseRobot):
"""
A RandomWalkRobot is a robot with the "random walk" movement
strategy: it chooses a new direction at random after each
time-step.
"""
def updatePositionAndClean(self):
"""
Simulate the passage of a single time-step.
Move the robot to a new position and mark the tile it is on as having
been cleaned. Choose a new random direction after each move.
"""
# get new position
self.new_x, self.new_y = Position(self.getRobotPosition()[0], self.getRobotPosition()[1])\
.getNewPosition(self.getRobotDirection(), self.speed)
# checking for negative establishes left and bottom boundaries
if self.new_x < 0 or self.new_y < 0:
# if the new position is out of the room, change direction and do it again
self.direction = random.randint(0, 359)
self.updatePositionAndClean()
# if it's in the room clean it. int rounds down to whole number.
elif self.room.isPositionInRoom((int(self.new_x), int(self.new_y))):
self.setRobotPosition((self.new_x, self.new_y)) # position must be kept as float, otherwise distance will keep being reset
self.room.cleanTileAtPosition((int(self.new_x), int(self.new_y))) # coordinates are integers. must keep with convention.
self.direction = random.randint(0, 359) # choose a random direction after cleaning
else:
# if the new position is out of the room, change direction and do it again
self.direction = random.randint(0, 359)
self.updatePositionAndClean()
##e = runSimulation(1, 20, 20, 1, .9, 1, RandomWalkRobot, True)
# === Problem 6
def showPlot5():
"""
Produces a plot comparing the two robot strategies. Shows the average time
to clean 75% of a 20x20 room as a function of number of robots.
It seems as though the most telling comparison is between the two approaches
is to between time and robot density. For a fixed room area, robot density
translates to number of robots.
RandomWalk is inferior, because it has too much repetition.
"""
robotlist = list(range(1, 11))
lengthlistReg = []
lengthlistRandom = []
for robot in robotlist:
tempsimReg = runSimulation(robot, 20, 20, 1, .75, 20, Robot, False)
tempsimRandom = runSimulation(robot, 20, 20, 1, .75, 20, RandomWalkRobot, False)
lengthlistReg.append(avgTrialTime(tempsimReg))
lengthlistRandom.append(avgTrialTime(tempsimRandom))
pylab.figure()
pylab.plot(robotlist,lengthlistReg, 'ro', robotlist,lengthlistRandom, 'bo')
pylab.axis([1, 10, 0, 1700])
pylab.legend(('NormalWalk' ,'RandomWalk'), loc = 1)
pylab.ylabel('Cleaning Time')
pylab.xlabel('Number of Robots')
pylab.title('Average Time to Clean 75% of a 20x20 Room with 1-10 Robots')
pylab.show()
##showPlot5()
ps_11_visualize_amended
# Problem Set 11:
# Visualization code for simulated robots.
#
# See the problem set for instructions on how to use this code.
import math
import time
from Tkinter import *
class RobotVisualization:
def __init__(self, num_robots, width, height, delay = 0.2):
"Initializes a visualization with the specified parameters."
# Number of seconds to pause after each frame
self.delay = delay
self.max_dim = max(width, height)
self.width = width
self.height = height
self.num_robots = num_robots
# Initialize a drawing surface
self.master = Tk()
self.w = Canvas(self.master, width=500, height=500)
self.w.pack()
self.master.update()
# Draw a backing and lines
x1, y1 = self._map_coords(0, 0)
x2, y2 = self._map_coords(width, height)
self.w.create_rectangle(x1, y1, x2, y2, fill = "white")
# Draw gray squares for dirty tiles
self.tiles = {}
for i in range(width):
for j in range(height):
x1, y1 = self._map_coords(i, j)
x2, y2 = self._map_coords(i + 1, j + 1)
self.tiles[(i, j)] = self.w.create_rectangle(x1, y1, x2, y2,
fill = "gray")
# Draw gridlines
for i in range(width + 1):
x1, y1 = self._map_coords(i, 0)
x2, y2 = self._map_coords(i, height)
self.w.create_line(x1, y1, x2, y2)
for i in range(height + 1):
x1, y1 = self._map_coords(0, i)
x2, y2 = self._map_coords(width, i)
self.w.create_line(x1, y1, x2, y2)
# Draw some status text
self.robots = None
self.text = self.w.create_text(25, 0, anchor=NW,
text=self._status_string(0, 0))
self.time = 0
self.master.update()
def _status_string(self, time, num_clean_tiles):
"Returns an appropriate status string to print."
percent_clean = 100 * num_clean_tiles / (self.width * self.height)
return "Time: %04d; %d tiles (%d%%) cleaned" % \
(time, num_clean_tiles, percent_clean)
def _map_coords(self, x, y):
"Maps grid positions to window positions (in pixels)."
return (250 + 450 * ((x - self.width / 2.0) / self.max_dim),
250 + 450 * ((self.height / 2.0 - y) / self.max_dim))
def _draw_robot(self, position, direction):
"Returns a polygon representing a robot with the specified parameters."
x, y = position[0], position[1]
d1 = direction + 165
d2 = direction - 165
x1, y1 = self._map_coords(x, y)
x2, y2 = self._map_coords(x + 0.6 * math.sin(math.radians(d1)),
y + 0.6 * math.cos(math.radians(d1)))
x3, y3 = self._map_coords(x + 0.6 * math.sin(math.radians(d2)),
y + 0.6 * math.cos(math.radians(d2)))
return self.w.create_polygon([x1, y1, x2, y2, x3, y3], fill="red")
def update(self, room, robots):
"Redraws the visualization with the specified room and robot state."
# Removes a gray square for any tiles have been cleaned.
for i in range(self.width):
for j in range(self.height):
if room.isTileCleaned(i, j):
self.w.delete(self.tiles[(i, j)])
# Delete all existing robots.
if self.robots:
for robot in self.robots:
self.w.delete(robot)
self.master.update_idletasks()
# Draw new robots
self.robots = []
for robot in robots:
pos = robot.getRobotPosition()
x, y = pos[0], pos[1]
x1, y1 = self._map_coords(x - 0.08, y - 0.08)
x2, y2 = self._map_coords(x + 0.08, y + 0.08)
self.robots.append(self.w.create_oval(x1, y1, x2, y2,
fill = "black"))
self.robots.append(
self._draw_robot(robot.getRobotPosition(), robot.getRobotDirection()))
# Update text
self.w.delete(self.text)
self.time += 1
self.text = self.w.create_text(
25, 0, anchor=NW,
text=self._status_string(self.time, room.getNumCleanedTiles()))
self.master.update()
time.sleep(self.delay)
def done(self):
"Indicate that the animation is done so that we allow the user to close the window."
mainloop()
No comments. Sign up or log in to comment # Problem Set 11: Simulating robots
# Name: Alex
import math
import ps11_visualize
from matplotlib import pyplot
import random
# === Provided classes
class Position(object):
"""
A Position represents a location in a two-dimensional room.
"""
def __init__(self, x, y):
self.x = x
self.y = y
def getX(self):
return self.x
def getY(self):
return self.y
def getNewPosition(self, angle, speed):
old_x, old_y = self.getX(), self.getY()
# Compute the change in position
delta_y = speed * math.cos(math.radians(angle))
delta_x = speed * math.sin(math.radians(angle))
# Add that to the existing position
new_x = old_x + delta_x
new_y = old_y + delta_y
return Position(new_x, new_y)
# === Problems 1 and 2
class RectangularRoom(object):
def __init__(self, width, height):
self.width = width
self.height = height
self.tiles = {}
for i in range(self.width):
for j in range(self.height):
self.tiles[(i, j)] = False
def cleanTileAtPosition(self, pos):
self.tiles[int(pos.getX()), int(pos.getY())] = True
def isTileCleaned(self, m, n):
return self.tiles[m, n]
def getNumTiles(self):
return len(self.tiles)
def getNumCleanedTiles(self):
return len(filter((lambda k: self.tiles[k] == True), self.tiles))
def getRandomPosition(self):
x = random.choice(range(self.width))
y = random.choice(range(self.height))
return Position(x, y)
def isPositionInRoom(self, pos):
if pos.getX() > 0 and pos.getY() > 0 and \
pos.getX() < self.width and pos.getY() < self.height:
return True
else:
return False
class BaseRobot(object):
def __init__(self, room, speed):
self.room = room
self.speed = speed
self.p = self.room.getRandomPosition()
self.d = random.choice(range(360))
def getRobotPosition(self):
return self.p
def getRobotDirection(self):
return self.d
def setRobotPosition(self, position):
self.p = position
def setRobotDirection(self, direction):
self.d = direction
class Robot(BaseRobot):
def updatePositionAndClean(self):
while 1:
tmp_p = self.p.getNewPosition(self.d, self.speed)
if self.room.isPositionInRoom(tmp_p):
break
else:
self.d = (random.choice(range(360)))
self.p = tmp_p
self.room.cleanTileAtPosition(self.p)
# === Problem 3
def runSimulation(num_robots, speed, width, height, min_coverage, num_trials,
robot_type, visualize):
"""
Runs NUM_TRIALS trials of the simulation and returns a list of
lists, one per trial. The list for a trial has an element for each
timestep of that trial, the value of which is the percentage of
the room that is clean after that timestep. Each trial stops when
MIN_COVERAGE of the room is clean.
The simulation is run with NUM_ROBOTS robots of type ROBOT_TYPE,
each with speed SPEED, in a room of dimensions WIDTH x HEIGHT.
Visualization is turned on when boolean VISUALIZE is set to True.
num_robots: an int (num_robots > 0)
speed: a float (speed > 0)
width: an int (width > 0)
height: an int (height > 0)
min_coverage: a float (0 <= min_coverage <= 1.0)
num_trials: an int (num_trials > 0)
robot_type: class of robot to be instantiated (e.g. Robot or
RandomWalkRobot)
visualize: a boolean (True to turn on visualization)
"""
result = []
# anim = ps11_visualize.RobotVisualization(num_robots, width, height)
for i in range(0, num_trials):
# anim = ps11_visualize.RobotVisualization(num_robots, width, height)
# Initialize room and robots
room = RectangularRoom(width, height)
robots = []
for j in range(0, num_robots):
robots.append(robot_type(room, speed))
# Run the simulation
room_coverrage = 0
trial_result = []
while room_coverrage < min_coverage:
for r in robots:
r.updatePositionAndClean()
room_coverrage = (float(room.getNumCleanedTiles()) / room.getNumTiles())
trial_result.append(room_coverrage)
# anim.update(room, robots)
result.append(trial_result)
# anim.done()
return result
# === Provided function
def computeMeans(list_of_lists):
"""
Returns a list as long as the longest list in LIST_OF_LISTS, where
the value at index i is the average of the values at index i in
all of LIST_OF_LISTS' lists.
Lists shorter than the longest list are padded with their final
value to be the same length.
"""
# Find length of longest list
longest = 0
for lst in list_of_lists:
if len(lst) > longest:
longest = len(lst)
# Get totals
tots = [0]*(longest)
for lst in list_of_lists:
for i in range(longest):
if i < len(lst):
tots[i] += lst[i]
else:
tots[i] += lst[-1]
# Convert tots to an array to make averaging across each index easier
tots = pylab.array(tots)
# Compute means
means = tots/float(len(list_of_lists))
return means
def avg_list_len(list):
"""Documentation"""
total_lenght = 0.0
for l in list:
total_lenght += len(l)
return total_lenght / len(list)
# === Problem 4
def showPlot1():
"""
Produces a plot showing dependence of cleaning time on room size.
"""
num_robots = 1
num_trials = 5
speed = 1
min_coverage = 0.75
x_values = []
y_values = []
for i in range(5, 30, 5):
y_values.append(avg_list_len(runSimulation(num_robots, speed, i, i,
min_coverage, num_trials, Robot, False)))
x_values.append(i)
pyplot.plot(x_values, y_values)
pyplot.xlabel('Room size')
pyplot.ylabel('Time')
pyplot.title('Time by room size')
pyplot.show()
# showPlot1()
def showPlot2():
"""
Produces a plot showing dependence of cleaning time on number of robots.
"""
room_width = 25
room_height = 25
num_trials = 5
speed = 1
min_coverage = 0.75
x_values = []
y_values = []
for i in range(1, 11):
y_values.append(avg_list_len(runSimulation(i, speed, room_width, room_height,
min_coverage, num_trials, Robot, False)))
x_values.append(i)
print y_values
pyplot.plot(x_values, y_values)
pyplot.xlabel('Robot count')
pyplot.ylabel('Time')
pyplot.title('Time by robot count')
pyplot.show()
#showPlot2()
def showPlot3():
"""
Produces a plot showing dependence of cleaning time on room shape.
"""
room_width = [20, 25, 40, 50, 80, 100]
room_height = [20, 16, 10, 8, 5, 4]
num_trials = 20
speed = 1
min_coverage = 0.75
x_values = []
y_values = []
for i in range(6):
print i
tw = room_width[i]
th = room_height[i]
y_values.append(avg_list_len(runSimulation(2, speed, tw, th,
min_coverage, num_trials, Robot, False)))
x_values.append(i)
print y_values
pyplot.plot(x_values, y_values)
pyplot.xlabel('Room dims')
pyplot.ylabel('Time')
pyplot.title('Time by room shape')
pyplot.show()
# showPlot3()
def showPlot4():
"""
Produces a plot showing cleaning time vs. percentage cleaned, for
each of 1-5 robots.
"""
room_width = 25
room_height = 25
num_trials = 1
speed = 1
for r in range(1, 6):
x_values = []
y_values = []
for i in range(1, 101):
cleanage_per = float(i) / 100
y_values.append(avg_list_len(runSimulation(r, speed, room_width,
room_height, cleanage_per, num_trials, Robot, False)))
x_values.append(i)
pyplot.figure(1)
pyplot.plot(x_values, y_values, label = str(r) + ' robots')
pyplot.xlabel('% cleanage')
pyplot.ylabel('Time')
pyplot.title('Time by % cleaned and robots')
pyplot.show()
#showPlot4()
# === Problem 5
class RandomWalkRobot(BaseRobot):
"""
A RandomWalkRobot is a robot with the "random walk" movement
strategy: it chooses a new direction at random after each
time-step.
"""
def updatePositionAndClean(self):
while 1:
self.d = (random.choice(range(360)))
tmp_p = self.p.getNewPosition(self.d, self.speed)
if self.room.isPositionInRoom(tmp_p):
break
else:
self.d = (random.choice(range(360)))
self.p = tmp_p
self.room.cleanTileAtPosition(self.p)
#runSimulation(1, 1, 10, 10, 1, 1, RandomWalkRobot, True)
# === Problem 6
def showPlot5():
"""
Produces a plot comparing the two robot strategies.
"""
num_robots = 5
num_trials = 10
speed = 1
min_coverage = 0.75
x_values = []
y_values = []
for i in range(5, 30, 5):
y_values.append(avg_list_len(runSimulation(num_robots, speed, i, i,
min_coverage, num_trials, Robot, False)))
x_values.append(i)
pyplot.figure(1)
pyplot.plot(x_values, y_values, label='Logic')
x_values = []
y_values = []
for i in range(5, 30, 5):
y_values.append(avg_list_len(runSimulation(num_robots, speed, i, i,
min_coverage, num_trials, RandomWalkRobot, False)))
x_values.append(i)
pyplot.figure(1)
pyplot.plot(x_values, y_values, label='Random')
pyplot.xlabel('Room size')
pyplot.ylabel('Time')
pyplot.title('Time by room size')
pyplot.legend()
pyplot.show()
showPlot5()
No comments. Sign up or log in to comment |
No comments. Sign up or log in to comment