Conway’s Game of Life is a cellular automata simulation that follows simple rules to create interesting patterns. It was invented by mathematician John Conway in 1970 and popularized by Martin Gardner’s “Mathematical Games” column in Scientific American. Today, it’s a favorite among programmers and computer scientists, though it’s more an interesting visualization than a true “game.” The two-dimensional board has a grid of “cells,” each of which follows three simple rules:
The living or dead state of the cells in the next step of the simulation depends entirely on their current state. The cells don’t “remember” any older states. There is a large body of research regarding the patterns that these simple rules produce. Tragically, Professor Conway passed away of complications from COVID-19 in April 2020. More information about Conway’s Game of Life can be found at https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life, and more information about Martin Gardner at https://en.wikipedia.org/wiki/Martin_Gardner.
When you run conwaysgameoflife.py, the output will look like this:
O O OO O O
O O O O O O OOOO O OO
OO O O O O O O O
OO O O OO OO
OO OO O O O OO
OO O O O OO
OOO OO OO O
O OOO
O O O O
OO OO OO OO O
OOO OO OOOO O O
O OO O O O OO OO O O OO
O O O O O OO O O OOO
O OOOO OO OO O OOOOO O
OO O O OOO O OOO OOOO O
The state of the cells is stored in dictionaries in the cells
and nextCells
variables. Both dictionaries have (x, y)
tuples for keys (where x
and y
are integers), 'O'
for living cells, and ' '
for dead cells. Lines 40 to 44 are set up to print a representation of these dictionaries onto the screen. The cells
variable’s dictionary represents the current state of the cells, while nextCells
stores the dictionary for the cells in the next step in the simulation.
1. """Conway's Game of Life, by Al Sweigart [email protected]
2. The classic cellular automata simulation. Press Ctrl-C to stop.
3. More info at: https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life
4. This code is available at https://nostarch.com/big-book-small-python-programming
5. Tags: short, artistic, simulation"""
6.
7. import copy, random, sys, time
8.
9. # Set up the constants:
10. WIDTH = 79 # The width of the cell grid.
11. HEIGHT = 20 # The height of the cell grid.
12.
13. # (!) Try changing ALIVE to '#' or another character:
14. ALIVE = 'O' # The character representing a living cell.
15. # (!) Try changing DEAD to '.' or another character:
16. DEAD = ' ' # The character representing a dead cell.
17.
18. # (!) Try changing ALIVE to '|' and DEAD to '-'.
19.
20. # The cells and nextCells are dictionaries for the state of the game.
21. # Their keys are (x, y) tuples and their values are one of the ALIVE
22. # or DEAD values.
23. nextCells = {}
24. # Put random dead and alive cells into nextCells:
25. for x in range(WIDTH): # Loop over every possible column.
26. for y in range(HEIGHT): # Loop over every possible row.
27. # 50/50 chance for starting cells being alive or dead.
28. if random.randint(0, 1) == 0:
29. nextCells[(x, y)] = ALIVE # Add a living cell.
30. else:
31. nextCells[(x, y)] = DEAD # Add a dead cell.
32.
33. while True: # Main program loop.
34. # Each iteration of this loop is a step of the simulation.
35.
36. print('\n' * 50) # Separate each step with newlines.
37. cells = copy.deepcopy(nextCells)
38.
39. # Print cells on the screen:
40. for y in range(HEIGHT):
41. for x in range(WIDTH):
42. print(cells[(x, y)], end='') # Print the # or space.
43. print() # Print a newline at the end of the row.
44. print('Press Ctrl-C to quit.')
45.
46. # Calculate the next step's cells based on current step's cells:
47. for x in range(WIDTH):
48. for y in range(HEIGHT):
49. # Get the neighboring coordinates of (x, y), even if they
50. # wrap around the edge:
51. left = (x - 1) % WIDTH
52. right = (x + 1) % WIDTH
53. above = (y - 1) % HEIGHT
54. below = (y + 1) % HEIGHT
55.
56. # Count the number of living neighbors:
57. numNeighbors = 0
58. if cells[(left, above)] == ALIVE:
59. numNeighbors += 1 # Top-left neighbor is alive.
60. if cells[(x, above)] == ALIVE:
61. numNeighbors += 1 # Top neighbor is alive.
62. if cells[(right, above)] == ALIVE:
63. numNeighbors += 1 # Top-right neighbor is alive.
64. if cells[(left, y)] == ALIVE:
65. numNeighbors += 1 # Left neighbor is alive.
66. if cells[(right, y)] == ALIVE:
67. numNeighbors += 1 # Right neighbor is alive.
68. if cells[(left, below)] == ALIVE:
69. numNeighbors += 1 # Bottom-left neighbor is alive.
70. if cells[(x, below)] == ALIVE:
71. numNeighbors += 1 # Bottom neighbor is alive.
72. if cells[(right, below)] == ALIVE:
73. numNeighbors += 1 # Bottom-right neighbor is alive.
74.
75. # Set cell based on Conway's Game of Life rules:
76. if cells[(x, y)] == ALIVE and (numNeighbors == 2
77. or numNeighbors == 3):
78. # Living cells with 2 or 3 neighbors stay alive:
79. nextCells[(x, y)] = ALIVE
80. elif cells[(x, y)] == DEAD and numNeighbors == 3:
81. # Dead cells with 3 neighbors become alive:
82. nextCells[(x, y)] = ALIVE
83. else:
84. # Everything else dies or stays dead:
85. nextCells[(x, y)] = DEAD
86.
87. try:
88. time.sleep(1) # Add a 1 second pause to reduce flickering.
89. except KeyboardInterrupt:
90. print("Conway's Game of Life")
91. print('By Al Sweigart [email protected]')
92. sys.exit() # When Ctrl-C is pressed, end the program.
After entering the source code and running it a few times, try making experimental changes to it. The comments marked with (!)
have suggestions for small changes you can make. On your own, you can also try to figure out how to do the following:
Try to find the answers to the following questions. Experiment with some modifications to the code and rerun the program to see what effect the changes have.
WIDTH = 79
on line 10 to WIDTH = 7
?print('\n' * 50)
on line 36?random.randint(0, 1)
on line 28 to random.randint(0, 10)
?nextCells[(x, y)] = DEAD
on line 85 to nextCells[(x, y)] = ALIVE
?