The Game of Life was invented by British mathematician John Conway and was popularized in Martin Gardner's Mathematical Games column in the October 1970 issue of Scientific American. The Game of Life is not actually a game. It is a powerful computational model that simplifies John Von Neumann's Cellular Automaton (CA) model.
The NetLogo version of Life is derived from BAM, the basic agent model. There are no turtles. Each patch (patches are called cells in a CA) is either alive or dead. This is determined by a Boolean attribute:
patches-own [alive?]
Living patches are white. Dead patches are black.
Initially, the user can use mouse clicks to specify which patches are alive or he can use a slider to specify the percentage of patches that are alive and let the computer randomly decide which patches are alive.
A patch updates itself by first counting the number of neighbors that are alive. NetLogo has three reporters that make this easy:
neighbors = the set of eight neighbors of the active cell
count AGENT-SET = the number of members in AGENT-SET
AGENT-SET with [CONDITION] = the subset of AGENT-SET with CONDITION = true
Here's how we put these together:
to update-patch
let num-living-neighbors count
neighbors with [alive?]
Note: If horizontal and vertical wrapping are both turned on, then every cell has exactly eight neighbors.
A living patch dies if it has too few (< 2) or too many living neighbors (> 3). That's okay. A dead patch can be reincarnated if it has exactly three living neighbors.
Here's the code:
Here's the actual model.
One point of interest in the model is the toggle-alive button. This repeatedly calls the pick-alive procedure, which calls the mouse-down? reporter. This reporter returns true if the mouse button happens to be down and stores the coordinates of the mouse in the pre-defined mouse-xcor and mouse-ycor global variables:
to pick-alive
if mouse-down?
[
ask patch mouse-xcor mouse-ycor
[
ifelse alive?
[
expire
]
[
reincarnate
]
; set was-alive? alive?
]
]
end
The ask command is sequential. In other words, the command:
ask patches [CMMD1 CMMD2 CMMD3]
asks the first patch to execute the entire block of three commands, then the second patch, then the third, etc.
This means that in the above version of Life patches expire
or are reincarnated sequentially. However, in
All three patches quickly die in the sequential version of Life, but in the concurrent version the middle cell remains alive while its north and south neighbors take turns living and dying with the east and west neighbors:
We can simulate concurrent Life by keeping track of the current and previous state of a patch:
patches-own [alive? was-alive?]
Before any patch updates its alive? attribute, all patches must update their was-alive? attribute:
set was-alive? alive?
One way to achieve this is to make update-patch a two-phase procedure. On even ticks it updates was-alive? on odd ticks it updates alive?
to update-patch
ifelse ticks mod 2 = 0
[
set was-alive? alive?
]
[
; update alive?
]
end
NetLogo provides a simulated concurrent version of ask:
ask-concurrent patches [CMMD1 CMMD2 CMMD3]
In this version each patch executes CMMD1. After all patches have executed CMMD1, then each patch executes CMMD2, etc.
Note: This rule only applies to commands that update non-local variables. There are a few other exceptions, too.
We can replace
ask patches [update-patch]
in update-model with:
ask-concurrent patches [set was-alive? alive? update-patches]
Here's the concurrent version:
Every patch can be viewed as a simple two state machine:
During each cycle a patch transitions from the "alive? = false" state to the "alive? = true" state only if num-living-neighbors is in the set {3}. If it's in the complement of this set: ~{3} = {0 1 2 4 5 6 7 8}, then the patch remains in the "alive? = false" state. If a patch is in the "alive? = true" state, then it transitions to the "alive? = false" state only if num-living-neighbors is in the set ~{2 3} = {0 1 4 5 6 7 8}, otherwise the state remains unchanged.
We can generalize the rules of Life by defining two subsets of the set {0 1 2 3 4 5 6 7 8}. The born-again set contains all of the numbers of living neighbors that cause a patch to change state from "alive? = false" to "alive? = true". The stay-alive set consists of all of the numbers of living neighbors that cause a patch in the "alive? = true" to stay in that state.
Here's a diagram:
For example, in the standard game of life we have:
born-again = {3}
stay-alive = {2 3}
We denote this rule B3S23.
Here are a few interesting rules:
HighLife = B36S23
Seeds = B2S
Sierpinski = B1S12 (starrt from a single live cell)
Majority = B5678S1234
Try these rules out using the generalized model: