diff --git a/agents.ipynb b/agents.ipynb
index 7976b12b2..8eba9f07e 100644
--- a/agents.ipynb
+++ b/agents.ipynb
@@ -8,7 +8,7 @@
"\n",
"An agent, as defined in 2.1 is anything that can perceive its environment through sensors, and act upon that environment through actuators based on its agent program. This can be a dog, robot, or even you. As long as you can perceive the environment and act on it, you are an agent. This notebook will explain how to implement a simple agent, create an environment, and create a program that helps the agent act on the environment based on its percepts.\n",
"\n",
- "Before moving on, review the Agent and Environment classes in [agents.py](https://github.com/aimacode/aima-python/blob/master/agents.py).\n",
+ "Before moving on, review the Agent and Environment classes in [agents.py](https://github.com/aimacode/aima-python/blob/master/agents.py).\n",
"\n",
"Let's begin by importing all the functions from the agents.py module and creating our first agent - a blind dog."
]
diff --git a/agents.py b/agents.py
index 650dfe97b..abd7b9f7a 100644
--- a/agents.py
+++ b/agents.py
@@ -55,16 +55,16 @@ def __repr__(self):
return '<{}>'.format(getattr(self, '__name__', self.__class__.__name__))
def is_alive(self):
- "Things that are 'alive' should return true."
+ """Things that are 'alive' should return true."""
return hasattr(self, 'alive') and self.alive
def show_state(self):
- "Display the agent's internal state. Subclasses should override."
+ """Display the agent's internal state. Subclasses should override."""
print("I don't know how to show_state.")
def display(self, canvas, x, y, width, height):
+ """Display an image of this Thing on the canvas."""
# Do we need this?
- "Display an image of this Thing on the canvas."
pass
@@ -89,7 +89,7 @@ def __init__(self, program=None):
self.performance = 0
if program is None:
def program(percept):
- return eval(input('Percept={}; action? ' .format(percept)))
+ return eval(input('Percept={}; action? '.format(percept)))
assert isinstance(program, collections.Callable)
self.program = program
@@ -129,14 +129,14 @@ def program(percept):
def RandomAgentProgram(actions):
- "An agent that chooses an action at random, ignoring all percepts."
+ """An agent that chooses an action at random, ignoring all percepts."""
return lambda percept: random.choice(actions)
# ______________________________________________________________________________
def SimpleReflexAgentProgram(rules, interpret_input):
- "This agent takes action based solely on the percept. [Figure 2.10]"
+ """This agent takes action based solely on the percept. [Figure 2.10]"""
def program(percept):
state = interpret_input(percept)
rule = rule_match(state, rules)
@@ -146,7 +146,7 @@ def program(percept):
def ModelBasedReflexAgentProgram(rules, update_state, model):
- "This agent takes action based on the percept and state. [Figure 2.8]"
+ """This agent takes action based on the percept and state. [Figure 2.8]"""
def program(percept):
program.state = update_state(program.state, program.action, percept, model)
rule = rule_match(program.state, rules)
@@ -157,7 +157,7 @@ def program(percept):
def rule_match(state, rules):
- "Find the first rule that matches state."
+ """Find the first rule that matches state."""
for rule in rules:
if rule.matches(state):
return rule
@@ -168,12 +168,12 @@ def rule_match(state, rules):
def RandomVacuumAgent():
- "Randomly choose one of the actions from the vacuum environment."
+ """Randomly choose one of the actions from the vacuum environment."""
return Agent(RandomAgentProgram(['Right', 'Left', 'Suck', 'NoOp']))
def TableDrivenVacuumAgent():
- "[Figure 2.3]"
+ """[Figure 2.3]"""
table = {((loc_A, 'Clean'),): 'Right',
((loc_A, 'Dirty'),): 'Suck',
((loc_B, 'Clean'),): 'Left',
@@ -189,7 +189,7 @@ def TableDrivenVacuumAgent():
def ReflexVacuumAgent():
- "A reflex agent for the two-state vacuum environment. [Figure 2.8]"
+ """A reflex agent for the two-state vacuum environment. [Figure 2.8]"""
def program(percept):
location, status = percept
if status == 'Dirty':
@@ -202,11 +202,11 @@ def program(percept):
def ModelBasedVacuumAgent():
- "An agent that keeps track of what locations are clean or dirty."
+ """An agent that keeps track of what locations are clean or dirty."""
model = {loc_A: None, loc_B: None}
def program(percept):
- "Same as ReflexVacuumAgent, except if everything is clean, do NoOp."
+ """Same as ReflexVacuumAgent, except if everything is clean, do NoOp."""
location, status = percept
model[location] = status # Update the model here
if model[loc_A] == model[loc_B] == 'Clean':
@@ -242,32 +242,29 @@ def thing_classes(self):
return [] # List of classes that can go into environment
def percept(self, agent):
- '''
- Return the percept that the agent sees at this point.
- (Implement this.)
- '''
+ """Return the percept that the agent sees at this point. (Implement this.)"""
raise NotImplementedError
def execute_action(self, agent, action):
- "Change the world to reflect this action. (Implement this.)"
+ """Change the world to reflect this action. (Implement this.)"""
raise NotImplementedError
def default_location(self, thing):
- "Default location to place a new thing with unspecified location."
+ """Default location to place a new thing with unspecified location."""
return None
def exogenous_change(self):
- "If there is spontaneous change in the world, override this."
+ """If there is spontaneous change in the world, override this."""
pass
def is_done(self):
- "By default, we're done when we can't find a live agent."
+ """By default, we're done when we can't find a live agent."""
return not any(agent.is_alive() for agent in self.agents)
def step(self):
"""Run the environment for one time step. If the
actions and exogenous changes are independent, this method will
- do. If there are interactions between them, you'll need to
+ do. If there are interactions between them, you'll need to
override this method."""
if not self.is_done():
actions = []
@@ -281,14 +278,14 @@ def step(self):
self.exogenous_change()
def run(self, steps=1000):
- "Run the Environment for given number of time steps."
+ """Run the Environment for given number of time steps."""
for step in range(steps):
if self.is_done():
return
self.step()
def list_things_at(self, location, tclass=Thing):
- "Return all things exactly at a given location."
+ """Return all things exactly at a given location."""
return [thing for thing in self.things
if thing.location == location and isinstance(thing, tclass)]
@@ -317,19 +314,19 @@ def delete_thing(self, thing):
except ValueError as e:
print(e)
print(" in Environment delete_thing")
- print(" Thing to be removed: {} at {}" .format(thing, thing.location))
- print(" from list: {}" .format([(thing, thing.location) for thing in self.things]))
+ print(" Thing to be removed: {} at {}".format(thing, thing.location))
+ print(" from list: {}".format([(thing, thing.location) for thing in self.things]))
if thing in self.agents:
self.agents.remove(thing)
class Direction():
- '''A direction class for agents that want to move in a 2D plane
+ """A direction class for agents that want to move in a 2D plane
Usage:
d = Direction("down")
To change directions:
d = d + "right" or d = d + Direction.R #Both do the same thing
Note that the argument to __add__ must be a string and not a Direction object.
- Also, it (the argument) can only be right or left.'''
+ Also, it (the argument) can only be right or left."""
R = "right"
L = "left"
@@ -396,7 +393,7 @@ def __init__(self, width=10, height=10):
perceptible_distance = 1
def things_near(self, location, radius=None):
- "Return all things within radius of location."
+ """Return all things within radius of location."""
if radius is None:
radius = self.perceptible_distance
radius2 = radius * radius
@@ -404,7 +401,7 @@ def things_near(self, location, radius=None):
if distance2(location, thing.location) <= radius2]
def percept(self, agent):
- '''By default, agent perceives things within a default radius.'''
+ """By default, agent perceives things within a default radius."""
return self.things_near(agent.location)
def execute_action(self, agent, action):
@@ -428,8 +425,8 @@ def default_location(self, thing):
return (random.choice(self.width), random.choice(self.height))
def move_to(self, thing, destination):
- '''Move a thing to a new location. Returns True on success or False if there is an Obstacle.
- If thing is holding anything, they move with him.'''
+ """Move a thing to a new location. Returns True on success or False if there is an Obstacle.
+ If thing is holding anything, they move with him."""
thing.bump = self.some_things_at(destination, Obstacle)
if not thing.bump:
thing.location = destination
@@ -449,9 +446,8 @@ def move_to(self, thing, destination):
# obs.thing_added(thing)
def add_thing(self, thing, location=(1, 1), exclude_duplicate_class_items=False):
- '''Adds things to the world.
- If (exclude_duplicate_class_items) then the item won't be added if the location
- has at least one item of the same class.'''
+ """Adds things to the world. If (exclude_duplicate_class_items) then the item won't be
+ added if the location has at least one item of the same class."""
if (self.is_inbounds(location)):
if (exclude_duplicate_class_items and
any(isinstance(t, thing.__class__) for t in self.list_things_at(location))):
@@ -459,12 +455,12 @@ def add_thing(self, thing, location=(1, 1), exclude_duplicate_class_items=False)
super(XYEnvironment, self).add_thing(thing, location)
def is_inbounds(self, location):
- '''Checks to make sure that the location is inbounds (within walls if we have walls)'''
+ """Checks to make sure that the location is inbounds (within walls if we have walls)"""
x,y = location
return not (x < self.x_start or x >= self.x_end or y < self.y_start or y >= self.y_end)
def random_location_inbounds(self, exclude=None):
- '''Returns a random location that is inbounds (within walls if we have walls)'''
+ """Returns a random location that is inbounds (within walls if we have walls)"""
location = (random.randint(self.x_start, self.x_end), random.randint(self.y_start, self.y_end))
if exclude is not None:
while(location == exclude):
@@ -472,7 +468,7 @@ def random_location_inbounds(self, exclude=None):
return location
def delete_thing(self, thing):
- '''Deletes thing, and everything it is holding (if thing is an agent)'''
+ """Deletes thing, and everything it is holding (if thing is an agent)"""
if isinstance(thing, Agent):
for obj in thing.holding:
super(XYEnvironment, self).delete_thing(obj)
@@ -484,7 +480,7 @@ def delete_thing(self, thing):
obs.thing_deleted(thing)
def add_walls(self):
- '''Put walls around the entire perimeter of the grid.'''
+ """Put walls around the entire perimeter of the grid."""
for x in range(self.width):
self.add_thing(Wall(), (x, 0))
self.add_thing(Wall(), (x, self.height - 1))
@@ -506,7 +502,7 @@ def add_observer(self, observer):
self.observers.append(observer)
def turn_heading(self, heading, inc):
- "Return the heading to the left (inc=+1) or right (inc=-1) of heading."
+ """Return the heading to the left (inc=+1) or right (inc=-1) of heading."""
return turn_heading(heading, inc)
@@ -526,7 +522,8 @@ class Wall(Obstacle):
# Continuous environment
class ContinuousWorld(Environment):
- """ Model for Continuous World."""
+ """Model for Continuous World."""
+
def __init__(self, width=10, height=10):
super(ContinuousWorld, self).__init__()
self.width = width
@@ -537,8 +534,9 @@ def add_obstacle(self, coordinates):
class PolygonObstacle(Obstacle):
+
def __init__(self, coordinates):
- """ Coordinates is a list of tuples."""
+ """Coordinates is a list of tuples."""
super(PolygonObstacle, self).__init__()
self.coordinates = coordinates
@@ -604,7 +602,7 @@ def thing_classes(self):
TableDrivenVacuumAgent, ModelBasedVacuumAgent]
def percept(self, agent):
- "Returns the agent's location, and the location status (Dirty/Clean)."
+ """Returns the agent's location, and the location status (Dirty/Clean)."""
return (agent.location, self.status[agent.location])
def execute_action(self, agent, action):
@@ -622,7 +620,7 @@ def execute_action(self, agent, action):
self.status[agent.location] = 'Clean'
def default_location(self, thing):
- "Agents start in either location at random."
+ """Agents start in either location at random."""
return random.choice([loc_A, loc_B])
# ______________________________________________________________________________
@@ -632,7 +630,7 @@ def default_location(self, thing):
class Gold(Thing):
def __eq__(self, rhs):
- '''All Gold are equal'''
+ """All Gold are equal"""
return rhs.__class__ == Gold
pass
@@ -648,7 +646,6 @@ class Pit(Thing):
class Breeze(Thing):
pass
-
class Arrow(Thing):
pass
@@ -671,7 +668,7 @@ class Explorer(Agent):
direction = Direction("right")
def can_grab(self, thing):
- '''Explorer can only grab gold'''
+ """Explorer can only grab gold"""
return thing.__class__ == Gold
@@ -684,7 +681,7 @@ def __init__(self, agent_program, width=6, height=6):
self.init_world(agent_program)
def init_world(self, program):
- '''Spawn items to the world based on probabilities from the book'''
+ """Spawn items to the world based on probabilities from the book"""
"WALLS"
self.add_walls()
@@ -715,7 +712,7 @@ def init_world(self, program):
self.add_thing(Explorer(program), (1, 1), True)
def get_world(self, show_walls=True):
- '''Returns the items in the world'''
+ """Returns the items in the world"""
result = []
x_start, y_start = (0, 0) if show_walls else (1, 1)
x_end, y_end = (self.width, self.height) if show_walls else (self.width - 1, self.height - 1)
@@ -727,16 +724,16 @@ def get_world(self, show_walls=True):
return result
def percepts_from(self, agent, location, tclass=Thing):
- '''Returns percepts from a given location, and replaces some items with percepts from chapter 7.'''
+ """Returns percepts from a given location, and replaces some items with percepts from chapter 7."""
thing_percepts = {
Gold: Glitter(),
Wall: Bump(),
Wumpus: Stench(),
Pit: Breeze()}
- '''Agents don't need to get their percepts'''
+ """Agents don't need to get their percepts"""
thing_percepts[agent.__class__] = None
- '''Gold only glitters in its cell'''
+ """Gold only glitters in its cell"""
if location != agent.location:
thing_percepts[Gold] = None
@@ -746,8 +743,8 @@ def percepts_from(self, agent, location, tclass=Thing):
return result if len(result) else [None]
def percept(self, agent):
- '''Returns things in adjacent (not diagonal) cells of the agent.
- Result format: [Left, Right, Up, Down, Center / Current location]'''
+ """Returns things in adjacent (not diagonal) cells of the agent.
+ Result format: [Left, Right, Up, Down, Center / Current location]"""
x, y = agent.location
result = []
result.append(self.percepts_from(agent, (x - 1, y)))
@@ -756,7 +753,7 @@ def percept(self, agent):
result.append(self.percepts_from(agent, (x, y + 1)))
result.append(self.percepts_from(agent, (x, y)))
- '''The wumpus gives out a a loud scream once it's killed.'''
+ """The wumpus gives out a a loud scream once it's killed."""
wumpus = [thing for thing in self.things if isinstance(thing, Wumpus)]
if len(wumpus) and not wumpus[0].alive and not wumpus[0].screamed:
result[-1].append(Scream())
@@ -765,8 +762,8 @@ def percept(self, agent):
return result
def execute_action(self, agent, action):
- '''Modify the state of the environment based on the agent's actions.
- Performance score taken directly out of the book.'''
+ """Modify the state of the environment based on the agent's actions.
+ Performance score taken directly out of the book."""
if isinstance(agent, Explorer) and self.in_danger(agent):
return
@@ -794,7 +791,7 @@ def execute_action(self, agent, action):
agent.performance += 1000 if Gold() in agent.holding else 0
self.delete_thing(agent)
elif action == 'Shoot':
- '''The arrow travels straight down the path the agent is facing'''
+ """The arrow travels straight down the path the agent is facing"""
if agent.has_arrow:
arrow_travel = agent.direction.move_forward(agent.location)
while(self.is_inbounds(arrow_travel)):
@@ -807,7 +804,7 @@ def execute_action(self, agent, action):
agent.has_arrow = False
def in_danger(self, agent):
- '''Checks if Explorer is in danger (Pit or Wumpus), if he is, kill him'''
+ """Checks if Explorer is in danger (Pit or Wumpus), if he is, kill him"""
for thing in self.list_things_at(agent.location):
if isinstance(thing, Pit) or (isinstance(thing, Wumpus) and thing.alive):
agent.alive = False
@@ -817,8 +814,8 @@ def in_danger(self, agent):
return False
def is_done(self):
- '''The game is over when the Explorer is killed
- or if he climbs out of the cave only at (1,1).'''
+ """The game is over when the Explorer is killed
+ or if he climbs out of the cave only at (1,1)."""
explorer = [agent for agent in self.agents if isinstance(agent, Explorer) ]
if len(explorer):
if explorer[0].alive:
@@ -845,7 +842,7 @@ def compare_agents(EnvFactory, AgentFactories, n=10, steps=1000):
def test_agent(AgentFactory, steps, envs):
- "Return the mean score of running an agent in each of the envs, for steps"
+ """Return the mean score of running an agent in each of the envs, for steps"""
def score(env):
agent = AgentFactory()
env.add_thing(agent)