Howdy, Stranger!

We are about to switch to a new forum software. Until then we have removed the registration on this forum.

  • Clustering pixels in an image by colour over time

    @daddydean -- if you want pixels to be moving through a grid with no negative space, then you probably want pixel swapping behaviors -- and it is quite likely that your swapping behaviors are part of a cellular automaton for pixels.

    The good news is that there is tons of code out there (and on this forum) for cellular automata.

    There is some bad news. One is that writing simple rules for pixel swapping (for example, giving each pixel a goal location and having it swap in the direction of that goal) and then applying it to every pixel in a grid will create some pretty crazy artifacts -- stable spaces of pixels in the final arrangement that seem to have nothing to do with your understanding of the original values and the goals.

    For just one example, two pixels facing in the same direction may be frozen forever swapping with each other. This can create bands, dead zones, and all kinds of oddities where you expect pixels to self-organize nicely.

    Thing get a bit better if you add complications like:

    1. randomly sample which pixels get to move each turn
    2. let pixels swap at different distances depending on how far they are from their goal, with further pixels swapping farther
    3. add random jitter to pixel swapping so that they don't always head straight for the goal

    Approaches like these can things can break up log-jams and create more fluid outcomes.

    PixelMovers4-a PixelMovers4-b

    There is more bad news, however. 2D cellular automata are not reversible unless they are broken into blocks and each block is updated with an invertible function...

    ...so you aren't going to be able to play your 2D cellular automaton backwards algorithmically. Two approaches that might work, however:

    1. record every frame (of data or an image), like a movie, then play the frame recordings back in reverse order, or:

    2. Pair every single pixel in the outcome with a target pixel in the original image, then have them seek again until they finally reassemble the original image -- it almost certainly won't be the same shuffle, but it will arrive at the origin.


    Models of a big group of things all shuffling around in a space and heading in their own directions is actually of interest in flocking, traffic analysis, et cetera. Normally the space isn't perfectly dense the way an image is, but see for example "A Cellular Automaton model for pedestrian counterflow with swapping" https://www.sciencedirect.com/science/article/pii/S037843711730122X

  • how can I export this cellular automata files in pdf??

    edit post, highlight code, press ctrl-o to format.

    the pdf examples linked to from the libraries part of the website are some of the best documentation there.

    that said, 'automata' and 'pdf' isn't a great match

  • how can I export this cellular automata files in pdf??

    help, I am a complete beginner.. I found this code on open processing and I would like to export the frames in pdf. who can help me? thank you very much

    code cellular automata:

    class CellularAutomata
    {
      // tape: a tape of symbols indexed by integers
      int[] tape;
    
      // NS: the neighborhood size
      int NS = 7;
    
      // ruleset: an array encoding the rules of this cellular automata
      int[] ruleset;
    
      // iterations: the iteration count
      int iterations;
    
      // maxIterations: the maximum number of iterations we will draw on the canvas
      int maxIterations;
    
      CellularAutomata(int N)
      {
        // randomly initialize the tape contents
        tape = new int[N];
        for(int i = 0; i < tape.length; i++)
        {
          tape[i] = (int)random(2);
        }
    
        maxIterations = (tape.length)*(height/width);
    
        iterations = 0;
    
        ruleset = new int[(int)pow(2,NS)];
        for(int i = 0; i < ruleset.length; i++)
        {
          ruleset[i] = (int)random(2);
        }
      }
    
      // based on the tape contents and the cellular automata's rules, update the tape contents
      void updateTape()
      {
        // because we want the update process to be a synchronous one, we need to store the updated contents on an auxiliary array
        int[] newtape = new int[tape.length];
    
        // for each position 'i' in the tape
        for(int i = 0; i < tape.length; i++)
        {
          // we take the tape contents in the positions adjacent to 'i'
          int[] neighbor = new int[NS];
          for(int j = 0; j < NS; j++)
          {
              neighbor[j] = tape[ (i+(j-(int)(NS/2))+tape.length)%(tape.length) ];
          }
    
          // we compute the updated state for position 'i' through the cellular automata's rules
          newtape[i] = rules(neighbor);
        }
    
        // now we can replace the old tape with the updated contents
        tape = newtape;
    
        iterations++;
      }
    
      /**
        we can very easily encode a ruleset through an array of length 2^NS
        reasoning:
          1. there are 2^NS possible combinations of values for the NS binary variables in 'neighbors'
          2. the rule for each of these combinations can be encoded on a given index of an (2^NS)-sized array
          3. we can sort these combinations through a lexicographic ordering
      */
    
      int rules(int[] neighbor)
      {
        int index = 0;
    
        for(int i = 0; i < NS; i++)
        {
          index += ((int)pow(2,NS-i-1))*neighbor[i];
        }
    
        return ruleset[index];
      }
    
      void draw()
      {  
        for(int i = 0; i < tape.length; i++)
        {
          if(tape[i] == 1) fill(255);
          else fill(0);
    
          // L: cell side length
          float L = float(width)/float(tape.length);
    
          rect
          (
            i*L,
            iterations*L,
            L,
            L
          );
        }
      }
    }
    
    CellularAutomata CA;
    
    void setup()
    {
      size(512,512);
      background(0);
      noStroke();  
      frameRate(10000);
    
      CA = new CellularAutomata(width);
    }
    
    void draw()
    {
      CA.draw();
      CA.updateTape();
    }
    
    void mousePressed()
    {
      background(0);
      CA = new CellularAutomata(width);
      draw();
    }
    
  • Why won't my CA work?

    I'm trying to implement a simple cellular automata in processing and I've run into a strange problem. My code is here. I have a methods that change the state of two arrays, currentArray and nextArray, but for some reason I am having trouble changing the values in the array. I run the program and any changes I make don't seem to stick. Is this some sort of scope problem? I'd appreciate any help you can offer.

  • Specific neighbourhoods in the Game of Life

    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

  • Cellular automaton's rules storage

    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;
      }
    }
    
  • Cellular automaton's rules storage

    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);}
    
  • Cellular automaton's rules storage

    @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.

  • Polarized Perpendicular Photons

    Applied the celluar automata concept of looking at just two neighbours and putting white or black rather their color.
    And rule 90 emerged again, together with rule 30.
    I don't know how i'd apply this to the quanta though.

    https://www.openprocessing.org/sketch/410830 <- EDIT:
    rewrote the old code into a carbon copy of wolfram's automata, with rules in correct order

    Also I looked at GLSL shaders which looked really difficult so I'll have to find some other way to speed things up for the 2D and 3D stuff, maybe multithreading or AVX, whatever works and isn't too big of a hurdle

  • "Smooth paintbrush"

    This was supposed to be a celluar automata kind of thing but it was blinking so annoyingly.
    Got a smoother turbulence thing going and added random painting to it which looks pretty cool in motion.

    paint

    https://youtube.com/watch?v=cd-ZNymt6Ko&feature=youtu.be

    newer video -> https://youtube.com/watch?v=cbCyq5RMXLk

    leftclick, paint, rightclick erase

    Update2,

    Faster version any key changes "rule"

    int button;
    int speed;
    int paint; 
    int xyz;
    int vdit;
    int[] field;
    int[] b;
    boolean closerThan(int distance,int x0,int y0){
      int dx = x0-mouseX; dx*=dx;
      int dy = y0-mouseY; dy*=dy;
    return dx+dy<distance;}
    int sts (int l){ return ((l%4==0)?0:2)*((floor(l/4)%2==1)?-1:1);}
    int[] pbox(int n, int layer){
    int px,py,xt,yt; xt=yt=0;
      px=(layer%2==0)?0:1;
      py=(layer<=1)?0:1;
      if(n<=7){ xt=px==0?1:-1;}
      else    { yt=py==0?1:-1;}
      xt += sts(n);
      yt += sts(n+2);
      return new int[]{xt,yt};
    } 
    int[] pboxresult = new int[2];
    int[][] overview = { 
    { 1,2,3,2,3,0,3,-2, 1,-2,-1,-2,-1,0,-1,2,0,3,2,3,2, 1,2,-1,0,-1,-2,-1,-2, 1,-2,3},
    {-1,2,1,2,1,0,1,-2,-1,-2,-3,-2,-3,0,-3,2,0,3,2,3,2, 1,2,-1,0,-1,-2,-1,-2, 1,-2,3},
    { 1,2,3,2,3,0,3,-2, 1,-2,-1,-2,-1,0,-1,2,0,1,2,1,2,-1,2,-3,0,-3,-2,-3,-2,-1,-2,1},
    {-1,2,1,2,1,0,1,-2,-1,-2,-3,-2,-3,0,-3,2,0,1,2,1,2,-1,2,-3,0,-3,-2,-3,-2,-1,-2,1}
    };
    
    int[][] compare = new int[4][32];
    int[][] transform = new int[4][32];
    long RULE;
    long randomlong(){
      long result = floor(random(0,65536));
      for(int i=0;i<3;i++){
      result<<= 24;
      result+=floor(random(0,16777216));
      }
      return result;
    }
    void compare_update(){
    for(int i=0; i<4; i++){
    for(int j=0; j<16; j++){
    compare[i][j*2  ] = overview[i][j*2  ]; // map(overview[i][j*2  ],-width,width,-1,1);
    compare[i][j*2+1] = overview[i][j*2+1]; // map( -height,height,-1,1);
    }}}
    void transform_update(){
    for(int i=0; i<4; i++){
    RULE = randomlong();
    for(int j=0; j<16; j++){
    pboxresult = pbox(int((RULE>>(j*4))&15),i);
    transform[i][j*2  ]=pboxresult[0];
    transform[i][j*2+1]=pboxresult[1];
    }}}
    
    void setup() {
      size(384, 384);
      xyz=width*height;
      field=new int[xyz];
      b=new int[xyz];
      loadPixels();
      compare_update();
      new_rule();
    }
    
    void keyPressed(){
      new_rule();
    }
    void new_rule(){
      transform_update();
    }
    int frag(int p){
      int x=p%width;
      int y=p/width;
      int comp=0;
      int mine;
    
      if(mousePressed && closerThan(speed,x,y)){ 
        return paint;
    } else { 
      int mylayer = (x%2==0?0:1)+(y%2==0?0:2);
      mine = b[p];
      for(int i =0; i<15; i++){
      comp +=((b[((x+compare[mylayer][i*2]+(y+compare[mylayer][i*2+1])*width)+xyz)%xyz]<mine)?1:0);
      }
      return b[((x+transform[mylayer][comp*2]+(y+transform[mylayer][comp*2+1])*width)+xyz)%xyz];
    }
    }
    void worker_a(){
      for(int p=0; p<xyz; p++){
        b[p]=pixels[p]=field[p];
      }
    }
    void worker_b(){
      for(int p=0; p<xyz; p++){
        field[p]=frag(p);
      }
    }
    void draw(){
      println(frameRate);
      if(mousePressed){
      if( mouseButton == LEFT ){
        button=1;
        paint=floor(random(#000000,#ffffff));
      } else{button =2; paint=#fffffe;}
    }
      else { button = 0; }
      speed = int(sq(mouseX-pmouseX)+sq(mouseY-pmouseY)); // intentionally not using sqrt()
      rect(0,0,width,height);
      thread("worker_a");
      thread("worker_b");
      updatePixels();
    }
    

    Object oriented version

    int paint;
    int dis;
    int speed;
    int rulecounter;
    int smooth = 1;
    int xyz=256;
    field g;
    int randomcolor(){return floor(random(#000000,#ffffff));}
    void setup(){size(256,256,P2D);g = new field();loadPixels();}
    void draw() {
        speed=floor(dist(pmouseX,pmouseY,mouseX,mouseY));
        if(mousePressed){
          if(mouseButton==LEFT) {
            paint = randomcolor();
            } else { paint = #ffffff; }
        }
      g.update();
      g.display();
      if(rulecounter++%100==0){g.randomrule();}
    }
    class field {
      subdivision[][] rid;
      long[] RULE;
      field() {
          RULE = new long[4];
          randomrule();
          int[] VAL;
          rid = new subdivision[xyz][xyz];
          for (int y = 0 ; y < xyz; y++) {
          for (int x = 0 ; x < xyz; x++) {
            VAL = new int []{#ffffff,#ffffff,#ffffff,#ffffff};
            rid[x][y] = new subdivision(x,y,VAL,RULE);
          }}
          for (int y = 0 ; y < xyz; y++) {
          for (int x = 0 ; x < xyz; x++) {
            rid[x][y].set_neighbours(this.rid);
        }}
      }
    long randomlong(){
      long result = floor(random(0,65536)); 
      for(int i=0;i<3;i++){
      result<<= 24;
      result+=floor(random(0,16777216));
      }
      return result;
    }
    void randomrule(){
      RULE[0] = randomlong();
      RULE[1] = randomlong();
      RULE[2] = randomlong();
      RULE[3] = randomlong();
    }
    void update(){
      for (int y=0;y<xyz;y++){
      for (int x=0;x<xyz;x++){
        rid[x][y].update_pixels();
      }}
    }
    void display(){
      updatePixels();
      for (int y=0;y<xyz;y++){
      for (int x=0;x<xyz;x++){
          rid[x][y].buffer();
      }}
    }
    }
    class subdivision{
      long [] rule;
      int [] ra; // results array
      int [] val; // value array
      int x,y; // coordinate of the pixel
      int xy; // x,y in one dimensional framebuffer
      int [][] neighbours;
      subdivision(int X, int Y,    int[]VAL, long[]RULE){
                    x=X;   y=Y;     val=VAL;  rule=RULE;
                    xy = x+xyz*y;
                    neighbours = new int [8][4];
                    ra = new int [4];
      }
      void set_neighbours(subdivision[][] rid){
        int x1,x3,y1,y3;
        for ( int i=0; i < 4; i++) {
          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] = rid[x1][y3].val;
          neighbours[ 1] = rid[x1][ y].val;
          neighbours[ 2] = rid[x1][y1].val;
          neighbours[ 3] = rid[ x][y1].val;
          neighbours[ 4] = rid[x3][y1].val;
          neighbours[ 5] = rid[x3][ y].val;
          neighbours[ 6] = rid[x3][y3].val;
          neighbours[ 7] = rid[ x][y3].val;  
        }
      }
    
      /* Thanks to u/ErasmusDarwin */
      int blackbox(long n,long rule){return int((rule>>(n*4))&15);}
    
      int pixel(int foo, int bar) { 
      if (smooth <= 0){return foo;} else if(smooth >= 8){return bar;} else{
      int r,g,b;
      r = ( ( (foo >> 16 & 0xFF) * ((1 << smooth) -1) + (bar >> 16 & 0xFF) ) >> smooth ) << 16;
      g = ( ( (foo >>  8 & 0xFF) * ((1 << smooth) -1) + (bar >>  8 & 0xFF) ) >> smooth ) << 8;
      b = ( ( (foo       & 0xFF) * ((1 << smooth) -1) + (bar       & 0xFF) ) >> smooth );
      return r+g+b;
      }
      }
    
      int merge(){
      int r,g,b;
      r = (((ra[0] >> 16 & 0xFF) + (ra[1] >> 16 & 0xFF) + (ra[2] >> 16 & 0xFF) + (ra[3] >> 16 & 0xFF)) >> 2) << 16;
      g = (((ra[0] >>  8 & 0xFF) + (ra[1] >>  8 & 0xFF) + (ra[2] >>  8 & 0xFF) + (ra[3] >>  8 & 0xFF)) >> 2) << 8;
      b = ((ra[0]        & 0xFF) + (ra[1]       & 0xFF) + (ra[2]       & 0xFF) + (ra[3]       & 0xFF)) >> 2;
      return #000000+r+g+b;
      }
      void update_pixels() {
        dis=floor(dist(mouseX,mouseY,x,y));
        int c;   // comparission
        int t;  // transformation
        int r; // result
        int top, bottom, layer; // 
        for (int l=0; l<4; l++){
          if(mousePressed) {
            smooth = max(0,min(8,dis >> 6));
            } else {
            smooth=0;
            }
          if(mousePressed && dis<1+speed) {
            r = paint;
            } else {
            top = (l+1)%4; bottom=(l+3)%4;
            c=0;
            for (int n=0; n<8; n++){
            if ( val[l] > neighbours[ n][top] ) {c++;}
            if ( val[l] > neighbours[ n][bottom] ) {c++;}
            }
            t=blackbox(c,rule[l]);
            if (t<=7){ layer = top; } else { t-=8; layer=bottom; }
            r=neighbours[t][layer];
            }
          ra[l]=pixel(r,val[l]);
        }
        pixels[xy] = merge();
      }
      void buffer() {
        for (int l=0; l<4; l++) {
          val[l]=ra[l];
        }
      }
    }
    

    Original version

    /* Thanks to u/ErasmusDarwin for map function*/
    //int rule_map(int n,int rule){return(rule>>(n*2))&3;} 4^4, rules 2^8
    //int rule_map(int n,int rule){return int((rule>>(n*3))&7);} 8^8, rules 2^24
    int rule_map(long n,long rule){return int((rule>>(n*4))&15);} // 16^16, 2^64 rules
    void rla(){
      for(int i=0;i<4;i++){
      rule[i]=randomlong();
      }
    }
    long randomlong(){
      long result = floor(random(0,65536)); 
      for(int i=0;i<3;i++){
      result<<= 24;
      result+=floor(random(0,16777216));
      }
      return result;
    }
    int rlac,smooth = 1;
    class gray { gray(){}
    int pixel(int[]ca) { 
      if (smooth == 0){return ca[3];} else{
      int r,g,b;
      r = ( ( (ca[3] >> 16 & 0xFF) * ((1 << smooth) -1) + (ca[0] >> 16 & 0xFF) ) >> smooth ) << 16;
      g = ( ( (ca[3] >>  8 & 0xFF) * ((1 << smooth) -1) + (ca[0] >>  8 & 0xFF) ) >> smooth ) << 8;
      b = ( ( (ca[3]       & 0xFF) * ((1 << smooth) -1) + (ca[0]       & 0xFF) ) >> smooth );
      return r+g+b;
      }
      }
    int merge(int[]ca) {
      int r,g,b;
      r = (((ca[0] >> 16 & 0xFF) + (ca[1] >> 16 & 0xFF) + (ca[2] >> 16 & 0xFF) + (ca[3] >> 16 & 0xFF)) >> 2) << 16;
      g = (((ca[0] >>  8 & 0xFF) + (ca[1] >>  8 & 0xFF) + (ca[2] >>  8 & 0xFF) + (ca[3] >>  8 & 0xFF)) >> 2) << 8;
      b = ((ca[0]       & 0xFF) + (ca[1]       & 0xFF) + (ca[2]       & 0xFF) + (ca[3]       & 0xFF)) >> 2;
      return r+g+b;
      }
    }
    gray gs = new gray();
    int randomcolor(){return floor(random(0x0,0xffffff));}
    int paint = 0x0;
    int swap,cc,xyz=256;
    long[] rule = new long [4];
    int[][][][] fields = new int[2][4][xyz][xyz];
    int[]ca=new int[4];
    int[]aa=new int[4];
    void clear() {
      for(int b=0;b<2;b++){
        for(int d=0;d<4;d++){
          for (int x=0;x < xyz; x++) {
            for (int y = 0; y < xyz; y++) {
              fields[b][d][x][y] = #ffffff;}}}}}
    
    int algorithm(int d,int x0,int y0){
      int dis=floor(dist(mouseX,mouseY,x0,y0));
      int speed=floor(dist(pmouseX,pmouseY,mouseX,mouseY));
      int [][]n1=fields[swap][(d+4+1)%4]; 
      int [][]n2=fields[swap][(d+4+3)%4];
      int m=fields[swap][d][x0][y0];
      aa[0]=aa[1]=aa[2]=aa[3]=m & 0xfffffe;
      if(mousePressed){
        if(dis<1+speed){if(mouseButton==LEFT){return paint;}else{return 0xffffff;}}
        smooth=max(0,min(8,dis >> 6));
                      } else{smooth=0;}
    
      int t=0*0;
      int y1=(y0+1)%xyz,y3=(y0+xyz-1)%xyz,
          x1=(x0+1)%xyz,x3=(x0+xyz-1)%xyz;
      int c = max(0,(((m>n1[x0][y0])?1:0)+
                     ((m>n1[x0][y1])?1:0)+
                     ((m>n1[x0][y3])?1:0)+
                     ((m>n1[x1][y0])?1:0)+
                     ((m>n1[x3][y0])?1:0)+
                     ((m>n2[x0][y0])?1:0)+
                     ((m>n2[x0][y1])?1:0)+
                     ((m>n2[x0][y3])?1:0)+
                     ((m>n2[x1][y0])?1:0)+
                     ((m>n2[x3][y0])?1:0))-1);
           switch((rule_map(c,rule[d]))%16){
           case 0:t= n1[x0][y1];break;
           case 1:t= n1[x0][y3];break;
           case 2:t= n1[x1][y0];break;
           case 3:t= n1[x3][y0];break;
           case 4:t= n1[x1][y1];break;
           case 5:t= n1[x3][y3];break;
           case 6:t= n1[x3][y1];break;
           case 7:t= n1[x1][y3];break;
           case 8:t= n2[x0][y1];break;
           case 9:t= n2[x0][y3];break;
           case 10:t= n2[x1][y0];break;
           case 11:t= n2[x3][y0];break;
           case 12:t= n2[x1][y1];break;
           case 13:t= n2[x3][y3];break;
           case 14:t= n2[x3][y1];break;
           case 15:t= n2[x1][y3];break;
           default:break;}
           aa[3]=t;
           return gs.pixel(aa);
       }
    void setup(){size(256,256,P2D);rla();clear();loadPixels();}
    void draw() { for (int x=0;x<xyz;x++){
                  for (int y=0;y<xyz;y++){
                  for (int d=0;d<4;d++){
                  fields[(swap+1)%2][d][x][y]=ca[d]=algorithm(d,x,y);
                  if(d==3){pixels[x+xyz*y]=gs.merge(ca);}}}
                } updatePixels(); paint = randomcolor();
                  if(swap==0){swap=1;}else{swap=0;}
                  if(rlac++%100==0){rla();}
                }
    
  • Polarized Perpendicular Photons

    Well, Wolfram is a key thinker in the history of CA -- it is definitely worth a look, even if you don't read books. More specific to Processing, Shiffman devotes a chapter of his Processing book "The Nature of Code" to cellular automata -- you can check out the online copy and examples here:

  • Polarized Perpendicular Photons

    If you continue working on this project, this might be of interest: Wolfram wrote a controversial (but much, much less crank-ish than DraftScience) book called called A New Kind of Science (2002) on the idea that many aspects of the physical universe might be modeled as cellular automata.

    I intend to work on it, but I need to put more thought into it before I continue,
    I got a couple sketches of gravity and some UI-stuff that I jump back and forth between as I'm hitting roadblocks, as I'm learning how to code while working on them.

    And thanks, I saw his ted talk but don't read books.
    It was pretty interesting and took some ideas from it like using rules,
    didn't feel like re-coding it though.

  • Polarized Perpendicular Photons

    @prince_polka --

    Interesting sketch -- thanks for sharing!

    If you continue working on this project, this might be of interest: Wolfram wrote a controversial (but much, much less crank-ish than DraftScience) book called called A New Kind of Science (2002) on the idea that many aspects of the physical universe might be modeled as cellular automata.

  • Polarized Perpendicular Photons

    First attempt at automata, EDIT: I was a bit too eager to share before it was finnished.
    Removed the open processing sketch since it didn't like the jenkins hash functions for generating "rules" https://en.wikipedia.org/wiki/Jenkins_hash_function which is a pretty essential thing.
    Here's the code though it should just be copy-pasteable, if you have processing running.

    Right click to generate a random pattern.
    Cycle "rule" with mouseclick or hardcode int rule =2; to something else as startingpoint, most rules looks same and like shit though.
    Planning on doing a better algorithm.

    int x = 200;
    int y = 200;
    int rule = 2;
    int[][][][] fields = new int[2][4][x][y];
    boolean swap;
    void drandomize() {
      for (int k = 0; k < 2; k++) {
        for (int l = 0; l < 4; l++) { 
          for (int i = 0; i < x; i++) {
            for (int j = 0; j < y; j++) {
              fields[k][l][i][j] = int(random(#000000, #ffffff));
            }
          }
        }
      }
    }
    void setup() {
      size(200, 200);
      drandomize();
      loadPixels();
    }
    
    int jenkins(long k) {
      long hash = rule;
      hash += k;
      hash += hash << 10;
      hash ^= hash >> 6;
      hash += hash << 3;
      hash ^= hash >> 11;
      hash += hash << 15;
      return int(hash%8);
    }
    
    int algorithm(int d, int i, int j) {
      int hue = 0;
      int me = fields[(swap)?1:0][(d+4+0)%4][(i+x-1)%x][(j+y+0)%y] ;
      int c = //                       _          _          _
        ((me < fields[(swap)?1:0][(d+4+1)%4][(i+x+0)%x][(j+y+0)%y]) ? 1:0) +
        ((me < fields[(swap)?1:0][(d+4+1)%4][(i+x+0)%x][(j+y+1)%y]) ? 1:0) +
        ((me < fields[(swap)?1:0][(d+4+1)%4][(i+x+1)%x][(j+y+0)%y]) ? 1:0) +
        ((me < fields[(swap)?1:0][(d+4+1)%4][(i+x+1)%x][(j+y+1)%y]) ? 1:0) +
        ((me < fields[(swap)?1:0][(d+4-1)%4][(i+x+0)%x][(j+y-0)%y]) ? 1:0) +
        ((me < fields[(swap)?1:0][(d+4-1)%4][(i+x+0)%x][(j+y-1)%y]) ? 1:0) +
        ((me < fields[(swap)?1:0][(d+4-1)%4][(i+x-1)%x][(j+y+0)%y]) ? 1:0) +
        ((me < fields[(swap)?1:0][(d+4-1)%4][(i+x-1)%x][(j+y-1)%y]) ? 1:0);
    
    switch(jenkins(c)) {//                              _          _          _
      case 0:   return fields[(swap)?1:0][(d+4+1)%4][(i+x+0)%x][(j+y+0)%x];
      case 1:   return fields[(swap)?1:0][(d+4+1)%4][(i+x+0)%x][(j+y+1)%x];
      case 2:   return fields[(swap)?1:0][(d+4+1)%4][(i+x+1)%x][(j+y+0)%x];
      case 3:   return fields[(swap)?1:0][(d+4+1)%4][(i+x+1)%x][(j+y+1)%x];
      case 4:   return fields[(swap)?1:0][(d+4-1)%4][(i+x-0)%x][(j+y-0)%x];
      case 5:   return fields[(swap)?1:0][(d+4-1)%4][(i+x+0)%x][(j+y-1)%x];
      case 6:   return fields[(swap)?1:0][(d+4-1)%4][(i+x-1)%x][(j+y+0)%x];
      case 7:   return fields[(swap)?1:0][(d+4-1)%4][(i+x-1)%x][(j+y-1)%x];
      default: return #000000;
      }
    }
    void draw() {
      for (int d = 0; d < 4; d++) {
        for (int i = 0; i < x; i++) {
          for (int j = 0; j < y; j++) {
            fields[(swap)?0:1][d][i][j] = algorithm(d, i, j); //viewport+1+d)%4
            if(d==0){pixels[i+x*j] = fields[(swap)?0:1][0][i][j];}
          }
        }
        if (swap) {swap=false;} else {swap=true;}
        background(0);
        updatePixels();
        fill(255); textSize(40);
        text("#"+str(rule),80,105);
      }
    }
    void mouseClicked(){
             if (mouseButton == LEFT   ) { rule++; println(rule);}
      else if (mouseButton == RIGHT) { drandomize(); }
    }
    

    The "math" is pretty much just +1 -1 but the structure is a bit messy. The "fields" of pixels, (not using any vectors) start up randomized in setup and follow the "algorithm" from there.
    It seems to be able to do some trippy looking stuff, although it seems to be repeating patterns and the randomness just just coming from the random setup. And this first sketch is mostly just for practicing using arrays and drawing pixels on screen.

    But I have an idea about the arrows thing, I'll be drawing them in inkscape and trying to think of "my own" rules rather than trying to follow draft sciences, for how to make patterns. Its very unclear what happens when for example 3 arrows converge and there seems to be many different ways you can concieve of them going. Probably the best approach is to let the computer brute force through all possible variations. And i kind of think of them as just "neighbour relations" of points in a field rather than vectors. And by fields I just mean "numbers in space".
    I think I'll use 12 fields, 4*3 for x-y and rgb , and maybe need another dimension, maybe its very wasteful but I haven't figured out the details yet I am going to draw a plan.

  • Polarized Perpendicular Photons

    I think you've put your finger on the problem.

    Contra all those sketches, at first glance I don'e see how one could get cellular automata to generate circular orbiting structures ex nihilo by just bumping vector values into each other. There would have to be higher rules in the code reflecting the "all-of-the-rest-of-physics" that DraftScience hides in statements like "It is a quality of the physical universe which enables such patterns to become durable that is responsible for all that we know as matter."

    If you are interested in playing around with rendering systems of arrows and/or cellular automata and flocking, some recent posts that might be interesting:

    rendering a field of arrows:

    particle field project:

    past discussions of CA:

  • efficient referencing between classes

    I'm using processing/ just java, afaik that thread is about 2d array iteration with one or two properties, relevance? i also have no idea what your code is doing in any of those posts.

    I've made loads of different automata sketches in the past with no issues. My question here is about how to organise a sketch in the aforementioned specific situation.

    Anyway I get the general message, I need to be more clever and read up more on how to structure my sketches, only post in forum with more specific/ concrete query

  • john conways game of life

    I see -- this doesn't really have anything to do with the Game of Life or with cellular automata, then.

    Happy to help!

    Here is the formula for a Fibonacci sequence described on "Math is Fun":

    So we can write the rule:

    The Rule is xn = xn-1 + xn-2

    Once you calculate it, you can show text (such as a number) on the screen using the function:

    Try to make this sketch and then share it. If you have problems, share your properly formatted source code here and ask specific questions for feedback on how to make it work.

  • Turning a simple grid into readable grid references?

    Simple answer here is to make OOP grid. Have a class for a Cell and a class for a Grid. You can then create a system that will return you a reference for particular cell and you will be able to manipulate it. I recommend "Nature of code" by Shiffman, particulary, there's a chapter explaining grids in detail: http://natureofcode.com/book/chapter-7-cellular-automata/ If this would seem too hard, start the book from the beginning.

  • 3D Cellular Automata Problem... Failed....

    Hi. I am very new to processing, and currently I am doing some exploration on 3D Cellular Automata. Basically, I followed the tutorial of Cellular Automata by Jose Sanchez ( in 2d) and I am trying to edit the codes into 3d. The first intention is to make the cell grows in the z-axis. I tried a few times, and I did not manage to do it. So in the end I chose to make the whole thing as a box, and have the activity of cells inside the box. But I failed. I have no idea what's the problem with my codes. Could anyone help me please?

    Below is the code:

        import peasy.*;
        import toxi.geom.*;
        PeasyCam cam; 
    
        int generations;
        int cols = 50; // population
        int rows = 50;
        int depth = 50;
    
    
        CA [][][] grid = new CA [cols][rows][depth]; //declare two dimmensional array
    
        void setup () {
          size(1280, 720, P3D);
          frameRate (12);
          generations = 0;
          cam = new PeasyCam (this, 100);
    
          for (int i = 0; i < cols; i++) {
            for (int j = 0; j < rows; j++) {
              for ( int k = 0; k < depth; k++) {
    
                Vec3D ptLoc = new Vec3D ( i* 10, j * 10, k*10);
                grid [i][j][k] = new CA (ptLoc, i, j, k, 3, 0.8);
              }
            }
          }
        }
    
        void draw () {
          background (0);
          stroke (255);
    
          generations++;
          rotateX(radians(45));
          rotateZ(radians(45));
    
          fill(255);
          cam.beginHUD();
          text("Generations: "+generations, width-150, height-20);
          cam.endHUD();
    
          // rect (0,0,600,600);
    
          for (int i = 0; i < cols; i++) {
            for (int j = 0; j < rows; j++) {
              for ( int k = 0; k < depth; k++) {
    
                grid[i][j][k].run();
              }
            }
          }
    
          for (int i = 0; i < cols; i++) {
            for (int j = 0; j < rows; j++) {
              for ( int k = 0; k < depth; k++) {
                grid[i][j][k].updateType();
                grid[i][j][k].loc.z = grid[i][j][k].loc.z  ;
              }
            }
          }
        }
    
    ////////////////////////////////////////////////// CLASS CA
    
    class CA {
      Vec3D loc;
      int x;
      int y;
      int z;
      float density = 0.8;
      int sz = 3;
      int [][][][] world;
    
      //specify your neighbour
      int type = 0;
      int futType = 100;
    
      CA(Vec3D _loc, int _x, int _y, int _z, int _sz, float _density) {
        loc = _loc;
        x = _x;
        y = _y;
        z = _z;
        density = _density;
        sz = _sz;
        world = new int [x][y][z][2];
        for (int i = 0; i < density*x*y*z; i+=sz ) {
          for (int j = 0; j < density*x*y*z; j+=sz ) {
            for (int k = 0; k < density*x*y*z; k+=sz ) {
              world [( int ) random (x)] [( int ) random (y)] [( int ) random (z)] [0] = 1;
    
              //   float rnd = random (100);
              // if (rnd < 50) {
    
              // type = 1;
              //}
            }
          }
        }
      }
    
      void run() {
        display();
        evo1N();
      }
    
      void updateType() {
        type = futType;
      }
    
      void evo1N() {
    
        int count = 0;
        if ( grid [(x+cols-1)%cols] [(y+rows-1)%rows ]  [(z+depth+1)  %depth].type == 1) count ++;
        if ( grid [(x+cols)%cols]   [(y+rows-1)%rows]   [(z+depth-1)  %depth].type == 1) count ++;
        if ( grid [(x+cols+1)%cols] [(y+rows-1)%rows]   [(z+depth)  %depth].type == 1) count ++;
        if ( grid [(x+cols-1)%cols] [(y+rows)%rows]     [(z+depth-1)    %depth].type == 1) count ++;
        if ( grid [(x+cols+1)%cols] [(y+rows)%rows]     [(z+depth)    %depth].type == 1) count ++;
        if ( grid [(x+cols-1)%cols] [(y+rows+1)%rows]   [(z+depth)  %depth].type == 1) count ++;
        if ( grid [(x+cols)%cols]   [(y+rows+1)%rows]   [(z+depth+1)  %depth].type == 1) count ++;
        if ( grid [(x+cols+1)%cols] [(y+rows+1)%rows]   [(z+depth+1)  %depth].type == 1) count ++;
    
        //if i have too many neighbours around me, i die out of the over population
        if (type == 1 && count < 2) {
          futType = 0;
        }
    
        if (type == 1 && count <=3 && count >=2) {
          futType = 1;
        }
    
        if (type ==1 && count > 3) {
          futType = 0;
        }
    
        if (type == 0 && count == 3) {
          futType = 1;
        }
      }
    
      void display () {
        if (type == 1) {
    
          stroke (255);
          pushMatrix ();
          translate ( cols, rows, depth );
          box ( sz );
          popMatrix ();
          strokeWeight ( 2 );
          point (loc.x, loc.y, loc.z);
        }
      }
    }
    

    Thank you.