John Conway's Game Of Life: Threaded Edition

Some of the following code is adapted from https://jakevdp.github.io/blog/2013/08/07/conways-game-of-life/


In [ ]:
from time import sleep
from threading import Thread

import numpy as np

from ipycanvas import MultiCanvas, hold_canvas

In [ ]:
def life_step(x):
    """Game of life step"""
    nbrs_count = sum(np.roll(np.roll(x, i, 0), j, 1)
                     for i in (-1, 0, 1) for j in (-1, 0, 1)
                     if (i != 0 or j != 0))
    return (nbrs_count == 3) | (x & (nbrs_count == 2))

In [ ]:
def draw(x, canvas, color='black'):
    with hold_canvas(canvas):
        canvas.clear()
        canvas.fill_style = color

        r = 0
        for row in x:
            c = 0
            for value in row:
                if value:
                    canvas.fill_rect(r * n_pixels, c * n_pixels, n_pixels, n_pixels)

                c += 1
            r += 1

In [ ]:
glider_gun =\
[[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,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,1,0,0,0,0,0,0,0,0,0,0,0],
 [0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1],
 [0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1],
 [1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
 [1,1,0,0,0,0,0,0,0,0,1,0,0,0,1,0,1,1,0,0,0,0,1,0,1,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,1,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,1,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,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]]

x = np.zeros((50, 70), dtype=bool)
x[1:10,1:37] = glider_gun

In [ ]:
n_pixels = 10

multi = MultiCanvas(2, size=(x.shape[1] * n_pixels, x.shape[0] * n_pixels))
multi[0].fill_style = '#FFF0C9'
multi[0].fill_rect(0, 0, multi.size[0], multi.size[1])

multi

In [ ]:
draw(x, multi[1], '#5770B3')

In [ ]:
class GameOfLife(Thread):
    def __init__(self, x, canvas):
        self.x = x
        self.canvas = canvas
        super(GameOfLife, self).__init__()

    def run(self):
        for _ in range(1_000):
            self.x = life_step(self.x)
            draw(self.x, self.canvas, '#5770B3')

            sleep(0.1)

GameOfLife(x, multi[1]).start()

The game is now running in a separate thread, nothing stops you from changing the background color:


In [ ]:
multi[0].fill_style = '#D0FFB3'
multi[0].fill_rect(0, 0, multi.size[0], multi.size[1])