annotate Life.py @ 48:98eb01502cf5 tip

Follow up to last commit. Re-orient the r-pentomino. Added progress display.
author Brian Neal <bgneal@gmail.com>
date Wed, 31 Jul 2013 20:37:12 -0500
parents 2b0e229e163c
children
rev   line source
bgneal@47 1 """ Code example from Complexity and Computation, a book about
bgneal@47 2 exploring complexity science with Python. Available free from
bgneal@47 3
bgneal@47 4 http://greenteapress.com/complexity
bgneal@47 5
bgneal@47 6 Copyright 2011 Allen B. Downey.
bgneal@47 7 Distributed under the GNU General Public License at gnu.org/licenses/gpl.html.
bgneal@47 8
bgneal@47 9 Modified by Brian Neal to add a variable delay to the animation and to provide
bgneal@47 10 the cval parameter to convolve.
bgneal@47 11
bgneal@47 12 """
bgneal@47 13
bgneal@47 14 import numpy
bgneal@47 15 import scipy.ndimage
bgneal@47 16
bgneal@47 17 import matplotlib
bgneal@47 18 matplotlib.use('TkAgg')
bgneal@47 19 import matplotlib.pyplot as pyplot
bgneal@47 20
bgneal@47 21
bgneal@47 22 class Life(object):
bgneal@47 23 """Implements Conway's Game of Life.
bgneal@47 24
bgneal@47 25 n: the number of rows and columns
bgneal@47 26 """
bgneal@47 27
bgneal@48 28 def __init__(self, n, mode='wrap', cval=0.0, random=False,
bgneal@48 29 show_progress=None):
bgneal@47 30 """Attributes:
bgneal@47 31 n: number of rows and columns
bgneal@47 32 mode: how border conditions are handled
bgneal@47 33 array: the numpy array that contains the data.
bgneal@47 34 weights: the kernel used for convolution
bgneal@47 35 """
bgneal@47 36 self.n = n
bgneal@47 37 self.mode = mode
bgneal@47 38 self.cval = cval
bgneal@48 39 self.show_progress = show_progress
bgneal@48 40 self.steps = 0
bgneal@48 41
bgneal@47 42 if random:
bgneal@47 43 self.array = numpy.random.random_integers(0, 1, (n, n))
bgneal@47 44 else:
bgneal@47 45 self.array = numpy.zeros((n, n), numpy.int8)
bgneal@47 46
bgneal@47 47 self.weights = numpy.array([[1,1,1],
bgneal@47 48 [1,10,1],
bgneal@47 49 [1,1,1]])
bgneal@47 50
bgneal@47 51 def add_glider(self, x=0, y=0):
bgneal@47 52 coords = [(0,1), (1,2), (2,0), (2,1), (2,2)]
bgneal@47 53 for i, j in coords:
bgneal@47 54 self.array[x+i, y+j] = 1
bgneal@47 55
bgneal@47 56 def loop(self, steps=1):
bgneal@47 57 """Executes the given number of time steps."""
bgneal@48 58 for i in xrange(steps):
bgneal@48 59 self.step()
bgneal@47 60
bgneal@47 61 def step(self):
bgneal@47 62 """Executes one time step."""
bgneal@47 63 con = scipy.ndimage.filters.convolve(self.array,
bgneal@47 64 self.weights,
bgneal@47 65 mode=self.mode,
bgneal@47 66 cval=self.cval)
bgneal@47 67
bgneal@47 68 boolean = (con==3) | (con==12) | (con==13)
bgneal@47 69 self.array = numpy.int8(boolean)
bgneal@47 70
bgneal@48 71 self.steps += 1
bgneal@48 72 if self.show_progress and self.steps % self.show_progress == 0:
bgneal@48 73 print self.steps
bgneal@48 74
bgneal@47 75
bgneal@47 76 class LifeViewer(object):
bgneal@47 77 """Generates an animated view of the grid."""
bgneal@47 78 def __init__(self, life, cmap=matplotlib.cm.gray_r, delay=1000):
bgneal@47 79 self.life = life
bgneal@47 80 self.cmap = cmap
bgneal@47 81 self.delay = delay
bgneal@47 82
bgneal@47 83 self.fig = pyplot.figure()
bgneal@47 84 pyplot.axis([0, life.n, 0, life.n])
bgneal@47 85 pyplot.xticks([])
bgneal@47 86 pyplot.yticks([])
bgneal@47 87
bgneal@47 88 self.pcolor = None
bgneal@47 89 self.update()
bgneal@47 90
bgneal@47 91 def update(self):
bgneal@47 92 """Updates the display with the state of the grid."""
bgneal@47 93 if self.pcolor:
bgneal@47 94 self.pcolor.remove()
bgneal@47 95
bgneal@47 96 a = self.life.array
bgneal@47 97 self.pcolor = pyplot.pcolor(a, cmap=self.cmap)
bgneal@47 98 self.fig.canvas.draw()
bgneal@47 99
bgneal@47 100 def animate(self, steps=10):
bgneal@47 101 """Creates the GUI and then invokes animate_callback.
bgneal@47 102
bgneal@47 103 Generates an animation with the given number of steps.
bgneal@47 104 """
bgneal@47 105 self.steps = steps
bgneal@47 106 self.fig.canvas.manager.window.after(self.delay, self.animate_callback)
bgneal@47 107 pyplot.show()
bgneal@47 108
bgneal@47 109 def animate_callback(self):
bgneal@47 110 """Runs the animation."""
bgneal@47 111 for i in range(self.steps):
bgneal@47 112 self.life.step()
bgneal@47 113 self.update()
bgneal@47 114
bgneal@47 115
bgneal@47 116 def main(script, n=20, *args):
bgneal@47 117
bgneal@47 118 n = int(n)
bgneal@47 119
bgneal@47 120 life = Life(n, random=False)
bgneal@47 121 life.add_glider()
bgneal@47 122 viewer = LifeViewer(life)
bgneal@47 123 viewer.animate(steps=100)
bgneal@47 124
bgneal@47 125
bgneal@47 126 if __name__ == '__main__':
bgneal@47 127 import sys
bgneal@47 128
bgneal@47 129 profile = False
bgneal@47 130 if profile:
bgneal@47 131 import cProfile
bgneal@47 132 cProfile.run('main(*sys.argv)')
bgneal@47 133 else:
bgneal@47 134 main(*sys.argv)