Skip to content

Commit a2b003a

Browse files
committed
Merge pull request #93 from MircoT/master
Finished porting to Python 3
2 parents e40b72c + f100f01 commit a2b003a

35 files changed

Lines changed: 1491 additions & 765 deletions

.gitmodules

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
[submodule "aima-data"]
2-
path = aima-data
1+
[submodule "aimaPy/aima-data"]
2+
path = aimaPy/aima-data
33
url = https://github.com/aimacode/aima-data

.travis.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,13 @@ language:
44
python:
55
- "3.5"
66

7+
before_install:
8+
- git submodule update --remote
9+
710
install:
811
- pip install flake8
912
- pip install -r requirements.txt
13+
- python setup.py install
1014

1115
script:
1216
- py.test

MANIFEST.in

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
graft aimaPy/aima-data
2+
graft aimaPy/images

aima-data

Lines changed: 0 additions & 1 deletion
This file was deleted.

aimaPy/__init__.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
from . import agents
2+
from . import csp
3+
from . import games
4+
from . import grid
5+
from . import learning
6+
from . import logic
7+
from . import mdp
8+
from . import nlp
9+
from . import planning
10+
from . import probability
11+
from . import rl
12+
from . import search
13+
from . import text
14+
from . import utils

agents.py renamed to aimaPy/agents.py

Lines changed: 79 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -35,17 +35,20 @@
3535
#
3636
# Speed control in GUI does not have any effect -- fix it.
3737

38-
from utils import *
38+
from . utils import *
3939
import random
4040
import copy
41+
import collections
4142

4243
#______________________________________________________________________________
4344

4445

4546
class Thing(object):
47+
4648
"""This represents any physical object that can appear in an Environment.
4749
You subclass Thing to get the things you want. Each thing can have a
4850
.__name__ slot (used for output only)."""
51+
4952
def __repr__(self):
5053
return '<{}>'.format(getattr(self, '__name__', self.__class__.__name__))
5154

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

68+
6569
class Agent(Thing):
70+
6671
"""An Agent is a subclass of Thing with one required slot,
6772
.program, which should hold a function that takes one argument, the
6873
percept, and returns an action. (What counts as a percept or action
@@ -80,19 +85,21 @@ def __init__(self, program=None):
8085
self.bump = False
8186
if program is None:
8287
def program(percept):
83-
return input('Percept={}; action? ' .format(percept))
84-
assert callable(program)
88+
return eval(input('Percept={}; action? ' .format(percept)))
89+
assert isinstance(program, collections.Callable)
8590
self.program = program
8691

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

97+
9298
def TraceAgent(agent):
9399
"""Wrap the agent's program to print its input and output. This will let
94100
you see what the agent is doing in the environment."""
95101
old_program = agent.program
102+
96103
def new_program(percept):
97104
action = old_program(percept)
98105
print('{} perceives {} and does {}'.format(agent, percept, action))
@@ -102,24 +109,28 @@ def new_program(percept):
102109

103110
#______________________________________________________________________________
104111

112+
105113
def TableDrivenAgentProgram(table):
106114
"""This agent selects an action based on the percept sequence.
107115
It is practical only for tiny domains.
108116
To customize it, provide as table a dictionary of all
109117
{percept_sequence:action} pairs. [Fig. 2.7]"""
110118
percepts = []
119+
111120
def program(percept):
112121
percepts.append(percept)
113122
action = table.get(tuple(percepts))
114123
return action
115124
return program
116125

126+
117127
def RandomAgentProgram(actions):
118128
"An agent that chooses an action at random, ignoring all percepts."
119129
return lambda percept: random.choice(actions)
120130

121131
#______________________________________________________________________________
122132

133+
123134
def SimpleReflexAgentProgram(rules, interpret_input):
124135
"This agent takes action based solely on the percept. [Fig. 2.10]"
125136
def program(percept):
@@ -129,6 +140,7 @@ def program(percept):
129140
return action
130141
return program
131142

143+
132144
def ModelBasedReflexAgentProgram(rules, update_state):
133145
"This agent takes action based on the percept and state. [Fig. 2.12]"
134146
def program(percept):
@@ -139,6 +151,7 @@ def program(percept):
139151
program.state = program.action = None
140152
return program
141153

154+
142155
def rule_match(state, rules):
143156
"Find the first rule that matches state."
144157
for rule in rules:
@@ -147,7 +160,7 @@ def rule_match(state, rules):
147160

148161
#______________________________________________________________________________
149162

150-
loc_A, loc_B = (0, 0), (1, 0) # The two locations for the Vacuum world
163+
loc_A, loc_B = (0, 0), (1, 0) # The two locations for the Vacuum world
151164

152165

153166
def RandomVacuumAgent():
@@ -174,27 +187,37 @@ def TableDrivenVacuumAgent():
174187
def ReflexVacuumAgent():
175188
"A reflex agent for the two-state vacuum environment. [Fig. 2.8]"
176189
def program(location, status):
177-
if status == 'Dirty': return 'Suck'
178-
elif location == loc_A: return 'Right'
179-
elif location == loc_B: return 'Left'
190+
if status == 'Dirty':
191+
return 'Suck'
192+
elif location == loc_A:
193+
return 'Right'
194+
elif location == loc_B:
195+
return 'Left'
180196
return Agent(program)
181197

198+
182199
def ModelBasedVacuumAgent():
183200
"An agent that keeps track of what locations are clean or dirty."
184201
model = {loc_A: None, loc_B: None}
202+
185203
def program(location, status):
186204
"Same as ReflexVacuumAgent, except if everything is clean, do NoOp."
187-
model[location] = status ## Update the model here
188-
if model[loc_A] == model[loc_B] == 'Clean': return 'NoOp'
189-
elif status == 'Dirty': return 'Suck'
190-
elif location == loc_A: return 'Right'
191-
elif location == loc_B: return 'Left'
205+
model[location] = status # Update the model here
206+
if model[loc_A] == model[loc_B] == 'Clean':
207+
return 'NoOp'
208+
elif status == 'Dirty':
209+
return 'Suck'
210+
elif location == loc_A:
211+
return 'Right'
212+
elif location == loc_B:
213+
return 'Left'
192214
return Agent(program)
193215

194216
#______________________________________________________________________________
195217

196218

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

212235
def thing_classes(self):
213-
return [] ## List of classes that can go into environment
236+
return [] # List of classes that can go into environment
214237

215238
def percept(self, agent):
216239
"Return the percept that the agent sees at this point. (Implement this.)"
@@ -247,7 +270,8 @@ def step(self):
247270
def run(self, steps=1000):
248271
"Run the Environment for given number of time steps."
249272
for step in range(steps):
250-
if self.is_done(): return
273+
if self.is_done():
274+
return
251275
self.step()
252276

253277
def list_things_at(self, location, tclass=Thing):
@@ -282,11 +306,13 @@ def delete_thing(self, thing):
282306
print(" in Environment delete_thing")
283307
print(" Thing to be removed: {} at {}" .format(thing, thing.location))
284308
print(" from list: {}" .format([(thing, thing.location)
285-
for thing in self.things]))
309+
for thing in self.things]))
286310
if thing in self.agents:
287311
self.agents.remove(thing)
288312

313+
289314
class XYEnvironment(Environment):
315+
290316
"""This class is for environments on a 2D plane, with locations
291317
labelled by (x, y) points, either discrete or continuous.
292318
@@ -301,7 +327,8 @@ def __init__(self, width=10, height=10):
301327

