Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Finished porting to Python 3 #93

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Mar 7, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[submodule "aima-data"]
path = aima-data
[submodule "aimaPy/aima-data"]
path = aimaPy/aima-data
url = https://github.com/aimacode/aima-data
4 changes: 4 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,13 @@ language:
python:
- "3.5"

before_install:
- git submodule update --remote

install:
- pip install flake8
- pip install -r requirements.txt
- python setup.py install

script:
- py.test
Expand Down
2 changes: 2 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
graft aimaPy/aima-data
graft aimaPy/images
1 change: 0 additions & 1 deletion aima-data
Submodule aima-data deleted from 75a59e
14 changes: 14 additions & 0 deletions aimaPy/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from . import agents
from . import csp
from . import games
from . import grid
from . import learning
from . import logic
from . import mdp
from . import nlp
from . import planning
from . import probability
from . import rl
from . import search
from . import text
from . import utils
109 changes: 79 additions & 30 deletions agents.py → aimaPy/agents.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,20 @@
#
# Speed control in GUI does not have any effect -- fix it.

from utils import *
from . utils import *
import random
import copy
import collections

#______________________________________________________________________________


class Thing(object):

"""This represents any physical object that can appear in an Environment.
You subclass Thing to get the things you want. Each thing can have a
.__name__ slot (used for output only)."""

def __repr__(self):
return '<{}>'.format(getattr(self, '__name__', self.__class__.__name__))

Expand All @@ -62,7 +65,9 @@ def display(self, canvas, x, y, width, height):
"Display an image of this Thing on the canvas."
pass


class Agent(Thing):

"""An Agent is a subclass of Thing with one required slot,
.program, which should hold a function that takes one argument, the
percept, and returns an action. (What counts as a percept or action
Expand All @@ -80,19 +85,21 @@ def __init__(self, program=None):
self.bump = False
if program is None:
def program(percept):
return input('Percept={}; action? ' .format(percept))
assert callable(program)
return eval(input('Percept={}; action? ' .format(percept)))
assert isinstance(program, collections.Callable)
self.program = program

def can_grab(self, thing):
"""Returns True if this agent can grab this thing.
Override for appropriate subclasses of Agent and Thing."""
return False


def TraceAgent(agent):
"""Wrap the agent's program to print its input and output. This will let
you see what the agent is doing in the environment."""
old_program = agent.program

def new_program(percept):
action = old_program(percept)
print('{} perceives {} and does {}'.format(agent, percept, action))
Expand All @@ -102,24 +109,28 @@ def new_program(percept):

#______________________________________________________________________________


def TableDrivenAgentProgram(table):
"""This agent selects an action based on the percept sequence.
It is practical only for tiny domains.
To customize it, provide as table a dictionary of all
{percept_sequence:action} pairs. [Fig. 2.7]"""
percepts = []

def program(percept):
percepts.append(percept)
action = table.get(tuple(percepts))
return action
return program


def RandomAgentProgram(actions):
"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. [Fig. 2.10]"
def program(percept):
Expand All @@ -129,6 +140,7 @@ def program(percept):
return action
return program


def ModelBasedReflexAgentProgram(rules, update_state):
"This agent takes action based on the percept and state. [Fig. 2.12]"
def program(percept):
Expand All @@ -139,6 +151,7 @@ def program(percept):
program.state = program.action = None
return program


def rule_match(state, rules):
"Find the first rule that matches state."
for rule in rules:
Expand All @@ -147,7 +160,7 @@ def rule_match(state, rules):

#______________________________________________________________________________

loc_A, loc_B = (0, 0), (1, 0) # The two locations for the Vacuum world
loc_A, loc_B = (0, 0), (1, 0) # The two locations for the Vacuum world


def RandomVacuumAgent():
Expand All @@ -174,27 +187,37 @@ def TableDrivenVacuumAgent():
def ReflexVacuumAgent():
"A reflex agent for the two-state vacuum environment. [Fig. 2.8]"
def program(location, status):
if status == 'Dirty': return 'Suck'
elif location == loc_A: return 'Right'
elif location == loc_B: return 'Left'
if status == 'Dirty':
return 'Suck'
elif location == loc_A:
return 'Right'
elif location == loc_B:
return 'Left'
return Agent(program)


def ModelBasedVacuumAgent():
"An agent that keeps track of what locations are clean or dirty."
model = {loc_A: None, loc_B: None}

def program(location, status):
"Same as ReflexVacuumAgent, except if everything is clean, do NoOp."
model[location] = status ## Update the model here
if model[loc_A] == model[loc_B] == 'Clean': return 'NoOp'
elif status == 'Dirty': return 'Suck'
elif location == loc_A: return 'Right'
elif location == loc_B: return 'Left'
model[location] = status # Update the model here
if model[loc_A] == model[loc_B] == 'Clean':
return 'NoOp'
elif status == 'Dirty':
return 'Suck'
elif location == loc_A:
return 'Right'
elif location == loc_B:
return 'Left'
return Agent(program)

#______________________________________________________________________________


class Environment(object):

"""Abstract class representing an Environment. 'Real' Environment classes
inherit from this. Your Environment will typically need to implement:
percept: Define the percept that an agent sees.
Expand All @@ -210,7 +233,7 @@ def __init__(self):
self.agents = []

