Skip to content

Instantly share code, notes, and snippets.

@mebeim
Created December 30, 2023 13:52
Show Gist options
  • Save mebeim/fe71a766baeeb310463e11e94380a304 to your computer and use it in GitHub Desktop.
Save mebeim/fe71a766baeeb310463e11e94380a304 to your computer and use it in GitHub Desktop.
LED Name Badge Conway's Game of Life Glider Gun
#!/usr/bin/env python3
#
# @mebeim - 2023-12-30
#
# ./glider_gun.py
# sudo python3 ./led-badge-11x44.py -s 8 -m 5 :glider_gun_sprite.png:
#
# Generate a Glider Gun PNG sprite for the LED name badge, writable to the badge
# using the code here https://github.com/jnweiger/led-name-badge-ls32
#
# Result should look like this: https://x.com/mebeim/status/1740886207662608774
#
# Dependencies: Pillow (https://pypi.org/project/Pillow/)
#
from itertools import product
from PIL import Image
def evolve_cell(grid, r, c, h, w):
alive = 0
for dr, dc in ((-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1)):
rr, cc = r + dr, c + dc
if 0 <= rr < h and 0 <= cc < w:
alive += grid[rr][cc]
return alive == 3 or (alive == 2 and grid[r][c])
def evolve(grid):
h, w = len(grid), len(grid[0])
new = [[False] * w for _ in range(h)]
for r, c in product(range(h), range(w)):
new[r][c] = evolve_cell(grid, r, c, h, w)
return new
def conway(grid):
while 1:
yield grid
grid = evolve(grid)
def grid_to_pixels(grid):
for y in range(len(grid)):
for x in range(len(grid[0])):
yield (x, y), ((255,255,255) if grid[y][x] else (0,0,0))
# Initial configuration (longer on the bottom, will be cut to 11 rows later)
start = '''\
............................#...............
..........................#.#...............
................##......##............##....
...............#...#....##............##....
....##........#.....#...##..................
....##........#...#.##....#.#...............
..............#.....#.......#...............
...............#...#........................
................##..........................
............................................
............................................
............................................
............................................
............................................
............................................
............................................
'''
grid = []
for line in start.splitlines():
grid.append([x == '#' for x in line])
# Test out animation on terminal?
# from time import sleep
# for g in conway(grid):
# for line in g:
# print(''.join('#' if x else ' ' for x in line))
# sleep(0.1)
# import sys; sys.exit(0)
# From the 7th frame onwards, the animation will cycle every 30 frames, so skip
# the first 6 frames.
for _ in range(6):
grid = evolve(grid)
frames = {}
for i, g in enumerate(conway(grid)):
px = g[:11]
h, w = len(px), len(px[0])
k = frozenset((r, c) for r, c in product(range(h), range(w)) if px[r][c])
if k in frames:
print('Animation is', i, 'frames')
break
frames[k] = (i, px)
frames = {i: px for i, px in frames.values()}
h, w = len(frames[0]), len(frames[0][0])
assert h == 11 and w == 44
imgs = []
for i in range(len(frames)):
frame = frames[i]
im = Image.new('RGB', (w, h))
px = im.load()
for xy, color in grid_to_pixels(frames[i]):
px[xy] = color
imgs.append(im)
hblank = 4
sprite_w = (w + hblank) * len(imgs)
out = Image.new('RGB', (sprite_w, h))
for i, im in enumerate(imgs):
out.paste(im, ((w + hblank) * i, 0))
out.save('glider_gun_sprite.png')
print('Saved to glider_gun_sprite.png')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment