annotate ch6ex3.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
children
rev   line source
bgneal@43 1 """Chapter 6, exercise 3 in Allen Downey's Think Complexity book.
bgneal@43 2
bgneal@43 3 This exercise asks you to experiment with Rule 110 and see how many spaceships you can find.
bgneal@43 4
bgneal@43 5 1. Modify your program from the previous exercises so it starts with an initial
bgneal@43 6 condition that yields the stable background pattern.
bgneal@43 7
bgneal@43 8 2. Modify the initial condition by adding different patterns in the center of
bgneal@43 9 the row and see which ones yield spaceships. You might want to enumerate all
bgneal@43 10 possible patterns of n bits, for some reasonable value of n. For each
bgneal@43 11 spaceship, can you find the period and rate of translation? What is the
bgneal@43 12 biggest spaceship you can find?
bgneal@43 13
bgneal@43 14 """
bgneal@43 15 import os.path
bgneal@43 16 import cPickle
bgneal@43 17
bgneal@43 18 from CircularCA import CircularCA
bgneal@43 19 from CADrawer import PyplotDrawer
bgneal@43 20
bgneal@43 21 FILENAME = 'rule110.pkl'
bgneal@43 22 RULE = 110
bgneal@43 23
bgneal@43 24 def find_ic(show=False):
bgneal@43 25 """This function sets up a rule 110 CA with a random initial condition and
bgneal@43 26 runs it for 600 time steps. The last row is the initial condition (IC) we
bgneal@43 27 are interested in for producing future CA to investigate rule 110 and
bgneal@43 28 spaceships.
bgneal@43 29
bgneal@43 30 We use 600 steps because of figure 6.6 in Think Complexity.
bgneal@43 31
bgneal@43 32 The CA is run through 600 steps and then the last row is pickled in a file
bgneal@43 33 for future use.
bgneal@43 34
bgneal@43 35 """
bgneal@43 36 ca = CircularCA(RULE, 600, 600)
bgneal@43 37 ca.start_random()
bgneal@43 38 ca.loop(599)
bgneal@43 39
bgneal@43 40 if show:
bgneal@43 41 drawer = PyplotDrawer()
bgneal@43 42 drawer.draw(ca)
bgneal@43 43 drawer.show()
bgneal@43 44
bgneal@43 45 # get the last row of the CA and pickle it to a file so we can use it in the
bgneal@43 46 # future:
bgneal@43 47
bgneal@43 48 last_row = ca.array[599, :]
bgneal@43 49 with open(FILENAME, 'wb') as fp:
bgneal@43 50 cPickle.dump(last_row, fp, protocol=2)
bgneal@43 51
bgneal@43 52 print "last row pickled in {}".format(FILENAME)
bgneal@43 53
bgneal@43 54
bgneal@43 55 def rule110(script, n):
bgneal@43 56 """Open the IC pickle file and initialize a CA with it.
bgneal@43 57 Modify the 32 center columns with the bit pattern given by n, which should
bgneal@43 58 be a hexidecimal number.
bgneal@43 59 Then step the CA and display it.
bgneal@43 60
bgneal@43 61 """
bgneal@43 62 print 'loading {}...'.format(FILENAME)
bgneal@43 63 with open(FILENAME, 'rb') as fp:
bgneal@43 64 ic = cPickle.load(fp)
bgneal@43 65
bgneal@43 66 print 'creating CA...'
bgneal@43 67 ca = CircularCA(RULE, 600, 600)
bgneal@43 68 ca.start_row(ic)
bgneal@43 69
bgneal@43 70 n = int(n, 16)
bgneal@43 71 print 'modifying center of row with {:x}'.format(n)
bgneal@43 72 a = ca.array
bgneal@43 73 mask = 1 << 31
bgneal@43 74 j = 600 / 2 - 16 + 1 # +1 because of the ghost column on the left
bgneal@43 75 for i in xrange(32):
bgneal@43 76 a[0, j] = 1 if n & mask else 0
bgneal@43 77 j += 1
bgneal@43 78 mask >>= 1
bgneal@43 79
bgneal@43 80 print 'stepping CA...'
bgneal@43 81 ca.loop(599)
bgneal@43 82
bgneal@43 83 drawer = PyplotDrawer()
bgneal@43 84 drawer.draw(ca)
bgneal@43 85 drawer.show()
bgneal@43 86
bgneal@43 87
bgneal@43 88 if __name__ == '__main__':
bgneal@43 89 import sys
bgneal@43 90
bgneal@43 91 if not os.path.exists(FILENAME):
bgneal@43 92 find_ic()
bgneal@43 93
bgneal@43 94 rule110(*sys.argv)