Skip to content

Commit

Permalink
fixed the rum drinking problem
Browse files Browse the repository at this point in the history
  • Loading branch information
bitcraft committed Nov 25, 2012
1 parent 8d5c7bd commit 74c5857
Show file tree
Hide file tree
Showing 6 changed files with 52 additions and 92 deletions.
50 changes: 18 additions & 32 deletions npc/pirate/actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ def get_position(entity, memory):
"""
Return the position of [entity] according to memory.
"""
for precept in memory.of_class(PositionPrecept):
if precept.entity is entity:
return precept.position
for pct in memory.of_class(PositionPrecept):
if pct.entity is entity:
return pct.position


class MoveAction(ActionContext):
Expand Down Expand Up @@ -46,7 +46,7 @@ class PickupAction(CalledOnceContext):
pass


class DrinkRunAction(ActionContext):
class DrinkRumAction(ActionContext):
def start(self):
self.caller.drunkness = 1
super(drink_rum, self).start()
Expand Down Expand Up @@ -77,15 +77,15 @@ class move_to_entity(ActionBuilder):
def get_actions(self, caller, memory):
visited = []

for precept in memory.of_class(PositionPrecept):
if precept.entity is caller or precept.position in visited:
for pct in memory.of_class(PositionPrecept):
if pct.entity is caller or pct.position in visited:
continue

visited.append(precept.position)
visited.append(pct.position)

action = MoveAction(caller)
action.setEndpoint(precept.position[1])
action.effects.append(PositionGoal(caller, precept.position))
action.setEndpoint(pct.position[1])
action.effects.append(PositionGoal(caller, pct.position))
yield action

exported_actions.append(move_to_entity)
Expand All @@ -98,42 +98,28 @@ def get_actions(self, caller, memory):
"""
here = get_position(caller, memory)

for precept in memory.of_class(PositionPrecept):
if here == precept.position and precept.entity is not caller:
for pct in memory.of_class(PositionPrecept):
if here == pct.position and pct.entity is not caller:
action = PickupAction(caller)
action.effects.append(HasItemGoal(precept.entity))
action.effects.append(HasItemGoal(pct.entity))
yield action

exported_actions.append(pickup)



class drink_rum(ActionBuilder):
"""
drink rum that is in caller's inventory
"""

def make_action(self, caller, tag, memory):
a = drink_rum_action(caller)
a.effects.append(SimpleGoal(is_drunk=True))
a.effects.append(EvalGoal("charisma = charisma + 10"))

return a

def get_actions(self, caller, memory):
"""
return list of actions that will drink rum from player's inv
"""

a = []
for precept in memory.of_class(PositionPrecept):
if precept.position[0] == caller:
if DEBUG: print "[drink rum] 1 {}".format(tag)
if tag['obj'].name=="rum":
if DEBUG: print "[drink rum] 2 {}".format(tag)
a.append(self.make_action(caller, tag, memory))
for pct in memory.of_class(PositionPrecept):
if pct.position[0] == 'self' and pct.entity.name == "rum":
action = DrinkRumAction(caller)
action.effects.append(SimpleGoal(is_drunk=True))
action.effects.append(EvalGoal("charisma = charisma + 10"))
yield action

return a

exported_actions.append(drink_rum)

30 changes: 13 additions & 17 deletions pygoap/agent.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from environment import ObjectBase
from planning import plan
from actions import ActionContext
from blackboard import Blackboard, MemoryManager
from blackboard import MemoryManager
from actionstates import *
from precepts import *
import logging
Expand Down Expand Up @@ -88,30 +88,26 @@ def replan(self):
"""

# get the relevancy of each goal according to the state of the agent
s = [ (g.get_relevancy(self.memory), g) for g in self.goals ]
s = [ g for g in s if g[0] > 0 ]
s = ( (g.get_relevancy(self.memory), g) for g in self.goals )
s = [ g for g in s if g[0] > 0.0 ]
s.sort(reverse=True)

debug("[agent] goals %s", s)

# starting for the most relevant goal, attempt to make a plan
# starting for the most relevant goal, attempt to make a plan
plan = []
for score, goal in s:
ok, plan = self.planner(
self,
self.actions,
self.current_action,
self.memory,
goal)

if ok:
pretty = list(reversed(plan[:]))
tentative_plan = self.planner(self, self.actions,
self.current_action, self.memory, goal)

