DAPPLE Example: life
Source code:
// life -- parallel, 2-dimensional, cellular automaton.
// according to the rules of the game of life.
// written using the Data-Parallel Programming Library for Education (DAPPLE)
//
// Each cell in the array is either occupied or not. At each iteration
// (generation), every cell counts its neighbors. This is done for all
// cells in parallel. Then, simple rules determine which cells are occupied
// in the next generation. After each generation we map the array to a
// character array, and print it. Boundaries are assumed to have unoccupied
// neighbors off the edge, rather than cyclic boundary conditions.
//
// The initial state is kinda boring.
//
// David Kotz 1994
// $Id: life.cc,v 2.13 94/09/29 12:18:04 dfk Exp $
#include
#include
#include "dapple.h"
const int N = 10;
const int ITERATIONS = 5;
// which VP am I? useful for VP-specific math
const intVector VP(N, Identity);
// which row or column am I? useful for VP-specific math
const intMatrix VProw(N, N, IdentityR);
const intMatrix VPcol(N, N, IdentityC);
int mapchar(const int c) { // map it to something printable
return (c == 0 ? '.' : 'O');
}
int
main(int argc, char **argv)
{
// 1 means life there, 0 means nothing
// so this initializes a 2x3 square in the center, to 1s, the rest 0s
intMatrix cells( (VProw >= N/2-1 && VProw <= N/2+1)
&& (VPcol >= N/2-1 && VPcol <= N/2+1));
intMatrix neighbors(N,N);
cells[6][_] = 1; // and fill a solid row
cells[_][6] = 1; // and fill a full column
cout << "Initial:" << endl;
cout << charMatrix(apply(mapchar, cells)) << endl;
// note that because we use shift(), we assume boundaries of 0
// if we used rotate, we would get periodic boundary conditions (torus)
for (int i = 0; i < ITERATIONS; i++) {
neighbors = ( shift(cells, 0, -1)
+ shift(cells, 0, 1)
+ shift(cells, -1, -1)
+ shift(cells, -1, 0)
+ shift(cells, -1, 1)
+ shift(cells, 1, -1)
+ shift(cells, 1, 0)
+ shift(cells, 1, 1));
// cout << "neighbors:" << endl;
// cout << neighbors << endl;
// The Rules:
// If an organism has 0 or 1 neighbors, it dies of loneliness.
// If an organism has 2 or 3 neighbors, it survives.
// If an organism has 4 or more neighbors, it dies of overcrowding.
// If an empty cell has exactly 3 neighbors, a new organism is born.
ifp (neighbors != 2)
ifp (neighbors == 3)
cells = 1; // either existing survives, or new is born
else
cells = 0; // either lonely or overcrowded
else
; // no change with two neighbors
cout << "Generation " << i+1 << endl;
cout << charMatrix(apply(mapchar, cells)) << endl;
}
return(0);
}
Demonstration:
life
Initial:
......O...
......O...
......O...
......O...
....OOO...
....OOO...
OOOOOOOOOO
......O...
......O...
......O...
Generation 1
..........
.....OOO..
.....OOO..
......OO..
....O..O..
.OO.....O.
.OOO....O.
.OOOO...O.
.....OOO..
..........
Generation 2
......O...
.....O.O..
........O.
........O.
......OOO.
.O.....OO.
O...O..OOO
.O..OOO.O.
..OOOOOO..
......O...
Generation 3
......O...
......OO..
.......OO.
........OO
......O..O
..........
OO..O....O
.OO......O
..OO......
...OO.OO..
Generation 4
......OO..
......O.O.
......O..O
.........O
........OO
..........
OOO.......
O.........
.O..O.....
..OOO.....
Generation 5
......OO..
.....OO.O.
.......OOO
.........O
........OO
.O........
OO........
O.O.......
.OO.O.....
..OOO.....