Sunday, 7 December 2014

Rule 30

Wolfram's Rule 30 is proper interesting, isn't it?

Here is a Java implementation:

Wolfram.java

package org.adrianwalker.cellularautomation;

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import javax.imageio.ImageIO;

public final class Wolfram {

  private static final int MAX_TIME = 500;
  private static final int MAX_SPACE = MAX_TIME * 2;
  private static final int WHITE = Color.WHITE.getRGB();
  private static final int BLACK = Color.BLACK.getRGB();
  private static final String FORMAT = "png";
  private static final String OUTPUT = "/var/tmp/output.png";

  // cell to RGB lookup
  private static final Map<Integer, Integer> CELL_RGB = new HashMap<>();
  static {
    CELL_RGB.put(0, WHITE);
    CELL_RGB.put(1, BLACK);
  }

  // RGB to cell lookup
  private static final Map<Integer, Integer> RGB_CELL = new HashMap<>();
  static {
    RGB_CELL.put(WHITE, 0);
    RGB_CELL.put(BLACK, 1);
  }

  // http://en.wikipedia.org/wiki/Rule_30
  //
  // current pattern          111 110 101 100 011 010 001 000
  // new state for center cell 0   0   0   1   1   1   1   0
  private static final Map<Integer, Integer> RULE_30 = new HashMap<>();
  static {
    RULE_30.put(Arrays.hashCode(new int[]{1, 1, 1}), 0);
    RULE_30.put(Arrays.hashCode(new int[]{1, 1, 0}), 0);
    RULE_30.put(Arrays.hashCode(new int[]{1, 0, 1}), 0);
    RULE_30.put(Arrays.hashCode(new int[]{1, 0, 0}), 1);
    RULE_30.put(Arrays.hashCode(new int[]{0, 1, 1}), 1);
    RULE_30.put(Arrays.hashCode(new int[]{0, 1, 0}), 1);
    RULE_30.put(Arrays.hashCode(new int[]{0, 0, 1}), 1);
    RULE_30.put(Arrays.hashCode(new int[]{0, 0, 0}), 0);
  }

  public static void main(final String[] args) throws Throwable {

    BufferedImage image = new BufferedImage(MAX_SPACE, MAX_TIME, BufferedImage.TYPE_INT_RGB);

    init(image);
    execute(image, RULE_30);

    ImageIO.write(image, FORMAT, new File(OUTPUT));
  }

  private static void init(final BufferedImage image) {

    int time;
    int space;
    for (time = 0; time < MAX_TIME; time++) {
      for (space = 0; space < MAX_SPACE; space++) {
        image.setRGB(space, time, WHITE);
      }
    }

    time = 0;
    space = MAX_SPACE / 2;
    image.setRGB(space, time, BLACK);
  }

  private static void execute(final BufferedImage image, final Map<Integer, Integer> rule) {

    for (int time = 1; time < MAX_TIME; time++) {
      for (int space = 1; space < MAX_SPACE - 1; space++) {

        int[] pattern = {
          RGB_CELL.get(image.getRGB(space - 1, time - 1)),
          RGB_CELL.get(image.getRGB(space, time - 1)),
          RGB_CELL.get(image.getRGB(space + 1, time - 1))
        };

        int cell = rule.get(Arrays.hashCode(pattern));
        image.setRGB(space, time, CELL_RGB.get(cell));
      }
    }
  }
}

Output


(Click To Enlarge)