Specific neighbourhoods in the Game of Life

tl;dr : I reset the variable to store the neighbours in everytime I checked a new neighbour.

I recently found processing and thought the Game of Life would be an easy first project. But when I tried going from neighbourCount only, to saving neighbours in order - in an Array - I stopped getting neighbourCounts bigger than one.

I know it is not needed to store the specific configuration of neighbours to make the Game of Life work, but I want to expand on the idea once I get this working. Why am I not getting the right neighbourCount? I know it's a lot, but I put in as many comments as possible to make it easier on the eyes.

int interval = 1000;                         // time between iterations
int lastRecordedTime = 0;                    // timer

int cellSize = 5;                            // size of one Cell
int counterLocal;                            // variable for storing neighbourCount
int [] neighbourhood = {0,0,0,0,0,0,0,0};    // Array for storing neighbourhood configuration
int [][] cells;                              // 2D Cells Array
int [][] cellsBuffer;                        // 2D Buffer Array to work on while leaving cells[][] unharmed

float prob = 30;                             // probability of Cell being alive at setup

color alive = color(0, 0, 0);                // Alive color = black
color dead = color(255, 255, 255);           // Dead color = white




void setup() {
  size (200, 200);
  cells = new int [width/cellSize][height/cellSize];
  cellsBuffer = new int [width/cellSize][height/cellSize];
  stroke(48);
  noSmooth();

  for ( int x = 0; x < width/cellSize; x++) {                // Randomize cells[][]
    for ( int y = 0; y < height/cellSize; y++) {
      float state = random(100);
      if (state > prob) {
        state = 0;
      } else {
        state = 1;
      }
      cells[x][y] = int(state);
    }
  }
  background(0);
} // end of setup()




void draw() {                                                // Loop through every cell in cells[][] and draw them according to their state
  for ( int x = 0; x < width/cellSize; x++) {
    for ( int y = 0; y < height/cellSize; y++) {
      if (cells[x][y] == 1) {
        fill(alive);
      } else {
        fill (dead);
      }
      rect (x*cellSize, y*cellSize, cellSize, cellSize);
    }
  }
  if (millis() - lastRecordedTime > interval) {
    iteration();
    lastRecordedTime = millis();
  }
} // end of draw()





