Skip to content
Closed
19 changes: 11 additions & 8 deletions examples/WolfSheep/wolf_sheep/agents.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ class Sheep(RandomWalker):

energy = None

def __init__(self, pos, model, moore, energy=None):
super().__init__(pos, model, moore=moore)
def __init__(self, unique_id, pos, model, moore, energy=None):
super().__init__(unique_id, pos, model, moore=moore)
self.energy = energy

def step(self):
Expand Down Expand Up @@ -47,7 +47,8 @@ def step(self):
# Create a new sheep:
if self.model.grass:
self.energy /= 2
lamb = Sheep(self.pos, self.model, self.moore, self.energy)
lamb = Sheep(self.model.next_id(), self.pos, self.model,
self.moore, self.energy)
self.model.grid.place_agent(lamb, self.pos)
self.model.schedule.add(lamb)

Expand All @@ -59,8 +60,8 @@ class Wolf(RandomWalker):

energy = None

def __init__(self, pos, model, moore, energy=None):
super().__init__(pos, model, moore=moore)
def __init__(self, unique_id, pos, model, moore, energy=None):
super().__init__(unique_id, pos, model, moore=moore)
self.energy = energy

def step(self):
Expand All @@ -87,7 +88,8 @@ def step(self):
if random.random() < self.model.wolf_reproduce:
# Create a new wolf cub
self.energy /= 2
cub = Wolf(self.pos, self.model, self.moore, self.energy)
cub = Wolf(self.model.next_id(), self.pos, self.model,
self.moore, self.energy)
self.model.grid.place_agent(cub, cub.pos)
self.model.schedule.add(cub)

Expand All @@ -97,17 +99,18 @@ class GrassPatch(Agent):
A patch of grass that grows at a fixed rate and it is eaten by sheep
'''

def __init__(self, pos, model, fully_grown, countdown):
def __init__(self, unique_id, pos, model, fully_grown, countdown):
'''
Creates a new patch of grass

Args:
grown: (boolean) Whether the patch of grass is fully grown or not
countdown: Time for the patch of grass to be fully grown again
'''
super().__init__(pos, model)
super().__init__(unique_id, model)
self.fully_grown = fully_grown
self.countdown = countdown
self.pos = pos

def step(self):
if not self.fully_grown:
Expand Down
9 changes: 5 additions & 4 deletions examples/WolfSheep/wolf_sheep/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ def __init__(self, height=20, width=20,
once it is eaten
sheep_gain_from_food: Energy sheep gain from grass, if enabled.
'''

