Mesa 3.0.0a3__py3-none-any.whl → 3.0.0a5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of Mesa might be problematic. Click here for more details.

Files changed (40) hide show
  1. mesa/__init__.py +2 -3
  2. mesa/agent.py +193 -75
  3. mesa/batchrunner.py +18 -23
  4. mesa/cookiecutter-mesa/hooks/post_gen_project.py +2 -0
  5. mesa/cookiecutter-mesa/{{cookiecutter.snake}}/{{cookiecutter.snake}}/__init__.py +1 -0
  6. mesa/datacollection.py +138 -27
  7. mesa/experimental/UserParam.py +67 -0
  8. mesa/experimental/__init__.py +5 -1
  9. mesa/experimental/cell_space/__init__.py +7 -0
  10. mesa/experimental/cell_space/cell.py +61 -20
  11. mesa/experimental/cell_space/cell_agent.py +12 -7
  12. mesa/experimental/cell_space/cell_collection.py +54 -17
  13. mesa/experimental/cell_space/discrete_space.py +16 -5
  14. mesa/experimental/cell_space/grid.py +19 -8
  15. mesa/experimental/cell_space/network.py +9 -7
  16. mesa/experimental/cell_space/voronoi.py +26 -33
  17. mesa/experimental/components/altair.py +81 -0
  18. mesa/experimental/components/matplotlib.py +242 -0
  19. mesa/experimental/devs/__init__.py +2 -0
  20. mesa/experimental/devs/eventlist.py +36 -15
  21. mesa/experimental/devs/examples/epstein_civil_violence.py +71 -39
  22. mesa/experimental/devs/examples/wolf_sheep.py +43 -44
  23. mesa/experimental/devs/simulator.py +55 -15
  24. mesa/experimental/solara_viz.py +453 -0
  25. mesa/main.py +6 -4
  26. mesa/model.py +64 -61
  27. mesa/space.py +154 -123
  28. mesa/time.py +57 -67
  29. mesa/visualization/UserParam.py +19 -6
  30. mesa/visualization/__init__.py +14 -2
  31. mesa/visualization/components/altair.py +18 -1
  32. mesa/visualization/components/matplotlib.py +26 -2
  33. mesa/visualization/solara_viz.py +231 -225
  34. mesa/visualization/utils.py +9 -0
  35. {mesa-3.0.0a3.dist-info → mesa-3.0.0a5.dist-info}/METADATA +2 -1
  36. mesa-3.0.0a5.dist-info/RECORD +44 -0
  37. mesa-3.0.0a3.dist-info/RECORD +0 -39
  38. {mesa-3.0.0a3.dist-info → mesa-3.0.0a5.dist-info}/WHEEL +0 -0
  39. {mesa-3.0.0a3.dist-info → mesa-3.0.0a5.dist-info}/entry_points.txt +0 -0
  40. {mesa-3.0.0a3.dist-info → mesa-3.0.0a5.dist-info}/licenses/LICENSE +0 -0
@@ -1,3 +1,5 @@
1
+ """Eventlist which is at the core of event scheduling."""
2
+
1
3
  from __future__ import annotations
2
4
 
3
5
  import itertools
@@ -10,15 +12,17 @@ from weakref import WeakMethod, ref
10
12
 
11
13
 
12
14
  class Priority(IntEnum):
15
+ """Enumeration of priority levels."""
16
+
13
17
  LOW = 10
14
18
  DEFAULT = 5
15
19
  HIGH = 1
16
20
 
17
21
 
18
22
  class SimulationEvent:
19
- """A simulation event
23
+ """A simulation event.
20
24
 
21
- the callable is wrapped using weakref, so there is no need to explicitly cancel event if e.g., an agent
25
+ The callable is wrapped using weakref, so there is no need to explicitly cancel event if e.g., an agent
22
26
  is removed from the simulation.
23
27
 
24
28
  Attributes:
@@ -34,7 +38,7 @@ class SimulationEvent:
34
38
  _ids = itertools.count()
