# 8.7. Implementing Life¶

The exercises at the end of this chapter ask you to experiment with and modify the Game of Life, and implement other 2-D cellular automatons. This section explains an implementation of GoL That you can use as a starting place for your experiments.

To represent the state of the cells, we use a NumPy array of 8-bit unsigned integers. As an example, the following line creates a 10 by 10 array initialized with random values of 0 and 1.

```
a = np.random.randint(2, size=(10, 10), dtype=np.uint8)
```

There are a few ways we can compute the GoL rules. The simplest is to use for loops to iterate through the rows and columns of the array:

```
b = np.zeros_like(a)
rows, cols = a.shape
for i in range(1, rows-1):
for j in range(1, cols-1):
state = a[i, j]
neighbors = a[i-1:i+2, j-1:j+2]
k = np.sum(neighbors) - state
if state:
if k==2 or k==3:
b[i, j] = 1
else:
if k == 3:
b[i, j] = 1
```

Initially, `b`

is an array of zeros with the same size as `a`

. Each time through the loop, `state`

is the condition of the center cell and `neighbors`

is the 3x3 neighborhood. `k`

is the number of live neighbors (not including the center cell). The nested `if`

statements evaluate the GoL rules and turn on cells in `b`

accordingly.

This implementation is a straightforward translation of the rules, but it is verbose and slow. We can do better using cross-correlation, as we saw in Section 7.11. There, we used `np.correlate`

to compute a 1-D correlation. Now, to perform 2-D correlation, we’ll use `correlate2d`

from `scipy.signal`

, a SciPy module that provides functions related to signal processing:

```
from scipy.signal import correlate2d
kernel = np.array([[1, 1, 1],
[1, 0, 1],
[1, 1, 1]])
c = correlate2d(a, kernel, mode='same')
```

What we called a “window” in the context of 1-D correlation is called a “kernel” in the context of 2-D correlation, but the idea is the same: `correlate2d`

multiplies the kernel and the array to select a neighborhood, then adds up the result. This kernel selects the 8 neighbors that surround the center cell.

`correlate2d`

applies the kernel to each location in the array. With `mode='same'`

, the result has the same size as `a`

.

Now we can use logical operators to compute the rules:

```
b = (c==3) | (c==2) & a
b = b.astype(np.uint8)
```

The first line computes a boolean array with `True`

where there should be a live cell and `False`

elsewhere. Then `astype`

converts the boolean array to an array of integers.

This version is faster, and probably good enough, but we can simplify it slightly by modifying the kernel:

```
kernel = np.array([[1, 1, 1],
[1,10, 1],
[1, 1, 1]])
c = correlate2d(a, kernel, mode='same')
b = (c==3) | (c==12) | (c==13)
b = b.astype(np.uint8
```

This version of the kernel includes the center cell and gives it a weight of 10. If the center cell is 0, the result is between 0 and 8; if the center cell is 1, the result is between 10 and 18. Using this kernel, we can simplify the logical operations, selecting only cells with the values 3, 12, and 13.

That might not seem like a big improvement, but it allows one more simplification: with this kernel, we can use a table to look up cell values, as we did in Section 7.12.

```
table = np.zeros(20, dtype=np.uint8)
table[[3, 12, 13]] = 1
c = correlate2d(a, kernel, mode='same')
b = table[c]
```

`table`

has zeros everywhere except locations 3, 12, and 13. When we use `c`

as an index into `table`

, NumPy performs element-wise lookup; that is, it takes each value from `c`

, looks it up in `table`

, and puts the result into `b`

.

This version is faster and more concise than the others; the only drawback is that it takes more explaining.

`Life.py`

, which is included in the repository for this book, provides a `Life`

class that encapsulates this implementation of the rules. If you run `Life.py`

, you should see an animation of a “puffer train”, which is a spaceship that leaves a trail of detritus in its wake.

Q-1: The text says the simplest method to compute the GoL rules is to use

Q-2: What does the author say about that version of implementation? *Refer back to the implementation method referred to in the previous question.*