Skip to content

Instantly share code, notes, and snippets.

@Noxitu
Last active February 7, 2023 00:12
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 Noxitu/5f53e9a2d198c759bf2e1228edf48a40 to your computer and use it in GitHub Desktop.
Save Noxitu/5f53e9a2d198c759bf2e1228edf48a40 to your computer and use it in GitHub Desktop.
import time
import numpy as np
import numba
# Comparison: C++ code from episode: 15 μs per advance()
# Pure Python code from episode: 14000 μs per advance()
def add_glider(area, x, y):
xs = (np.array([0, 1, 2, 0, 1]) + x) % area.shape[1]
ys = (np.array([0, 1, 1, 2, 2]) + y) % area.shape[0]
area[list(ys), list(xs)] = 1
# 250 μs
# def advance(area):
# padded_area = np.pad(area, 1, mode='wrap')
# windows = np.lib.stride_tricks.sliding_window_view(padded_area, (3, 3))
# counts = np.sum(windows, axis=(2, 3))
# return (counts == 3) | (counts == 4) & (area == 1)
# 125 μs
# def create_faster_advance(h, w):
# padded_area = np.zeros((h+2, w+2), dtype=bool)
# windows = np.lib.stride_tricks.sliding_window_view(padded_area, (3, 3))
# def advance(area):
# padded_area[1:-1, 1:-1] = area
# padded_area[0] = padded_area[-2]
# padded_area[-1] = padded_area[1]
# padded_area[:, 0] = padded_area[:, -2]
# padded_area[:, -1] = padded_area[:, 1]
# counts = np.sum(windows, axis=(2, 3))
# return (counts == 3) | (counts == 4) & (area == 1)
# return advance
# advance = create_faster_advance(20, 40)
# 30 μs
def create_faster_advance(h, w):
padded_area = np.zeros((h+2, w+2), dtype=bool)
windows = np.lib.stride_tricks.sliding_window_view(padded_area, (3, 3))
counts = np.zeros((h, w), dtype='u1')
@numba.njit
def update_counts(counts):
for y in range(h):
for x in range(w):
counts[y, x] = np.sum(windows[y, x])
@numba.vectorize([numba.bool_(numba.bool_, numba.uint8)])
def check_counts(area, counts):
return (counts == 3) | (counts == 4) & (area == 1)
update_counts(counts)
check_counts(padded_area[1:-1, 1:-1], counts)
def advance(area):
padded_area[1:-1, 1:-1] = area
padded_area[0] = padded_area[-2]
padded_area[-1] = padded_area[1]
padded_area[:, 0] = padded_area[:, -2]
padded_area[:, -1] = padded_area[:, 1]
update_counts(counts)
return check_counts(area, counts)
return advance
advance = create_faster_advance(20, 40)
def draw(area):
area = np.array(['.', 'X'])[area.astype('u1')]
print(*[''.join(row) for row in area], sep='\n')
print()
area = np.zeros((20, 40), dtype=bool)
add_glider(area, 0, 18)
count = 10_000
t1 = time.perf_counter()
for i in range(0, count):
area = advance(area)
t2 = time.perf_counter()
draw(area)
print(f'Game took {1_000 * (t2 - t1):.0f} ms.')
print(f'Advance took {1_000_000 * (t2 - t1) / count:.0f} micro.')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment