diff --git a/ActionAgent.py b/ActionAgent.py new file mode 100644 index 0000000..746c613 --- /dev/null +++ b/ActionAgent.py @@ -0,0 +1,38 @@ +import random +import action +import ztime + +# Parent Class for all Action Agents +# This class is used to create an Action Agent that can be used to perform actions on a target agent. + +class ActionAgent: + def __init__(self, sourceAgent, STATS): + self.target = sourceAgent + self.stats = STATS + self.name = sourceAgent.get_name() + + # Abstract Method to Update Target Agent On Each Run + def update(self, curtime): + pass + + # Abstract Method to Initialize Stats of Target Agent + # This method is set by the child class as some agents might have + # logic behind instantiating starting stats + def stat_init(self): + pass + + + +class ActionAgent_Action: + def __init__(self, name, effects, duration): + self.name = name + self.effects = effects + self.duration = duration + + # Performs Bulk Actions on the Target Agent + def act(self, targetAgent, cur_time): + for stat in self.effects: + targetAgent.change_stat(stat, self.effects[stat]) + + actionTime = ztime.Time(cur_time.minute + self.duration) + targetAgent.set_action(action.Action(self.name, 0, actionTime)) \ No newline at end of file diff --git a/SchoolActionAgent.py b/SchoolActionAgent.py new file mode 100644 index 0000000..706c22e --- /dev/null +++ b/SchoolActionAgent.py @@ -0,0 +1,138 @@ +import ActionAgent +import random + +# SchoolActionAgent class inherits from ActionAgent class and is used to perform actions on a target agent. + +class SchoolActionAgent(ActionAgent.ActionAgent): + + location_enums = { + "home": 0, + "school": 1, + "work": 2, + "OHOP": 3, + } + + actions = { + 'study': ActionAgent.ActionAgent_Action('study', {'purpose': 2, 'bored': 2, 'tired': 1, 'accomplished': 2, 'lazy': -2}, 10), + 'work': ActionAgent.ActionAgent_Action('work', {'money': 5, 'bored': 2, 'tired': 1, 'accomplished': 2, 'lazy': -2}, 15), + 'socialize': ActionAgent.ActionAgent_Action('socialize', {'lonely': -2, 'bored': -1, 'sad': -1}, 10), + 'exercise': ActionAgent.ActionAgent_Action('exercise', {'tired': 3, 'hungry': 2, 'accomplished': 2, 'lazy': -4}, 15), + 'relax': ActionAgent.ActionAgent_Action('relax', {'bored': 2, 'tired': -1, 'sad': -1, 'accomplished': -1}, 25), + 'eat': ActionAgent.ActionAgent_Action('eat', {'hungry': -5, 'tired': 1, 'sad': -1}, 10), + 'sleep': ActionAgent.ActionAgent_Action('sleep', {'tired': -5, 'accomplished': -1, 'sad': -1}, 60), + 'party': ActionAgent.ActionAgent_Action('party', {'bored': -2, 'lonely': -2, 'tired': 2, 'hungry': 2, 'money': -35}, 30), + } + + actionsAvailableAtLocation = { + "home": ['eat', 'sleep', 'relax'], + "school": ['study', 'socialize', 'exercise'], + "work": ['socialize', 'work'], + "OHOP": ['socialize', 'party'] + } + + statBasedActions = { + "hungry": ['eat'], + "tired": ['sleep', 'relax'], + "bored": ['study', 'work', 'socialize', 'exercise', 'relax', 'party'], + "lonely": ['socialize', 'party'], + "sad": ['socialize', 'party', 'relax'], + "money": ['work', 'study'], + "accomplished": ['study', 'work', 'exercise'], + "lazy": ['study', 'work', 'exercise'], + "frustrated": ['study', 'work', 'exercise'], + "purpose": ['study', 'work', 'exercise'], + } + + # List order is priority order for the stats + # cutoff is the max value for the stat which it will be triggered + statLimitsAndPriorities = { + "hungry": 10, + "tired": 12, + "bored": 8, + "money": 100, + "lonely": 10, + "sad": 10, + "frustrated": 10, + "lazy": 10, + "accomplished": 10, + "purpose": 10, + } + + # 24 entries, one for each hour of the day + # 0000, 0100, 0200, 0300, 0400, 0500, + # 0600, 0700, 0800, 0900, 1000, 1100, + # 1200, 1300, 1400, 1500, 1600, 1700, + # 1800, 1900, 2000, 2100, 2200, 2300 + schedule = { + "Sunday": ['home','home','home','home','home','home', + 'home','home','work','work','work','work', + 'work','work','work','work','work','work', + 'work','home','home','home','home','home'], + "Monday": ['home','home','home','home','home','home', + 'home','home','school','school','school','school', + 'school','school','school','school','school','school', + 'school','home','home','home','home','home'], + "Tuesday": ['home','home','home','home','home','home', + 'home','home','school','school','school','school', + 'school','school','school','school','school','school', + 'school','home','home','home','home','home'], + "Wednesday": ['home','home','home','home','home','home', + 'home','home','school','school','school','school', + 'school','school','school','school','school','school', + 'school','home','home','home','home','home'], + "Thursday": ['home','home','home','home','home','home', + 'home','home','school','school','school','school', + 'school','school','school','school','school','school', + 'school','home','OHOP','OHOP','OHOP','OHOP'], + "Friday": ['home','home','home','home','home','home', + 'home','home','school','school','school','school', + 'school','school','school','school','school','school', + 'school','home','OHOP','OHOP','OHOP','OHOP'], + "Saturday": ['home','home','home','home','home','home', + 'home','home','home','home','home','home', + 'home','home','home','home','home','home', + 'home','home','home','home','home','home'] + } + + # Update Target Agent on Each Run + def update(self, curtime): + self.target.update_action(curtime) + if self.target.is_idle(): + # Evaluate according to current location + currentLocation = self.schedule[curtime.day_of_week()][curtime.hour()] + + self.target.get_stat('location').index = self.location_enums[currentLocation] + + locationActions = self.actionsAvailableAtLocation[currentLocation] + + # Evaluate according to current stats + for statName in self.statLimitsAndPriorities: + # If the stat is above the threshold, perform an action based on the stat name + # and the current location of the target agent + if self.target.get_stat(statName).get_value() >= self.statLimitsAndPriorities[statName]: + # Get the list of actions that can be performed based on the stat name + actions = self.statBasedActions[statName] + + # Find the intersection of the two lists to get the available actions + availableActions = list(set(actions) & set(locationActions)) + + # If there are available actions, choose one at random and perform it + if len(availableActions) > 0: + action = self.actions[random.choice(availableActions)] + action.act(self.target, curtime) + return + # If no stat-based action is performed, perform a location-based action + if len(locationActions) > 0: + action = self.actions[random.choice(locationActions)] + action.act(self.target, curtime) + return + + # Initializes the Target Agent's Stats + # This particular agent can start at any random point + # as any day for a college student could be like any other + def stat_init(self): + for stat in self.stats: + randomStart = random.randint(0, len(self.stats[stat]) - 1) + self.target.change_stat(stat, randomStart) + + \ No newline at end of file diff --git a/__pycache__/ActionAgent.cpython-313.pyc b/__pycache__/ActionAgent.cpython-313.pyc new file mode 100644 index 0000000..5eca94a Binary files /dev/null and b/__pycache__/ActionAgent.cpython-313.pyc differ diff --git a/__pycache__/SchoolActionAgent.cpython-313.pyc b/__pycache__/SchoolActionAgent.cpython-313.pyc new file mode 100644 index 0000000..1e8a5d7 Binary files /dev/null and b/__pycache__/SchoolActionAgent.cpython-313.pyc differ diff --git a/__pycache__/action.cpython-313.pyc b/__pycache__/action.cpython-313.pyc new file mode 100644 index 0000000..224e27d Binary files /dev/null and b/__pycache__/action.cpython-313.pyc differ diff --git a/__pycache__/agent.cpython-313.pyc b/__pycache__/agent.cpython-313.pyc new file mode 100644 index 0000000..7e56fab Binary files /dev/null and b/__pycache__/agent.cpython-313.pyc differ diff --git a/__pycache__/agent_stat.cpython-313.pyc b/__pycache__/agent_stat.cpython-313.pyc new file mode 100644 index 0000000..829f149 Binary files /dev/null and b/__pycache__/agent_stat.cpython-313.pyc differ diff --git a/__pycache__/decision.cpython-313.pyc b/__pycache__/decision.cpython-313.pyc new file mode 100644 index 0000000..31381ba Binary files /dev/null and b/__pycache__/decision.cpython-313.pyc differ diff --git a/__pycache__/defs.cpython-313.pyc b/__pycache__/defs.cpython-313.pyc new file mode 100644 index 0000000..71631b2 Binary files /dev/null and b/__pycache__/defs.cpython-313.pyc differ diff --git a/__pycache__/ztime.cpython-313.pyc b/__pycache__/ztime.cpython-313.pyc new file mode 100644 index 0000000..15ad2b1 Binary files /dev/null and b/__pycache__/ztime.cpython-313.pyc differ diff --git a/agent.py b/agent.py index 9c1f1ad..cfefcf4 100644 --- a/agent.py +++ b/agent.py @@ -8,6 +8,7 @@ class Agent: self.stats = stats self.idle_message = idle_message self.action = action + self.action_agent = None def get_stat(self, stat_name): return self.stats[stat_name] def change_stat(self, stat_name, amt): @@ -32,4 +33,8 @@ class Agent: return self.idle_message else: return self.action.get_msg() + def set_action_agent(self, agent): + self.action_agent = agent + def get_action_agent(self): + return self.action_agent diff --git a/decision.py b/decision.py index 0198283..e1da5b5 100644 --- a/decision.py +++ b/decision.py @@ -2,10 +2,19 @@ import enum import ztime import action from defs import STATS +import SchoolActionAgent - +# Runs Every Tick! def tick_decisionsys(myagent, curtime): + myagent.get_action_agent().update(curtime) pass + +# Runs at the start def make_decisionsys(myagent): + # Set up the agent's action agent. This is later called to update + # The modulalarity here is that the following line can be replaced with any other action agent + # and this will drive the agents actions accordingly + myagent.set_action_agent(SchoolActionAgent.SchoolActionAgent(myagent, STATS)) + myagent.get_action_agent().stat_init() pass diff --git a/defs.py b/defs.py index 3d7e3b3..e86e3e2 100644 --- a/defs.py +++ b/defs.py @@ -13,8 +13,8 @@ GAME_SPEEDS = [ ('very fast', 1, 8)] # Background and text color -BG_COLOR = "lightblue1" -FG_COLOR = "black" +BG_COLOR = "black" +FG_COLOR = "white" # You should modify this list of agent stats @@ -23,21 +23,19 @@ FG_COLOR = "black" # The stats below are just examples to give you # some inspiration. Come up with your own set # based on the theme/setting you imagine. + STATS = { - 'location':['home','work','daycare','bar','park','jail'], + 'location':['home','school','work','OHOP'], 'hungry':list(range(0,20)), - 'tired':list(range(0,5)), - 'bored':list(range(0,2)), - 'purpose':list(range(0,3)), + 'tired':list(range(0,20)), + 'bored':list(range(0,20)), + 'purpose':list(range(0,20)), 'lonely':list(range(0,20)), 'money':list(range(0,1000)), - 'dirty':list(range(0,5)), - 'sad':list(range(0,10)), - 'crazy':list(range(0,10)), - 'frustrated':list(range(0,10)), - 'lazy':list(range(0,10)), - 'confident':list(range(0,10)), - 'accomplished':list(range(0,10)) + 'sad':list(range(0,20)), + 'frustrated':list(range(0,20)), + 'lazy':list(range(0,20)), + 'accomplished':list(range(0,20)) } # Probably don't change this line. @@ -45,5 +43,5 @@ STAT_NAMES = list(STATS.keys()) # Change if you want. I hope I don't get # 40 submissions all about an agent named, Jimbo. -AGENT_NAME = 'Jimbo' +AGENT_NAME = 'JimWithABow' START_TIME = 1800 # 6:00 AM Monday