We closed this forum 18 June 2010. It has served us well since 2005 as the ALPHA forum did before it from 2002 to 2005. New discussions are ongoing at the new URL http://forum.processing.org. You'll need to sign up and get a new user account. We're sorry about that inconvenience, but we think it's better in the long run. The content on this forum will remain online.
IndexProgramming Questions & HelpPrograms › life in "processing: a programming handbook"
Page Index Toggle Pages: 1
life in "processing: a programming handbook" (Read 1008 times)
life in "processing: a programming handbook"
Oct 30th, 2009, 9:32am
 
there is an example of conway's game of life in "processing: a programming handbook for visual designers and artists" that is confusing me.
at the end of the draw function, there are three lines of code:

int[][] temp = grid;
grid = futureGrid;
futureGrid = temp;

i just cannot understand why a temporary grid is needed and why you would want to save the old grid.  why doesn't this code work instead:

grid = futureGrid;
Re: life in "processing: a programming handbook"
Reply #1 - Oct 30th, 2009, 10:10am
 
Without looking at the rest of the code, I'll suggest that the idea is that there are two grids to play with: the current grid, and the future grid. When you've calculated the "future" grid, it then becomes the current grid. Rather than create an endless sequence of new future grids, the idea is to swap the two grids you have, so the new "future" grid is actually the old grid.

Note: temp is not a copy of grid. It is a reference to the same two-dimensional array.
Re: life in "processing: a programming handbook"
Reply #2 - Oct 30th, 2009, 11:18am
 
subpixel is right just like to add something about the game.

In Conway's "game of life" a cell maybe empty or contain a 'life'

At each step in time, the following transitions occur:
1. Any live cell with fewer than two live neighbours dies, as if caused by underpopulation.
2. Any live cell with more than three live neighbours dies, as if by overcrowding.
3. Any live cell with two or three live neighbours lives on to the next generation.
4. Any dead cell with exactly three live neighbours becomes a live cell.

If we had a single grid then changing a cell from life>death or death>life would adversely affect the calculation for its neighbour cells. We have to perform all the calculations for each cell without changing the starting values. Tie this in with subpixels's reply and hopefully you will realise why 2 grids.
Smiley
Re: life in "processing: a programming handbook"
Reply #3 - Oct 30th, 2009, 12:29pm
 
o duh, i forgot that arrays are just pointers. ok i get it.
Re: life in "processing: a programming handbook"
Reply #4 - Oct 31st, 2009, 11:56pm
 
You could probably do something like

grid = futureGrid.clone();

(Not sure if clone() does a deep copy of the array, but I'm sure there would be a method to do what you want).

Actively copying the contents of the array will almost certainly incur a performance hit.

-spxl
Re: life in "processing: a programming handbook"
Reply #5 - Nov 1st, 2009, 5:06am
 
The trick here in terms of performance is not to create arrays or copy arrays in the draw() function.

Step 1
Create 2 global arrays e.g.
Code:
int[][] g1, g2;

void setup(){
  g1 = new int[cols][rows];
  g2 = new int[cols][rows];
}

where cols and rows represent the size of the grid horizontally and vertically

Step 2
Add 2 more global references currGrid, newGrid i.e.
Code:
int[][] currGrid, newGrid; 



Step 3
Assume that g1 is used to hold the initial state of the game then in setup()
Code:
currGrid = g1;
newGrid = g2;


Step 4
Create a new function calcGrid() that ONLY uses reference currGrid and newGrid. It calculates the new state of EVERY cell in currGrid and stores it in newGrid.

Step 5
In draw() method we calculate the new Grid swap the reference to g1/g2, draw the grid and repeat e.g.
Code:
void draw(){
  calcGrid();
  if(newGrid == g1){
     newGrid = g2;
     currGrid = g1;
  }
  else {
     newGrid = g1;
     currGrid = g2;
  }
  // At this stage currGrid holds the current state of the grid
  // so use currGrid to display the grid here
}


Hope this helps  Smiley
Re: life in "processing: a programming handbook"
Reply #6 - Nov 2nd, 2009, 2:40pm
 
Quark wrote on Nov 1st, 2009, 5:06am:
The trick here in terms of performance is not to create arrays or copy arrays in the draw() function.

The other tricks are to not use 2D arrays, and to minimise the number of element accesses...

You don't need to count 8 neighbouring cells for each cell as you go along, because neighbouring cells have overlapping sets of neighbours.

I came up with a neat trick whereby you only need to look at 3 new cells for each cell calculation (instead of 9!)... well, except for the cells along the left edge of the grid (realisation: if you have many columns, the extra overhead for just the first column tends towards zero as an average for all columns, and hence all cells).

Conway_mod_by_spxl_1_3

Note: this program also does something a little different in that it doesn't calculate a futureGrid, as it were, but instead a "what are the changes grid"; I supposed that drawing the cells (plotting pixels) is slow, so instead of drawing the entire grid for each iteration, I only plot the births and deaths. This also allows for an interesting feature of plotting different colours to see a kind of history of the lives (and deaths) of the cells.

By the timing tests I'd run, this version runs nearly two and a half times as fast as the original that comes as a sample with the Processing environment, and represents the most advanced version of Life I've ever written. Having said that, it is still childs play compared to serious Life optimisations.

Check out a program called golly... you can run simulations thousands (or millions!) of cells wide and high at insane realtime speeds.  Cheesy
Page Index Toggle Pages: 1