void iteration() {    
  for (int x = 0; x < width/cellSize; x++) {                                       // copy cells Array to cellsBuffer
    for (int y = 0; y < height/cellSize; y++) {
      cellsBuffer[x][y] = cells[x][y];
    }
  } 



  for (int x = 0; x < width/cellSize; x++) {                                       // go through every cell
    for (int y = 0; y < height/cellSize; y++) {

      String neighbourCode = "0,0,0,0,0,0,0,0";                                    // string used to encode neighbour positions    

      for (int xx=x-1; xx<=x+1; xx++) {                                            // go through all neighbours of current Cell
        for (int yy=y-1; yy<=y+1; yy++) {  

          if (((xx>=0)&&(xx<width/cellSize))&&((yy>=0)&&(yy<height/cellSize))) {   // Make sure you are not out of bounds
            //if (!((xx==x)&&(yy==y))) {                                           // Make sure to to check against self (not needed)

              int[] codeArray = int(split(neighbourCode, ","));                    // Split string into Array

              if ((x - xx == 1) && (y - yy == 1)) {           //top left           //1. Check which neighbour you are (if, else if, else if...)
                if (cellsBuffer[xx][yy] == 1){
                codeArray[0] = 1;                                                  //2. if alive, set codeArray at corresponding index to 1
                }
              }

              else if ((x - xx == 0) && (y - yy == 1)) {      //top mid
                if (cellsBuffer[xx][yy] == 1){
                codeArray[1] = 1;
                }
              }

              else if ((x - xx == -1) && (y - yy == 1)) {     //top right
                if (cellsBuffer[xx][yy] == 1){
                codeArray[2] = 1;
                }
              }

              else if ((x - xx == 1) && (y - yy == 0)) {       //mid left
                if (cellsBuffer[xx][yy] == 1){
                codeArray[3] = 1;
                }
              }

              else if ((x - xx == -1) && (y - yy == 0)) {      //mid right
                if (cellsBuffer[xx][yy] == 1){
                codeArray[4] = 1;
                }
              }

              else if ((x - xx == 1) && (y - yy == -1)) {      //bot left
                if (cellsBuffer[xx][yy] == 1){
                codeArray[5] = 1;
                }
              }

              else if ((x - xx == 0) && (y - yy == -1)) {       //bot mid
                if (cellsBuffer[xx][yy] == 1){
                codeArray[6] = 1;
                }
              }

              else if ((x - xx == -1) && (y - yy == -1)) {      //bot right
                if (cellsBuffer[xx][yy] == 1){
                codeArray[7] = 1;
                }
              }                                                 // finished making codeArray


              for (int n = 0; n < codeArray.length; n++) {      // copy codeArray to public Array
                neighbourhood[n] = codeArray[n];
              }



              int neighbourCount = 0;
              for (int neighbourIndex = 0; neighbourIndex < codeArray.length; neighbourIndex++) {      // Converting neighbourCode to neighbourCount
                if (codeArray[neighbourIndex] == 1) {
                  neighbourCount = neighbourCount + 1;
                }
               }                                                // end of Conversion
               counterLocal = neighbourCount;                   // copy neighbourCount to public int

            //} // end of self check (not needed)
          } // end of out of Bounds check
        } // end of for (yy++) loop
      } // end of for (xx++) loop





        if (cellsBuffer[x][y] == 1) {                                              // applying ruleset for the game of life and writing to cells Array
          if (counterLocal < 2 || counterLocal > 3) {
            cells [x][y] = 0;
          }
        } else {
          if (counterLocal == 3) {
            cells[x][y] = 1;
          }
        }



    } // end of for (y++) loop
  } // end of for (x++) loop
}  //end of iteration ()

If you're still reading this, you are my hero.

