Computational Physics
Week 5 course work
Comments and questions to John Rowe.
This forms the first part of a two-week project.
The game of life
The game consists of a rectangular array of ones or zeros. A square is said to be
alive if it
has value one or
dead if it has value zero. Each cell has
eight neighbours, ie the cells that touch it including diagonally.
Initially
the grid is populated at random.
The game then iterates like this: for each iteration if a square is
initially alive and it has exactly two or three live neighbours it
stays alive. Otherwise it dies.
On the other hand, if the cell is initially dead and it has exactly
three occupied neighbours it becomes alive. Otherwise it stays
dead.
Thus you will have a loop a bit like
this:
for (;;) {
for (y = 0; y < NY; ++y)
for (x = 0; x < NX; ++x)
[Update the point (x,y)
[Now draw the new grid out to the screem]
}
Note how whilst
logically all the cells are meant to be
updated simultaneaously, in practice we have to do one at a time with
a double
for loop.
There are a few wrinkles we need to work out here:
The modulus operator
The % operator takes two integer
arguments and returns the remainder of the second when divided by
the first (eg 7 % 3 is 1,
13 % 8
is 5, 21 % 7 is zero).
Thus i % j returns an integer in the range
0 to j-1.
It can occasionally misbehave when i is negative so use
(i+j-1) % j instead of (i-1) % j
Data structure
Assuming NX NY and NY are constants defined
either at the top of a file or in a header file, what will we
need in a structure to tell us everything we need to know about
a game of life? If instead they are variables whose value is
read in when the program is run, how would that change things?
(You may assume whichever you prefer.)
Function structure
What are the functions we will need?
- A function to allocate a life structure.
- A function to initialise the grid at random.
- A function to calculate the new grid from the old one.
- A function to draw the new grid.
- A function to copy the new grid to the old one.
Looking at these, 3 looks a bit
complicated. What do we do when we need to write a complicated
function? Answer: we split it up into two or more sub-functions!
What are the steps involved in calculating the new grid? Well,
for each cell we first calculate the number of live neighbours
and then we use that number to calculate whether the cell is
alive or dead in the next generation.
So now our structure looks like:
- A function to allocate a life structure.
- A function to initialise the grid at random.
- A function to calculate the new grid from the old one:
- Calculate the number of neighbours of a particular cell.
- Use that to work out whether the cell lives or dies
- A function to draw the new grid.
- A function to copy the new grid to the old one.
3a should certainly be a separate function, it's up to you whether
3b is a separate function or just part of 3.
Writing the program
Do not write the program all at once. Think of a few functions
you will need and write them individually and test each one at a
time. Include a separate printout for each function and its test
program. Try it at first with a very small grid and print it out as
ones and zeros. Check that your update functions work properly
and prove to me that you have checked this.
Play your game a couple of times. Does it always do
the same thing? If so, try using
srand.
By the end of this week's work you should have been able to
initialise a grid of cells and be able to print them out to the
screen as ones and zeros. Ideally you will have debugged and
tested your update routine.
There is no need to hand in this week's work as it will form the
first half of next week's.