view CircularCA.py @ 43:6cd37534c12e

Chapter 6, exercise 3: exploring rule 110 cellular automata.
author Brian Neal <bgneal@gmail.com>
date Mon, 14 Jan 2013 20:41:41 -0600
parents 039249efe42f
children
line wrap: on
line source
"""Chapter 6, exercise 1 in Allen Downey's Think Complexity book.

"Create a new class called CircularCA that extends CA so that the cells are
arranged in a ring. Hint: you might find it useful to add a column of 'ghost
cells' to the array."

"""

import numpy

from CA import CA


class CircularCA(CA):
    """A circular cellular automaton; the cells are arranged in a ring."""

    def __init__(self, rule, n=100, m=50):
        """Parameters:

        * rule: an integer in the range 0-255 that represents the CA rule
        using Wolfram's encoding
        * n: the number of rows (time steps) in the result
        * m: the number of columns

        """
        self.table = self.make_table(rule)
        self.n = n
        # a ghost column is added to either end
        self.m = m + 2      # add 2 ghost columns
        self.array = numpy.zeros((n, self.m), dtype=numpy.int8)
        self.next = 0

    def start_single(self):
        self.array[0, 1] = 1
        self.next = 1

    def start_row(self, row):
        """Set the first row to row and set next to 1."""
        self.array[0, :] = row
        self.next = 1

    def step(self):
        """Executes one time step by computing the next row of the array."""
        i = self.next
        self.next += 1
        assert i > 0, 'call start_single() or start_random() first'

        a = self.array
        t = self.table

        # update the ghost cells to enable wrapping
        a[i - 1, 0] = a[i - 1, self.m - 2]
        a[i - 1, self.m - 1] = a[i - 1, 1]

        for j in xrange(1, self.m - 1):
            a[i, j] = t[tuple(a[i - 1, j-1:j+2])]

    def loop(self, steps=1):
        """Executes the given number of time steps."""
        for i in xrange(steps):
            self.step()

    def get_array(self, start=0, end=None):
        """Gets a slice of columns from the CA, with slice indices
        (start, end).

        """
        # do not return the ghost columns
        if end==None:
            return self.array[:, start+1:self.m-1]
        else:
            return self.array[:, start+1:end+1]

    def wrap(self):
        """Copies the last row to row 0, then resets the CA to start back at the
        top.

        """
        a = self.array
        a[0, :] = a[self.next - 1, :]
        self.next = 1


if __name__ == '__main__':

    import sys
    from CADrawer import PyplotDrawer

    def main(script, rule, n, m):
        rule = int(rule)
        n = int(n)
        m = int(m)
        ca = CircularCA(rule, n, m)
        ca.start_single()
        ca.loop(n - 1)

        drawer = PyplotDrawer()
        drawer.draw(ca)
        drawer.show()


    main(*sys.argv)