Engr 123

Life and other Automata

The game of Life was created by a mathematician named John H. Conway at the University of Cambridge. It was introduced to the world by Martin Gardner in the October 1970 issue of Scientific American in the Mathematical Games section of the magazine. Life is a game of cellular automata. The world of Life is typically a two dimensional grid where each cell in the grid may house a single life. The rules of Life are such that cells are born, live, or die depending on the number of neighbors a particular cell has. Neighbors of a cell are those which surround it (including the diagonal neighbors). So each cell has exactly 8 neighbors. The world of Life may be either flat or round. In a flat world the edges are surrounded by cells which are unoccupied (dead). In a round world the left side has the right side for neighbors and the top side has the bottom side for neighbors so that the world of Life wraps around.

The rules for cell life and death are as follows:

1. If a cell has less than 2 living neighbors it is lonely and dies in the next generation.

2. If a cell has exactly 2 living neighbors it is happy and continues life in the next generation.

3. If a cell has exactly 3 living neighbors a new cell is born in that cell or continues to exist if it is already alive.

4. If a cell has 4 or more neighbors it is overcrowded and dies in the next generation.

For example, in Figure 1 below, the initial generation 0 moves to generation 1 in which three cells have exactly three live neighbors so that new cells are born. Two cells are overcrowded with 4 neighbors and die out leaving the pattern shown. In Generation 1, two cells are born but the others die out because they have too few living neighbors. In Generation 3 all life dies out because no one has enough living neighbors.

Generation 0 Generation 1 Generation 2 Generation 3

o / o
o / o / o / o / o / o
o / o / o / o / o

Figure 1

In this case all life disappears in 4 generations.

Sometimes oscillating patterns occur. In fact, in larger more complicated schemes, Life eventually evolves to some sort of stable oscillation. Figure 2 shows a simple oscillator.

Generation 0 Generation 1 Generation 2 Generation 3

o / o
o / o / o / o / o / o / o / o
o / o

Figure 2

A simple oscillator.

There are several variations on the Game of Life including Seeds, High Life, and Life Without Death. Each of these differs from the original game only in rules for creating the next generation.

Rules of Seeds:

All cells are off except those which have exactly two neighbors.

Rules of High Life:

A new cell is born if it has exactly three or six neighbors.

A cell survives into the next generation if it has two neighbors.

All other cells die.

Rules of Life Without Death:

These rules are the same as regular Life except that no cell ever dies.

The outline below gives the details of how to create the Game of Life. For this assignment you will add the rules to allow the user to select one of four games: Life, Seeds, High Life, or Life Without Death. Begin by creating the form shown in Figure 3.

Figure 3

The form and its contents. The panel should be 500 x 500.

The form should be 500 x 500 and the numeric up down block should be set to range from 1 to 1000. Locate the button and other components in a convenient arrangement.

1. Add a class to your solution called Cell. This class will represent each cell on the grid. The code for the class is given below:

{classCell

{privatebool alive;

public Cell()

{alive = false;

}

//

public Cell(bool a)

{alive = a;

}

//

publicbool Alive

{get

{return alive;

}

set

{alive = value;

}

}

}

}

2. The game has an oldWorld and a world each of which consists of an array of 100 x 100 cells.

You will need the following public and private variables:

privateconstint MAXX = 100;

privateconstint MAXY = 100;

privateconstint CELLSIZE = 5;

//Declare a cell array representing the world

privateCell [,] world = newCell[MAXX, MAXY];

//Declare a cell array representing the world on the last iteration

privateCell [,] oldWorld = newCell[MAXX, MAXY];

privateint generations;

//Constructor

public Form1()

{InitializeComponent();

//Instantiate (run the constructor) the world and oldWorld arrays.

inti, j;

for(i=0;i<MAXX;i++)

{for(j=0;j<MAXY;j++)

{world[i, j] = newCell(false);

oldWorld[i, j] = newCell(false);

}

}

}

3. Create a Paint event for the panel:

privatevoidpnlSeeds_Paint(objectsender,PaintEventArgs e)

{int r, c;

GraphicsgrphPanel = e.Graphics;

BrushredBrush = newSolidBrush(Color.Red);

PenbluPen = newPen(Color.Blue);

grphPanel.DrawRectangle(bluPen, 0, 0, MAXX*CELLSIZE, MAXY*CELLSIZE);

for(c=0;c<MAXX;c++)

{for(r=0;r<MAXY;r++)

if(world[c, r].Alive)

grphPanel.FillRectangle(redBrush, c*CELLSIZE, r*CELLSIZE, CELLSIZE, CELLSIZE);

}

}

4. Add a MouseDown event for the panel:

privatevoidpnlSeeds_MouseDown(objectsender,MouseEventArgs e)

{if(MouseButtons.Left == e.Button)

{world[(int)(e.X/5), (int)(e.Y/5)].Alive = !world[(int)(e.X/5), (int)(e.Y/5)].Alive;

pnlSeeds.Invalidate();

}

elseif(MouseButtons.Right == e.Button)

{RunOne();

}

}

5. Add the function RunOne which does a single iteration:

privatevoidRunOne()

{int r, c;

for(r=0;r<MAXX;r++)

{for(c=0;c<MAXY;c++)

{oldWorld[r,c].Alive = world[r,c].Alive;

}

}

for(r=0;r<MAXX;r++)

{for(c=0;c<MAXY;c++)

{world[r,c].Alive = CountNeighbors(r, c);

}

}

pnlSeeds.Invalidate();

}

6. Add the CountNeighbors function along with the rules for each game.

privateboolCountNeighbors(int r, int c)

{inti, j, indxX, indxY;

intcnt = 0;

for(i=r-1;i<=r+1;i++)

{for(j=c-1;j<=c+1;j++)

{indxX = i;indxY = j;

if(i < 0)

indxX = MAXX-1;

if(j < 0)

indxY = MAXY-1;

if(i > MAXX-1)

indxX = 0;

if(j > MAXY-1)

indxY = 0;

if(!(i == r & j == c))

{if(oldWorld[indxX, indxY].Alive)

cnt++;

}

}

}

if(rdoSeeds.Checked)

{//Put the rules for Seeds here

}

elseif(rdoLifeWODeath.Checked)

{//Put the rules for Life without death here

}

elseif(rdoHighLife.Checked)

{//Put the rules for High Life here

}

else

{if(cnt >= 4 || cnt < 2) //These are the rules for Life

returnfalse;

elseif(cnt == 3)

returntrue;

returnoldWorld[r, c].Alive;

}

returnoldWorld[r, c].Alive;

}

7. The program, at this point will run as is. If you left click you turn a cell that is off to on and if it is on it is turned off. If you right click it runs one generation. Run your program and verify that all is working as it should.

To make the program iterates through multiple generations we need to add a timer so that we can see each iteration as it progresses. Add a timer from the toolbox to your design. This will not show up on your form but will show up beneath it. Name your timer tmrRun. In the properties menu for the timer add the timer tick event. For the button add a click event and name it btnRun.

The code for these two events is shown below:

privatevoidbtnRun_Click(objectsender,EventArgs e)

{generations = (int)nudGenerations.Value;

tmrRun.Enabled = true;

tmrRun.Interval = 1000;

tmrRun.Start();

}

privatevoidtmrRun_Tick(objectsender,EventArgs e)

{RunOne();

generations--;

if(generations < 1)

tmrRun.Stop();

}

Note that the button event enables the timer, sets its interval to 1000 msec = 1 second, and starts it running. When the timer times out it triggers the tick event which runs one iteration, decreases the generations counter by 1 and turns the timer off if the generations counter gets to zero.