Conway's game of life
It is also available from the Models
module as Models.game_of_life
.
using Agents, AgentsPlots
1. Define the rules
Rules of Conway's game of life: DSRO (Death, Survival, Reproduction, Overpopulation). Cells die if the number of their living neighbors is <D or >O, survive if the number of their living neighbors is ≤S, come to life if their living neighbors are ≥R and ≤O.
rules = (2, 3, 3, 3)
2. Build the model
First, define an agent type. It needs to have the compulsary id
and pos
fields, as well as an status
field that is true
for cells that are alive and false
otherwise.
mutable struct Cell <: AbstractAgent
id::Int
pos::Tuple{Int,Int}
status::Bool
end
The following function builds a 2D cellular automaton. rules
is of type Tuple{Int,Int,Int, Int}
representing DSRO.
dims
is a tuple of integers determining the width and height of the grid environment. Moore
specifies whether cells connect to their diagonal neighbors.
This function creates a model where all cells are "off".
function build_model(; rules::Tuple, dims = (100, 100), Moore = true)
space = GridSpace(dims, moore = Moore)
properties = Dict(:rules => rules)
model = ABM(Cell, space; properties = properties)
node_idx = 1
for x in 1:dims[1]
for y in 1:dims[2]
add_agent_pos!(Cell(node_idx, (x, y), false), model)
node_idx += 1
end
end
return model
end
Now we define a stepping function for the model to apply the rules to agents.
function ca_step!(model)
new_status = fill(false, nagents(model))
for (agid, ag) in model.agents
nlive = nlive_neighbors(ag, model)
if ag.status == true && (nlive ≤ model.rules[4] && nlive ≥ model.rules[1])
new_status[agid] = true
elseif ag.status == false && (nlive ≥ model.rules[3] && nlive ≤ model.rules[4])
new_status[agid] = true
end
end
for k in keys(model.agents)
model.agents[k].status = new_status[k]
end
end
function nlive_neighbors(ag, model)
neighbors_coords = node_neighbors(ag, model)
nlive = 0
for nc in neighbors_coords
nag = model.agents[Agents.coord2vertex((nc[2], nc[1]), model)]
if nag.status == true
nlive += 1
end
end
return nlive
end
now we can instantiate the model:
model = build_model(rules = rules, dims = (50, 50), Moore = true)
AgentBasedModel with 2500 agents of type Cell space: GridSpace with 2500 nodes and 9702 edges scheduler: fastest properties: Dict(:rules => (2, 3, 3, 3))
Let's make some random cells on
for i in 1:nv(model)
if rand() < 0.2
model.agents[i].status = true
end
end
3. Animate the model
We use the plotabm
function from AgentsPlots.jl
package for creating an animation.
ac(x) = x.status == true ? :black : :white
anim = @animate for i in 0:100
i > 0 && step!(model, dummystep, ca_step!, 1)
p1 = plotabm(model; ac = ac, as = 3, am = :square, showaxis = false)
end
We can now save the animation to a gif.
gif(anim, "game_of_life.gif", fps = 5)