Cellular automaton's rules storage

edited March 2017 in Questions about Code

Hi, I am programming a orthogonal cellular automaton class (a kind of generalized Game of Life). The basic principle is that at each generation, for each cell, we count the number of neighbors in each state and then use a list of rules indicating what state is gonna take that cell in function of the number of neighbors in each state and the cell's actual state.

My question is about how to stock and access the rules.

We have variables number S of states and N of neighbors (it doesn't change after automaton initialization), and I want to access a particular rule by giving the number of neighbors in each state and the cell's actual state.

So at first I thought to an array of size S (for the actual state) of emulated S-dimensional arrays of size N (N^S arrays).

For example, the rules of the Game of Life would look like that :

{{
    0,0,0,0,0,0,0,0, 0,
    0,0,0,0,0,0,0, 0,0,
    0,0,0,0,0,0, 0,0,0,
    0,0,0,0,0, 1,0,0,0,
    0,0,0,0, 0,0,0,0,0,
    0,0,0, 0,0,0,0,0,0,
    0,0, 0,0,0,0,0,0,0,
    0, 0,0,0,0,0,0,0,0,
     0,0,0,0,0,0,0,0,0
  }, {
    0,0,0,0,0,0,0,0, 0,
    0,0,0,0,0,0,0, 0,0,
    0,0,0,0,0,0, 1,0,0,
    0,0,0,0,0, 1,0,0,0,
    0,0,0,0, 0,0,0,0,0,
    0,0,0, 0,0,0,0,0,0,
    0,0, 0,0,0,0,0,0,0,
    0, 0,0,0,0,0,0,0,0,
     0,0,0,0,0,0,0,0,0
  }}

As you see it's really not optimal.

Because numbers of neighbors in each state add up to N, there are only (N + S - 1)! / (N! (S - 1)! elements used on the N^S in each sub array.

I run out of ideas, so I hope you might help find a better way to store my rules.

Answers

  • You could check previous related posts: https://forum.processing.org/two/search?Search=automata

    Shiffman devotes a chapter in his book: http://natureofcode.com/book/chapter-7-cellular-automata/

    Kf

  • I already did these. Unfortunately, I think my problem is kind of specific

  • edited March 2017 Answer ✓

    Do all cells have the same rule?

    So either you just program it like

    int newCellStateIs (int oldState, int[] statesOfNeighbours){ 
    
        // rule
    
    
        int N = countNeighbours(statesOfNeighbours); 
    
        return oldState * N; 
    
    }
    

    Or you invent rule language in Strings like "n+n*o" and store that for each cell differently

  • edited March 2017 Answer ✓

    @yaya671 -- This is unclear to me:

    we count the number of neighbors in each state and then use a list of rules indicating what state is gonna take that cell in function of the number of neighbors in each state and the cell's actual state.

    Do you mean like this?

    int cellUpdate (int cellState, int[] neighborStateCounts, RuleList rules) {
      int newState
      ... do something with rules ...
      return newState;
    }
    

    I'm surprised that Shiffman's chapter section 7.6 wasn't helpful.

    If you don't want to program your rules list there are options other than a sparse matrix -- in the general case you are essentially loading programmed rules from a data format into RuleList, e.g.:

    state, neighborPattern, newstate
    

    ... where "neighborPattern" supplies a configuration to a boolean function that acts on neightborStateCounts and, if true, sets state to newstate.

    Edit: looks like Chrisir beat me to some of this.

    This dynamic programming problem isn't specific to cellular automata, by the way -- it would come up any time you asked "how to I parameterize a general purpose comparator?" The easiest way of all of course is to write your rules in Processing (that is, Java -- a general purpose programming language). You could also try to dynamically load Java rules (e.g. using ClassLoader / URLClassLoader) -- but I believe this can be extremely fiddly.

  • Chrisir, yep, the rules are for all cells. But you mean I should access the rules by creating a string from the number of neighbours in each state and then use it in a Hash Table or something like that to find the rule?

  • I'm French, so I may miss some of the vocabulary, but if I understood you say I should use some kind of data format? I think I can go on from that, still it don't seem to be the most elegant way. Oh, and since Processing is based on Java, you can be sure I know about it ^^

  • edited March 2017 Answer ✓

    @yaya671 -- To clarify what I meant by mentioning Java -- when you said "My question is about how to stock and access the rules"

    ...the typical way to specify your rules is to write them in code -- e.g. Processing or Java code, like a switch statement or a bunch of if statements (rule checks). This is how the Game of Life example works in Shiffman's The Nature of Code 7.6. If you need multiple rulesets, write multiple batches of if statements and call one batch based on what ruleset you are using.

    So far, this is easy to do, and you just write it in Processing. Lots of if statements. Three rules? Three if checks. Five rules? Five if checks.

    HOWEVER, unlike the Shiffman example which you have already read, you seem to want to keep your rules in a data structure... presumably to be able to load different rule sets at runtime? In that case, you need a data structure that can be executed as a series of if statements. That is a pain when you try to model a "general purpose" approach to lots of types of potential rules, such as

    • neighborCount = m
    • neighborCount with state n = m
    • neighborCount with state n > m
    • neighborCount % n = m
    • ...etc.

    Eventually you need to either limit the kinds of rules you can write or you need to start creating a data format that is a mini programming language (as @Chrisir notes). Or you could just load code dynamically, as I pointed out -- although this can be a pain.

    When you say "it don't seem to be the most elegant way" I'm still not sure what you mean. Programming is the elegant way to define rules. However, it seems you are asking for some alternative.

  • edited March 2017 Answer ✓

    Or you could just load code dynamically, ...

    Java is already bundled w/ a JS script language spin-off called Nashorn: \m/
    https://forum.Processing.org/two/discussions/tagged?Tag=#nashorn

  • So far, this is easy to do, and you just write it in Processing. Lots of if statements. Three rules? Three if checks. Five rules? Five if checks.

    I can't write my rules directly in the code because of the generality I want. The problem is that there'll be different number of rules in function of the number of neighbors. I could write nested for (one for each state) and go through the rules, but then comes the fact that there's no fixed number of states.

    When you say "it don't seem to be the most elegant way" I'm still not sure what you mean.

    For example, with 3 different states and N neighbours, you can represent the rules in a 3 dimensional space such as the point (x, y, z) corresponds to the rule with x neighbours in state 0, y in state 1 and z in state 2. You can see that the possible rules (rules (x, y, z) with x + y + z = N) form a plane passing by (0, 0, N), (0, N, 0), (N, 0, 0). Use that fact to stock the rules would be elegant to me!

  • edited March 2017 Answer ✓

    This explanation of 8 states and 8 outputs is relevant ...

    Just treat rule as a concatenation of the 3 bit results for each of the 8 possible inputs. For example, if you map 0-4 to 6, 5 to 0, and 6-7 to 7, the bits of rule might look like (going from 7-0, parentheses added just for clarity): (111)(111)(000)(011)(011)(011)(011)(011) Then to pick a specific result out of rule, you can use shift and bitwise and. For example, if n = 4, we shift rule right by 4*3 bits: (111)(111)(000)(011) And then we do a bitwise and with 7: (011)
    In other words, it'd just be return (rule >> (n*3)) & 7;
    I probably have a few extra parentheses in there, but I'm too lazy to double-check precedence. - ErasmusDarwin

    So, It's hard to know exactly what you want when you say S and N,
    But just assuming you want 4 neighbors that can be 0 or 1, and want as many states as possible from them you get 16 states, and mapped to 0 or 1, that's 2 output's
    so 2^16 ≈ 65K rules

    You don't store these rules, you calculate them on the fly as such...

    state = (Neigbour1?1:0)+(Neighbour2?2:0)+(Neighbour3?4:0)+(Neighbour4?8:0);  
    cell = (( ( rule >> state ) & 1) == 1) ? 1:0;  
    

    If you want more possibilities than 4-neighbors 0/1 use this guideline

    rule = the "seed" you change to get new results state = a number representing a state you wish to convert into an output
    n = least number of bits needed to represent highest output
    o = highest output

    ( rule >> ( state * n ) ) & o;

    This works guaranteed. If you don't know how to use it or tweak it, read the quote at the top or show your code and what you want it to do I'll show you where to put it.

    or an example how to use it in practice in Wolfram automata, but it's the same principle... look at line 16 and 17

    int swap,xyz=200,rule=0;
    boolean[][][] fields = new boolean[2][xyz][xyz];
    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] = 0;}}}
    }
    void setup(){size(200,216);clear();loadPixels();}
    boolean algorithm(int d,int x0,int y0) {
        fields[0][100][0] = fields[1][100][0] = 1;
        up=(y0+xyz-1)%xyz;  
        boolean n1=fields[swap][(x0+xyz-1)%xyz][up];
        boolean m=fields[swap][x0][up];
        boolean n2=fields[swap][(x0+1)%xyz][up];
        int state = (n1?4:0)+(m?2:0)+(n2?1:0);
        return (((rule >> state) & 1) == 1)?1:0;
    }
    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);
      textSize(12);text("Rule = #"+str(rule),12,xyz+12);
    }
    void mouseClicked(){ if (mouseButton==LEFT) {clear();rule++;}
                    else if (mouseButton==RIGHT){clear();rule--;} rule=abs(rule%256);}
    
  • if you look into processing, menu file|examples, there are 4 CA under topics

    I was also saying store rules in Strings; for an example look at section Fractals and L-Systems and here PenroseTile under topics (which are not CA)

  • edited March 2017

    rule = the "seed" you change to get new results state = a number representing a state you wish to convert into an output

    I may not have been clear about it, the rules are given to the cellular automata at its initialisation. Still, maybe it's possible to obtain the rule value from the rules, which seems possible since it has to be calculated only once.

    If you wanna look at my code :

    class CellAut {
      protected int[] cells,
                      dim, //size in each dimension
                      dimSize;
      protected boolean[] junctions;
      protected int[][] neighbors,
                        rules;
      color[] states;
      CellAut(int[] dim, boolean[] junctions, color[] states, int[][] rules) {
        this.dim = dim;
        dimSize = new int[dim.length];
        dimSize[0] = 1;
        for (int i = 0; i < dim.length - 1; i++) dimSize[i + 1] = dimSize[i] * dim[i];
        this.junctions = junctions;
        this.states = states;
      }
    
      void iterate() {
        for (int i = 0; i < cells.length; i++) {
          int[] coords = getCoords(i);
          int[] neighborStates = new int[states.length];
          for (int neighborIndex : getNeighborsIndexes(coords)) {
            neighborStates[cells[neighborIndex]]++;
          }
        }
      }
    
      int[] getNeighborsIndexes(int[] coords) {
        int[] neighborsIndexes = new int[neighbors.length];
        for (int i = 0; i < neighbors.length; i++) {
          boolean exists = true;
          int[] neighborCoords = new int[dim.length];
          for (int d = 0; d < dim.length; d++) {
            int coordD = coords[d] + neighbors[i][d];
            exists &= coordD < dim[d] || junctions[d];
            if (!exists) break;
            neighborCoords[d] = coordD % dim[d];
          }
          neighborsIndexes[i] = exists ? getRuleIndex(neighborCoords) : -1;
        }
        return neighborsIndexes;
      }
    
      int getRule(int actualState, int... statesCount) {
        if (statesCount.length != states.length) return -1;
        //TODO
      }
    
      boolean setRule(int state, int actualState, int... statesCount) {
        if (statesCount.length != states.length || state < 0 || state >= states.length) return false;
        rules[actualState][getRuleIndex(statesCount)] = state;
        return true;
      }
      protected int[] getCoords(int index) {
        int[] coords = new int[dim.length];
        for (int i = 0; i < dim.length - 1; i++) {
          coords[i] = (index % dimSize[i + 1]) / dimSize[i];
          index -= coords[i];
        }
        coords[dim.length - 1] = index / dimSize[dim.length - 1];
        return coords;
      }
    }
    
  • edited March 2017

    I looked at your code but couldn't run it and reading it didn't make me much wiser where to put the rule.
    However I read your original post again and have a couple questions about how much generality you want.

    0,0,0,0,0,0,0,0, 
    0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,
    0,0,0,0,1,0,0,0,0
    0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0
    

    Would you like a standard game of life rules but with up to 64 neighbours,
    or any kind of boolean rule you want with up to 6 neighbours.
    If you wan't any of those two I can make a rough sketch for you to tweak (but not today), if it's more complex or more general than that then maybe next year.

  • By standard, you mean for example in these two cases :

     0         1
    121  and  021
     2         2
    

    the same rule will apply? If that's so, yeah that's what I want. As it's for personal purposes, I don't think I will ever use 64 neighbours, so your solution is really good PS: I missclicked, I marked your post in Not an answer, how do I change that?

  • edited March 2017

    By standard, you mean for example in these two cases : case1 and case 2, the same rule will apply?

    Short answer, yes..

    I haven't made a game of life automaton to be honest, but I think I have a pretty good idea on how to make one as I made something similar.

    https://forum.processing.org/two/discussion/21070/smooth-paintbrush#latest

    the black box is this ( rule >> ( state * n ) ) & o; thing

    It's a little bit over-complicated as is but I could simplify it into doing game of life (I think) and remove some unnecessary stuff that's not needed in "that game" and use the black box to generate different variations.
    I have one idea that you could "paint" the rule (kind of like filling in a lottery ticket") so that you get a visual representation of the rule rather than an incomprehensible number. But exactly how to vary the rules depends on how you wan't to vary them and and what's manageable. The rules get's very large with very little added complexity, kind of like the number of ways you could fill in a lottery ticket. So when you wan't generality you need some constrain on the generality or you'll get unmanageable large numbers , and you can't use float's for this you must use int's so it's also a computational problem if the generality is too general. Sorry for talking too much

  • edited March 2017

    @yaya671

    NEVER MIND THIS POST, SCROLL DOWN FURTHER

    I removed some of the fluff not necessary, (could probably simplify it more but it's a start) and tweaked it a regular game following this rule

    Any live cell with fewer than two live neighbours dies, as if caused by underpopulation. Any live cell with two or three live neighbours lives on to the next generation. Any live cell with more than three live neighbours dies, as if by overpopulation. Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.

    in code I wrote this as such...

    if ( ( val[0]==#000000 && c==2 ) || c==3 ) { r=#000000; } 
    else { r=#ffffff;} 
    

    And pressing the R-key toggles to a rule mode, and W and S cycles through 1024 standard rules. 9 neighbours (including the cell itself as a neighbour) makes 10 states, 2^10 = 1024.. Didn't double and triple-check that it's accurate but it's something.

    What I mean't by standard in other words is that all cells has the same significance on the state as such...

     state = Neigbour1?1+Neighbour2+Neighbour3...`
    

    and what I meant by any kind
    Is the states having different significane, as power of 2 like in a wolfram automaton
    state = (Neigbour1?1:0)+(Neighbour2?2:0)+(Neighbour3?4:0)+(Neighbour4?8:0);

    The difference being in the standard way it makes no difference which neighbors are alive just how many, and in the other one it matters.

    And that makes a huge difference, you'd have, hold on....
    2^1024 rules...
    Which is the range of double, and you can NOT use float's for this kind of thing.
    With an int you're lineighbours5 neighbors(including yourself) or 6 for a long, half of the rules will be negative but it doesn't matter too much, just means the rules will come in a different order.
    You could use multiple int's to push but I wouldn't bother with that.

    So.. the code below is a standard game of life with 1024 standard rules,
    paint black with left mouse, white with right, R to toggle between using rules or not and W and S to cycle rules, bear in mind I could have made some error in my code or explanation.
    I'm afraid it's not what you were looking for but I hope it's helpful

  • @yaya671 I wonder if my error is counting the cell as a neighbor is the error?
    I just assumed game of life was dead or alive, but it was separated into three...
    born,stay alive, and die

    Also maybe that's why you used 2 in this?

    0         1
    121  and  021
     2         2
    

    Just realized it now.

    So if this is the key to making variants of game of life, the black box should make 3 outputs..

    If that is so, some of my previous statements may be false.

    But I should probably read up on it rather than guess

  • edited March 2017

    oh yes...
    I got something working separating born and stay alive,
    ill clean up the code and fix some small errors another day..

        boolean use_rule = true;
        int rule = 12304;
        boolean [] bit_rule = new boolean[16];
    
        int paint;
        int bw;
        int dis;
        int speed;
        int xyz=256;
        field life;
        void setup(){size(256,256,P2D);life = new field();loadPixels();}
        void draw() {
            speed=floor(dist(pmouseX,pmouseY,mouseX,mouseY));
            if(mousePressed){
              if(mouseButton==LEFT) {
                paint = #000000;
                } else { paint = #ffffff; }
            }
          life.update();
    
          if(use_rule){
              for(int i=0; i<16; i++){
               bit_rule[i] = ( ((rule >> 15-i) & 1) == 1);
               bw = bit_rule[i]?#000000:#ffffff;
               fill(bw);
               rect(i*16,0,16,16);
               fill(#ff0000); textSize(30); text("Rule #" + str(rule),20,240);
          }
        }
        }
        void mouseClicked(){
          int foo;
          if (mouseY<16){
            foo = max(0,min(15,mouseX/16));
            bit_rule[foo] = bit_rule[foo]?false:true;
            rule+=pow(2,15-foo)*(bit_rule[foo]?1:-1);
            life = new field();
          }
        }
    
        void keyPressed() {
          if(key == 'r' || key == 'R' ){use_rule=use_rule?false:true;}
          if(key == 'w' || key == 'W' ){rule+=2;}
          if(key == 's' || key == 'S' ){rule-=2;}
         rule=max(0,min(1023,rule));
         life = new field();
        }
    
        class field {
          subdivision[][] world;
          field() {
              world = new subdivision[xyz][xyz];
              for (int y = 0 ; y < xyz; y++) {
              for (int x = 0 ; x < xyz; x++) {
                world[x][y] = new subdivision(x,y,new int[]{#ffffff});
              }}
              for (int y = 0 ; y < xyz; y++) {
              for (int x = 0 ; x < xyz; x++) {
                world[x][y].set_neighbours(this.world);
            }}
          }
        void update(){
          for (int y=0;y<xyz;y++){
          for (int x=0;x<xyz;x++){
            world[x][y].update_cell();
          }}
          updatePixels();
          for (int y=0;y<xyz;y++){
          for (int x=0;x<xyz;x++){
              world[x][y].buffer_cell();
          }}
        }
        }
        class subdivision{
          int r=#ffffff; // results
          int val[]; // value
          int x,y; // coordinate of the pixel
          int xy; // x,y in one dimensional framebuffer
          int [][] neighbours;
          subdivision(int X, int Y, int[] VAL){
                        x=X;   y=Y; val=VAL;
                        xy = x+xyz*y;
                        neighbours = new int [8][1];
          }
          void set_neighbours(subdivision[][] world){
            int x1,x3,y1,y3;
              x1=(x+1)%xyz; x3=(x+xyz-1)%xyz; // 3 is -1 as it "wraps around"
              y1=(y+1)%xyz; y3=(y+xyz-1)%xyz;
              // surrounding pixels clockwise
              neighbours[ 0] = world[x1][y3].val;
              neighbours[ 1] = world[x1][ y].val;
              neighbours[ 2] = world[x1][y1].val;
              neighbours[ 3] = world[ x][y1].val;
              neighbours[ 4] = world[x3][y1].val;
              neighbours[ 5] = world[x3][ y].val;
              neighbours[ 6] = world[x3][y3].val;
              neighbours[ 7] = world[ x][y3].val;  
          }
    
          /* Thanks to u/ErasmusDarwin */
          //int blackbox(int n,int rule){return int((rule>>n)&0x1);}
    
          void update_cell() {
            dis=floor(dist(mouseX,mouseY,x,y));
            int c=0;   // comparission
              if(mousePressed && dis<1+speed) {
                r = paint;
                } else {
                for (int n=0; n<8; n++){
                if ( neighbours[n][0] == #000000 ) {c++;}
                }
                c=max(0,min(7,c));
    
                // custom rules
                if(use_rule){
                  if ( (val[0]==#000000 && bit_rule[c]) || bit_rule[c+8] ) { r=#000000; } else { r=#ffffff; }
    
                }
    
               else{ if ( ( val[0]==#000000 && c==2 ) || c==3 ) { r=#000000; } else { r=#ffffff; } }
    
                }
            pixels[xy] = r;
          }
          void buffer_cell() {val[0]=r;}
        }
    
  • edited March 2017

    Made a less confusing way to input the rules,
    8 boxes saying dead,alive,born left to right

    There's a bug with "box" number one though, it's seems to be box number 0, :S

    Box 0 is shit, because if you start with a dead canvas and say for 0 live neighbours the cell will be born, the next step all cells will live, and look at rule for 8 neighbours which sais they'll all die, which causes this strobe bug...
    soo I "disabled it" not so cleverly until I fixed it.. The other boxes seems to work as expected.

    Let's assume you fix box 1, then you have ≈ 6500 different combinations, but it's converted into 16bits of an int which has ≈ 65K combinations..
    Which is a problem if you want to traverse through all possible combinations in order, as you'll be going through 10 times as many duplicates.
    This is not a problem if you're fine with clicking boxes though.

    int rule = 36;
    //boolean [] bit_rule = new boolean[16];
    String [] cell_text = {"DEAD","ALIVE","BORN"};
    int [] cell_text_color = {#ff0000,#00ff00,#ffffff};
    int [] cell_bg_color = {#ffffff,#aaaaaa,#000000};
    int [] bit_rule = new int[8];
    int paint;
    int bw;
    int dis;
    int speed;
    int xyz=256;
    field life;
    /* Thanks to u/ErasmusDarwin */
      int blackbox(int n,int rule){return min(2,((rule>>(n*2))&3));}
    void setup(){
      size(256,304,P2D);
      life = new field();
      loadPixels();
      textAlign(CENTER, CENTER);
      textSize(10);
    }
    void draw() {
        speed=floor(dist(pmouseX,pmouseY,mouseX,mouseY));
        if(mousePressed){
          if(mouseButton==LEFT) {
            paint = #000000;
            } else { paint = #ffffff; }
        }
      life.update();
      fill(0);
      rect(0,xyz,xyz,16);
        for(int i=0; i<8; i++){
      bit_rule[i] = blackbox(i,rule);
      fill(255);
      text(str(i+1),i*32+16,xyz+7);
      fill(cell_bg_color[bit_rule[i]]);
      rect(i*32,xyz+16,32,32);
      fill(cell_text_color[bit_rule[i]]);
      text(cell_text[bit_rule[i]],i*32+16,xyz+32);
      }  
    }
     void mouseClicked(){
      int foo;
      int bar;
      if (mouseY>xyz){
        foo = max(0,min(31,mouseX/32));
        bit_rule[foo] = (bit_rule[foo]+1)%3;
        bar = (bit_rule[foo]==0)?-2:1;
        rule+=pow(4,foo)*bar;
        life = new field();
      }
    }
    void keyPressed() {
      if(key == 'w' || key == 'W' ){rule+=1;}
      if(key == 's' || key == 'S' ){rule-=1;}
     rule=max(0,min(0xffff-1,rule));
     life = new field();
    }
    
    class field {
      subdivision[][] world;
      field() {
          world = new subdivision[xyz][xyz];
          for (int y = 0 ; y < xyz; y++) {
          for (int x = 0 ; x < xyz; x++) {
            world[x][y] = new subdivision(x,y,new int[]{#ffffff});
          }}
          for (int y = 0 ; y < xyz; y++) {
          for (int x = 0 ; x < xyz; x++) {
            world[x][y].set_neighbours(this.world);
        }}
      }
    void update(){
      for (int y=0;y<xyz;y++){
      for (int x=0;x<xyz;x++){
        world[x][y].update_cell();
      }}
      updatePixels();
      for (int y=0;y<xyz;y++){
      for (int x=0;x<xyz;x++){
          world[x][y].buffer_cell();
      }}
    }
    }
    class subdivision{
      int r=#ffffff; // results
      int val[]; // value
      int x,y; // coordinate of the pixel
      int xy; // x,y in one dimensional framebuffer
      int [][] neighbours;
      subdivision(int X, int Y, int[] VAL){
                    x=X;   y=Y; val=VAL;
                    xy = x+xyz*y;
                    neighbours = new int [8][1];
      }
      void set_neighbours(subdivision[][] world){
        int x1,x3,y1,y3;
          x1=(x+1)%xyz; x3=(x+xyz-1)%xyz; // 3 is -1 as it "wraps around"
          y1=(y+1)%xyz; y3=(y+xyz-1)%xyz;
          // surrounding pixels clockwise
          neighbours[ 0] = world[x1][y3].val;
          neighbours[ 1] = world[x1][ y].val;
          neighbours[ 2] = world[x1][y1].val;
          neighbours[ 3] = world[ x][y1].val;
          neighbours[ 4] = world[x3][y1].val;
          neighbours[ 5] = world[x3][ y].val;
          neighbours[ 6] = world[x3][y3].val;
          neighbours[ 7] = world[ x][y3].val;  
      }
     void update_cell() {
        dis=floor(dist(mouseX,mouseY,x,y));
        int c=-1;   // comparission
          if(mousePressed && dis<1+speed) {
            r = paint;
            } else {
            for (int n=0; n<8; n++){
            if ( neighbours[n][0] == #000000 ) {c++;}
            }
            c=max(0,min(8,c));
            // custom rules
            if(c!=0){ // disbled "box" 1 as it acts like box 0
            if ( ( val[0]==#000000 && blackbox(c,rule)==1 ) || blackbox(c,rule)==2 ) { r=#000000; } else { r=#ffffff; }
            }else { r=#ffffff; }
        pixels[xy] = r;
        }
      }
      void buffer_cell() {val[0]=r;}
    }
    
  • edited March 2017

    I wonder if my error is counting the cell as a neighbor is the error? I just assumed game of life was dead or alive, but it was separated into three... born, stay alive, and die

    Also maybe that's why you used 2 in this?

    You did great work, thanks to that, but yeah... no. I'm sorry if I hadn't been understandable from the beginning, my bad.

    Let's try to redo the explanation: It's an orthogonal cellular automaton defined by a class, in a number of dimensions D. Each cell is in one of the S states, and at each generation, we apply "standard" synchronous rules taking in function the states of its N neighbors and its own state (the set of rules and the set of neighbors* are the same for each cells). D, S, the set of neighbors and the rules are passed in argument in the constructor of the class.

    The question is about stocking the rules. For example, in GoF, there's no rule corresponding to 3 alive and 6 dead neighbors, because 3 + 6 != 8. It seems like there would be no problem by bothering only the number of alive neighbors, which is true. But it will not be possible with 3 or more states. The possible optimization I search should come from the fact that the sum of neighbors in each state will always be N

    *a neighbor is defined by relative coordinates. For example, the Moore neighborhood (used in GoF) is {{-1, -1}, {0, -1}, {1, -1}, {1, 0}, {1, 1}, {0, 1}, {-1, 1}, {-1, 0}}. A cell isn't its own neighbor, except of course if explicitely said so by having {0, 0} in neighbors list.

Sign In or Register to comment.