Skip to content

Commit 5c6a1e6

Browse files
committed
wolf-sheep
1 parent 4ad5bb5 commit 5c6a1e6

File tree

4 files changed

+66
-197
lines changed

4 files changed

+66
-197
lines changed

examples/wolf_sheep/wolf_sheep/agents.py

Lines changed: 56 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,93 +1,83 @@
11
import mesa
22

3-
from .random_walk import RandomWalker
3+
from mesa.experimental.cell_space import CellAgent, FixedAgent
44

55

6-
class Sheep(RandomWalker):
7-
"""
8-
A sheep that walks around, reproduces (asexually) and gets eaten.
9-
10-
The init is the same as the RandomWalker.
11-
"""
6+
class Animal(CellAgent):
7+
"""The base animal class."""
128

13-
energy = None
9+
def __init__(self, model, energy, p_reproduce, energy_from_food, cell):
10+
"""Initializes an animal.
1411
15-
def __init__(self, model, moore, energy=None):
16-
super().__init__(model, moore=moore)
12+
Args:
13+
model: a model instance
14+
energy: starting amount of energy
15+
p_reproduce: probability of sexless reproduction
16+
energy_from_food: energy obtained from 1 unit of food
17+
cell: the cell in which the animal starts
18+
"""
19+
super().__init__(model)
1720
self.energy = energy
21+
self.p_reproduce = p_reproduce
22+
self.energy_from_food = energy_from_food
23+
self.cell = cell
24+
25+
def spawn_offspring(self):
26+
"""Create offspring."""
27+
self.energy /= 2
28+
self.__class__(
29+
self.model,
30+
self.energy,
31+
self.p_reproduce,
32+
self.energy_from_food,
33+
self.cell,
34+
)
35+
36+
def feed(self): ... # noqa: D102
1837

1938
def step(self):
20-
"""
21-
A model step. Move, then eat grass and reproduce.
22-
"""
23-
self.random_move()
24-
living = True
25-
26-
if self.model.grass:
27-
# Reduce energy
28-
self.energy -= 1
29-
30-
# If there is grass available, eat it
31-
this_cell = self.model.grid.get_cell_list_contents([self.pos])
32-
grass_patch = next(obj for obj in this_cell if isinstance(obj, GrassPatch))
33-
if grass_patch.fully_grown:
34-
self.energy += self.model.sheep_gain_from_food
35-
grass_patch.fully_grown = False
39+
"""One step of the agent."""
40+
self.cell = self.cell.neighborhood.select_random_cell()
41+
self.energy -= 1
3642

37-
# Death
38-
if self.energy < 0:
39-
self.model.grid.remove_agent(self)
40-
self.remove()
41-
living = False
43+
self.feed()
4244

43-
if living and self.random.random() < self.model.sheep_reproduce:
44-
# Create a new sheep:
45-
if self.model.grass:
46-
self.energy /= 2
47-
lamb = Sheep(self.model, self.moore, self.energy)
48-
self.model.grid.place_agent(lamb, self.pos)
45+
if self.energy < 0:
46+
self.remove()
47+
elif self.random.random() < self.p_reproduce:
48+
self.spawn_offspring()
4949

5050

51-
class Wolf(RandomWalker):
52-
"""
53-
A wolf that walks around, reproduces (asexually) and eats sheep.
54-
"""
51+
class Sheep(Animal):
52+
"""A sheep that walks around, reproduces (asexually) and gets eaten."""
5553

56-
energy = None
54+
def feed(self):
55+
"""If possible eat the food in the current location."""
56+
# If there is grass available, eat it
57+
if self.model.grass:
58+
grass_patch = next(
59+
obj for obj in self.cell.agents if isinstance(obj, GrassPatch)
60+
)
61+
if grass_patch.fully_grown:
62+
self.energy += self.energy_from_food
63+
grass_patch.fully_grown = False
5764

58-
def __init__(self, model, moore, energy=None):
59-
super().__init__(model, moore=moore)
60-
self.energy = energy
6165

62-
def step(self):
63-
self.random_move()
64-
self.energy -= 1
66+
class Wolf(Animal):
67+
"""A wolf that walks around, reproduces (asexually) and eats sheep."""
6568

66-
# If there are sheep present, eat one
67-
x, y = self.pos
68-
this_cell = self.model.grid.get_cell_list_contents([self.pos])
69-
sheep = [obj for obj in this_cell if isinstance(obj, Sheep)]
69+
def feed(self):
70+
"""If possible eat the food in the current location."""
71+
sheep = [obj for obj in self.cell.agents if isinstance(obj, Sheep)]
7072
if len(sheep) > 0:
7173
sheep_to_eat = self.random.choice(sheep)
72-
self.energy += self.model.wolf_gain_from_food
74+
self.energy += self.energy_from_food
7375

