Permalink
Find file
Fetching contributors…
Cannot retrieve contributors at this time
138 lines (101 sloc) 4.01 KB
"""
Since a pyGOAP agent relies on cues from the environment when planning, having
a stable and efficient virtual environment is paramount. This environment is
simply a placeholder and demonstration.
When coding your game or simulation, you can think of the environment as the
conduit that connects your actors on screen to their simulated thoughts. This
environment simply provides enough basic information to the agents to work. It
is up to you to make it useful.
"""
from pygoap.agent import GoapAgent
from environment import Environment, Precept
import random, math
def distance((ax, ay), (bx, by)):
"The distance between two (x, y) points."
return math.hypot((ax - bx), (ay - by))
def distance2((ax, ay), (bx, by)):
"The square of the distance between two (x, y) points."
return (ax - bx)**2 + (ay - by)**2
def clip(vector, lowest, highest):
"""Return vector, except if any element is less than the corresponding
value of lowest or more than the corresponding value of highest, clip to
those values.
>>> clip((-1, 10), (0, 0), (9, 9))
(0, 9)
"""
return type(vector)(map(min, map(max, vector, lowest), highest))
class Pathfinding2D(object):
def get_surrounding(self, position):
"""
Return all positions around this one.
"""
x, y = position
return ((x-1, y-1), (x-1, y), (x-1, y+1), (x, y-1), (x, y+1),
(x+1, y-1), (x+1, y), (x+1, y+1))
def calc_h(self, position1, position2):
return distance(position1, position2)
class XYEnvironment(Environment, Pathfinding2D):
"""
This class is for environments on a 2D plane.
This class is featured enough to run a simple simulation.
"""
def __init__(self, width=10, height=10):
super(XYEnvironment, self).__init__()
self.width = width
self.height = height
def model_vision(self, precept, origin, terminus):
return precept
def model_sound(self, precept, origin, terminus):
return precept
def look(self, caller, direction=None, distance=None):
"""
Simulate vision by sending precepts to the caller.
"""
# a more intelligent approach would limit the number of agents
# to logical limit, ie: ones that could possibly been seen
agents = self.things[:]
agents.remove(caller)
model = self.model_precept
for a in agents:
p = Precept(sense='position', thing=a, position=a.position)
caller.handle_precept(model(p, caller))
def move(self, thing, pos):
"""
move an object in the world
"""
thing.position = pos
print "[env] move {} to {}".format(thing, pos)
[ self.look(a) for a in self.agents if a != thing ]
def objects_at(self, position):
"""
Return all objects exactly at a given position.
"""
return [ obj for obj in self.things if obj.position == position ]
def objects_near(self, position, radius):
"""
Return all objects within radius of position.
"""
radius2 = radius * radius
return [ obj for obj in self.things
if distance2(position, obj.position) <= radius2 ]
def default_position(self, thing):
loc = (random.randint(0, self.width), random.randint(0, self.height))
return (self, loc)
def model_precept(self, precept, other):
if precept.sense == "vision":
return precept
if precept.sense == "sound":
return precept
return precept
def can_move_from(self, agent, dist=100):
"""
return a list of positions that are possible for this agent to be
in if it were to move [dist] spaces or less.
"""
x, y = agent.position[1]
pos = []
for xx in xrange(x - dist, x + dist):
for yy in xrange(y - dist, y + dist):
if distance2((xx, yy), (x, y)) <= dist:
pos.append((self, (xx, yy)))
return pos