Game of Life Implementation Bug

Hi,

I’m trying to implement Life and I’ve written a class that should work, but I guess I’m missing something. I’ve followed all of the rules set forth in the book Cellular Automata Machines by Toffoli and Margolus.

I believe I’ve followed all four rules, but I can’t seem to make it work. The problem is my growth is completely unconstrained. It eventually overtakes the screen. I can’t seem to make it behave in the traditional Game of Life sense.

I’m using an enum for the cell state:

enum LifeCycle {
  ALIVE(0xff00FF00), 
    DEAD(0xff000000)
    ;

  private int c;

  private LifeCycle(int c) {
    this.c = c;
  }

  int getColor() {
    return c;
  }
}

And I have a simple integer pair coordinate structure:

class Coord{
  
  int x,y;
  
  Coord(int x, int y){
    this.x = x;
    this.y = y;
  }
  
}

Here’s my Cell class:

float probLife = 0.1; // 10% probability of starting out alive.

class Cell {

  Coord pos;

  LifeCycle currentCycle;

  Cell(Coord pos) {
    this.pos = pos;

    float state = random(1.0);
    if (state > probLife) {
      currentCycle = LifeCycle.DEAD;
    } else {
      currentCycle = LifeCycle.ALIVE;
    }
  }

  void display() {
    graphics.set(pos.x, pos.y, color(currentCycle.getColor()));
  }
}

Here’s my Life class:

class Life {

  Cell[][] cells;

  Life() {
    cells = new Cell[width][height];

    for (int y = 0; y < height; y++) {
      for (int x = 0; x < width; x++) {
        Coord pos = new Coord(x, y);
        cells[x][y] = new Cell(pos);
      }
    }
  }

  void step() {
    for (int y = 0; y < height; y++) {
      for (int x = 0; x < width; x++) {

        int neighbors = 0;

        for (int offy = y-1; offy <= y+1; offy++) {
          for (int offx = x-1; offx <= x+1; offx++) {

            if (offx < width && offx >=0 && offy < height && offy >= 0) {

              if (!((offx==x)&&(offy==y))) {

                if (cells[offx][offy].currentCycle == LifeCycle.ALIVE) {
                  neighbors++;
                }
              }
            }
          }
        }
        if (cells[x][y].currentCycle == LifeCycle.ALIVE) {
          if (neighbors < 2 || neighbors > 3) {
            cells[x][y].currentCycle = LifeCycle.DEAD;
          }
        } else {
          if (neighbors == 3) {
            cells[x][y].currentCycle = LifeCycle.ALIVE;
          }
        }
      }
    }
  }


  void display() {
    for (int y = 0; y < height; y++) {
      for (int x = 0; x < width; x++) {
        cells[x][y].display();
      }
    }
  }
}

I’m hoping someone will see my error. I’ve been looking at it for days. Thanks in advance.

You forgot a rule. A cell survives if it has 2 neighbors and spawns if it has 3

1 Like

Thanks for the suggestion. I get the same result. Unconstrained growth. I broke my code out to be more clear about the 4 rules. I do think I’m covering them all:

        // Is cell alive?
        if (cells[x][y].currentCycle == LifeCycle.ALIVE) {
          if (neighbors < 2) { // Rule 1: Fewer than two neighbors dies.
            cells[x][y].currentCycle = LifeCycle.DEAD;
          } else if (neighbors == 2 || neighbors == 3){ // Rule 2: 2 or 3 survives to the next generation.
            cells[x][y].currentCycle = LifeCycle.ALIVE;
          } else if (neighbors > 3) { // Rule 3: Death by overpopulation.
            cells[x][y].currentCycle = LifeCycle.DEAD;
          }
        } else { // If cell is dead.
          if (neighbors == 3) { // Rule 4: Does it have 3 neighbors? Birth by reproduction.
            cells[x][y].currentCycle = LifeCycle.ALIVE; // Swap it to be alive.
          }

Save

I fixed the unconstrained growth. :man_facepalming:t2: Thanks again for your help. It got me to go through and start methodically looking at how I was doing everything.

In the place where I’m checking to see if we’re on the center point so I can exclude it from the neighbor count I replaced this if

if (!((offx==x)&&(offy==y))) {

with this one

if (offx != x && offy != y) {

NOTs can be so confusing to me, so I’m unclear why one would differ from the other, but the program is stable now and there is no unconstrained growth.

It still does not look like Conway’s game of life, but at least it’s not running away.

The way I usually do it (done it several times) is

if(neigh == 2) if(cell.living) survive = true;
if(neigh == 3) survive = true;

if neigh == 2, only living survives,
if neight == 3, the cell will survive or be created

here is my code for reference:

Code
int m = 10;
int w = 16*m, h = 9*m, mx, my;
float scl;
int grid[][] = new int[w][h];
boolean survive[][] = new boolean[w][h];
void setup() {
  fullScreen();
  scl = width / w;
  for (int i = 0; i < w; i++) {
    for (int j = 0; j < h; j++) {
      grid[i][j] = ((random(100) < 0)? 1 : -1)    ;
      survive[i][j] = false;
    }
  }
  textSize(scl/2);
  textAlign(3, 3);
}

void draw() {
  background(0);
  noStroke();
  getMousePos();
  //checkStep();

  checkStep();
  for (int i = 0; i < w; i++) {
    for (int j = 0; j < h; j++) {
      if (grid[i][j] == -1) {
        fill(0);
      } else {
        fill(255);
      }
      rect(i*scl, j*scl, scl, scl);

      fill( ((survive[i][j])? 255 : 0));
      rect( (i+0.25)*scl, (j+0.25)*scl, scl/2, scl/2);
    }
  }

  stroke(255);
  noFill();
  rect(mx*scl, my*scl, scl, scl);
}

void mousePressed() {
  getMousePos();
  grid[mx][my] *= -1;
}

void getMousePos() {
  mx = floor(map(mouseX, 0, width, 0, w));
  my = floor(map(mouseY, 0, height, 0, h));
}

void keyPressed() {
  if (key == ' ') {
    step();
  }
}

void step() {
  checkStep();
  for(int i = 0; i < w; i++) {
    for(int j = 0; j < h; j++) {
      if(survive[i][j]) {
        grid[i][j] = 1;
      } else{
        grid[i][j] = -1;
      }
    }
  }
}

void checkStep() {
  for (int i = 0; i < w; i++) {
    for (int j = 0; j < h; j++) {
      int sum = 0;
      
      for (int y = -1; y < 2; y++) {
        for (int x = -1; x < 2; x ++) {
          if (x != 0 || y !=0) {
            //check sum

            if (inbounds(i+x, j+y)) {
              if (grid[i+x][j+y] == 1) {
                sum++;
              }
            }
          }
        }
      }
      //fill(255,0,0);
      
      survive[i][j] = false;
      
      if(sum == 3) {
        survive[i][j] = true;
      }
      if(sum == 2) {
        if(grid[i][j] == 1) {
          survive[i][j] = true;
        }
      }
      
      //text(sum,(i+0.25)*scl,(j+0.25)*scl);
      
    }
  }
}

boolean inbounds(int x, int y) {
  boolean retrn = false;

  if ( x > -1 && x < w && y > -1 && y < h) {
    retrn = true;
  }

  return(retrn);
}

Thanks for sharing your code.

I don’t think the implementation of the rules is really the problem. It’s something else that I can’t seem to figure out.

I know that you are supposed to use page flipping or a buffer (as you do in your code) so you don’t corrupt the data as you’re going through each pixel. I think this is probably the root of my issues, but I’ll have to keep working at it.