aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar rcoh <rcoh@mit.edu>2011-02-12 20:39:58 -0500
committerGravatar rcoh <rcoh@mit.edu>2011-02-12 20:39:58 -0500
commitc8316a35a1eb292f09db8b7ff36dd33b43dfe8b6 (patch)
tree4abd076114d333440c239af950f630cbbbcf329b
parenta239c7accdc634459d2db014b8d8b6d5b78bab1b (diff)
Added an override of setLastOutput to square.py. Added some pre-built queries into the BQS.
Modified the default behavior or setLastOutput to make a deep copy of ouput to prevent accidental interference.
-rw-r--r--behaviors/Square.py7
-rw-r--r--operationscore/Behavior.py31
-rw-r--r--tests/TestBQS.py4
-rw-r--r--util/BehaviorQuerySystem.py8
4 files changed, 46 insertions, 4 deletions
diff --git a/behaviors/Square.py b/behaviors/Square.py
index 9d3223a..5fdaeef 100644
--- a/behaviors/Square.py
+++ b/behaviors/Square.py
@@ -7,6 +7,7 @@ class Square(Behavior):
def processResponse(self, sensorInputs, recursiveInputs):
for sensory in sensorInputs:#TODO: consider replicating the dict
+ sensory['CenterLoc'] = list(sensory['Location'])
xLoc = sensory['Location'][0]
yLoc = sensory['Location'][1]
width = self['Width']
@@ -15,3 +16,9 @@ class Square(Behavior):
'{x}<'+str(xLoc+width)+',{x}>'+str(xLoc-width)+\
',{y}<'+str(yLoc+width)+',{y}>'+str(yLoc-width)
return (sensorInputs, recursiveInputs)
+
+ def setLastOutput(self, output):
+ coutput = Behavior.deepCopyPacket(output)
+ for data in coutput:
+ data['Location'] = data['CenterLoc']
+ return coutput
diff --git a/operationscore/Behavior.py b/operationscore/Behavior.py
index 7090a23..349c4cf 100644
--- a/operationscore/Behavior.py
+++ b/operationscore/Behavior.py
@@ -12,6 +12,7 @@ class Behavior(SmootCoreObject):
specifically designed to do this (like AddPixelEvent).
timeStep is called on every iteration of the LightInstallation
addInput is called on each individual input received, and the inputs queue"""
+
def init(self):
self.validateArgs('Behavior.params')
if type(self['Inputs']) != type([]):
@@ -21,34 +22,55 @@ class Behavior(SmootCoreObject):
self.outGoingQueue = []
self.lastState = None
self.behaviorInit()
+
def behaviorInit(self):
pass
+
def addMapper(fn):
def withmap(fn):
return self.addMapperToResponse(fn())
return withmap
+
def processResponse(self, sensorInputs, recursiveInputs):
raise Exception('ProcessResponse not defined!')
+
def addInput(self, sensorInput):
self.sensorResponseQueue.append(sensorInput)
+
#used for behavior chaining
+
def immediateProcessInput(self, sensorInputs, recursiveInputs=[]):
(outputs,recursions) = self.processResponse(sensorInputs, \
recursiveInputs)
return self.addMapperToResponse((outputs,recursions))
+
def addInputs(self, sensorInputs):
if type(sensorInputs) == type([]):
[self.addInput(sensorInput) for sensorInput in sensorInputs]
else:
self.addInput(sensorInputs)
- #private
+
+ @staticmethod
+ def deepCopyPacket(self, datapacket):
+ """Returns a deep copy of a behavior data packet (a list of dicts) so that modifying the
+ returned packet will not modify the incoming packet."""
+ ret = []
+ for d in datapacket:
+ d = dict(d)
+ ret.append[d]
+ return ret
+
def getLastOutput(self):
return self.lastState
+
def setLastOutput(self, output):
"""Override to modify state. For example: if you are using a behavior that does uses
strings for location specification, you will want to override this to point to a single
- location. Make sure you keep lastState as a [] of {}. (List of dicts)"""
- self.lastState = output
+ location. Make sure you keep lastState as a [] of {}. (List of dicts). Additonally,
+ ensure that you call Behavior.deepCopyPacket on the packet before hand to avoid inadvertent
+ down-stream modifications. Look at Square.py for an example of this."""
+ self.lastState = Behavior.deepCopyPacket(output)
+
def addMapperToResponse(self, responses):
if self['Mapper'] != None:
if type(responses) == type(tuple):
@@ -59,11 +81,14 @@ class Behavior(SmootCoreObject):
r['Mapper'] = self['Mapper']
return responses
return responses
+
def timeStep(self): #TODO: type checking. clean this up
(outputs, recursions) = self.processResponse(self.sensorResponseQueue, \
self.recursiveResponseQueue)
self.sensorResponseQueue = []
self.recursiveResponseQueue = recursions
self.setLastOutput(outputs)
+ if outputs != []:
+ pdb.set_trace()
main_log.debug(self['Id'] + ' Ouputs ' + str(outputs))
return self.addMapperToResponse(outputs)
diff --git a/tests/TestBQS.py b/tests/TestBQS.py
index 7316c31..c46b917 100644
--- a/tests/TestBQS.py
+++ b/tests/TestBQS.py
@@ -13,13 +13,16 @@ class TestBQS(unittest.TestCase):
c.addInput({'Location':(5,12)})
b.timeStep()
c.timeStep()
+
def tearDown(self):
bqs.initBQS()
+
def test_simple_query(self):
validQuery = lambda args:args['Color']==(255,0,0)
invalidQuery = lambda args:args['Color']==(254,0,0)
assert bqs.query(validQuery) == [{'Color':(255,0,0), 'Location':(3,4)}]
assert bqs.query(invalidQuery) == []
+
def test_dist_query(self):
validDist = lambda args:geo.dist(args['Location'], (0,0)) <= 5
invalidDist = lambda args:geo.dist(args['Location'], (0,0)) <= 2
@@ -30,7 +33,6 @@ class TestBQS(unittest.TestCase):
assert bqs.query(doubleDist) == [{'Color':(255,0,0), 'Location':(3,4)}, {'Color':(0,0,255),\
'Location':(5,12)}]
def test_complex_queries(self):
-
validQuery = lambda args:args['Color']==(255,0,0)
doubleDist = lambda args:geo.dist(args['Location'], (0,0)) <= 20
diff --git a/util/BehaviorQuerySystem.py b/util/BehaviorQuerySystem.py
index 643b95c..688eecb 100644
--- a/util/BehaviorQuerySystem.py
+++ b/util/BehaviorQuerySystem.py
@@ -7,6 +7,7 @@ def initBQS():
initialized = True
def addBehavior(behavior):
+ """Add a behavior to the behavior registry."""
behaviorList.append(behavior)
def query(predicateList):
@@ -36,4 +37,11 @@ def query(predicateList):
ret.append(output)
return ret
+def getDistLambda(loc, maxDist):
+ """Returns a lambda function that checks if for behaviors within maxDist of loc. Can be passed
+ in as an arg to query."""
+ return lambda args:geo.dist(args['Location'], loc) <= maxDist
+def getBehaviorsNear(loc, maxdist):
+ """A premade method to do the common task of finding behavior near a location."""
+ return query(getDistLambda(loc, maxDist))