super().__init__()
# Set parameters
self.height = height
self.width = width
Expand All @@ -84,7 +84,7 @@ def __init__(self, height=20, width=20,
x = random.randrange(self.width)
y = random.randrange(self.height)
energy = random.randrange(2 * self.sheep_gain_from_food)
sheep = Sheep((x, y), self, True, energy)
sheep = Sheep(self.next_id(), (x, y), self, True, energy)
self.grid.place_agent(sheep, (x, y))
self.schedule.add(sheep)

Expand All @@ -93,7 +93,7 @@ def __init__(self, height=20, width=20,
x = random.randrange(self.width)
y = random.randrange(self.height)
energy = random.randrange(2 * self.wolf_gain_from_food)
wolf = Wolf((x, y), self, True, energy)
wolf = Wolf(self.next_id(), (x, y), self, True, energy)
self.grid.place_agent(wolf, (x, y))
self.schedule.add(wolf)

Expand All @@ -108,7 +108,8 @@ def __init__(self, height=20, width=20,
else:
countdown = random.randrange(self.grass_regrowth_time)

patch = GrassPatch((x, y), self, fully_grown, countdown)
patch = GrassPatch(self.next_id(), (x, y), self,
fully_grown, countdown)
self.grid.place_agent(patch, (x, y))
self.schedule.add(patch)

Expand Down
4 changes: 2 additions & 2 deletions examples/WolfSheep/wolf_sheep/random_walk.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,15 @@ class RandomWalker(Agent):
y = None
moore = True

def __init__(self, pos, model, moore=True):
def __init__(self, unique_id, pos, model, moore=True):
'''
grid: The MultiGrid object in which the agent lives.
x: The agent's current x coordinate
y: The agent's current y coordinate
moore: If True, may move in all 8 directions.
Otherwise, only up, down, left, right.
'''
super().__init__(pos, model)
super().__init__(unique_id, model)
self.pos = pos
self.moore = moore

Expand Down
24 changes: 11 additions & 13 deletions examples/WolfSheep/wolf_sheep/schedule.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ class RandomActivationByBreed(RandomActivation):

Assumes that all agents have a step() method.
'''
agents_by_breed = defaultdict(list)
agents_by_breed = defaultdict(dict)

def __init__(self, model):
super().__init__(model)
self.agents_by_breed = defaultdict(list)
self.agents_by_breed = defaultdict(dict)

def add(self, agent):
'''
Expand All @@ -28,21 +28,19 @@ def add(self, agent):
agent: An Agent to be added to the schedule.
'''

self.agents.append(agent)
self.agents[agent.unique_id] = agent
agent_class = type(agent)
self.agents_by_breed[agent_class].append(agent)
self.agents_by_breed[agent_class][agent.unique_id] = agent

def remove(self, agent):
'''
Remove all instances of a given agent from the schedule.
'''

while agent in self.agents:
self.agents.remove(agent)
del self.agents[agent.unique_id]

agent_class = type(agent)
while agent in self.agents_by_breed[agent_class]:
self.agents_by_breed[agent_class].remove(agent)
del self.agents_by_breed[agent_class][agent.unique_id]

def step(self, by_breed=True):
'''
Expand All @@ -67,13 +65,13 @@ def step_breed(self, breed):
Args:
breed: Class object of the breed to run.
'''
agents = self.agents_by_breed[breed]
random.shuffle(agents)
for agent in agents:
agent.step()
agent_keys = list(self.agents_by_breed[breed].keys())
random.shuffle(agent_keys)
for agent_key in agent_keys:
self.agents_by_breed[breed][agent_key].step()

def get_breed_count(self, breed_class):
'''
Returns the current number of agents of certain breed in the queue.
'''
return len(self.agents_by_breed[breed_class])
return len(self.agents_by_breed[breed_class].values())
2 changes: 1 addition & 1 deletion mesa/batchrunner.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ def collect_model_vars(self, model):
def collect_agent_vars(self, model):
""" Run reporters and collect agent-level variables. """
agent_vars = {}
for agent in model.schedule.agents:
for agent in model.schedule.agents.values():
agent_record = {}
for var, reporter in self.agent_reporters.items():
agent_record[var] = reporter(agent)
Expand Down
2 changes: 1 addition & 1 deletion mesa/datacollection.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ def collect(self, model):
if self.agent_reporters:
for var, reporter in self.agent_reporters.items():
agent_records = []
for agent in model.schedule.agents:
for agent in model.schedule.agents.values():
agent_records.append((agent.unique_id, reporter(agent)))
self.agent_vars[var].append(agent_records)

Expand Down
6 changes: 6 additions & 0 deletions mesa/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ def __init__(self, seed=None):
random.seed(seed)
self.running = True
self.schedule = None
self.current_id = 0

def run_model(self):
""" Run the model until the end condition is reached. Overload as
Expand All @@ -42,3 +43,8 @@ def run_model(self):
def step(self):
""" A single step. Fill in here. """
pass

def next_id(self):
""" Return the next unique ID for agents, increment current_id"""
self.current_id += 1
return self.current_id
42 changes: 23 additions & 19 deletions mesa/time.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,14 @@ class BaseScheduler:
model = None
steps = 0
time = 0
agents = []
agents = {}

def __init__(self, model):
""" Create a new, empty BaseScheduler. """
self.model = model
self.steps = 0
self.time = 0
self.agents = []
self.agents = {}

def add(self, agent):
""" Add an Agent object to the schedule.
Expand All @@ -58,7 +58,7 @@ def add(self, agent):
have a step() method.

"""
self.agents.append(agent)
self.agents[agent.unique_id] = agent

def remove(self, agent):
""" Remove all instances of a given agent from the schedule.
Expand All @@ -67,19 +67,19 @@ def remove(self, agent):
agent: An agent object.

"""
while agent in self.agents:
self.agents.remove(agent)
del self.agents[agent.unique_id]

def step(self):
""" Execute the step of all the agents, one at a time. """
for agent in self.agents:
agent.step()
agent_keys = list(self.agents.keys())
for agent_key in agent_keys:
self.agents[agent_key].step()
self.steps += 1
self.time += 1

def get_agent_count(self):
""" Returns the current number of agents in the queue. """
return len(self.agents)
return len(self.agents.keys())


class RandomActivation(BaseScheduler):
Expand All @@ -97,9 +97,11 @@ def step(self):
random order.

"""
random.shuffle(self.agents)
for agent in self.agents:
agent.step()
agent_keys = list(self.agents.keys())
random.shuffle(agent_keys)

for agent_key in agent_keys:
self.agents[agent_key].step()
self.steps += 1
self.time += 1

Expand All @@ -114,10 +116,11 @@ class SimultaneousActivation(BaseScheduler):
"""
def step(self):
""" Step all agents, then advance them. """
for agent in self.agents:
agent.step()
for agent in self.agents:
agent.advance()
agent_keys = list(self.agents.keys())
for agent_key in agent_keys:
self.agents[agent_key].step()
for agent_key in agent_keys:
self.agents[agent_key].advance()
self.steps += 1
self.time += 1

Expand Down Expand Up @@ -161,13 +164,14 @@ def __init__(self, model, stage_list=["step"], shuffle=False,

def step(self):
""" Executes all the stages for all agents. """
agent_keys = list(self.agents.keys())
if self.shuffle:
random.shuffle(self.agents)
random.shuffle(agent_keys)
for stage in self.stage_list:
for agent in self.agents:
getattr(agent, stage)() # Run stage
for agent_key in agent_keys:
getattr(self.agents[agent_key], stage)() # Run stage
if self.shuffle_between_stages:
random.shuffle(self.agents)
random.shuffle(agent_keys)
self.time += self.stage_time

self.steps += 1
3 changes: 3 additions & 0 deletions tests/test_batchrunner.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,6 @@ def test_agent_level_vars(self):
len(self.params['model_param']) * \
self.iterations
assert agent_vars.shape == (rows, 6)

if __name__ == '__main__':
unittest.main()
5 changes: 4 additions & 1 deletion tests/test_datacollector.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def setUp(self):
for i in range(7):
self.model.step()
# Write to table:
for agent in self.model.schedule.agents:
for agent in self.model.schedule.agents.values():
agent.write_final_values()

def test_model_vars(self):
Expand Down Expand Up @@ -117,3 +117,6 @@ def test_exports(self):

with self.assertRaises(Exception):
table_df = data_collector.get_table_dataframe("not a real table")

if __name__ == '__main__':
unittest.main()
3 changes: 3 additions & 0 deletions tests/test_grid.py
Original file line number Diff line number Diff line change
Expand Up @@ -317,3 +317,6 @@ def test_neighbors(self):

neighbors = self.grid.get_neighbors((1, 3), moore=False, radius=2)
assert len(neighbors) == 11

if __name__ == '__main__':
unittest.main()
Loading