Lesson 3 - Conway’s Game of Life

Author

Valentine Gilbart

Published

May 28, 2025

7 Introduction

7.1 Aim of the class

This last class is to pratice the notions learned on a couple of (larger) exercises.

Figure 7.1: pssssss

The exercises have one provided solution, but it is not the only one. We all have a different coding style, and it evolves with time. So do not worry if you have a different solution, as long as your result is correct, that’s already great!

7.2 Requirements

Remembering some of lesson 1 and 2.

8 Conway’s Game of Life (basic)

8.1 Instructions

Create an implementation of Conway’s Game of Life in a script called conway_life_basic.py.

The game consists in initializing a 2D matrix of binary value (0 or 1), and, by following certain rules, observing its evolution at each generation.

Each value represent a cell, that can either be live (0) or dead (1).

8.2 Rules

Cells interact with their neighbors such that:

  • Any live cell with fewer (<) than two live neighbors dies (as if by underpopulation)
  • Any live cell with more than three (>) live neighbors dies (as if by overpopulation)
  • Any live cell with two or three live neighbors lives on to the next generation
  • Any dead cell with exactly three live neighbors becomes a live cell (as if by reproduction)

The new matrix created corresponds to a new generation.

The original game is played on a infinite board, but we’ll implement it to a finite board. When a cell is in a corner, it has 3 neighbors. When a cell is on a side it has 5 neighbors.

8.3 Functions to create

You should create:

  • a count_neighbors function that counts the number of live neighbors around a cell
  • a survival function that determines if a cell survives or dies based on the rules of the game
  • a generation function that generate the next generation of the game
  • an animate_life function that animate the game of life

You should use basic python, and print each generation to the terminal as follows:

  • live cells are represented by a *
  • dead cells are represented by a .

e.g. the following 3-by-3 2D matrix has one live cell in the center:

. . . 
. * . 
. . . 

You will need to initialize a matrix to begin the game, then it should run on its own for a defined amount of generations.

8.4 Optional function

As an option, you can create a function called initialize_universe to initialize the grid with one of the following seeds that have specific proprieties:

# Dictionary containing different seed patterns for the game
seeds = {
    "diehard": [
        [0, 0, 0, 0, 0, 0, 1, 0],
        [1, 1, 0, 0, 0, 0, 0, 0],
        [0, 1, 0, 0, 0, 1, 1, 1],
    ],
    "boat": [[1, 1, 0], [1, 0, 1], [0, 1, 0]],
    "r_pentomino": [[0, 1, 1], [1, 1, 0], [0, 1, 0]],
    "pentadecathlon": [
        [1, 1, 1, 1, 1, 1, 1, 1],
        [1, 0, 1, 1, 1, 1, 0, 1],
        [1, 1, 1, 1, 1, 1, 1, 1],
    ],
    "beacon": [[1, 1, 0, 0], [1, 1, 0, 0], [0, 0, 1, 1], [0, 0, 1, 1]],
    "acorn": [[0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0], [1, 1, 0, 0, 1, 1, 1]],
    "spaceship": [[0, 0, 1, 1, 0], [1, 1, 0, 1, 1], [1, 1, 1, 1, 0], [0, 1, 1, 0, 0]],
    "block_switch_engine": [
        [0, 0, 0, 0, 0, 0, 1, 0],
        [0, 0, 0, 0, 1, 0, 1, 1],
        [0, 0, 0, 0, 1, 0, 1, 0],
        [0, 0, 0, 0, 1, 0, 0, 0],
        [0, 0, 1, 0, 0, 0, 0, 0],
        [1, 0, 1, 0, 0, 0, 0, 0],
    ],
    "infinite": [
        [1, 1, 1, 0, 1],
        [1, 0, 0, 0, 0],
        [0, 0, 0, 1, 1],
        [0, 1, 1, 0, 1],
        [1, 0, 1, 0, 1],
    ],
}

8.5 Exemple of input and output

Here’s an example of input, and the desired output:

# Initialize by hand
universe = [
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 1, 1, 1, 0, 1, 0, 0, 0],
  [0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 1, 1, 0, 0, 0],
  [0, 0, 0, 1, 1, 0, 1, 0, 0, 0],
  [0, 0, 1, 0, 1, 0, 1, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
]

animate_life(universe, generations = 3, delay=0.5)
. . . . . . . . . .
. . . * . . . . . .
. . * * . . . . . .
. . * . * . * . . .
. . . * * * * . . .
. . . * * . * * . .
. . . . * . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .


. . . . . . . . . .
. . * * . . . . . .
. . * . * . . . . .
. . * . . . * . . .
. . * . . . . . . .
. . . . . . * * . .
. . . * * * . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .


. . . . . . . . . .
. . * * . . . . . .
. * * . . . . . . .
. * * . . . . . . .
. . . . . . * * . .
. . . * * * * . . .
. . . . * * * . . .
. . . . * . . . . .
. . . . . . . . . .
. . . . . . . . . .

The same matrix can be initialized by the following (if you are doing the optional initialize_universe function):

# Initialize with a seed
universe = initialize_universe(universe_size = (10, 10), seed = "infinite", seed_position = (2, 2))
for row in universe:
  print(row)
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 1, 1, 1, 0, 1, 0, 0, 0]
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 1, 1, 0, 0, 0]
[0, 0, 0, 1, 1, 0, 1, 0, 0, 0]
[0, 0, 1, 0, 1, 0, 1, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

With this matrix, if the number of generations increases (> 30), it should stabilize over:

. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . * * .
. . * * . . * . . *
. . * * . . . * . *
. . . . . . . . * .
. . . . . . . . . .
. . . . . . . . . .

8.6 Tips

  • Take an exemple and do it by hand to better understand the game.
  • Before jumping into coding, try to have a plan of how you will implement it all. Imagine what will be the input and output of each function.
  • To visualize the evolution of the grid, you can print it, and then can clean the terminal by using os.system('cls' if os.name == 'nt' else 'clear') (you will need to import os at the beginning of your script).
  • To wait between two generations you can use time.sleep(delay) (you will need to import time at the beginning of your script).

9 Conway’s Game of Life (advanced)

9.1 Instructions

Create another implementation of Conway’s Game of Life, with the following characteristics:

  • the file parses arguments from command line (if you use argparse, you can check the help of your function by running in the terminal python conway_life_advanced.py --help)
  • use pandas (or numpy as there it is only numerical data) to deal with the matrix
  • use matplotlib to plot each generation, and create a final gif

Example of a final gif generated from the same universe matrix as the one from basic implementation

10 Solutions

Both solutions are available in the folder exercise/script/.