bgneal@40: """Chapter 6, exercise 1 in Allen Downey's Think Complexity book. bgneal@40: bgneal@40: "Create a new class called CircularCA that extends CA so that the cells are bgneal@40: arranged in a ring. Hint: you might find it useful to add a column of 'ghost bgneal@40: cells' to the array." bgneal@40: bgneal@40: """ bgneal@40: bgneal@40: import numpy bgneal@40: bgneal@40: from CA import CA bgneal@40: bgneal@40: bgneal@40: class CircularCA(CA): bgneal@40: """A circular cellular automaton; the cells are arranged in a ring.""" bgneal@40: bgneal@42: def __init__(self, rule, n=100, m=50): bgneal@40: """Parameters: bgneal@40: bgneal@40: * rule: an integer in the range 0-255 that represents the CA rule bgneal@40: using Wolfram's encoding bgneal@40: * n: the number of rows (time steps) in the result bgneal@42: * m: the number of columns bgneal@40: bgneal@40: """ bgneal@40: self.table = self.make_table(rule) bgneal@40: self.n = n bgneal@40: # a ghost column is added to either end bgneal@42: self.m = m + 2 # add 2 ghost columns bgneal@40: self.array = numpy.zeros((n, self.m), dtype=numpy.int8) bgneal@40: self.next = 0 bgneal@40: bgneal@40: def start_single(self): bgneal@40: self.array[0, 1] = 1 bgneal@40: self.next = 1 bgneal@40: bgneal@40: def step(self): bgneal@40: """Executes one time step by computing the next row of the array.""" bgneal@40: i = self.next bgneal@40: self.next += 1 bgneal@40: assert i > 0, 'call start_single() or start_random() first' bgneal@40: bgneal@40: a = self.array bgneal@40: t = self.table bgneal@40: bgneal@40: # update the ghost cells to enable wrapping bgneal@40: a[i - 1, 0] = a[i - 1, self.m - 2] bgneal@40: a[i - 1, self.m - 1] = a[i - 1, 1] bgneal@40: bgneal@40: for j in xrange(1, self.m - 1): bgneal@40: a[i, j] = t[tuple(a[i - 1, j-1:j+2])] bgneal@40: bgneal@42: def loop(self, steps=1): bgneal@42: """Executes the given number of time steps.""" bgneal@42: for i in xrange(steps): bgneal@42: self.step() bgneal@40: bgneal@40: def get_array(self, start=0, end=None): bgneal@40: """Gets a slice of columns from the CA, with slice indices bgneal@40: (start, end). bgneal@40: bgneal@40: """ bgneal@40: # do not return the ghost columns bgneal@40: if end==None: bgneal@40: return self.array[:, start+1:self.m-1] bgneal@40: else: bgneal@40: return self.array[:, start+1:end+1] bgneal@40: bgneal@42: def wrap(self): bgneal@42: """Copies the last row to row 0, then resets the CA to start back at the bgneal@42: top. bgneal@42: bgneal@42: """ bgneal@42: a = self.array bgneal@42: a[0, :] = a[self.next - 1, :] bgneal@42: self.next = 1 bgneal@42: bgneal@40: bgneal@40: if __name__ == '__main__': bgneal@40: bgneal@40: import sys bgneal@40: from CADrawer import PyplotDrawer bgneal@40: bgneal@42: def main(script, rule, n, m): bgneal@40: rule = int(rule) bgneal@40: n = int(n) bgneal@42: m = int(m) bgneal@42: ca = CircularCA(rule, n, m) bgneal@40: ca.start_single() bgneal@40: ca.loop(n - 1) bgneal@40: bgneal@40: drawer = PyplotDrawer() bgneal@40: drawer.draw(ca) bgneal@40: drawer.show() bgneal@40: bgneal@40: bgneal@40: main(*sys.argv)