302328
def things_near(self, location, radius=None):
303329
"Return all things within radius of location."
304-
if radius is None: radius = self.perceptible_distance
330+
if radius is None:
331+
radius = self.perceptible_distance
305332
radius2 = radius * radius
306333
return [thing for thing in self.things
307334
if distance2(location, thing.location) <= radius2]
@@ -330,7 +357,7 @@ def execute_action(self, agent, action):
330357
if agent.holding:
331358
agent.holding.pop()
332359

333-
def thing_percept(self, thing, agent): #??? Should go to thing?
360+
def thing_percept(self, thing, agent): # ??? Should go to thing?
334361
"Return the percept for this thing."
335362
return thing.__class__.__name__
336363

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

410+
383411
class Obstacle(Thing):
412+
384413
"""Something that can cause a bump, preventing an agent from
385414
moving into the same square it's in."""
386415
pass
387416

417+
388418
class Wall(Obstacle):
389419
pass
390420

391421
#______________________________________________________________________________
392-
## Vacuum environment
422+
# Vacuum environment
423+
393424

394425
class Dirt(Thing):
395426
pass
396427

428+
397429
class VacuumEnvironment(XYEnvironment):
430+
398431
"""The environment of [Ex. 2.12]. Agent perceives dirty or clean,
399432
and bump (into obstacle) or not; 2D discrete world of unknown size;
400433
performance measure is 100 for each dirt cleaned, and -1 for
@@ -411,7 +444,8 @@ def thing_classes(self):
411444
def percept(self, agent):
412445
"""The percept is a tuple of ('Dirty' or 'Clean', 'Bump' or 'None').
413446
Unlike the TrivialVacuumEnvironment, location is NOT perceived."""
414-
status = ('Dirty' if self.some_things_at(agent.location, Dirt) else 'Clean')
447+
status = ('Dirty' if self.some_things_at(
448+
agent.location, Dirt) else 'Clean')
415449
bump = ('Bump' if agent.bump else'None')
416450
return (status, bump)
417451

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

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

468504
#______________________________________________________________________________
469-
## The Wumpus World
505+
# The Wumpus World
506+
507+
508+
class Gold(Thing):
509+
pass
510+
511+
512+
class Pit(Thing):
513+
pass
514+
515+
516+
class Arrow(Thing):
517+
pass
518+
519+
520+
class Wumpus(Agent):
521+
pass
522+
523+
524+
class Explorer(Agent):
525+
pass
470526

471-
class Gold(Thing): pass
472-
class Pit(Thing): pass
473-
class Arrow(Thing): pass
474-
class Wumpus(Agent): pass
475-
class Explorer(Agent): pass
476527

477528
class WumpusEnvironment(XYEnvironment):
478529

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

486-
## Needs a lot of work ...
537+
# Needs a lot of work ...
487538

488539

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

551+
500552
def test_agent(AgentFactory, steps, envs):
501553
"Return the mean score of running an agent in each of the envs, for steps"
502554
def score(env):
503555
agent = AgentFactory()
504556
env.add_thing(agent)
505557
env.run(steps)
506558
return agent.performance
507-
return mean(map(score, envs))
559+
return mean(list(map(score, envs)))
508560

509561
#_________________________________________________________________________
510562

@@ -537,6 +589,3 @@ def score(env):
537589
>>> 0.5 < testv(RandomVacuumAgent) < 3
538590
True
539591
"""
540-
541-
542-

aimaPy/aima-data

Submodule aima-data added at 5b0526a

0 commit comments

Comments
 (0)