# Predator-prey model

using EasyABM

## Step 1: Create Agents and Model

We create 200 agents all of type sheep to begin with. Our model properties are

• max_energy : The maximum energy that an agent (sheep or wolf) can have.
• wolf_birth_rate : Probability of a wolf agent to reproduce once its energy is greater than max_energy/2.
• sheep_birth_rate : Probability of a sheep agent to reproduce once its energy is greater than max_energy/2.
• wolves_kill_ability : The probability of a wolf to kill a neighboring sheep.
• grass_grow_prob : The probability of one unit of grass growing on a patch at a given timestep.
• max_grass : Max grass a patch can have.
• initial_wolf_percent : The percent of agents which are wolf initially.
@enum agenttype sheep wolf
agents = grid_2d_agents(200, pos = Vect(1,1), color = cl"white", atype = sheep,
energy = 10.0, keeps_record_of=Set([:pos, :energy ]))
model = create_2d_model(agents,
size = (20,20), #space size
agents_type = Mortal, # agents are mortal, can take birth or die
space_type = NPeriodic, # nonperiodic space
# below are all the model properties
max_energy = 50,
wolf_birth_rate = 0.01,
sheep_birth_rate = 0.1,
wolves_kill_ability = 0.2,
max_grass = 5,
initial_wolf_percent = 0.2,
grass_grow_prob = 0.2)

## Step 2: Initialise the model

In the second step we initialise the patches and agents by defining initialiser! function and sending it as an argument to init_model!. In the initialiser! function we randomly set amount of grass and accordingly color of each patch. We also set a fraction initial_wolf_percent of agents to be of type wolf. We set color of sheeps to white and that of wolves to black. We also randomly set the energy and positions of agents. In the init_model! function through argument props_to_record we tell EasyABM to record the color property of patches during model run.

function initialiser!(model)
max_grass = model.properties.max_grass
for j in 1:model.size[2]
for i in 1:model.size[1]
grass = rand(1:max_grass)
model.patches[i,j].grass = grass
hf = Int(ceil(max_grass/2))
model.patches[i,j].color = grass > hf ? cl"green" : (grass > 0 ? cl"blue" : cl"grey")
end
end
for agent in model.agents
if rand()< model.properties.initial_wolf_percent
agent.atype = wolf
agent.color = cl"black"
else
agent.atype = sheep
agent.color = cl"white"
end
agent.energy = rand(1:model.properties.max_energy)+0.0
agent.pos = Vect(rand(1:model.size[1]), rand(1:model.size[2]))
end

end

init_model!(model, initialiser = initialiser!, props_to_record = Dict("patches"=>Set([:color])))

## Step 3: Defining the step_rule! and running the model

In this step we implement the step logic of the predator prey model in the step_rule! function and run the model for 100 steps.

function change_pos!(agent)
dx = rand(-1:1)
dy = rand(-1:1)
agent.pos += Vect(dx, dy)
end

function reproduce!(agent, model)
new_agent = create_similar(agent)
agent.energy = agent.energy/2
new_agent.energy = agent.energy
end

function eat_sheep!(wolf, sheep, model)
kill_agent!(sheep, model)
wolf.energy+=1
end

function act_asa_wolf!(agent, model)
if !(is_alive(agent))
return
end
energy = agent.energy
if energy > 0.5*model.properties.max_energy
if rand()<model.properties.wolf_birth_rate
reproduce!(agent, model)
end
elseif energy > 0
nbrs = collect(neighbors_moore(agent, model, 1))
n = length(nbrs)
if n>0
nbr = nbrs[rand(1:n)]
if (nbr.atype == sheep)&&(is_alive(nbr))
ability = model.properties.wolves_kill_ability
(rand()<ability)&&(eat_sheep!(agent, nbr, model))
end
end
change_pos!(agent)
else
kill_agent!(agent, model)
end
end

function act_asa_sheep!(agent, model)
if !(is_alive(agent))
return
end
energy = agent.energy
if energy >0.5* model.properties.max_energy
if rand()<model.properties.sheep_birth_rate
reproduce!(agent, model)
end
change_pos!(agent)
elseif energy > 0
patch = get_grid_loc(agent)
grass = model.patches[patch...].grass
if grass>0
model.patches[patch...].grass-=1
agent.energy +=1
end
change_pos!(agent)
else
kill_agent!(agent, model)
end
end

function step_rule!(model)
if model.max_id>800 # use some upper bound on max agents to avoid system hang
return
end
for agent in model.agents
if agent.atype == wolf
act_asa_wolf!(agent,model)
end
if agent.atype == sheep
act_asa_sheep!(agent, model)
end
end
for j in 1:model.size[2]
for i in 1:model.size[1]
patch = model.patches[i,j]
grass = patch.grass
max_grass = model.properties.max_grass
if grass < max_grass
if rand()<model.properties.grass_grow_prob
patch.grass+=1
hf = Int(ceil(max_grass/2))
patch.color = grass > hf ? cl"green" : (grass > 0 ? cl"yellow" : cl"grey")
end
end
end
end
end

run_model!(model, steps=100, step_rule = step_rule! )

## Step 4: Visualisation

In order to draw the model at a specific frame, say 4th, one can use draw_frame(model, frame = 4, show_patches=true). If one wants to see the animation of the model run, it can be done as

animate_sim(model, show_patches=true)

After defining the step_rule! function we can also choose to create an interactive application (which currently works in Jupyter with WebIO installation) as shown below. It is recommended to define a fresh model and not initialise it with init_model! or run with run_model! before creating interactive app.

agents = grid_2d_agents(200, pos = Vect(1,1), color = cl"white", atype = sheep,
energy = 10.0, keeps_record_of=Set([:pos, :energy ]))

model = create_2d_model(agents,
size = (20,20), #space size
agents_type = Mortal, # agents are mortal, can take birth or die
space_type = NPeriodic, # nonperiodic space
# below are all the model properties
max_energy = 50,
wolf_birth_rate = 0.01,
sheep_birth_rate = 0.1,
wolves_kill_ability = 0.2,
max_grass = 5,
initial_wolf_percent = 0.2,
grass_grow_prob = 0.2)

create_interactive_app(model, initialiser= initialiser!,
step_rule= step_rule!,
model_controls=[
(:wolf_birth_rate, "slider", 0:0.01:1.0),
(:sheep_birth_rate, "slider", 0.01:0.01:1.0),
(:initial_wolf_percent, "slider", 0.01:0.01:0.9),
(:wolves_kill_ability, "slider", 0.01:0.01:1.0),
(:grass_grow_prob, "slider", 0.01:0.01:0.5)
],
agent_plots=Dict("sheep"=> agent-> agent.atype == sheep ? 1 : 0,
"wolf"=> agent-> agent.atype == wolf ? 1 : 0),
frames=200, show_patches=true)

## Step 4: Fetch Data

We can fetch the number of wolves and sheeps at each time step as follows.

df = get_nums_agents(model, agent-> agent.atype == sheep,
agent->agent.atype == wolf, labels=["Sheep", "Wolf"],
plot_result = true)

Individual agent data recorded during model run can be obtained as

df = get_agent_data(model.agents[1], model).record

## References

1. Wilensky, U. (1997). NetLogo Wolf Sheep Predation model. http://ccl.northwestern.edu/netlogo/models/WolfSheepPredation. Center for Connected Learning and Computer-Based Modeling, Northwestern University, Evanston, IL.