From 794095391e566e53b1009e80c5d49d3b78a5c56f Mon Sep 17 00:00:00 2001 From: Ben Davies Date: Sun, 22 May 2011 01:43:19 +1000 Subject: [PATCH] Added iterations and observations of interactions --- src/critters.py | 19 ++++++- src/main.py | 21 +++++--- src/world.py | 135 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 168 insertions(+), 7 deletions(-) create mode 100644 src/world.py diff --git a/src/critters.py b/src/critters.py index e1eac4f..77684c8 100644 --- a/src/critters.py +++ b/src/critters.py @@ -29,8 +29,25 @@ def __init__(self, strategy): self.name = "Critter_%d" % Critter.number_of def interact(self, other_critter): + '''Interact with another critter + >>> c1 = Critter(CheatStrategy()) + >>> c2 = Critter(CheatStrategy()) + >>> c1.interact(c2) + 0 + ''' return self.strategy.interact(other_critter) + def observe_interaction(self, critter1, critter1_action, + critter2, critter2_action): + ''' + take into account an interaction + >>> c1 = Critter(CheatStrategy()) + >>> c2 = Critter(CheatStrategy()) + >>> c1.observe_interaction(c1,0,c2,0) + ''' + self.strategy.observe_interaction(critter1, critter1_action, + critter2, critter2_action) + def add_food(self, food_amount): ''' Adds food to the critter @@ -69,7 +86,7 @@ def interact(self, other_agent): def observe_interaction(self, agent1, agent1_action, agent2, agent2_action): ''' - provides information to the agent about what transpired in an interaction. + provides information to the strategy about what transpired in an interaction. Does not return anything >>> strategy = AbstractStrategy() >>> strategy.observe_interaction(Critter(None), 1, Critter(None), 0) diff --git a/src/main.py b/src/main.py index b39149d..8a1f8e1 100644 --- a/src/main.py +++ b/src/main.py @@ -4,10 +4,10 @@ @author: ben ''' -import sys, getopt +import sys, getopt, world def main(argv): - name = 'world' + world_to_run = 'PrisonersDilemma' try: opts, args = getopt.getopt(argv, 'h','--help') @@ -18,15 +18,24 @@ def main(argv): if opt in ('-h','--help'): usage() sys.exit() - name = "".join(args) or name - print "Hello, %s" % name - + world_to_run = "".join(args) or world_to_run + + print "running world %s" % world_to_run + + instantiate_world(world_to_run).run() + def usage(): '''prints usage instructions''' - print('Usage: main.py [name]') + print('Usage: main.py [world]') + +def instantiate_world(name_of_world): + '''instantiates the named world (class = world.[name_of_world]World)''' + return world.PrisonersDilemmaWorld() + if __name__ == '__main__': main(sys.argv[1:]) + diff --git a/src/world.py b/src/world.py new file mode 100644 index 0000000..2f09b61 --- /dev/null +++ b/src/world.py @@ -0,0 +1,135 @@ +''' +Created on May 21, 2011 + +@author: bendavies +''' +import critters + +class World(object): + ''' + abstract class for defining an interface for world objects. World objects can be + configured and run. + ''' + + def __init__(self): + ''' + Constructor + ''' + + def run(self): + ''' + Runs the world with the configuration provided + ''' + return 0 + + +class PrisonersDilemmaWorld(World): + ''' + creates a world with critters using different strategies to determine what + happens when they interact; Do they cooperate or not? Based on their mutual + decisions they are provided food + ''' + + def run(self): + ''' + executes the world + >>> world = PrisonersDilemmaWorld() + >>> world.run() # doctest:+ELLIPSIS + Critter_...Critter_... + 1:...0...200 + 2:...0...400 + ... + simulation complete. + ''' + NUMBER_OF_ITERATIONS = 15 + + #create critter population + sucker = critters.Critter(critters.SuckerStrategy()) + cheater = critters.Critter(critters.CheatStrategy()) + population = (sucker, cheater) + + + #write headers + print('%s\t%s' %(population[0].name, population[1].name)) + + #execute iterations + for i in range(1,NUMBER_OF_ITERATIONS + 1): + self.run_iteration(population) + print('%d:\t%d\t%d' % + (i,population[0].food,population[1].food)) + + #finish simulation + print('simulation complete.') + + def run_iteration(self, population): + ''' + runs a single iteration for population. The population itself is updated + in the course of the exection. A population is a list of critters + >>> world = PrisonersDilemmaWorld() + >>> c1 = critters.Critter(critters.CheatStrategy()) + >>> c2 = critters.Critter(critters.CheatStrategy()) + >>> population = (c1,c2) + >>> world.run_iteration(population) + >>> population[1].food + 0 + + ''' + + interaction_list = \ + [(c1,c2) for c1 in population for c2 in population if c1 < c2] + + for c1, c2 in interaction_list: + self.interact_critters(c1,c2) + + + def interact_critters(self, critter1, critter2): + ''' + executes an interaction between 2 critters. Based on their own + response to the interaction, each is rewarded food (or not) based on + their response + >>> world = PrisonersDilemmaWorld() + >>> c1 = critters.Critter(critters.CheatStrategy()) + >>> c2 = critters.Critter(critters.CheatStrategy()) + >>> world.interact_critters(c1,c2) + ''' + COOPERATE_FOOD = 100 + CHEATER_FOOD = 200 + SUCKER_FOOD = 0 + + COOPERATE = critters.AbstractStrategy.COOPERATE + UNCOOPERATE = critters.AbstractStrategy.UNCOOPERATE + + + critter1_interaction = critter1.interact(critter2) + critter2_interaction = critter2.interact(critter1) + + if (critter1_interaction == COOPERATE & + critter2_interaction == COOPERATE): + + critter1.add_food(COOPERATE_FOOD) + critter2.add_food(COOPERATE_FOOD) + + elif (critter1_interaction == UNCOOPERATE & + critter2_interaction == UNCOOPERATE): + #neither gets food + pass + else: + #one cheated the other + if critter1_interaction == COOPERATE: + #critter1 is the sucker + critter1.add_food(SUCKER_FOOD) + critter2.add_food(CHEATER_FOOD) + else: + #critter2 is the sucker + critter2.add_food(SUCKER_FOOD) + critter1.add_food(CHEATER_FOOD) + + #Critters observe the outcome + critter1.observe_interaction(critter1,critter1_interaction, + critter2,critter2_interaction) + critter2.observe_interaction(critter1,critter1_interaction, + critter2,critter2_interaction) + +if __name__ == '__main__': + import doctest + doctest.testmod()