annotate CircularCA.py @ 45:1804f09a7adb

Chapter 6, exercise 4, part 4. A Turing Machine drawer.
author Brian Neal <bgneal@gmail.com>
date Sat, 19 Jan 2013 14:17:12 -0600
parents 6cd37534c12e
children
rev   line source
bgneal@40 1 """Chapter 6, exercise 1 in Allen Downey's Think Complexity book.
bgneal@40 2
bgneal@40 3 "Create a new class called CircularCA that extends CA so that the cells are
bgneal@40 4 arranged in a ring. Hint: you might find it useful to add a column of 'ghost
bgneal@40 5 cells' to the array."
bgneal@40 6
bgneal@40 7 """
bgneal@40 8
bgneal@40 9 import numpy
bgneal@40 10
bgneal@40 11 from CA import CA
bgneal@40 12
bgneal@40 13
bgneal@40 14 class CircularCA(CA):
bgneal@40 15 """A circular cellular automaton; the cells are arranged in a ring."""
bgneal@40 16
bgneal@42 17 def __init__(self, rule, n=100, m=50):
bgneal@40 18 """Parameters:
bgneal@40 19
bgneal@40 20 * rule: an integer in the range 0-255 that represents the CA rule
bgneal@40 21 using Wolfram's encoding
bgneal@40 22 * n: the number of rows (time steps) in the result
bgneal@42 23 * m: the number of columns
bgneal@40 24
bgneal@40 25 """
bgneal@40 26 self.table = self.make_table(rule)
bgneal@40 27 self.n = n
bgneal@40 28 # a ghost column is added to either end
bgneal@42 29 self.m = m + 2 # add 2 ghost columns
bgneal@40 30 self.array = numpy.zeros((n, self.m), dtype=numpy.int8)
bgneal@40 31 self.next = 0
bgneal@40 32
bgneal@40 33 def start_single(self):
bgneal@40 34 self.array[0, 1] = 1
bgneal@40 35 self.next = 1
bgneal@40 36
bgneal@43 37 def start_row(self, row):
bgneal@43 38 """Set the first row to row and set next to 1."""
bgneal@43 39 self.array[0, :] = row
bgneal@43 40 self.next = 1
bgneal@43 41
bgneal@40 42 def step(self):
bgneal@40 43 """Executes one time step by computing the next row of the array."""
bgneal@40 44 i = self.next
bgneal@40 45 self.next += 1
bgneal@40 46 assert i > 0, 'call start_single() or start_random() first'
bgneal@40 47
bgneal@40 48 a = self.array
bgneal@40 49 t = self.table
bgneal@40 50
bgneal@40 51 # update the ghost cells to enable wrapping
bgneal@40 52 a[i - 1, 0] = a[i - 1, self.m - 2]
bgneal@40 53 a[i - 1, self.m - 1] = a[i - 1, 1]
bgneal@40 54
bgneal@40 55 for j in xrange(1, self.m - 1):
bgneal@40 56 a[i, j] = t[tuple(a[i - 1, j-1:j+2])]
bgneal@40 57
bgneal@42 58 def loop(self, steps=1):
bgneal@42 59 """Executes the given number of time steps."""
bgneal@42 60 for i in xrange(steps):
bgneal@42 61 self.step()
bgneal@40 62
bgneal@40 63 def get_array(self, start=0, end=None):
bgneal@40 64 """Gets a slice of columns from the CA, with slice indices
bgneal@40 65 (start, end).
bgneal@40 66
bgneal@40 67 """
bgneal@40 68 # do not return the ghost columns
bgneal@40 69 if end==None:
bgneal@40 70 return self.array[:, start+1:self.m-1]
bgneal@40 71 else:
bgneal@40 72 return self.array[:, start+1:end+1]
bgneal@40 73
bgneal@42 74 def wrap(self):
bgneal@42 75 """Copies the last row to row 0, then resets the CA to start back at the
bgneal@42 76 top.
bgneal@42 77
bgneal@42 78 """
bgneal@42 79 a = self.array
bgneal@42 80 a[0, :] = a[self.next - 1, :]
bgneal@42 81 self.next = 1
bgneal@42 82
bgneal@40 83
bgneal@40 84 if __name__ == '__main__':
bgneal@40 85
bgneal@40 86 import sys
bgneal@40 87 from CADrawer import PyplotDrawer
bgneal@40 88
bgneal@42 89 def main(script, rule, n, m):
bgneal@40 90 rule = int(rule)
bgneal@40 91 n = int(n)
bgneal@42 92 m = int(m)
bgneal@42 93 ca = CircularCA(rule, n, m)
bgneal@40 94 ca.start_single()
bgneal@40 95 ca.loop(n - 1)
bgneal@40 96
bgneal@40 97 drawer = PyplotDrawer()
bgneal@40 98 drawer.draw(ca)
bgneal@40 99 drawer.show()
bgneal@40 100
bgneal@40 101
bgneal@40 102 main(*sys.argv)