# Conway's Game of Life

using EasyABM

## Step 1: Create Agents and Model

We work with only patches in this model. The size of the grid in the model created is 20x20 and alive_percent is the fraction of patches that are alive initially.

model = create_2d_model(size = (20,20), alive_percent = 0.4)

## Step 2: Initialise the model

In the second step we initialise the patches by defining initialiser! function and sending it as an argument to init_model!. In the initialiser! function we randomly set patches to be either of color cl"green" or cl"white" (a named color, say "green", can be defined in EasyABM as cl"green" or as Col("green") or more generally as Col(0,1,0) or Col(0,1,0,1)). The patches with green color have their is_alive property set to true and the patches with white color have their is_alive property set to false. We specify the patch properties color and is_alive that we want to be recorded during time evolution in the props_to_record argument to the init_model! function.

function initialiser!(model)
for j in 1:model.size[2]
for i in 1:model.size[1]
if rand()<model.properties.alive_percent
model.patches[i,j].color = cl"green"
model.patches[i,j].is_alive = true
else
model.patches[i,j].color = cl"white"
model.patches[i,j].is_alive = false
end
end
end
end

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

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

In this step we implement the step logic of the Conway's Game of Life in the step_rule! function and run the model for 100 steps. Since Conway's model requires all patches to be updated at the same time, in the step_rule! function we first compute the is_alive property for all patches and then apply it to patches.

function calculate_vals(model)
vals = [false for i in 1:model.size[1], j in 1:model.size[2]]
for j in 1:model.size[2]
for i in 1:model.size[1]
patch = model.patches[i,j]
nbrs = neighbor_patches_moore((i,j), model, 1)
num_alive = 0
for nbr in nbrs
num_alive+= model.patches[nbr...].is_alive
end
condition1 = patch.is_alive && ((num_alive == 2) || (num_alive == 3))
condition2 = !(patch.is_alive) && (num_alive == 3)
if condition1 || condition2
vals[i,j] = true
end
end
end
return vals
end

function apply_vals!(model, vals)
for j in 1:model.size[2]
for i in 1:model.size[1]
is_alive = vals[i,j]
model.patches[i,j].is_alive = is_alive
model.patches[i,j].color = is_alive ? cl"green" : cl"white"
end
end
end

function step_rule!(model)
vals = calculate_vals(model)
apply_vals!(model, vals)
end

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

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.

model = create_2d_model(size = (20,20), alive_percent = 0.4)

create_interactive_app(model, initialiser= initialiser!,
props_to_record=Dict("patches"=>Set([:color, :is_alive])),
step_rule= step_rule!,
model_controls=[
(:alive_percent, "slider", 0:0.01:1.0)
],
frames=200, show_patches=true) 

## Step 4: Fetch Data

We can fetch the data of number alive patches as follows.

df = get_nums_patches(model, patch-> patch.is_alive, labels=["Alive"],
plot_result = true)

## References

1. https://en.wikipedia.org/wiki/Conway%27sGameof_Life