The Game Of Life

By far the most famous cellular automata so far, the Game Of Life was modelled for the first time by the british mathematician and computer scientist John Conway, who looked into common processes seen in population dynamics, like birth, death and stasis, to generate simple rules on which a tile changes its state from alive to dead. In memory of John Conway, it's needed to say that this is not his most influential nor meaningful contribution to the field of mathematics, as he also pioneered in the theory of finite groups, knot theory and game theory, among other fields. However, the Game Of Life remains a meaningful example on the emergence of complex behaviors based on simple rules found at lower levels of organization.


The parameters of the Algorithm

  • DIMS: (int, int) - the number of columns and rows of tiles that make the grid
  • CELLSIZE: int - dimensions of each cell
  • SCREEN: (int, int) - the dimensions of the screen given in pixels
  • CELL: Cell() - Compound datatype that contains the information about the cell
  • GRID: [[CELL, ..., n=DIMS[0]], ..., n=DIMS[1]] - a 2D array of CELL
# An OOP implementation to COnway's Game of Life
import pygame
import random

DIMS = (80,80)
CELLSIZE = 8
SCREEN = (DIMS[0]*CELLSIZE, DIMS[1]*CELLSIZE)
FPS = 10

class Cell():
    def __init__(self, c,r):
        self.c = c
        self.r = r
        self.x = self.c * CELLSIZE
        self.y = self.r * CELLSIZE
        self.state = 1 if random.randint(0,100)<20 else 0
        self.nextState = 0
        self.rect = pygame.Rect(self.x,self.y,CELLSIZE,CELLSIZE)

    def getColor(self):
        if self.state == 1:
            return "white"
        return "black"


# DD. GRID
# grid = [[CELL, ...][]...]
# interp. a grid of cells to be used in the game of life
grid = []
for r in range(DIMS[1]):
    cellRow = []
    for c in range(DIMS[0]):
        cell = Cell(c, r)
        cellRow.append(cell)
    grid.append(cellRow)

# TEMPLATE FOR GRID
# for row in grid:
#   for cell in row:
#       ... cell 



# variables required by pygame but secondary to the main scope of the program
display = pygame.display.set_mode(SCREEN)
clock = pygame.time.Clock()
pygame.init()

The Algorithm

  • For every CELL in GRID:
    • Calculate TOTAL_N: Add the state of the eight neighbors around this CELL
    • Is the CELL state 1 (alive)?
      • T: if TOTAL_N is less than 2 OR more than 3, CELL nextState = 0 (dies)
      • F: if TOTAL_N is 3, CELL nextState = 1 (birth)

Here's a step by step tutorial on how to implement Conway's Game of Life!
# An OOP implementation to COnway's Game of Life
import pygame
import random

DIMS = (80,80)
CELLSIZE = 8
SCREEN = (DIMS[0]*CELLSIZE, DIMS[1]*CELLSIZE)
FPS = 10

class Cell():
    def __init__(self, c,r):
        self.c = c
        self.r = r
        self.x = self.c * CELLSIZE
        self.y = self.r * CELLSIZE
        self.state = 1 if random.randint(0,100)<20 else 0
        self.nextState = 0
        self.rect = pygame.Rect(self.x,self.y,CELLSIZE,CELLSIZE)

    def getColor(self):
        if self.state == 1:
            return "white"
        return "black"


# DD. GRID
# grid = [[CELL, ...][]...]
# interp. a grid of cells to be used in the game of life
grid = []
for r in range(DIMS[1]):
    cellRow = []
    for c in range(DIMS[0]):
        cell = Cell(c, r)
        cellRow.append(cell)
    grid.append(cellRow)

# TEMPLATE FOR GRID
# for row in grid:
#   for cell in row:
#       ... cell 



# variables required by pygame but secondary to the main scope of the program
display = pygame.display.set_mode(SCREEN)
clock = pygame.time.Clock()
pygame.init()

# CODE

def draw():
    display.fill("green")
    for row in grid:
      for cell in row:
          pygame.draw.rect(display,cell.getColor(),cell.rect)
    pygame.display.flip()
    clock.tick(FPS)

def update():
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()

    # Count neighbors and apply rules
    for row in grid:
      for cell in row:
        r= cell.r
        c= cell.c
        ns = [
            grid[r-1][c-1],grid[r-1][c],grid[r-1][(c+1)%DIMS[0]],
            grid[r][c-1],               grid[r][(c+1)%DIMS[0]],
            grid[(r+1)%DIMS[1]][c-1],grid[(r+1)%DIMS[1]][c],grid[(r+1)%DIMS[1]][(c+1)%DIMS[0]],
        ]

        totalN = 0
        for n in ns:
            totalN += n.state
        if cell.state == 1:
            if totalN <2 or totalN > 3:
                cell.nextState = 0
        else:
            if totalN == 3:
                cell.nextState = 1

    # Update the states
    for row in grid:
      for cell in row:
          cell.state = cell.nextState


while True:
    draw()
    update()