• fullscreen
  • elementary_cellular_automata.pde
  • //int W_WIDTH = screen.width/2;
    //int W_HEIGHT = screen.height/2;
    final int W_WIDTH = 896;
    final int W_HEIGHT = 480;
    int INPUT_LENGTH = 64;
    List<Long[]> bitLines = new LinkedList<Long[]> ();
    int CELL_SIZE = 7;
    
    int PIXELS_PER_COL = 64;
    int LINES_PER_FRAME = 1;
    int RULE = 105;
    int MAJOR_COLS = 0;
    int GRID_HEIGHT = 0;
    int GRID_WIDTH = 0;
    
    int DRAW_METHOD = 0; // 0 for bitwise, 1 for words, 2 for bytes
    final int DRAW_BITS = 0, DRAW_WORDS = 1, DRAW_BYTES = 2;
    
    int COLOR_ROTATION = 0;
    float COLOR_CYCLE_LENGTH = 60; // In seconds
    
    Long[] input;
    
    PFont fnt, smallFnt;
    PGraphics pBuf = createGraphics (W_WIDTH,W_HEIGHT,JAVA2D);
    
    void Reset () {
      MAJOR_COLS = W_WIDTH/CELL_SIZE/PIXELS_PER_COL;
      GRID_HEIGHT = W_HEIGHT/CELL_SIZE;
      GRID_WIDTH = PIXELS_PER_COL*MAJOR_COLS;
      COLOR_ROTATION = 0;
      input = new Long[MAJOR_COLS];
      bitLines.clear();
      for (int i=0; i<input.length; i++) input[i] = 0L;
      if ( (float)MAJOR_COLS % 2 == 0)
        input [MAJOR_COLS/2-1] = 1L;
      else
        input[MAJOR_COLS/2] = 1L << 32;
      bitLines.add (input);
      pBuf.beginDraw ();
      pBuf.background (0,0,0);
      pBuf.endDraw ();
    }
    
    void setup () {
      //size (W_WIDTH,W_HEIGHT);
      size (896,480);
      frameRate(30);
      noSmooth ();
      noStroke ();
      fnt = loadFont ("Lane-Narrow-48.vlw");
      smallFnt = loadFont ("Lane-Narrow-24.vlw");
      textFont (fnt,48);
      pBuf.beginDraw ();
      pBuf.background (0,0,0);
      pBuf.endDraw ();
      Reset ();
      addMouseWheelListener(new java.awt.event.MouseWheelListener() { 
        public void mouseWheelMoved(java.awt.event.MouseWheelEvent evt) { 
          mouseWheel(evt.getWheelRotation());
      }}); 
    }
    
    Long[] ComputeLine (Long[] inputStr, int rule) {
      Long[] output = new Long[MAJOR_COLS];
      long tripleMask = 0x07L;
      long remainder = 0L;
    
      for (int col=MAJOR_COLS-1; col>=0; col--) {
        long inSegment = inputStr[col];
        long outSegment = 0L;
        
        // Special case for first bit of output
        int token = (int) (((inSegment << 1) | remainder) & tripleMask);
        int ruleBit = 1 << token;
        if ((rule & ruleBit) == ruleBit)
          outSegment = outSegment | 1L;
          
        for (int i=0; i<=61; i++) {
          token = (int) ((inSegment >>> i) & tripleMask); // Get three-digit code (eg: 101)
          ruleBit = 1 << token; // Get bitmask to check rule
          if ((rule & ruleBit) == ruleBit) // Rule is draw pixel
            outSegment = outSegment | (1L << (i+1));
        }
        
        // Special case for last bit of output, if not on last column
        if (col > 0) {
          long nextSegment = inputStr[col-1];
          long firstBitMask = (nextSegment << 2) & tripleMask;
          token = (int) (((inSegment >> 62) | firstBitMask) & tripleMask);
          ruleBit = 1 << token;
          if ((rule & ruleBit) == ruleBit)
            outSegment = outSegment | (1L << 63);
        } else {
          token = (int) ((inSegment >> 62) & tripleMask);
          ruleBit = 1 << token;
          if ((rule & ruleBit) == ruleBit)
            outSegment = outSegment | (1L << 63);
        }
        
        remainder = inSegment >>> 63;
        output[col] = outSegment;
      }
      return output;
    }
    
    void PrintLine (Long[] inputStr) {
      for (int col=0; col<inputStr.length; col++) {
        print ("[");
        long inSegment = inputStr[col];
        for (int i=0; i<64; i++) {
          long bitMask = 1L << (63-i);
          if ((inSegment & bitMask) == bitMask) print ("1");
          else print ("0");
        }
        print ("]");
      }
      print ("\n");
    }
    
    void DrawBitLine (Long[] inputStr, int x, int y) {
      for (int col=MAJOR_COLS-1; col>=0; col--) {
        long inSegment = inputStr[col];
        for (int i=0; i<64; i++) {
          long bitMask = 1L << (63-i);
          if ((inSegment & bitMask) == bitMask) {
            pBuf.fill(0,200,0);
            pBuf.rect (col*CELL_SIZE*64 + x + i*CELL_SIZE + 1,y + 1, CELL_SIZE - 2,CELL_SIZE - 2);
          }
          else pBuf.fill(255,255,255);
        
        }
      }
    }
    
    void DrawWordLine (Long[] inputStr, int x, int y) {
      for (int col=MAJOR_COLS-1; col>=0; col--) {
        long inSegment = inputStr[col];
        for (int i=0; i<63; i+=2) {
          long bitMask = 3L;
          long digits = inSegment >> (62-i);
          long word = digits & bitMask;
          switch ((int) word) {
            case 0: continue;
            case 1: pBuf.fill (255,0,0);
                    break;
            case 2: pBuf.fill (0,255,0);
                    break;
            case 3: pBuf.fill (0,0,255);
                    break;
          }
          pBuf.rect (col*CELL_SIZE*32 + x + (i/2)*CELL_SIZE + 1,y + 1, CELL_SIZE - 2,CELL_SIZE - 2);    
        }
      }
    }
    
    void DrawByteLine (Long[] inputStr, int x, int y) {
      for (int col=MAJOR_COLS-1; col>=0; col--) {
        long inSegment = inputStr[col];
        for (int i=0; i<61; i+=4) {
          long bitMask = 15L;
          long digits = inSegment >> (62-i);
          long word = digits & bitMask;
          if (word == 0) continue;
          
          float t = (TWO_PI) * (frameCount % (frameRate*COLOR_CYCLE_LENGTH)) / (float)(frameRate*COLOR_CYCLE_LENGTH);
          float n = (word+5) % 16;
          int r = (int) (sin(t)*75 +              180*(((int)word+0)%16)/16);
          int g = (int) (sin(t+(TWO_PI/3))*75 +   180*(((int)word+5)%16)/16);
          int b = (int) (sin(t+(2*TWO_PI/3))*75 + 180*(((int)word+10)%16)/16);
          pBuf.fill (r,g,b);
          pBuf.rect (col*CELL_SIZE*PIXELS_PER_COL + x + (i/4)*CELL_SIZE + 1,y + 1, CELL_SIZE - 2,CELL_SIZE - 2);    
        }
      }
    }
    
    void DrawLine (Long[] input, int idx) {
      switch (DRAW_METHOD) {
          case DRAW_BITS: DrawBitLine(input,0, idx*CELL_SIZE);
                          break;
          case DRAW_WORDS: DrawWordLine(input,0,idx*CELL_SIZE);
                           break;
          case DRAW_BYTES: DrawByteLine(input,0, idx*CELL_SIZE);
                           break;
        }
    }
    
    void draw () {
      background (0,0,0);
      pBuf.beginDraw ();
      
      if (bitLines.size() == 1) DrawLine (bitLines.get(0), 0);
      if (bitLines.size() + LINES_PER_FRAME > GRID_HEIGHT) {
        int nShift = (bitLines.size () + LINES_PER_FRAME) - GRID_HEIGHT;
        for (int i=0; i<nShift; i++) bitLines.remove (0);
        int pShift = nShift * CELL_SIZE;
        pBuf.copy (0,pShift,W_WIDTH,W_HEIGHT-pShift,0,0,W_WIDTH,W_HEIGHT-pShift);
        pBuf.fill (0,0,0);
        pBuf.rect (0,W_HEIGHT-pShift,W_WIDTH,pShift);
      }
      for (int i=0;i<LINES_PER_FRAME;i++) {
        input = ComputeLine (input, RULE);
        bitLines.add (input);
        
        DrawLine (input, bitLines.size()-1);
      }
      pBuf.endDraw ();
      image (pBuf,0,0);
      
      fill (0,0,0,128);
      rect (5,5,200,55);
      rect (5,W_HEIGHT-60,200,55);
      fill (255,255,255);
      textFont (fnt,48);
      text ("Rule " + Integer.toString(RULE),13,50);
      //textFont (smallFnt,24);
      text ("FPS:  " + Integer.toString((int)frameRate),13,W_HEIGHT-17);
    }
    
    Long[] PadBitstring (Long[] bitstring, int padding) {
      int paddingCols = padding / 64;
      int remainder = padding % 64;
      List<Long> paddedBitstring = new LinkedList<Long> ();
      for (int i=0; i<paddingCols; i++) paddedBitstring.add (0L);
      long remainingData = 0L;
      int startIdx = 0;
      if (remainder > 0) {
        long section = bitstring[0] >> remainder;
        remainingData = bitstring[0] << remainder;
        paddedBitstring.add (section);
        startIdx = 1;
      }
      for (int i=startIdx; i<bitstring.length; i++) {
        long section = bitstring[i];
        long newSection = (section >> remainder) | remainingData;
        if (remainder > 0) remainingData = section << remainder;
        paddedBitstring.add (newSection);
      }
      if (remainder > 0) {
        paddedBitstring.add (remainingData);
      }
      for (int i=0; i<paddingCols; i++) paddedBitstring.add (0L);
      Long[] r = new Long[paddedBitstring.size()];
      r = paddedBitstring.toArray (r);
      return r;
    }
    
    Long[] StripBitstring (Long[] bitstring, int amount) {
      int stripped = 0;
      int toStrip = amount;
      int bitsToKeep = bitstring.length * 64 - amount * 2;
      int keptSoFar = 0;
      List<Long> strippedBitstring = new LinkedList<Long> ();
      
      int idx = 0;
      for (toStrip=amount; toStrip>=64; toStrip-=64)
        idx += 1;
      for (int i=idx; i<bitstring.length && keptSoFar < bitsToKeep; i++) { 
        long section = bitstring[i];
        if (toStrip == 0) {
          strippedBitstring.add (section);
          keptSoFar += 64;
          if (keptSoFar > bitsToKeep) print ("kept too many bits!");
          continue;
        }
        long newSection = section << toStrip;
        long nextChunk = bitstring[i+1];
        newSection = newSection | (nextChunk >>> toStrip);
        strippedBitstring.add (newSection);
        keptSoFar += 64;
      }
      Long[] r = new Long[strippedBitstring.size()];
      r = strippedBitstring.toArray (r);
      return r;
    }
    
    void oldsetup () {
      Long[] bstr = new Long[2];
      Long[] padstr, padstr2, strpstr;
      bstr[0] = 1L;//(1L << 63);
      bstr[1] = 0L;
      padstr = PadBitstring(bstr,32);
      padstr2 = PadBitstring(padstr,96);
      PrintLine (bstr);
      PrintLine (padstr);
      strpstr = StripBitstring (padstr,32);
      
      //PrintLine (padstr2);
      PrintLine (strpstr);
    }
    
    void keyPressed () {
      if (keyCode == RIGHT) {
        RULE += 1;
        if (RULE > 255) RULE = 1;
      } else if (keyCode == LEFT) {
        RULE -= 1;
        if (RULE < 1) RULE = 255;
      } else if (keyCode == UP) {
        RULE += 10;
        if (RULE > 255) RULE = RULE - 255;
      } else if (keyCode == DOWN) {
        RULE -= 10;
        if (RULE < 1) RULE = 255 + RULE;
      }
    }
    
    void mousePressed () {
      if (mouseButton == LEFT) {
        //oldsetup (); print ("\n");
        Long[] firstLine = bitLines.get(0);
        int oldLength = bitLines.size ();
        DRAW_METHOD += 1;
        if (DRAW_METHOD > 2) DRAW_METHOD = 0;
        Long[] newInput = null;
        switch (DRAW_METHOD) {
          case DRAW_BITS:  PIXELS_PER_COL = 64;
                           newInput = StripBitstring (firstLine, MAJOR_COLS*64*3/4/2);
                           break;
          case DRAW_WORDS: PIXELS_PER_COL = 32;
                           newInput = PadBitstring (firstLine, MAJOR_COLS*64/2);
                           break;
          case DRAW_BYTES: PIXELS_PER_COL = 16;
                           newInput = PadBitstring (firstLine, MAJOR_COLS*64/2);
                           break;
        }
        Reset ();
        bitLines.clear ();
        input = newInput;
        pBuf.beginDraw ();
        bitLines.add (input);
        DrawLine (input, 0);
        for (int i=0;i<oldLength-1;i++) {
          input = ComputeLine (input, RULE);
          bitLines.add (input);
          DrawLine (input, bitLines.size()-1);
        }
        pBuf.endDraw ();
      } else if (mouseButton == RIGHT) {
        Reset ();
      }
    }
    
    void mouseWheel (int delta) {
      LINES_PER_FRAME += delta;
      if (LINES_PER_FRAME < 0) LINES_PER_FRAME = 0;
    }
    

    code

    tweaks (0)

    about this sketch

    This sketch is running as Java applet, exported from Processing.

    license

    advertisement

    Luke Williams

    elementary cellular automata

    Add to Faves Me Likey@!
    You must login/register to add this sketch to your favorites.

    ARROW KEYS to cycle through rules
    LEFT CLICK to cycle through views (bit, word, byte)
    RIGHT CLICK to clear the screen
    SCROLL WHEEL to speed up, slow down or pause the automaton

    You need to login/register to comment.