3535#
3636# Speed control in GUI does not have any effect -- fix it.
3737
38- from utils import *
38+ from . utils import *
3939import random
4040import copy
41+ import collections
4142
4243#______________________________________________________________________________
4344
4445
4546class 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+
6569class 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+
9298def 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+
105113def 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+
117127def 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+
123134def 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+
132144def 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+
142155def 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
153166def RandomVacuumAgent ():
@@ -174,27 +187,37 @@ def TableDrivenVacuumAgent():
174187def 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+
182199def 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
197219class 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+
289314class 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+
383411class 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+
388418class Wall (Obstacle ):
389419 pass
390420
391421#______________________________________________________________________________
392- ## Vacuum environment
422+ # Vacuum environment
423+
393424
394425class Dirt (Thing ):
395426 pass
396427
428+
397429class 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+
431466class 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
477528class 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+
500552def 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
538590True
539591"""
540-
541-
542-
0 commit comments