There are a number of Python programs around for playing the classical 'Game of Life', and most of them offer nice graphic animations which allow one to follow the fantastic patterns emerging from the game. Such programs are fine for interactive use on a computer, but I have found very difficult to find one that provides static graphic output intended for printed pages (like those displayed in the 1970 article by Martin Gardner which presented the Game of Life to the world: The fantastic combinations of John Conway's new solitaire game "life"). There are many programs that offer text-based output of Life patterns, but I have not found any one capable of doing the same thing with Matplolib graphics. So, I started writing one, as shown in the code below:
import matplotlib.pyplot as plt
def iterate(Z):
shape = len(Z), len(Z[0])
N = [[0,]*(shape[0]+2) for i in range(shape[1]+2)]
# Compute number of neighbours for each cell
for x in range(1,shape[0]-1):
for y in range(1,shape[1]-1):
N[x][y] = Z[x-1][y-1]+Z[x][y-1]+Z[x+1][y-1] \
+ Z[x-1][y] +Z[x+1][y] \
+ Z[x-1][y+1]+Z[x][y+1]+Z[x+1][y+1]
# Update cells
for x in range(1,shape[0]-1):
for y in range(1,shape[1]-1):
if Z[x][y] == 0 and N[x][y] == 3:
Z[x][y] = 1
elif Z[x][y] == 1 and not N[x][y] in [2,3]:
Z[x][y] = 0
return Z
# The 'beehive' pattern
Z = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
n_generations = 10
fig, axes = plt.subplots(2, 5, figsize=(8, 8))
for i in range(n_generations):
iterate(Z)
ax = axes.flat[i]
ax.imshow(Z, interpolation='nearest', cmap=plt.cm.binary)
ax.set_axis_off()
ax.set_title('Generation {}'.format(i+1))
plt.grid(True)
plt.tight_layout()
plt.show()
This works, but it far from good, because:
(1) I would like that each plot showed grid lines, so that they could reproduce the original figures of Gardner's article, but I have not been able to found out how to do that;
(2) I would also like to be able to use spheres instead of squares for representing the living cells (just like they appear in Gardner's article);
Any help towards improving this code will be much appreciated!
To produce grid lines you need ticks at the respective positions. Using a MultipleLocator
would produce ticks at multiples of 1.
Circles are standard scatter markers. You can plot the data as scatter instead of image.
Together it might look as follows, where I also made the code a bit more compact.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
def iterate(Z):
# http://www.labri.fr/perso/nrougier/from-python-to-numpy/code/game_of_life_numpy.py
N = (Z[0:-2, 0:-2] + Z[0:-2, 1:-1] + Z[0:-2, 2:] +
Z[1:-1, 0:-2] + Z[1:-1, 2:] +
Z[2: , 0:-2] + Z[2: , 1:-1] + Z[2: , 2:])
birth = (N == 3) & (Z[1:-1, 1:-1] == 0)
survive = ((N == 2) | (N == 3)) & (Z[1:-1, 1:-1] == 1)
Z[...] = 0
Z[1:-1, 1:-1][birth | survive] = 1
return Z
# The 'beehive' pattern
Z = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
Z = np.array(Z)
X, Y = np.meshgrid(np.arange(Z.shape[1])+.5, np.arange(Z.shape[0])+.5)
fig, axes = plt.subplots(2, 5, figsize=(8, 4))
for i, ax in enumerate(axes.flat):
Z = iterate(Z)
ax.scatter(X[Z > 0], Y[Z > 0], color="k")
ax.grid(True, color="k")
ax.xaxis.set_major_locator(mticker.MultipleLocator())
ax.yaxis.set_major_locator(mticker.MultipleLocator())
ax.tick_params(size=0, length=0, labelleft=False, labelbottom=False)
ax.set(xlim=(0, Z.shape[1]), ylim=(Z.shape[0], 0),
title='Generation {}'.format(i+1), aspect="equal")
plt.tight_layout()
plt.show()