Answers

  • To make clear what I want: Check neighbourhood of each cell and record them, so their "location data" (relative to current cell) gets preserved until I am done applying the rules.

    Right now I am trying to save them in codeArray[]

    I calculate the index at which I save the neighbour in codeArray by comparing x and y of the current cell to xx and yy (those are the coordinates of the neighbour I am currently looking at).

    So for a cell which has the 4 neighbours in the cardinal directions alive and every other is dead I would hope the array looks like this: {0,1,0,1,1,0,1,0} Also this was heavily inspired by: https://processing.org/examples/gameoflife.html

  • I haven't reviewed this code yet, but a common error in GoL implementations is to alter the matrix as you read it. You can't do that. You need to take one pass and calculate all the neighbor counts, then a second pass and update the matrix. Are you already doing this, or are you editing cells while you are reading / updating your cellBuffer? That's a first guess at a problem to check for.

  • edited June 2017

    Have not programmed much last month and a half but this idea sparked my interest to get back into it.
    From the PM's it sounds like what you're trying to do could also be described as an "elementary CA", but with 9 bits and in 2D rather than just the 3 bits ontop?

    This is a bit crude and might contain misstakes but a start

    EDIT: changed code as I found the rule corresponding to game of life

    import java.math.*;
    BigInteger rule; 
    int swap,xyz=200;
    boolean[][][] fields = new boolean[2][xyz][xyz];
    
    boolean closerThan(int len, int x0, int y0, int x1, int y1){
      float delx = x0-x1;
      float dely = y0-y1;
      delx*=delx;
      dely*=dely;
      len*=len;
      return delx+dely < len;
    }
    
    void clear() {
      for(int b=0;b<2;b++){
          for (int x=0;x < xyz; x++) {
            for (int y = 0; y < xyz; y++) {
              fields[b][x][y] = false;
            }}}
    }
    void setup(){
    size(200,200);
    clear();
    loadPixels();
    rule = new BigInteger("95269658970504075026401947768164943776577911284651056525821775275694548745963441068740035536685992072438984633721408802547302109256447217920");
    }
    boolean algorithm(int d,int x0,int y0) {
    
      if ( closerThan(10,x0,y0,mouseX,mouseY) ){
        return true;
      }
        int up=(y0+xyz-1)%xyz;  
        int down=(y0+xyz+1)%xyz; 
        boolean n0=fields[swap][(x0+xyz-1)%xyz][up];
        boolean n1=fields[swap][x0][up];
        boolean n2=fields[swap][(x0+1)%xyz][up];
        boolean n3=fields[swap][(x0+xyz-1)%xyz][y0];
        boolean n4=fields[swap][x0][y0];
        boolean n5=fields[swap][(x0+1)%xyz][y0];
        boolean n6=fields[swap][(x0+xyz-1)%xyz][down];
        boolean n7=fields[swap][x0][down];
        boolean n8=fields[swap][(x0+1)%xyz][down];
        int state = (n0?1:0)+
                    (n1?2:0)+
                    (n2?4:0)+
                    (n3?8:0)+
                    (n4?16:0)+
                    (n5?32:0)+
                    (n6?64:0)+
                    (n7?128:0)+
                    (n8?256:0);
        return rule.shiftRight(state).testBit(1);
    }
    void draw() { 
      for (int y=0;y<xyz;y++){
      for (int x=0;x<xyz;x++){
      fields[(swap+1)%2][x][y]=algorithm(0,x,y);
      pixels[x+xyz*y]=algorithm(0,x,y)?#000000:#ffffff;}}
      if(swap==0){swap=1; updatePixels();}else{swap=0;}
      fill(0);rect(0,xyz,xyz,16);fill(255);
    }
    
  • edited June 2017

    @jeremydouglass

    Ok let me work through this out loud to understand it myself:

    1. Copy cells[][] to cellsBuffer[][] (lines 63ff)

    2. Loop through cellsBuffer[][]

      • for each cell in Buffer: (lines 72 - 80)

        • count its neighbours, (lines 83 - 146)
        • update cells[][] according to rules (lines 157 - 165)
      • go to next cell in Buffer.

    Saving my cells[][] is the only time I write to cellsBuffer[][], so I am never reading and writing to the same array in the same step. I strongly suspect the problem is with the actual counting of the neighbours and/or the int array I try to save them to... (lines 75+83ff)

    Thanks for the suggestion

    @prince_polka

    Thank you so much for taking your time, there's a lot in there to check out. I've had trouble with the pixels array on my first try, so I started over and replaced it with my own 2D array, after watching The Coding Train videos on CA...

    Also: you can do return in a void method? (your code line39) Or only in setup?

  • no problem,
    A method has to return whatever type it starts with, void means nothing and thus can't return anything.

  • made a sketch to find the rule for game of life for the 9-bit automata above

    import java.math.*;
    BigInteger gol;
    int n;
    boolean alive;
    void setup(){
      gol= new BigInteger("0");
      for (int i=0; i<512; i++){
        n=0;
        for (int j=0; j<9; j++){
          if (j!=4){
          n+= (i >> j)&1;
          }
        }
        alive=((i>>4)&1)==1;
          if ( alive && n==2 ){ gol = gol.setBit(i+1); }
        if(n==3){ gol = gol.setBit(i+1);
    
      }
      }
      println(gol.toString());
    }  
    

    turns out to be

    95269658970504075026401947768164943776577911284651056525821775275694548745963441068740035536685992072438984633721408802547302109256447217920

  • @prince_polka That's nice, but I think you are skipping every other frame, even though you're doing the calculations correctly, from just looking at the pictures.

    To be honest, your calculations are a bit beyond me.. I sort of understand how you get neighbours positions with the booleans. I don't quite get

    int state = (n0?1:0)+
                (n1?2:0)+
                (n2?4:0)+
                (n3?8:0)+
                (n4?16:0)+
                (n5?32:0)+
                (n6?64:0)+
                (n7?128:0)+
                (n8?256:0);
    return rule.shiftRight(state).testBit(1)
    

    I know you're converting from boolean to int, but not how the state interacts with the BigInteger

    (oh and a small thing: int swap,xyz=200; is that the same as int swap=200; int xyz=200; ?

  • Answer ✓

    I haven't noticed the skipping and I'm aware my code is cryptic.

    (oh and a small thing: int swap,xyz=200; is that the same as int swap=200; int xyz=200; ?
    no its swap undeclared, xyz = 200, if you wanted to set both to 200 you could do

    int swap,xyz;
    swap=xyz=200;  
    

    the one i call swap I at least intended to swap back and forth each frame between 0-1 to get a ping pong buffering kind of thing going.
    xyz is the dimensions

    one thing I'm wondering is if you have any ideas for an interface to enter alternative rules into the system?

  • edited June 2017

    Ah it's starting to make sense now. At least I got a lot of material now to continue my google adventures. No need to apologize for cryptic code, have you looked at my hot mess?

    Still have too many ideas for interfaces, I'll have to familiarize myself with libraries first I think, making buttons and stuff seems like a hassle. One thing I'm sure I want is a feature to make a random ruleset with a variable ratio of (configurations that result in death)/(configurations that result in life) Quickly swap out rulesets maybe

    I'm also interested in comparing different methods of doing the same thing; so your code really helps a lot, thanks. wrapping my head around arrays, lists, bit manipulation.. honestly I'm just having fun with it.

  • edited June 2017 Answer ✓

    @HolyMoley -- yes, from your description it sounds like you are using the buffer correctly. My first guess was probably wrong.

    when I tried going from neighbourCount only, to saving neighbours in order - in an Array - I stopped getting neighbourCounts bigger than one.

    These are the lines that jump out at me:

    else if ((x - xx == 0) && (y - yy == 1))
    

    ...should that else be there in else if?

    Those elses make it look like you are only registering one neighbor per neighborhood, then skipping to the end of the conditions. You probably want to test each condition independently with a set of eight simple if blocks...?

  • edited June 2017

    I fixed the else ifs to ifs and I finally figured it out... It would help if I don't make a new Array every time I go to the next neighbour. Took the initialization of the Array out of the xx,yy loop and it works now. What a silly mistake... This is my interation() now:

    for (int x = 0; x < width/cellSize; x++) {  // Go through every cell
        for (int y = 0; y < height/cellSize; y++) {
    
            boolean codeArray[] = {false, false, false, false, false, false, false, false}; // Make array to store neighbourhood
    
            for (int xx=x-1; xx<=x+1; xx++) {  // Go through all neighbours of current Cell
                for (int yy=y-1; yy<=y+1; yy++) {
                    construct Array in here.
    
                }
            }
        }
    }
    
  • Why do you need the 3x3 array?

  • edited June 2017

    @koogs converting the 9 states of current cell in the 2D cells[][] Array, that define the neighbourhood, into a 1D codeArray[]. Compare codeArray to rules and update cells accordingly. I could make the rules use a 2D array as well, but then I'd have to convert down eventually..I think.

  • edited June 2017

    I know you're converting from boolean to int, but not how the state interacts with the BigInteger

    looking at the n'th bit, counted "backwards".

    Maybe the rightshift is superfluos to do this,

    rule.shiftRight(state).testBit(1) rule.testBit(state)

    havent tested it yet

    return rule.testBit(state+1); works

    have you looked at my hot mess?

    I actuallt barelly looked at your actual code to be honest.

  • I think your original code is redundant because you run xx and yy over all neighbours but then you check with if which neighbour you are looking at.

    I got rid of the for xx and for yy loop and put the neighbour check in a sub function checkNeighbours :

    int interval = 1000;                         // time between iterations
    int lastRecordedTime = 0;                    // timer
    
    int cellSize = 5;                            // size of one Cell
    int counterLocal;                            // variable for storing neighbourCount
    int [] neighbourhood = {0, 0, 0, 0, 0, 0, 0, 0};    // Array for storing neighbourhood configuration
    int [][] cells;                              // 2D Cells Array
    int [][] cellsBuffer;                        // 2D Buffer Array to work on while leaving cells[][] unharmed
    
    float prob = 30;                             // probability of Cell being alive at setup
    
    color alive = color(0, 0, 0);                // Alive color = black
    color dead = color(255, 255, 255);           // Dead color = white
    
    void setup() {
      size (200, 200);
      cells = new int [width/cellSize][height/cellSize];
      cellsBuffer = new int [width/cellSize][height/cellSize];
      stroke(48);
      noSmooth();
    
      // Randomize cells[][]
      for ( int x = 0; x < width/cellSize; x++) {            
        for ( int y = 0; y < height/cellSize; y++) {
          float state = random(100);
          if (state > prob) {
            state = 0;
          } else {
            state = 1;
          }
          cells[x][y] = int(state);
        }
      }
      background(0);
    } // end of setup()
    
    void draw() {                                               
      // Loop through every cell in cells[][] and draw them according to their state
      for ( int x = 0; x < width/cellSize; x++) {
        for ( int y = 0; y < height/cellSize; y++) {
          if (cells[x][y] == 1) {
            fill(alive);
          } else {
            fill (dead);
          }
          rect (x*cellSize, y*cellSize, cellSize, cellSize);
        }
      }
      if (millis() - lastRecordedTime > interval) {
        iteration();
        lastRecordedTime = millis();
      }
    } // end of draw()
    
    // ---------------------------------------------------------------------
    
    void iteration() {    
      //
      for (int x = 0; x < width/cellSize; x++) {   // copy cells Array to cellsBuffer
        for (int y = 0; y < height/cellSize; y++) {
          cellsBuffer[x][y] = cells[x][y];
        }
      }
    
      for (int x = 0; x < width/cellSize; x++) {        // go through every cell
        for (int y = 0; y < height/cellSize; y++) {
    
          String neighbourCode = "0,0,0,0,0,0,0,0";     // string used to encode neighbour positions
    
          // go through all neighbours of current Cell
          int[] codeArray  = checkNeighbours(x, y); 
    
          for (int n = 0; n < codeArray.length; n++) {      // copy codeArray to public Array
            neighbourhood[n] = codeArray[n];
          }
    
          int neighbourCount = 0;
          // Converting neighbourCode to neighbourCount
          for (int neighbourIndex = 0; neighbourIndex < codeArray.length; neighbourIndex++) {     
            if (codeArray[neighbourIndex] == 1) {
              neighbourCount = neighbourCount + 1;
            }
          }                  // end of Conversion
          counterLocal = neighbourCount;     // copy neighbourCount to public int
    
          // applying ruleset for the game of life and writing to cells Array
          if (cellsBuffer[x][y] == 1) {                  
            if (counterLocal < 2 || counterLocal > 3) {
              cells [x][y] = 0;
            }
          } else {
            if (counterLocal == 3) {
              cells[x][y] = 1;
            }
          }
        } // end of for (y++) loop
      } // end of for (x++) loop
    }  //end of function iteration ()
    
    int[] checkNeighbours(int x, int y) {
    
      // Make array to store neighbourhood
      // int codeArray[] = {false, false, false, false, false, false, false, false};
      int codeArray[] = {0, 0, 0, 0, 0, 0, 0, 0}; // Make array to store neighbourhood
    
      // if alive, set codeArray at corresponding index to 1
    
      final int top=y-1; 
      final int mid=y;
      final int bottom=y+1; 
    
      final int left=x-1; 
      final int midX=x;
      final int right=x+1; 
    
      if (isValid(left, top) && cellsBuffer[left][top] == 1) {   // top left 
        codeArray[0] = 1;
      }
    
      if (isValid(midX, top) &&cellsBuffer[midX][top] == 1) {     //top mid
        codeArray[1] = 1;
      }
    
      if (isValid(right, top) && cellsBuffer[right][top] == 1) {     //top right
        codeArray[2] = 1;
      }
    
      if (isValid(left, mid) && cellsBuffer[left][mid] == 1) {    //mid left
        codeArray[3] = 1;
      }
    
      if (isValid(right, mid) && cellsBuffer[right][mid] == 1) {    //mid right
        codeArray[4] = 1;
      }
    
      if (isValid(left, bottom) && cellsBuffer[left][bottom] == 1) { //bottom left
        codeArray[5] = 1;
      }
    
      if (isValid(midX, bottom) && cellsBuffer[midX][bottom] == 1) {  //bottom mid
        codeArray[6] = 1;
      }
    
      if (isValid(right, bottom) && cellsBuffer[right][bottom] == 1) {    //bottom right
        codeArray[7] = 1;
      }                                                
      // finished making codeArray
    
      return codeArray;
    } 
    
    boolean isValid(int x, int y) {
    
      // Make sure you are not out of bounds
    
      if ( (x>=0) &&
        (x<width/cellSize) &&   
        (y>=0) &&
        (y<height/cellSize) ) 
        return true; // correct
    
      // otherwise return false 
      return false;
    }
    
    //
    
  • import java.math.*;
    BigInteger rule; 
    int swap,n;
    int xyz=40;
    int cellsize=5;
    boolean alive;
    boolean[][][] fields = new boolean[2][xyz][xyz];
    boolean codeArray[] = new boolean[9];
    boolean closerThan(int len, int x0, int y0, int x1, int y1){
      float delx = x0-x1;
      float dely = y0-y1;
      delx*=delx;
      dely*=dely;
      len*=len;
      return delx+dely < len;
    }
    
    void setgol(){
      rule= new BigInteger("0");
      for (int i=0; i<512; i++){
        n=0;
        for (int j=0; j<9; j++){
          if (j!=4){
          n+= (i >> j)&1;
          }
        }
        alive=((i>>4)&1)==1;
          if ( alive && n==2 ){ rule = rule.setBit(i); }
        if(n==3){ rule = rule.setBit(i);
      }
      }
    }  
    
    void clear() {
      for(int b=0;b<2;b++){
          for (int x=0;x < xyz; x++) {
            for (int y = 0; y < xyz; y++) {
              fields[b][x][y] = false;
            }}}
    }
    void setup(){
    size(200,200);
    clear();
    loadPixels();
    setgol();
    frameRate(15);
    }
    boolean judge(int d,int x0,int y0) {
      if ( closerThan(10,x0,y0,mouseX/cellsize,mouseY/cellsize) ){ return true; }
        int up=(y0+xyz-1)%xyz;  
        int down=(y0+xyz+1)%xyz; 
        codeArray[0]=fields[swap][(x0+xyz-1)%xyz][up];
        codeArray[1]=fields[swap][x0][up];
        codeArray[2]=fields[swap][(x0+1)%xyz][up];
        codeArray[3]=fields[swap][(x0+xyz-1)%xyz][y0];
        codeArray[4]=fields[swap][x0][y0];
        codeArray[5]=fields[swap][(x0+1)%xyz][y0];
        codeArray[6]=fields[swap][(x0+xyz-1)%xyz][down];
        codeArray[7]=fields[swap][x0][down];
        codeArray[8]=fields[swap][(x0+1)%xyz][down];
        int state = 0;
        for (int i=0; i<9; i++){
          state+= codeArray[i]?(int(pow(2,i))):0;
        }
        return rule.testBit(state);
    }
    void draw() {
      for (int y=0;y<xyz;y++){
      for (int x=0;x<xyz;x++){
      fields[(swap+1)%2][x][y]=judge(0,x,y);
      fill(judge(0,x,y)?#000000:#ffffff);
      rect(x*cellsize,y*cellsize,cellsize,cellsize);
      }}
      //pixels[x+xyz*y]=judge(0,x,y)?#000000:#ffffff;}}
      if(swap==0){
      swap=1; 
    //updatePixels();
     } else {swap=0;}
    }
    
  • edited June 2017 Answer ✓

    Compare codeArray to rules and update cells accordingly.

    so the rules are more than just a count?

    my optimisation for this whole bit (original post)

              if ((x - xx == 1) && (y - yy == 1)) {           //top left           //1. Check which neighbour you are (if, else if, else if...)
                if (cellsBuffer[xx][yy] == 1){
                codeArray[0] = 1;                                                  //2. if alive, set codeArray at corresponding index to 1
                }
              }
              else if ((x - xx == 0) && (y - yy == 1)) {      //top mid
                if (cellsBuffer[xx][yy] == 1){
                codeArray[1] = 1;
                }
              }
              else if ((x - xx == -1) && (y - yy == 1)) {     //top right
                if (cellsBuffer[xx][yy] == 1){
                codeArray[2] = 1;
                }
              }
              else if ((x - xx == 1) && (y - yy == 0)) {       //mid left
                if (cellsBuffer[xx][yy] == 1){
                codeArray[3] = 1;
                }
              }
              else if ((x - xx == -1) && (y - yy == 0)) {      //mid right
                if (cellsBuffer[xx][yy] == 1){
                codeArray[4] = 1;
                }
              }
              else if ((x - xx == 1) && (y - yy == -1)) {      //bot left
                if (cellsBuffer[xx][yy] == 1){
                codeArray[5] = 1;
                }
              }
              else if ((x - xx == 0) && (y - yy == -1)) {       //bot mid
                if (cellsBuffer[xx][yy] == 1){
                codeArray[6] = 1;
                }
              }
              else if ((x - xx == -1) && (y - yy == -1)) {      //bot right
                if (cellsBuffer[xx][yy] == 1){
                codeArray[7] = 1;
                }
              }                                                 // finished making codeArray
    

    would be to just to use a counter. set it to 0 outside the xx, yy loops and then the loop body becomes

    codeArray[count] = cellsBuffer[xx][yy];
    count++;
    

    that's it. no need for all those checks. the loops in lines 77 and 78 iterate over the neighbours in the correct order, you just need to remember the position. (this array also includes the cell being checked, whereas you omit it)

    but if i was coding the classic game of life i'd do it completely differently - loop over all the current pixels and iff the pixel is set then increment all the neighbours in the array for the next step. much fewer comparisons, no overlaps. and you only have to process the black squares.

  • edited June 2017

    @koogs Yes! I was scratching my head for so long, thinking about how to convert the relative coordinates to an index, when I could've just counted them.

    This will be perfect for the new and clean project, where I use objects and make things pretty. Thanks a lot!

  • edited June 2017

    implemented interface to change rules
    EDIT: and grayscale

    import java.math.*;
    BigInteger rule; 
    golbutton[] button = new golbutton[512];
    PImage viewport;
    
    boolean codeArray[] = new boolean[9];
    int box=10;
    int swap;
    int xyz=100;
    boolean[][][] fields = new boolean[2][xyz][xyz];
    int cellsize=5;
    color store;
    
    boolean mpa,click; //mouse variable
    int[] stay ={2};
    int[] born = {3};
    void setgol(int[]stay,int[]born){
      boolean alive;
      int n;
      rule= new BigInteger("0");
      for (int i=0; i<512; i++){
        n=0;
        alive=((i>>4)&1)==1;
        for (int j=0; j<9; j++){
          if (j!=4){
          n+= (i >> j)&1;
          }
        }
        for (int j=0;j<stay.length;j++){
          if ( alive && n==stay[j] ) { 
          rule = rule.setBit(i); 
          break;
        }
        }
        for (int j=0;j<born.length;j++){
          if (n==born[j] ) { 
          rule = rule.setBit(i); 
          break;
        }
        }
      }
      }
      boolean judge(int d,int midx,int midy) {
      if ( closerThan(10,midx,midy,mouseX/cellsize,mouseY/cellsize) ){
        return true;
      }
        int up=(midy+xyz-1)%xyz;  
        int down=(midy+xyz+1)%xyz; 
        int left=(midx+xyz-1)%xyz; 
        int right=(midx+1)%xyz; 
        boolean[][]f = fields[swap];
        codeArray[0]=f[left][up];
        codeArray[1]=f[midx][up];
        codeArray[2]=f[right][up];
        codeArray[3]=f[left][midy];
        codeArray[4]=f[midx][midy];
        codeArray[5]=f[right][midy];
        codeArray[6]=f[left][down];
        codeArray[7]=f[midx][down];
        codeArray[8]=f[right][down];
        int state = 0;
        for (int i=0; i<9; i++){
          state+= codeArray[i]?(int(pow(2,i))):0;
        }
        store = color(255-state/2);
        return rule.testBit(state);
    }
    
    boolean closerThan(int len, int x0, int y0, int x1, int y1){
      float delx = x0-x1;
      float dely = y0-y1;
      delx*=delx;
      dely*=dely;
      len*=len;
      return delx+dely < len;
    }
    
    color fillcolor;
    class golbutton{
      int posx;
      int posy;
      int i;
      int margin=box/2;
      int size=box*4;
      boolean alive;
      boolean mob;
      golbutton(int I){
      i=I;
      alive=rule.testBit(i);
      posx=500+box/2+(i%32)*size;
      posy=box/2+(i/32)*size;
    }
    void toggle(){
      alive=!alive;
      if(alive){ rule = rule.setBit(i);}
      else     { rule = rule.clearBit(i);}
    }
      void show(){
        mob = (mouseX>posx && mouseX<posx+size && mouseY>posy && mouseY<posy+size);
        if(mob && click){toggle();}
        fillcolor=alive? #00ff00 : #ff0000;
        if(mob){fillcolor=#ffff00;}
        fill(fillcolor);
        rect(posx,posy,box*4,box*4);
    
     for (int j=0; j<9; j++){
       fillcolor = ((i>>j)&1) == 1 ? #000000 : #ffffff;
       fill(fillcolor);
       rect(posx+margin+(j%3)*box,posy+margin+j/3*box,box,box);
     }
      }
    }
    
    void setup(){
      size(1790,650);
      noStroke();
      noSmooth();
      viewport = createImage(xyz,xyz,ARGB);
      viewport.loadPixels();
      loadPixels();
      setgol(stay,born);
      for (int i=0; i<512; i++){ 
        button[i] = new golbutton(i);
      }
    }
    void draw(){
     click=(!mpa && mousePressed);
      for (int i=0; i<512; i++){
        button[i].show();
     }
     for (int y=0;y<xyz;y++){
      for (int x=0;x<xyz;x++){
      fields[(swap+1)%2][x][y]=judge(0,x,y);
      //fill(judge(0,x,y)?#000000:#ffffff);
      viewport.pixels[x+y*xyz]=store;
      //rect(x*cellsize,y*cellsize,cellsize,cellsize);
      }}
      viewport.updatePixels();
      image(viewport,0,0,xyz*cellsize,xyz*cellsize);
      if(swap==0){swap=1;}else{swap=0;}
     mpa=mousePressed;
    }
    
Sign In or Register to comment.