35
39
 
36
40
  @property
37
- def CANCELED(self) -> bool:
41
+ def CANCELED(self) -> bool: # noqa: D102
38
42
  return self._canceled
39
43
 
40
44
  def __init__(
@@ -45,6 +49,15 @@ class SimulationEvent:
45
49
  function_args: list[Any] | None = None,
46
50
  function_kwargs: dict[str, Any] | None = None,
47
51
  ) -> None:
52
+ """Initialize a simulation event.
53
+
54
+ Args:
55
+ time: the instant of time of the simulation event
56
+ function: the callable to invoke
57
+ priority: the priority of the event
58
+ function_args: arguments for callable
59
+ function_kwargs: keyword arguments for the callable
60
+ """
48
61
  super().__init__()
49
62
  if not callable(function):
50
63
  raise Exception()
@@ -64,20 +77,20 @@ class SimulationEvent:
64
77
  self.function_kwargs = function_kwargs if function_kwargs else {}
65
78
 
66
79
  def execute(self):
67
- """execute this event"""
80
+ """Execute this event."""
68
81
  if not self._canceled:
69
82
  fn = self.fn()
70
83
  if fn is not None:
71
84
  fn(*self.function_args, **self.function_kwargs)
72
85
 
73
86
  def cancel(self) -> None:
74
- """cancel this event"""
87
+ """Cancel this event."""
75
88
  self._canceled = True
76
89
  self.fn = None
77
90
  self.function_args = []
78
91
  self.function_kwargs = {}
79
92
 
80
- def __lt__(self, other):
93
+ def __lt__(self, other): # noqa
81
94
  # Define a total ordering for events to be used by the heapq