if tentative_plan:
pretty = list(reversed(tentative_plan[:]))
debug("[agent] %s has planned to %s", self, goal)
debug("[agent] %s has plan %s", self, pretty)
return plan
else:
debug("[agent] %s cannot %s", self, goal)
plan = tentative_plan
break

return []
return plan

@property
def current_action(self):
Expand Down
36 changes: 8 additions & 28 deletions pygoap/blackboard.py
Original file line number Diff line number Diff line change
@@ -1,34 +1,13 @@
"""
Memories are stored precepts.
A blackboard is a device to share information amongst actions.
This implementation uses sqlite3 as a backend for storing memories.
The MemManager class is not used.
"""



class MemoryManager(set):
"""
a memory manager's purpose is to store and manage stored precepts.
"""

def of_class(self, klass):
for i in self:
if isinstance(i, klass):
yield i

class Blackboard(dict):
"""
a blackboard is an abstract memory device.
alternative, more robust solution would be a xml backend or database
tags belong to a set of values that are known by the actions that an actor
would find useful. tag names are simple strings and have a value
associated with them. for simplicity, a blackboard could be used like a
standard python dictionary.
Store and manage precepts.
shared blackboards violate reality in that multiple agents share the same
thoughts, to extend the metaphore. but, the advantage of this is that in
a real-time simulation, it gives the player the impression that the agents
Expand All @@ -38,9 +17,10 @@ class Blackboard(dict):
that being said, i have chosen to restrict blackboards to a per-agent
basis. this library is meant for rpgs, where the action isn't real-time
and would require a more realistic simulation of intelligence.
however, i will still develop blackboards with the intention that they are
shared, so that in the future, it will be easier to simulate agents with
shared knowledge and subtle communication.
"""
pass

def of_class(self, klass):
for i in self:
if isinstance(i, klass):
yield i

18 changes: 11 additions & 7 deletions pygoap/goals.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@
class GoalBase(object):
"""
Goals:
can be satisfied.
can be valid
can be tested
can be relevant
Goals, ActionPrereqs and ActionEffects are now that same class. They share
so much functionality that they have been combined into one class.
Expand All @@ -42,12 +42,10 @@ def __init__(self, *args, **kwargs):
except IndexError:
self.condition = None

self.value = 1.0
self.weight = 1.0
self.args = args
self.kw = kwargs

self.self_test()

def touch(self, memory):
pass

Expand All @@ -61,7 +59,8 @@ def get_relevancy(self, memory):
as a general rule, the return value here should never equal
what is returned from test()
"""
return self.value if not self.test(memory) else 0.0
score = 1 - self.test(memory)
return self.weight * score

def self_test(self):
"""
Expand Down Expand Up @@ -153,7 +152,11 @@ def do_it(expr, d):
d = {}
d['__builtins__'] = None

memory.post(Tag(kw=do_it(self.args[0], d)))
for k, v in d.items():
if k == '__builtins__':
continue

memory.add(DatumPrecept(k, v))

return True

Expand Down Expand Up @@ -208,6 +211,7 @@ def test(self, memory):
return 1.0

else:

d = distance(position, target_position)
if d > self.dist:
return (float(self.dist / d)) * float(self.dist)
Expand Down
4 changes: 2 additions & 2 deletions pygoap/planning.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,9 @@ def plan(caller, actions, start_action, start_memory, goal):
keyNode = keyNode.parent
path0.append(keyNode.action)

return True, path0
return path0

else:
return False, []
return []


6 changes: 0 additions & 6 deletions test.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,21 +81,15 @@ def run_once():
if time == 1:
pirate = Human("Male", "jack")
load_commands(pirate, os.path.join("npc", "pirate"))
#pirate.add_goal(SimpleGoal(is_idle=True))
pirate.add_goal(SimpleGoal(is_drunk=True))
formosa.add(pirate)
formosa.set_position(pirate, (formosa, (0,0)))

elif time == 3:
rum = ObjectBase("rum")
pirate.add_goal(HasItemGoal(rum))
formosa.add(rum)
formosa.set_position(rum, (formosa, (0,2)))

elif time == 5:
#formosa.move(rum, pirate.position)
pass

elif time == 6:
wench = Human("Female", "wench")
formosa.add(wench)
Expand Down

0 comments on commit 74c5857

Please sign in to comment.