life.py

A minimal Game of Life in Python.

I was impressed with the style of code in an implementation of Conway’s Game of Life mentioned in this video. It reminded me a lot of Peter Norvig’s style in Udacity CS212 Design of Computer Programs. So, I stopped it and copied the update function. Then I added in a few extra lines to print the board, some comments, and some changes to make the board toroidal, and here we go.

Code

(Download here)

#!/usr/bin/env python

# This is copied from Jack Diederich's enjoyable talk
# http://pyvideo.org/video/880/stop-writing-classes

# I changed it only by making the board toroidal and printing the
# board out on each iteration and putting three well-known entities in
# the initial board.

from __future__ import print_function
import itertools, time

size = 15

def neighbours(point):
    x, y = point
    yield x, (y+1)%size
    yield x, (y-1)%size
    yield (x+1)%size, (y+1)%size
    yield (x+1)%size, y
    yield (x+1)%size, (y-1)%size
    yield (x-1)%size, (y+1)%size
    yield (x-1)%size, y
    yield (x-1)%size, (y-1)%size

def advance(board):
    newstate = set()
    # only currently-live points and neighbours of currently-live
    # points need be considered.
    recalc = board | set(itertools.chain(*map(neighbours, board)))
    for point in recalc:
        # how many neighbours?
        count = sum((neigh in board)
                    for neigh in neighbours(point))
        # if 3 neighbours, or 2 + self, live!
        if count == 3 or (count == 2 and point in board):
            newstate.add(point)
    return newstate

def print_board(board):
    print("-" * (2*size+3)) # print top border
    for x in range(size):
        print("| ", end="") # print left-hand border
        for y in range(size):
            if (x, y) in board:
                # living cell
                print("* ", end="")
            else:
                # dead cell
                print("  ", end="")
        print("|") # print right-hand border
    print("-" * (2*size+3)) # print bottom border

def main():
    glider = set([(0, 0), (1, 0), (2, 0), (0, 1), (1, 2)])
    blinker = set([(12, 2), (11, 2), (10, 2)])
    beacon = set([(2, 10), (3, 10), (2, 11), (4, 13), (5, 12), (5, 13)])
    board = glider | blinker | beacon

    for i in range(1000):
        print_board(board)
        board = advance(board)
        time.sleep(0.1)

if __name__ == "__main__": main()