Why use a set of coordinates?
A large empty grid does not need to be stored. Only a live cell or one of its neighbours can be alive next generation. The coordinate set can expand in every direction, including negative coordinates, without a wrapping rule or a clipped edge.
The complete example
# Unbounded B3/S23. Coordinates are integer (x, y) tuples.
from collections import Counter
def next_generation(live):
counts = Counter(
(x + dx, y + dy)
for x, y in live
for dy in (-1, 0, 1)
for dx in (-1, 0, 1)
if dx != 0 or dy != 0
)
return {
position
for position, count in counts.items()
if count == 3 or (count == 2 and position in live)
}
if __name__ == "__main__":
live = {(0, 1), (1, 1), (2, 1)}
for generation in range(3):
print(generation, sorted(live))
live = next_generation(live)
Download game_of_life.pyRun and verify it
Save the file and run python3 game_of_life.py. At generation 0 the live cells are (0,1), (1,1), (2,1). At generation 1 they are (1,0), (1,1), (1,2). Generation 2 returns to the first set.
Check the same two-step cycle in the browser.
Three checks before changing the rule
- Exclude the centre cell from its own neighbour count.
- Keep the old live set unchanged while constructing the next set.
- Test an isolated cell (it dies), a block (it stays unchanged), and a glider (the same shape translates after four steps).
Limits and next experiments
This direct sparse algorithm is for small experiments, not a replacement for Hashlife on huge patterns. A long-running seed can still use a lot of time and memory. The visual teaching board uses finite edges, while this example uses an unbounded plane.
Inspect the small-seed experiment · Read the B3/S23 rules · Open the advanced viewer