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@40
|
17 def __init__(self, rule, n=100, ratio=2):
|
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@40
|
23 * ratio: the ratio of columns to rows
|
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@40
|
29 self.m = ratio * n + 3 # 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@40
|
37 def step(self):
|
bgneal@40
|
38 """Executes one time step by computing the next row of the array."""
|
bgneal@40
|
39 i = self.next
|
bgneal@40
|
40 self.next += 1
|
bgneal@40
|
41 assert i > 0, 'call start_single() or start_random() first'
|
bgneal@40
|
42
|
bgneal@40
|
43 a = self.array
|
bgneal@40
|
44 t = self.table
|
bgneal@40
|
45
|
bgneal@40
|
46 # update the ghost cells to enable wrapping
|
bgneal@40
|
47 a[i - 1, 0] = a[i - 1, self.m - 2]
|
bgneal@40
|
48 a[i - 1, self.m - 1] = a[i - 1, 1]
|
bgneal@40
|
49
|
bgneal@40
|
50 for j in xrange(1, self.m - 1):
|
bgneal@40
|
51 a[i, j] = t[tuple(a[i - 1, j-1:j+2])]
|
bgneal@40
|
52
|
bgneal@40
|
53
|
bgneal@40
|
54 def get_array(self, start=0, end=None):
|
bgneal@40
|
55 """Gets a slice of columns from the CA, with slice indices
|
bgneal@40
|
56 (start, end).
|
bgneal@40
|
57
|
bgneal@40
|
58 """
|
bgneal@40
|
59 # do not return the ghost columns
|
bgneal@40
|
60 if end==None:
|
bgneal@40
|
61 return self.array[:, start+1:self.m-1]
|
bgneal@40
|
62 else:
|
bgneal@40
|
63 return self.array[:, start+1:end+1]
|
bgneal@40
|
64
|
bgneal@40
|
65
|
bgneal@40
|
66 if __name__ == '__main__':
|
bgneal@40
|
67
|
bgneal@40
|
68 import sys
|
bgneal@40
|
69 from CADrawer import PyplotDrawer
|
bgneal@40
|
70
|
bgneal@40
|
71 def main(script, rule, n):
|
bgneal@40
|
72 rule = int(rule)
|
bgneal@40
|
73 n = int(n)
|
bgneal@40
|
74 ca = CircularCA(rule, n)
|
bgneal@40
|
75 ca.start_single()
|
bgneal@40
|
76 ca.loop(n - 1)
|
bgneal@40
|
77
|
bgneal@40
|
78 drawer = PyplotDrawer()
|
bgneal@40
|
79 drawer.draw(ca)
|
bgneal@40
|
80 drawer.show()
|
bgneal@40
|
81
|
bgneal@40
|
82
|
bgneal@40
|
83 main(*sys.argv)
|