Exercises (7)

The Game of Life

M. E. Mauel
Columbia University
(with help from 
Computer Simulations with Mathematica, 
R. Gaylord and P. Wellin, Springer-Verlag 1995)

Introduction

In this exercise, you are to write a program to simulate the Game of Life.

The Game of Life was invented by the mathematician John Conway and first published in Scientific American in 1970. The game made Conway internationally famous and launched a whole new field of mathematica research which includes "cellular automation".

The basic idea of the Game of Life is to consider a rectangular domain of square sites, or cells, which can be empty or be occupied by no more than one organism. The population of "organisms" are dynamic since some "die" and new organisms are "born" each generation. Conway's genetic laws are the "rules" for the game of life. Conway devised these rules so that (1) it could not be proven that an initial population would grow without bound, (2) there are some initial population patterns that appear to grow, and (3) some initial patterns have very interesting dynamics.

The Rules of the Game of Life are very simple. They are:
1. Death by overcrowding: Any site with four or more neighbors dies by overcrowding.
2. Birth: Any empty site with exactly three neighbors gives birth to new life.
3. Death by loneliness: Any site with one or none nearest neighbors, dies from loneliness.

For example, the Cheshire cat proceeds to from a simple up-down asymmetric pattern to a smile and finally to a stationary 2x2 block.

Note a key feature of cellular simulations: The configuration of each site for each new generation must be computed simultaneously!

To help you with your exercise, we will begin with a few steps that illustrate the efficient use of lists. Mathematica stores data in the form of lists and lists of lists (also called "arrays" or "matricies".)

Initialize the Game Board (in-class)

You may initialize the game board in any way that you would like. Feel free to experiment. For the purposes of introduction, we'll initialize the game board randomly. The integer 1 will represent the presence of life; the integer 0 represents the absence of life.

nGrid = 5; (* The dimension of sites along each side. *)

life=RandomInteger[{0,1},{nGrid,nGrid}];

life // MatrixForm

ArrayPlot[life, Mesh -> All, ColorRules -> {1 -> Green, 0 -> Brown}]

Notice: use the ColorRules option to assign specific colors to life (1) and no life (0).

Counting Nearest Neighbors (in-class)

How should we count the number of neighbors for each and every cell?

By using operators which act at once on entire lists, very efficient Mathematica programs can be written. Use the built-in command RotateRight[…] to define a new command, called neighbors[l_List], that computes the number of nearest neighbors to every cell on the game board. Use doubly periodic boundary conditions. This means that the top boundary is adjacent to the bottom, and the right is adjacent to the left.

Solution

?RotateRight

{life // MatrixForm, RotateRight[life, {1,0}] // MatrixForm}

{life // MatrixForm, RotateRight[life, {-1,0}] // MatrixForm}

{life // MatrixForm, RotateRight[life, {0,1}] // MatrixForm}

{life // MatrixForm, RotateRight[life, {1,1}] // MatrixForm}

The following is the same as
	Apply[Plus, Map[RotateRight[l, #]&, {...} ]
Note the compact "easy-to-type" syntax. Note, also, how difficult it will be for anyone to remember all of these syntax shorthands!

neighbors[l_List] := Plus @@ (RotateRight[l, #]& /@ {{1,1}, {1, 0}, {1,-1}, {0,1}, {0,-1}, {-1,1}, {-1,0}, {-1,-1}})

?neighbors

{life // MatrixForm, neighbors[life] // MatrixForm}

Notice that our grid is a torus!

Making Life and Death Decisions

In this part, we apply the rules of Life.

Define a command that takes two arguments. (For simplicity, make the name of your command be "lifeORdeath".) The command will be applied to every cell. The first argument will be 1 if life is presence at the cell; 0 otherwise. The second argument will be the count of the neighbors to the cell. The value of the command will be -1 if the site dies, +1 if there is a birth at the site; and 0 if neither a death or a birth occurs.

Finally, set the attributes of this newly-defined command to "Listable", by using the Attributes[…] command. Test your command.

When lifeORdeath = -1, the site dies. When lifeORdeath = +1, there is a birth.

lifeORdeath[1, a_] := -1 /; (a ≥ 4 || a ≤ 1)

lifeORdeath[0,a_] := 1 /; a == 3

lifeORdeath[_, _] := 0

Attributes[lifeORdeath] = Listable;

?Listable

?lifeORdeath

lifeORdeath[0,3]

Each New Generation (in-class)

Using your command, the game board evolves in time according to the formula below:

newLife[l_List] := l + lifeORdeath[l, neighbors[l]]

Since your command has the "Listable" attribute, you can apply it to entire arrays!

Test your function on the game board called "life".

Solution

newLife[life] // MatrixForm

A Bigger Simulation

Demonstrate the Game of Life on larger grid (nGrid = 50 for example) and (if you would like) with various initial conditions. Create an animation.