Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@villares
Last active May 19, 2023 14:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save villares/2334c2c014070b9d0ac1e06c1170338c to your computer and use it in GitHub Desktop.
Save villares/2334c2c014070b9d0ac1e06c1170338c to your computer and use it in GitHub Desktop.
GOL with numpy & scipy convolve2d
# based on https://www.jpytr.com/post/game_of_life/
# previous version calculated neighbours twice at each step... it could be useful to color cells but I removed it.
import py5
import numpy as np
from scipy.signal import convolve2d
board_img = None
def setup():
global status
py5.size(600, 600)
py5.no_smooth()
status = get_init_status((py5.width, py5.height))
def draw():
global status, board_img
status = apply_conways_game_of_life_rules(status)
board_img = py5.create_image_from_numpy(status * 255, 'L', dst=board_img)
py5.image(board_img, 0, 0)
def get_init_status(size=(50, 50), initial_prob_life=0.5):
status = np.random.uniform(0, 1, size=size) <= initial_prob_life
return status
def apply_conways_game_of_life_rules(status):
"""Applies Conway's Game of Life rules given the current status of the game"""
live_neighbors = count_live_neighbors(status)
survive_underpopulation = live_neighbors >= 2
survive_overpopulation = live_neighbors <= 3
survive = status * survive_underpopulation * survive_overpopulation
new_status = np.where(live_neighbors==3, True, survive) # Born
return new_status
def count_live_neighbors(status):
"""Counts the number of neighboring live cells"""
kernel = np.array(
[[1, 1, 1],
[1, 0, 1],
[1, 1, 1]])
return convolve2d(status, kernel, mode='same', boundary="wrap")
py5.run_sketch()
@hx2A
Copy link

hx2A commented May 19, 2023

Good job writing this! Using convolve2d works very well here.

There are two alternate implementations I will point out to you:

def draw():
    global status, board_img
    status = apply_conways_game_of_life_rules(status)
    board_img.set_np_pixels(status * 255, bands='L')
    py5.image(board_img, 0, 0)

or you can remove board_img entirely with this:

def draw():
    global status
    status = apply_conways_game_of_life_rules(status)
    py5.set_np_pixels(status * 255, bands='L')

@hx2A
Copy link

hx2A commented May 19, 2023

When you pass a dst param to py5.create_image_from_numpy it will simply make a call to the Py5Image object's set_np_pixels() method, so the first alternate implementation is basically identical to what you coded.

I would expect the second one to be slightly faster than the first.

@villares
Copy link
Author

Very cool, thanks @hx2A !

I have used the second one at times, but I have missed the Py5Image method used in the first one, nice to know both!

@hx2A
Copy link

hx2A commented May 19, 2023

You are welcome, @villares!

I thought you would be interested to see some of the other useful approaches for this kind of work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment