Skip to content

Commit

Permalink
[MRG] ENH: Small improvements for agents.py (aimacode#1139)
Browse files Browse the repository at this point in the history
* ENH: Small improvements for agents.py

* FIXUP: fix `add_thing` to pass the tests

* [MRG] ENH: Add small chnages to agents.py

* [MRG] FIX: `default_location` now returns a valid location

* FIXUP: fix `default_location` in agents4e.py and modify tests
  • Loading branch information
tirthasheshpatel authored and antmarakis committed Dec 17, 2019
1 parent c587f2c commit 04b3326
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 33 deletions.
36 changes: 22 additions & 14 deletions agents.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
from utils import distance_squared, turn_heading
from statistics import mean
from ipythonblocks import BlockGrid
from IPython.display import HTML, display
from IPython.display import HTML, display, clear_output
from time import sleep

import random
Expand Down Expand Up @@ -89,7 +89,7 @@ def __init__(self, program=None):
self.bump = False
self.holding = []
self.performance = 0
if program is None or not isinstance(program, collections.Callable):
if program is None or not isinstance(program, collections.abc.Callable):
print("Can't find a valid program for {}, falling back to default.".format(self.__class__.__name__))

def program(percept):
Expand Down Expand Up @@ -455,15 +455,17 @@ def move_forward(self, from_location):
>>> l1
(1, 0)
"""
# get the iterable class to return
iclass = from_location.__class__
x, y = from_location
if self.direction == self.R:
return x + 1, y
return iclass((x + 1, y))
elif self.direction == self.L:
return x - 1, y
return iclass((x - 1, y))
elif self.direction == self.U:
return x, y - 1
return iclass((x, y - 1))
elif self.direction == self.D:
return x, y + 1
return iclass((x, y + 1))


class XYEnvironment(Environment):
Expand Down Expand Up @@ -518,7 +520,11 @@ def execute_action(self, agent, action):
agent.holding.pop()

def default_location(self, thing):
return random.choice(self.width), random.choice(self.height)
location = self.random_location_inbounds()
while self.some_things_at(location, Obstacle):
# we will find a random location with no obstacles
location = self.random_location_inbounds()
return location

def move_to(self, thing, destination):
"""Move a thing to a new location. Returns True on success or False if there is an Obstacle.
Expand All @@ -534,10 +540,12 @@ def move_to(self, thing, destination):
t.location = destination
return thing.bump

def add_thing(self, thing, location=(1, 1), exclude_duplicate_class_items=False):
def add_thing(self, thing, location=None, exclude_duplicate_class_items=False):
"""Add 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 location is None:
super().add_thing(thing)
elif self.is_inbounds(location):
if (exclude_duplicate_class_items and
any(isinstance(t, thing.__class__) for t in self.list_things_at(location))):
return
Expand Down Expand Up @@ -666,16 +674,16 @@ def run(self, steps=1000, delay=1):

def update(self, delay=1):
sleep(delay)
if self.visible:
self.conceal()
self.reveal()
else:
self.reveal()
self.reveal()

def reveal(self):
"""Display the BlockGrid for this world - the last thing to be added
at a location defines the location color."""
self.draw_world()
# wait for the world to update and
# apply changes to the same grid instead
# of making a new one.
clear_output(1)
self.grid.show()
self.visible = True

Expand Down
36 changes: 22 additions & 14 deletions agents4e.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
from utils4e import distance_squared, turn_heading
from statistics import mean
from ipythonblocks import BlockGrid
from IPython.display import HTML, display
from IPython.display import HTML, display, clear_output
from time import sleep

import random
Expand Down Expand Up @@ -89,7 +89,7 @@ def __init__(self, program=None):
self.bump = False
self.holding = []
self.performance = 0
if program is None or not isinstance(program, collections.Callable):
if program is None or not isinstance(program, collections.abc.Callable):
print("Can't find a valid program for {}, falling back to default.".format(self.__class__.__name__))

def program(percept):
Expand Down Expand Up @@ -455,15 +455,17 @@ def move_forward(self, from_location):
>>> l1
(1, 0)
"""
# get the iterable class to return
iclass = from_location.__class__
x, y = from_location
if self.direction == self.R:
return x + 1, y
return iclass((x + 1, y))
elif self.direction == self.L:
return x - 1, y
return iclass((x - 1, y))
elif self.direction == self.U:
return x, y - 1
return iclass((x, y - 1))
elif self.direction == self.D:
return x, y + 1
return iclass((x, y + 1))


class XYEnvironment(Environment):
Expand Down Expand Up @@ -518,7 +520,11 @@ def execute_action(self, agent, action):
agent.holding.pop()

def default_location(self, thing):
return random.choice(self.width), random.choice(self.height)
location = self.random_location_inbounds()
while self.some_things_at(location, Obstacle):
# we will find a random location with no obstacles
location = self.random_location_inbounds()
return location

def move_to(self, thing, destination):
"""Move a thing to a new location. Returns True on success or False if there is an Obstacle.
Expand All @@ -534,10 +540,12 @@ def move_to(self, thing, destination):
t.location = destination
return thing.bump

def add_thing(self, thing, location=(1, 1), exclude_duplicate_class_items=False):
def add_thing(self, thing, location=None, exclude_duplicate_class_items=False):
"""Add 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 location is None:
super().add_thing(thing)
elif self.is_inbounds(location):
if (exclude_duplicate_class_items and
any(isinstance(t, thing.__class__) for t in self.list_things_at(location))):
return
Expand Down Expand Up @@ -666,16 +674,16 @@ def run(self, steps=1000, delay=1):

def update(self, delay=1):
sleep(delay)
if self.visible:
self.conceal()
self.reveal()
else:
self.reveal()
self.reveal()

def reveal(self):
"""Display the BlockGrid for this world - the last thing to be added
at a location defines the location color."""
self.draw_world()
# wait for the world to update and
# apply changes to the same grid instead
# of making a new one.
clear_output(1)
self.grid.show()
self.visible = True

Expand Down
11 changes: 9 additions & 2 deletions tests/test_agents.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,13 @@
SimpleReflexAgentProgram, ModelBasedReflexAgentProgram, Wall, Gold, Explorer, Thing, Bump, Glitter,
WumpusEnvironment, Pit, VacuumEnvironment, Dirt, Direction, Agent)

random.seed("aima-python")

# random seed may affect the placement
# of things in the environment which may
# lead to failure of tests. Please change
# the seed if the tests are failing with
# current changes in any stochastic method
# function or variable.
random.seed(9)

def test_move_forward():
d = Direction("up")
Expand Down Expand Up @@ -88,6 +93,7 @@ def test_RandomVacuumAgent():


def test_TableDrivenAgent():
random.seed(10)
loc_A, loc_B = (0, 0), (1, 0)
# table defining all the possible states of the agent
table = {((loc_A, 'Clean'),): 'Right',
Expand Down Expand Up @@ -346,6 +352,7 @@ def constant_prog(percept):


def test_WumpusEnvironmentActions():
random.seed(9)
def constant_prog(percept):
return percept

Expand Down
13 changes: 10 additions & 3 deletions tests/test_agents4e.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,13 @@
SimpleReflexAgentProgram, ModelBasedReflexAgentProgram, Wall, Gold, Explorer, Thing, Bump,
Glitter, WumpusEnvironment, Pit, VacuumEnvironment, Dirt, Direction, Agent)

random.seed("aima-python")

# random seed may affect the placement
# of things in the environment which may
# lead to failure of tests. Please change
# the seed if the tests are failing with
# current changes in any stochastic method
# function or variable.
random.seed(9)

def test_move_forward():
d = Direction("up")
Expand Down Expand Up @@ -88,6 +93,7 @@ def test_RandomVacuumAgent():


def test_TableDrivenAgent():
random.seed(10)
loc_A, loc_B = (0, 0), (1, 0)
# table defining all the possible states of the agent
table = {((loc_A, 'Clean'),): 'Right',
Expand Down Expand Up @@ -271,7 +277,7 @@ def test_VacuumEnvironment():
# get an agent
agent = ModelBasedVacuumAgent()
agent.direction = Direction(Direction.R)
v.add_thing(agent)
v.add_thing(agent, location=(1, 1))
v.add_thing(Dirt(), location=(2, 1))

# check if things are added properly
Expand Down Expand Up @@ -345,6 +351,7 @@ def constant_prog(percept):


def test_WumpusEnvironmentActions():
random.seed(9)
def constant_prog(percept):
return percept

Expand Down

0 comments on commit 04b3326

Please sign in to comment.