82
95
  return (self.time, self.priority, self.unique_id) < (
83
96
  other.time,
@@ -87,30 +100,31 @@ class SimulationEvent:
87
100
 
88
101
 
89
102
  class EventList:
90
- """An event list
103
+ """An event list.
91
104
 
92
105
  This is a heap queue sorted list of events. Events are always removed from the left, so heapq is a performant and
93
106
  appropriate data structure. Events are sorted based on their time stamp, their priority, and their unique_id
94
107
  as a tie-breaker, guaranteeing a complete ordering.
95
108
 
109
+
96
110
  """
97
111
 
98
112
  def __init__(self):
113
+ """Initialize an event list."""
99
114
  self._events: list[SimulationEvent] = []
100
115
  heapify(self._events)
101
116
 
102
117
  def add_event(self, event: SimulationEvent):
103
- """Add the event to the event list
118
+ """Add the event to the event list.
104
119
 
105
120
  Args:
106
121
  event (SimulationEvent): The event to be added
107
122
 
108
123
  """
109
-
110
124
  heappush(self._events, event)
111
125
 
112
126
  def peak_ahead(self, n: int = 1) -> list[SimulationEvent]:
113
- """Look at the first n non-canceled event in the event list
127
+ """Look at the first n non-canceled event in the event list.
114
128
 
115
129
  Args:
116
130
  n (int): The number of events to look ahead
@@ -139,7 +153,7 @@ class EventList:
139
153
  return peek
140
154
 
141
155
  def pop_event(self) -> SimulationEvent:
142
- """pop the first element from the event list"""
156
+ """Pop the first element from the event list."""
143
157
  while self._events:
144
158
  event = heappop(self._events)
145
159
  if not event.CANCELED:
@@ -147,16 +161,17 @@ class EventList:
147
161
  raise IndexError("Event list is empty")
148
162
 
149
163
  def is_empty(self) -> bool:
164
+ """Return whether the event list is empty."""
150
165
  return len(self) == 0
151
166
 
152
- def __contains__(self, event: SimulationEvent) -> bool:
167
+ def __contains__(self, event: SimulationEvent) -> bool: # noqa
153
168
  return event in self._events
154
169
 
155
- def __len__(self) -> int:
170
+ def __len__(self) -> int: # noqa
156
171
  return len(self._events)
157
172
 
158
173
  def __repr__(self) -> str:
159
- """Return a string representation of the event list"""
174
+ """Return a string representation of the event list."""
160
175
  events_str = ", ".join(
161
176
  [
162
177
  f"Event(time={e.time}, priority={e.priority}, id={e.unique_id})"
@@ -167,7 +182,12 @@ class EventList:
167
182
  return f"EventList([{events_str}])"
168
183
 
169
184
  def remove(self, event: SimulationEvent) -> None:
170
- """remove an event from the event list"""
185
+ """Remove an event from the event list.
186
+
187
+ Args:
188
+ event (SimulationEvent): The event to be removed
189
+
190
+ """
171
191
  # we cannot simply remove items from _eventlist because this breaks
172
192
  # heap structure invariant. So, we use a form of lazy deletion.
173
193
  # SimEvents have a CANCELED flag that we set to True, while popping and peak_ahead
@@ -175,4 +195,5 @@ class EventList:
175
195
  event.cancel()
176
196
 
177
197
  def clear(self):
198
+ """Clear the event list."""
178
199
  self._events.clear()
@@ -1,3 +1,5 @@
1
+ """Epstein civil violence example using ABMSimulator."""
2
+
1
3
  import enum
2
4
  import math
3
5
 
@@ -7,21 +9,32 @@ from mesa.space import SingleGrid
7
9
 
8
10
 
9
11
  class EpsteinAgent(Agent):
10
- def __init__(self, unique_id, model, vision, movement):
11
- super().__init__(unique_id, model)
12
+ """Epstein Agent."""
13
+
14
+ def __init__(self, model, vision, movement):
15
+ """Initialize the agent.
16
+
17
+ Args:
18
+ model: a model instance
19
+ vision: size of neighborhood
20
+ movement: boolean whether agent can move or not
21
+ """
22
+ super().__init__(model)
12
23
  self.vision = vision
13
24
  self.movement = movement
14
25
 
15
26
 
16
27
  class AgentState(enum.IntEnum):
28
+ """Agent states."""
29
+
17
30
  QUIESCENT = enum.auto()
18
31
  ARRESTED = enum.auto()
19
32
  ACTIVE = enum.auto()
20
33
 
21
34
 
22
35
  class Citizen(EpsteinAgent):
23
- """
24
- A member of the general population, may or may not be in active rebellion.
36
+ """A member of the general population, may or may not be in active rebellion.
37
+
25
38
  Summary of rule: If grievance - risk > threshold, rebel.
26
39
 
27
40
  Attributes:
@@ -46,7 +59,6 @@ class Citizen(EpsteinAgent):
46
59
 
47
60
  def __init__(
48
61
  self,
49
- unique_id,
50
62
  model,
51
63
  vision,
52
64
  movement,
@@ -56,11 +68,13 @@ class Citizen(EpsteinAgent):
56
68
  threshold,
57
69
  arrest_prob_constant,
58
70
  ):
59
- """
60
- Create a new Citizen.
71
+ """Create a new Citizen.
72
+
61
73
  Args:
62
- unique_id: unique int
63
74
  model : model instance
75
+ vision: number of cells in each direction (N, S, E and W) that
76
+ agent can inspect. Exogenous.
77
+ movement: whether agent can move or not
64
78
  hardship: Agent's 'perceived hardship (i.e., physical or economic
65
79
  privation).' Exogenous, drawn from U(0,1).
66
80
  regime_legitimacy: Agent's perception of regime legitimacy, equal
@@ -68,10 +82,10 @@ class Citizen(EpsteinAgent):
68
82
  risk_aversion: Exogenous, drawn from U(0,1).
69
83
  threshold: if (grievance - (risk_aversion * arrest_probability)) >
70
84
  threshold, go/remain Active
71
- vision: number of cells in each direction (N, S, E and W) that
72
- agent can inspect. Exogenous.
85
+ arrest_prob_constant : agent's assessment of arrest probability
86
+
73
87
  """
74
- super().__init__(unique_id, model, vision, movement)
88
+ super().__init__(model, vision, movement)
75
89
  self.hardship = hardship
76
90
  self.regime_legitimacy = regime_legitimacy
77
91
  self.risk_aversion = risk_aversion
@@ -82,9 +96,7 @@ class Citizen(EpsteinAgent):
82
96
  self.arrest_prob_constant = arrest_prob_constant
83
97
 
84
98
  def step(self):
85
- """
86
- Decide whether to activate, then move if applicable.
87
- """
99
+ """Decide whether to activate, then move if applicable."""
88
100
  self.update_neighbors()
89
101
  self.update_estimated_arrest_probability()
90
102
  net_risk = self.risk_aversion * self.arrest_probability
@@ -97,9 +109,7 @@ class Citizen(EpsteinAgent):
97
109
  self.model.grid.move_agent(self, new_pos)
98
110
 
99
111
  def update_neighbors(self):
100
- """
101
- Look around and see who my neighbors are
102
- """
112
+ """Look around and see who my neighbors are."""
103
113
  self.neighborhood = self.model.grid.get_neighborhood(
104
114
  self.pos, moore=True, radius=self.vision
105
115
  )
@@ -109,10 +119,7 @@ class Citizen(EpsteinAgent):
109
119
  ]
110
120
 
111
121
  def update_estimated_arrest_probability(self):
112
- """
113
- Based on the ratio of cops to actives in my neighborhood, estimate the
114
- p(Arrest | I go active).
115
- """
122
+ """Based on the ratio of cops to actives in my neighborhood, estimate the p(Arrest | I go active)."""
116
123
  cops_in_vision = len([c for c in self.neighbors if isinstance(c, Cop)])
117
124
  actives_in_vision = 1.0 # citizen counts herself
118
125
  for c in self.neighbors:
@@ -123,18 +130,25 @@ class Citizen(EpsteinAgent):
123
130
  )
124
131
 
125
132
  def sent_to_jail(self, value):
133
+ """Sent agent to jail.
134
+
135
+ Args:
136
+ value: duration of jail sentence
137
+
138
+ """
126
139
  self.model.active_agents.remove(self)
127
140
  self.condition = AgentState.ARRESTED
128
141
  self.model.simulator.schedule_event_relative(self.release_from_jail, value)
129
142
 
130
143
  def release_from_jail(self):
144
+ """Release agent from jail."""
131
145
  self.model.active_agents.add(self)
132
146
  self.condition = AgentState.QUIESCENT
133
147
 
134
148
 
135
149
  class Cop(EpsteinAgent):
136
- """
137
- A cop for life. No defection.
150
+ """A cop for life. No defection.
151
+
138
152
  Summary of rule: Inspect local vision and arrest a random active agent.
139
153
 
140
154
  Attributes:
@@ -144,15 +158,20 @@ class Cop(EpsteinAgent):
144
158
  able to inspect
145
159
  """
146
160
 
147
- def __init__(self, unique_id, model, vision, movement, max_jail_term):
148
- super().__init__(unique_id, model, vision, movement)
161
+ def __init__(self, model, vision, movement, max_jail_term):
162
+ """Initialize a Cop agent.
163
+
164
+ Args:
165
+ model: a model instance
166
+ vision: size of neighborhood
167
+ movement: whether agent can move or not
168
+ max_jail_term: maximum jail sentence
169
+ """
170
+ super().__init__(model, vision, movement)
149
171
  self.max_jail_term = max_jail_term
150
172
 
151
173
  def step(self):
152
- """
153
- Inspect local vision and arrest a random active agent. Move if
154
- applicable.
155
- """
174
+ """Inspect local vision and arrest a random active agent. Move if applicable."""
156
175
  self.update_neighbors()
157
176
  active_neighbors = []
158
177
  for agent in self.neighbors:
@@ -166,9 +185,7 @@ class Cop(EpsteinAgent):
166
185
  self.model.grid.move_agent(self, new_pos)
167
186
 
168
187
  def update_neighbors(self):
169
- """
170
- Look around and see who my neighbors are.
171
- """
188
+ """Look around and see who my neighbors are."""
172
189
  self.neighborhood = self.model.grid.get_neighborhood(
173
190
  self.pos, moore=True, radius=self.vision
174
191
  )
@@ -179,9 +196,8 @@ class Cop(EpsteinAgent):
179
196
 
180
197
 
181
198
  class EpsteinCivilViolence(Model):
182
- """
183
- Model 1 from "Modeling civil violence: An agent-based computational
184
- approach," by Joshua Epstein.
199
+ """Model 1 from "Modeling civil violence: An agent-based computational approach," by Joshua Epstein.
200
+
185
201
  http://www.pnas.org/content/99/suppl_3/7243.full
186
202
  Attributes:
187
203
  height: grid height
@@ -220,6 +236,23 @@ class EpsteinCivilViolence(Model):
220
236
  max_iters=1000,
221
237
  seed=None,
222
238
  ):
239
+ """Initialize the Eppstein civil violence model.
240
+
241
+ Args:
242
+ width: the width of the grid
243
+ height: the height of the grid
244
+ citizen_density: density of citizens
245
+ cop_density: density of cops
246
+ citizen_vision: size of citizen vision
247
+ cop_vision: size of cop vision
248
+ legitimacy: perceived legitimacy
249
+ max_jail_term: maximum jail term
250
+ active_threshold: threshold for citizen to become active
251
+ arrest_prob_constant: arrest probability
252
+ movement: allow agent movement or not
253
+ max_iters: number of iterations
254
+ seed: seed for random number generator
255
+ """
223
256
  super().__init__(seed)
224
257
  if cop_density + citizen_density > 1:
225
258
  raise ValueError("Cop density + citizen density must be less than 1")
@@ -236,7 +269,6 @@ class EpsteinCivilViolence(Model):
236
269
  for _, pos in self.grid.coord_iter():
237
270
  if self.random.random() < self.cop_density:
238
271
  agent = Cop(
239
- self.next_id(),
240
272
  self,
241
273
  cop_vision,
242
274
  movement,
@@ -244,7 +276,6 @@ class EpsteinCivilViolence(Model):
244
276
  )
245
277
  elif self.random.random() < (self.cop_density + self.citizen_density):
246
278
  agent = Citizen(
247
- self.next_id(),
248
279
  self,
249
280
  citizen_vision,
250
281
  movement,
@@ -261,7 +292,8 @@ class EpsteinCivilViolence(Model):
261
292
  self.active_agents = self.agents
262
293
 
263
294
  def step(self):
264
- self.active_agents.shuffle(inplace=True).do("step")
295
+ """Run one step of the model."""
296
+ self.active_agents.shuffle_do("step")
265
297
 
266
298
 
267
299
  if __name__ == "__main__":
@@ -270,4 +302,4 @@ if __name__ == "__main__":
270
302
 
271
303
  simulator.setup(model)
272
304
 
273
- simulator.run(time_delta=100)
305
+ simulator.run_for(time_delta=100)
@@ -1,36 +1,39 @@
1
- """
2
- Wolf-Sheep Predation Model
3
- ================================
4
-
5
- Replication of the model found in NetLogo:
6
- Wilensky, U. (1997). NetLogo Wolf Sheep Predation model.
7
- http://ccl.northwestern.edu/netlogo/models/WolfSheepPredation.
8
- Center for Connected Learning and Computer-Based Modeling,
9
- Northwestern University, Evanston, IL.
10
- """
1
+ """Example of using ABM simulator for Wolf-Sheep Predation Model."""
11
2
 
12
3
  import mesa
13
4
  from mesa.experimental.devs.simulator import ABMSimulator
14
5
 
15
6
 
16
7
  class Animal(mesa.Agent):
17
- def __init__(self, unique_id, model, moore, energy, p_reproduce, energy_from_food):
18
- super().__init__(unique_id, model)
8
+ """Base Animal class."""
9
+
10
+ def __init__(self, model, moore, energy, p_reproduce, energy_from_food):
11
+ """Initialize Animal instance.
12
+
13
+ Args:
14
+ model: a model instance
15
+ moore: using moore grid or not
16
+ energy: initial energy
17
+ p_reproduce: probability of reproduction
18
+ energy_from_food: energy gained from 1 unit of food
19
+ """
20
+ super().__init__(model)
19
21
  self.energy = energy
20
22
  self.p_reproduce = p_reproduce
21
23
  self.energy_from_food = energy_from_food
22
24
  self.moore = moore
23
25
 
24
26
  def random_move(self):
27
+ """Move to random neighboring cell."""
25
28
  next_moves = self.model.grid.get_neighborhood(self.pos, self.moore, True)
26
29
  next_move = self.random.choice(next_moves)
27
30
  # Now move:
28
31
  self.model.grid.move_agent(self, next_move)
29
32
 
30
33
  def spawn_offspring(self):
34
+ """Create offspring."""
31
35
  self.energy /= 2
32
36
  offspring = self.__class__(
33
- self.model.next_id(),
34
37
  self.model,
35
38
  self.moore,
36
39
  self.energy,
@@ -39,13 +42,15 @@ class Animal(mesa.Agent):
39
42
  )
40
43
  self.model.grid.place_agent(offspring, self.pos)
41
44
 
42
- def feed(self): ...
45
+ def feed(self): ... # noqa: D102
43
46
 
44
47
  def die(self):
48
+ """Die."""
45
49
  self.model.grid.remove_agent(self)
46
50
  self.remove()
47
51
 
48
52
  def step(self):
53
+ """Execute one step of the agent."""
49
54
  self.random_move()
50
55
  self.energy -= 1
51
56
 
@@ -58,13 +63,10 @@ class Animal(mesa.Agent):
58
63
 
59
64
 
60
65
  class Sheep(Animal):
61
- """
62
- A sheep that walks around, reproduces (asexually) and gets eaten.
63
-
64
- The init is the same as the RandomWalker.
65
- """
66
+ """A sheep that walks around, reproduces (asexually) and gets eaten."""
66
67
 
67
68
  def feed(self):
69
+ """Eat grass and gain energy."""
68
70
  # If there is grass available, eat it
69
71
  agents = self.model.grid.get_cell_list_contents(self.pos)
70
72
  grass_patch = next(obj for obj in agents if isinstance(obj, GrassPatch))
@@ -74,11 +76,10 @@ class Sheep(Animal):
74
76
 
75
77
 
76
78
  class Wolf(Animal):
77
- """
78
- A wolf that walks around, reproduces (asexually) and eats sheep.
79
- """
79
+ """A wolf that walks around, reproduces (asexually) and eats sheep."""
80
80
 
81
81
  def feed(self):
82
+ """Eat wolf and gain energy."""
82
83
  agents = self.model.grid.get_cell_list_contents(self.pos)
83
84
  sheep = [obj for obj in agents if isinstance(obj, Sheep)]
84
85
  if len(sheep) > 0:
@@ -90,12 +91,10 @@ class Wolf(Animal):
90
91
 
91
92
 
92
93
  class GrassPatch(mesa.Agent):
93
- """
94
- A patch of grass that grows at a fixed rate and it is eaten by sheep
95
- """
94
+ """A patch of grass that grows at a fixed rate and it is eaten by sheep."""
96
95
 
97
96
  @property
98
- def fully_grown(self) -> bool:
97
+ def fully_grown(self) -> bool: # noqa: D102
99
98
  return self._fully_grown
100
99
 
101
100
  @fully_grown.setter
@@ -109,15 +108,16 @@ class GrassPatch(mesa.Agent):
109
108
  function_args=[self, "fully_grown", True],
110
109
  )
111
110
 
112
- def __init__(self, unique_id, model, fully_grown, countdown, grass_regrowth_time):
113
- """
114
- Creates a new patch of grass
111
+ def __init__(self, model, fully_grown, countdown, grass_regrowth_time):
112
+ """Creates a new patch of grass.
115
113
 
116
114
  Args:
117
- grown: (boolean) Whether the patch of grass is fully grown or not
115
+ model: a model instance
116
+ fully_grown: (boolean) Whether the patch of grass is fully grown or not
118
117
  countdown: Time for the patch of grass to be fully grown again
118
+ grass_regrowth_time: regrowth time for the grass
119
119
  """
120
- super().__init__(unique_id, model)
120
+ super().__init__(model)
121
121
  self._fully_grown = fully_grown
122
122
  self.grass_regrowth_time = grass_regrowth_time
123
123
 
@@ -126,13 +126,12 @@ class GrassPatch(mesa.Agent):
126
126
  setattr, countdown, function_args=[self, "fully_grown", True]
127
127
  )
128
128
 
129
- def set_fully_grown(self):
129
+ def set_fully_grown(self): # noqa
130
130
  self.fully_grown = True
131
131
 
132
132
 
133
133
  class WolfSheep(mesa.Model):
134
- """
135
- Wolf-Sheep Predation Model
134
+ """Wolf-Sheep Predation Model.
136
135
 
137
136
  A model for simulating wolf and sheep (predator-prey) ecosystem modelling.
138
137
  """
@@ -152,10 +151,11 @@ class WolfSheep(mesa.Model):
152
151
  simulator=None,
153
152
  seed=None,
154
153
  ):
155
- """
156
- Create a new Wolf-Sheep model with the given parameters.
154
+ """Create a new Wolf-Sheep model with the given parameters.
157
155
 
158
156
  Args:
157
+ height: height of the grid
158
+ width: width of the grid
159
159
  initial_sheep: Number of sheep to start with
160
160
  initial_wolves: Number of wolves to start with
161
161
  sheep_reproduce: Probability of each sheep reproducing each step
@@ -165,7 +165,9 @@ class WolfSheep(mesa.Model):
165
165
  grass_regrowth_time: How long it takes for a grass patch to regrow
166
166
  once it is eaten
167
167
  sheep_gain_from_food: Energy sheep gain from grass, if enabled.
168
- moore:
168
+ moore: whether to use moore or von Neumann grid
169
+ simulator: Simulator to use for simulating wolf and sheep
170
+ seed: Random seed
169
171
  """
170
172
  super().__init__(seed=seed)
171
173
  # Set parameters
@@ -191,7 +193,6 @@ class WolfSheep(mesa.Model):
191
193
  )
192
194
  energy = self.random.randrange(2 * sheep_gain_from_food)
193
195
  sheep = Sheep(
194
- self.next_id(),
195
196
  self,
196
197
  moore,
197
198
  energy,
@@ -208,7 +209,6 @@ class WolfSheep(mesa.Model):
208
209
  )
209
210
  energy = self.random.randrange(2 * wolf_gain_from_food)
210
211
  wolf = Wolf(
211
- self.next_id(),
212
212
  self,
213
213
  moore,
214
214
  energy,
@@ -225,14 +225,13 @@ class WolfSheep(mesa.Model):
225
225
  countdown = grass_regrowth_time
226
226
  else:
227
227
  countdown = self.random.randrange(grass_regrowth_time)
228
- patch = GrassPatch(
229
- self.next_id(), self, fully_grown, countdown, grass_regrowth_time
230
- )
228
+ patch = GrassPatch(self, fully_grown, countdown, grass_regrowth_time)
231
229
  self.grid.place_agent(patch, pos)
232
230
 
233
231
  def step(self):
234
- self.get_agents_of_type(Sheep).shuffle(inplace=True).do("step")
235
- self.get_agents_of_type(Wolf).shuffle(inplace=True).do("step")
232
+ """Perform one step of the model."""
233
+ self.agents_by_type[Sheep].shuffle_do("step")
234
+ self.agents_by_type[Wolf].shuffle_do("step")
236
235
 
237
236
 
238
237
  if __name__ == "__main__":