PHY 411-506 Home Home  |  Course Outline  |  Lectures  |  Homework  |  Files

Lecture 34: April 13


One-dimensional Boolean cellular automaton

Cellular automata were first developed by von Neumann and Ulam.

The following applet is based on the program CA1.java, which is a translation of PROGRAM ca1 on pages 503-504 of the textbook.

Here is the code which generates this applet:

// CA1.java

import comphys.graphics.*;
import java.awt.event.*;

public class CA1 extends Animation {

    int[] update = new int[8];

    int maxL = 500;
    int[] site = new int[maxL + 2];
    int[] initialSite = new int[maxL + 2];
    int[] previousSite = new int[maxL + 2];

    int rule = 90;

    void setrule () {
        int r = rule;
        int powerOf2 = 128;
        for (int i = 0; i < 8; i++) {
            update[i] = r / powerOf2;
            r -= powerOf2 * update[i];
            powerOf2 /= 2;
        }
    }

    int L = 20;
    int t = 0;
    static final int DEAD = 0;
    static final int ALIVE = DEAD + 1;
    static final int RANDOM = ALIVE + 1;
    int initialConfig = RANDOM;
    boolean singleSite;
    
    void initial () {
        t = 0;
        for (int i = 1; i <= L; i++) {
            initialSite[i] = DEAD;
            if (singleSite) {
                if (i == L / 2)
                    initialSite[i] = ALIVE;
            } else {
                if (initialConfig == ALIVE)
                    initialSite[i] = ALIVE;
                else if (initialConfig == RANDOM && Math.random() < 0.5)
                    initialSite[i] = ALIVE;
            }
            previousSite[i] = site[i] = initialSite[i];
        }
        // boundary conditions
        initialSite[0] = previousSite[0] = site[0] = site[L];
        initialSite[L+1] = previousSite[L+1] = site[L+1] = site[1];
        needToClear = true;
    }

    void stepInTime () {
        ++t;
        for (int i = 1; i <= L; i++) {
            int index = 4 * previousSite[i - 1]
                      + 2 * previousSite[i] + previousSite[i + 1];
            site[i] = update[index];
        }
        for (int i = 1; i <= L; i++) {
            previousSite[i] = site[i];
        }
        site[0] = previousSite[0] = site[L];
        site[L + 1] = previousSite[L + 1] = site[1];
    }

    boolean sameAsPrevious () {
        for (int i = 1; i <= L; i++)
            if (site[i] != previousSite[i])
                return false;
        return true;
    }

    boolean sameAsInitial () {
        for (int i = 1; i <= L; i++)
            if (site[i] != initialSite[i])
                return false;
        return true;
    }

    boolean needToClear;
    
    class Evolution extends Plot {
        double xSize = 400;
        double ySize = 400;

        public void paint () {
            if (needToClear) {
                clear();
                needToClear = false;
            }
            setWindow(0, xSize, 0, ySize);
            double dx = xSize / L;
            int d = (int) dx - 1;
            if (d < 2)
                d = 2;
            int timeSteps = L;
            double x0 = 0;
            double y = 0;
            // draw initial configuration at bottom of picture
            if (t == 0) {
                setColor("red");
                for (int i = 0; i < L; i++) {
                    if (initialSite[i+1] == ALIVE) {
                        double x = x0 + i * dx;
                        boxArea(x, x + d, y, y + d);
                    }
                }
            }
            int row = t % timeSteps;
            y = row * dx;
            setColor("white");
            boxArea(0, xSize, y, y + d);
            if (sameAsInitial())
                setColor("red");
            else
                setColor("black");
            for (int i = 0; i < L; i++) {
                if (site[i + 1] == ALIVE) {
                    double x = x0 + i * dx;
                    boxArea(x, x + d, y, y + d);
                }
            }
        }
    }

    class RuleWindow extends Plot implements MouseListener {
        int xPixels = 400;
        int yPixels = 70;

        RuleWindow () {
            setSize(xPixels, yPixels);
            addMouseListener(this);
        }

        String[] states = { "111", "110", "101", "100",
                            "011", "010", "001", "000" };

        public void paint () {
            setWindow(0, xPixels, 0, yPixels);
            clear();
            setColor("blue");
            boxArea(0, xPixels, 0, yPixels);
            setColor("white");
            int dx = xPixels / 9;
            int x0 = dx / 2;
            int dy = 20;
            int y = yPixels - dy;

            plotString("Binary local rule (click to change bit)" +
                       "   Time step = " + t, x0, y);
            y -= dy;
            for (int i = 0; i < 8; i++) {
                plotString(states[i], x0 + i * dx, y);
                plotString("" + update[i], x0 + 8 + i * dx, y - dy);
            }
        }

        public void mouseClicked (MouseEvent me) { }
        public void mouseEntered (MouseEvent me) { }
        public void mouseExited (MouseEvent me) { }

        public void mousePressed (MouseEvent me) {

            int dx = xPixels / 9;
            int x0 = dx / 2;
            int i = (me.getX() - x0) / dx;
            int j = me.getY();

            if (j > 20 && j < 70 && i >= 0 && i < 8) {
                if (update[i] == 0)
                    update[i] = 1;
                else
                    update[i] = 0;
                repaint();
                getrule();
            }
        }
        public void mouseReleased (MouseEvent me) { }
    }

    Evolution evolution;
    RuleWindow ruleWindow;
    Reader LReader, ruleReader, singleSiteReader;
    
    public void init () {
        initial();
        setrule();
        add(evolution = new Evolution());
        add(ruleWindow = new RuleWindow());
        add(LReader = new Reader("L = ", L));
        add(ruleReader = new Reader("Decimal rule", rule));
        add(singleSiteReader = new Reader("Single site", singleSite));
        addControlPanel();
    }

    public void step () {
        stepInTime();
        evolution.repaint();
        ruleWindow.repaint();
    }

    public void reset () {
        L = LReader.readInt();
        rule = ruleReader.readInt();
        singleSite = singleSiteReader.readBoolean();
        setrule();
        initial();
        needToClear = true;
        evolution.repaint();
        ruleWindow.repaint();
    }

    void getrule () {
        rule = 0;
        int powerOf2 = 128;
        for (int i = 0; i < 8; i++) {
            rule += powerOf2 * update[i];
            powerOf2 /= 2;
        }
        ruleReader.setInt(rule);
        ruleWindow.repaint();
    }

    public static void main (String[] args) {
        CA1 ca1 = new CA1();
        ca1.frame("One-dimensional Boolean cellular automaton", 430, 650);
    }
}


UB Physics Home Questions or comments: phygons@acsu.buffalo.edu