Game Of Life implemented with for-loops and a boolean-array

There's a Follow-up: Game Of Life rewritten into two classes, PetriDish and Cell

I wrote an implementation of the Game Of Life using the easiest approach, a bunch of loops and a boolean array. Yet I feel like I missed something very elemental.

The basic implementation is:

• Check the old generation with loops
• Check each neighbor of each cell...with loops
• Set the status in the generation
• Copy the new generation over the old one

This seems to have some serious downsides, especially the heavy use of loops which makes me a little bit itchy.

private boolean[] cells; // Will be set at construction
private int width;
private int height;

/**
* Evolve into the next nextGeneration.
*/
private void doGeneration() {
boolean[] nextGeneration = new boolean[cells.length];

for (int x = 1; x < width - 1; x++) {
for (int y = 1; y < height - 1; y++) {
int neighbors = 0;

// Check surrounding cells.
for (int neighborX = x - 1; neighborX <= x + 1; neighborX++) {
for (int neighborY = y - 1; neighborY <= y + 1; neighborY++) {
if (neighborX != x || neighborY != y) {
if (cells[neighborX * width + neighborY]) {
neighbors++;
}
}
}
}

int idx = x * width + y;

switch (neighbors) {
case 0:
case 1:
nextGeneration[idx] = false;
break;

case 2:
nextGeneration[idx] = cells[idx];
break;

case 3:
nextGeneration[idx] = true;
break;

default:
nextGeneration[idx] = false;
break;
}
}
}

cells = nextGeneration;
}


Edit: The whole application (Slick dependent for input and drawing) can be found at GitHub.

Edit2: There's a bug in the above code. The index should of course be y * width + x. I stumbled against that yesterday when I tried to handle non-square grids, but I just realized what was wrong some minutes ago while riding the bus.

I'd start it with a Cell and a Grid class and probably a two-dimensional Cell array field in the Grid. Cell provides type-safety and more readable code while probably contains only a boolean flag.

Anyway, this implementation can be improved. I'd extract out a List<Integer> getSurroundingCells(int cellIndex) and an int countLiveCells(final List<Integer> cellIndexes) method. A boolean getNextValue(int cellIndex, boolean oldValue, int liveNeighborCount) also could help.

• While I hesitated to write classes for it, you're right. Thinking about it I came to the conclusion that it would ease things in the end, f.e. handling of neighbors and the new generation. I'll do that next. Commented Dec 7, 2011 at 11:10