2
\$\begingroup\$

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.

\$\endgroup\$
2
\$\begingroup\$

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.

\$\endgroup\$
  • 1
    \$\begingroup\$ 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. \$\endgroup\$ – Bobby Dec 7 '11 at 11:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.