7476
# Kill the sheep
75-
self.model.grid.remove_agent(sheep_to_eat)
7677
sheep_to_eat.remove()
7778

78-
# Death or reproduction
79-
if self.energy < 0:
80-
self.model.grid.remove_agent(self)
81-
self.remove()
82-
else:
83-
if self.random.random() < self.model.wolf_reproduce:
84-
# Create a new wolf cub
85-
self.energy /= 2
86-
cub = Wolf(self.model, self.moore, self.energy)
87-
self.model.grid.place_agent(cub, self.pos)
88-
8979

90-
class GrassPatch(mesa.Agent):
80+
class GrassPatch(FixedAgent):
9181
"""
9282
A patch of grass that grows at a fixed rate and it is eaten by sheep
9383
"""

examples/wolf_sheep/wolf_sheep/model.py

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,12 @@
1010
"""
1111

1212
import mesa
13+
from mesa.experimental.cell_space import OrthogonalMooreGrid
1314

1415
from .agents import GrassPatch, Sheep, Wolf
1516

1617

18+
1719
class WolfSheep(mesa.Model):
1820
"""
1921
Wolf-Sheep Predation Model
@@ -50,6 +52,7 @@ def __init__(
5052
grass=False,
5153
grass_regrowth_time=30,
5254
sheep_gain_from_food=4,
55+
seed=None
5356
):
5457
"""
5558
Create a new Wolf-Sheep model with the given parameters.
@@ -65,20 +68,16 @@ def __init__(
6568
once it is eaten
6669
sheep_gain_from_food: Energy sheep gain from grass, if enabled.
6770
"""
68-
super().__init__()
71+
super().__init__(seed=None)
6972
# Set parameters
7073
self.width = width
7174
self.height = height
7275
self.initial_sheep = initial_sheep
7376
self.initial_wolves = initial_wolves
74-
self.sheep_reproduce = sheep_reproduce
75-
self.wolf_reproduce = wolf_reproduce
76-
self.wolf_gain_from_food = wolf_gain_from_food
7777
self.grass = grass
7878
self.grass_regrowth_time = grass_regrowth_time
79-
self.sheep_gain_from_food = sheep_gain_from_food
8079

81-
self.grid = mesa.space.MultiGrid(self.width, self.height, torus=True)
80+
self.grid = OrthogonalMooreGrid((self.width, self.height), torus=True)
8281

8382
collectors = {
8483
"Wolves": lambda m: len(m.agents_by_type[Wolf]),
@@ -95,20 +94,18 @@ def __init__(
9594
x = self.random.randrange(self.width)
9695
y = self.random.randrange(self.height)
9796
energy = self.random.randrange(2 * self.sheep_gain_from_food)
98-
sheep = Sheep(self, True, energy)
99-
self.grid.place_agent(sheep, (x, y))
97+
Sheep(self, energy, sheep_reproduce, sheep_gain_from_food, self.grid[(x,y)])
10098

10199
# Create wolves
102100
for _ in range(self.initial_wolves):
103101
x = self.random.randrange(self.width)
104102
y = self.random.randrange(self.height)
105103
energy = self.random.randrange(2 * self.wolf_gain_from_food)
106-
wolf = Wolf(self, True, energy)
107-
self.grid.place_agent(wolf, (x, y))
104+
Wolf(self, energy, wolf_reproduce, wolf_gain_from_food, self.grid[(x,y)])
108105

109106
# Create grass patches
110107
if self.grass:
111-
for agent, (x, y) in self.grid.coord_iter():
108+
for cell in self.grid.all_cells:
112109
fully_grown = self.random.choice([True, False])
113110

114111
if fully_grown:
@@ -117,7 +114,7 @@ def __init__(
117114
countdown = self.random.randrange(self.grass_regrowth_time)
118115

119116
patch = GrassPatch(self, fully_grown, countdown)
120-
self.grid.place_agent(patch, (x, y))
117+
patch.cell = cell
121118

122119
self.running = True
123120
self.datacollector.collect(self)
@@ -128,7 +125,7 @@ def step(self):
128125
# Conceptually, it can be argued that this should be modelled differently.
129126
self.random.shuffle(self.agent_types)
130127
for agent_type in self.agent_types:
131-
self.agents_by_type[agent_type].do("step")
128+
self.agents_by_type[agent_type].shuffle_do("step")
132129

133130
# collect data
134131
self.datacollector.collect(self)

examples/wolf_sheep/wolf_sheep/random_walk.py

Lines changed: 0 additions & 40 deletions
This file was deleted.

examples/wolf_sheep/wolf_sheep/test_random_walk.py

Lines changed: 0 additions & 78 deletions
This file was deleted.

0 commit comments

Comments
 (0)