def thing_classes(self):
return [] ## List of classes that can go into environment
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.)"
Expand Down Expand Up @@ -247,7 +270,8 @@ def step(self):
def run(self, steps=1000):
"Run the Environment for given number of time steps."
for step in range(steps):
if self.is_done(): return
if self.is_done():
return
self.step()

def list_things_at(self, location, tclass=Thing):
Expand Down Expand Up @@ -282,11 +306,13 @@ def delete_thing(self, thing):
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]))
for thing in self.things]))
if thing in self.agents:
self.agents.remove(thing)


class XYEnvironment(Environment):

"""This class is for environments on a 2D plane, with locations
labelled by (x, y) points, either discrete or continuous.

Expand All @@ -301,7 +327,8 @@ def __init__(self, width=10, height=10):

def things_near(self, location, radius=None):
"Return all things within radius of location."
if radius is None: radius = self.perceptible_distance
if radius is None:
radius = self.perceptible_distance
radius2 = radius * radius
return [thing for thing in self.things
if distance2(location, thing.location) <= radius2]
Expand Down Expand Up @@ -330,7 +357,7 @@ def execute_action(self, agent, action):
if agent.holding:
agent.holding.pop()

def thing_percept(self, thing, agent): #??? Should go to thing?
def thing_percept(self, thing, agent): # ??? Should go to thing?
"Return the percept for this thing."
return thing.__class__.__name__

Expand Down Expand Up @@ -380,21 +407,27 @@ def turn_heading(self, heading, inc):
"Return the heading to the left (inc=+1) or right (inc=-1) of heading."
return turn_heading(heading, inc)


class Obstacle(Thing):

"""Something that can cause a bump, preventing an agent from
moving into the same square it's in."""
pass


class Wall(Obstacle):
pass

#______________________________________________________________________________
## Vacuum environment
# Vacuum environment


class Dirt(Thing):
pass


class VacuumEnvironment(XYEnvironment):

"""The environment of [Ex. 2.12]. Agent perceives dirty or clean,
and bump (into obstacle) or not; 2D discrete world of unknown size;
performance measure is 100 for each dirt cleaned, and -1 for
Expand All @@ -411,7 +444,8 @@ def thing_classes(self):
def percept(self, agent):
"""The percept is a tuple of ('Dirty' or 'Clean', 'Bump' or 'None').
Unlike the TrivialVacuumEnvironment, location is NOT perceived."""
status = ('Dirty' if self.some_things_at(agent.location, Dirt) else 'Clean')
status = ('Dirty' if self.some_things_at(
agent.location, Dirt) else 'Clean')
bump = ('Bump' if agent.bump else'None')
return (status, bump)

Expand All @@ -428,7 +462,9 @@ def execute_action(self, agent, action):
if action != 'NoOp':
agent.performance -= 1


class TrivialVacuumEnvironment(Environment):

"""This environment has two locations, A and B. Each can be Dirty
or Clean. The agent perceives its location and the location's
status. This serves as an example of how to implement a simple
Expand Down Expand Up @@ -466,13 +502,28 @@ def default_location(self, thing):
return random.choice([loc_A, loc_B])

#______________________________________________________________________________
## The Wumpus World
# The Wumpus World


class Gold(Thing):
pass


class Pit(Thing):
pass


class Arrow(Thing):
pass


class Wumpus(Agent):
pass


class Explorer(Agent):
pass

class Gold(Thing): pass
class Pit(Thing): pass
class Arrow(Thing): pass
class Wumpus(Agent): pass
class Explorer(Agent): pass

class WumpusEnvironment(XYEnvironment):

Expand All @@ -483,7 +534,7 @@ def __init__(self, width=10, height=10):
def thing_classes(self):
return [Wall, Gold, Pit, Arrow, Wumpus, Explorer]

## Needs a lot of work ...
# Needs a lot of work ...


#______________________________________________________________________________
Expand All @@ -497,14 +548,15 @@ def compare_agents(EnvFactory, AgentFactories, n=10, steps=1000):
return [(A, test_agent(A, steps, copy.deepcopy(envs)))
for A in AgentFactories]


def test_agent(AgentFactory, steps, envs):
"Return the mean score of running an agent in each of the envs, for steps"
def score(env):
agent = AgentFactory()
env.add_thing(agent)
env.run(steps)
return agent.performance
return mean(map(score, envs))
return mean(list(map(score, envs)))

#_________________________________________________________________________

Expand Down Expand Up @@ -537,6 +589,3 @@ def score(env):
>>> 0.5 < testv(RandomVacuumAgent) < 3
True
"""



1 change: 1 addition & 0 deletions aimaPy/aima-data
Submodule aima-data added at 5b0526
Loading