Conway's Game of Life

This is a (slightly) modified version of Glowing Python's code. I make it available here because it features a few nice things:

  • how to make a movie using matplotlib.animation
  • how to write a generator (function with yield)
  • how to plot a sparce array (spy)

See the result on my website, yairmau.com, specifically the page /tutorials/python.

In [1]:
import numpy as np
from matplotlib import pyplot as plt
import matplotlib.animation as manimation


def life(X, steps):
    """
     Conway's Game of Life.
     - X, matrix with the initial state of the game.
     - steps, number of generations.
    """
    def roll_it(x, y):
        # rolls the matrix X in a given direction
        # x=1, y=0 left;  x=-1, y=0 right;
        return np.roll(np.roll(X, y, axis=0), x, axis=1)

    for _ in range(steps):
        # count the number of neighbours
        # the universe is considered toroidal
        Y = roll_it(1, 0) + roll_it(0, 1) + \
            roll_it(-1, 0) + roll_it(0, -1) + \
            roll_it(1, 1) + roll_it(-1, -1) + \
            roll_it(1, -1) + roll_it(-1, 1)
        # game of life rules
        X = np.logical_or(np.logical_and(X, Y == 2), Y == 3)
        X = X.astype(int)
        yield X
In [2]:
dimensions = (90, 160)  # height, width
X = np.zeros(dimensions)  # Y by X dead cells
middle_y = dimensions[0] / 2
middle_x = dimensions[1] / 2

N_iterations = 600

# acorn initial condition
# http://www.conwaylife.com/w/index.php?title=Acorn
X[middle_y, middle_x:middle_x+2] = 1
X[middle_y, middle_x+4:middle_x+7] = 1
X[middle_y+1, middle_x+3] = 1
X[middle_y+2, middle_x+1] = 1
In [3]:
FFMpegWriter = manimation.writers['ffmpeg']
metadata = dict(title='Game of life', artist='Acorn initial condition')
writer = FFMpegWriter(fps=10, metadata=metadata)

fig = plt.figure()
fig.patch.set_facecolor('black')
with writer.saving(fig, "game_of_life.mp4", 300):  # last argument: dpi
    plt.spy(X, origin='lower')
    plt.axis('off')
    writer.grab_frame()
    plt.clf()
    for i, x in enumerate(life(X, N_iterations)):
        plt.title("iteration: {:03d}".format(i + 1))
        plt.spy(x, origin='lower')
        plt.axis('off')
        writer.grab_frame()
        plt.clf()