Understand Conway's Game of Life
00:00 In the previous lesson, I gave an overview of the course. In this lesson, I’ll introduce you to Cellular Automata and Conway’s specific rules to implement.
00:09 One, Conway’s game of life isn’t so much a game as a simulation. It is one type of cellular automata, which is a kind of visual math puzzle that has a regular grid of cells where each cell has a finite number of states and the system is based on rules using the current state to produce the next state in the system.
00:31 You can think of it as a graphical representation of a bunch of interlocking state machines all operating at once.
00:39 Conway’s game of life is named after John Horton Conway, a British mathematician who in 1970 devised a specific set of rules. His version of the game uses a 2D grid of squares.
00:52 Some more complex cellular automata use hexes or even go into the third dimension in Conway’s version. Each square in his grid has only two states, usually referred to as alive or dead, and there are just a few simple rules for determining the next state, all of which are based on the immediate neighbors in the grid.
01:14 Let’s walk through the set of rules. Each of these gets applied to the current state or frame to determine the next state for any given cell. If it is alive and less than two of its neighbors are alive, it dies.
01:29 This is sometimes called the underpopulation rule. If it is alive and more than three of its neighbors are alive, it dies, sometimes called the overpopulation rule.
01:41 If a cell is alive and exactly two or three of its neighbors are alive, it stays alive. And finally, if a cell is dead and exactly three of its neighbors are alive, the dead cell becomes alive.
01:54 This is sometimes called the reproduction rule.
01:58 Let’s walk through the content of frame one and build up frame two. By applying these four rules, consider the cell with the question mark in the two frames.
02:08 This is the first cell I’m going to process using the rules on the left to populate the cell in frame two, based on the neighbors of the cell in frame one.
02:19 In frame one, I’ve colored the neighbors of the question mark. Green indicates the three neighbors in the grid while the other neighbors are outside the grid’s boundaries.
02:29 You can think of this in two different ways, either as the grid being infinite, but only those items being displayed get processed. Or you can think of it as bound and treat out of bound cells as dead.
02:41 Every time I determine the future state of a cell, I consider eight neighbors. In this case, five of which are outside the boundary. None of these eight cells is currently alive, so the first rule applies: less than two are alive, so the future state of the cell is dead, the same as its current state.
03:01 I’ve moved a little further along, once again looking at the question mark cells. The blue shaded cells in frame two indicate cells that have already been processed.
03:10 It’s not really important as you can process the cells in any order, but I figured I’d give you a little visualization note that you’re not doing in-cell editing.
03:20 The entire future state is based on the entire current state. You don’t change values in the same grid as you go. There is a variation on the game that does this, but it doesn’t cause the same results.
03:32 Like with the previous question mark case, the green on the left-hand side indicates the neighbors of the cell being computed. This cell has one alive neighbor.
03:43 Note that the cell itself is not considered a neighbor.
03:47 Once again, the first rule is getting applied and the future state of this cell is dead. So in frame two, the state is different than the current state.
03:58 I’ve processed a few more cells, once again looking at the question marks. This time there are three neighbors inside the green cells. The current cell is dead and it has exactly three neighbors.
04:10 So rule four gets invoked, this cell gets it on, triggering the reproduction rule, and the future state is alive. Future moving one cell to the right, the center cell is alive and has exactly two neighbors.
04:24 So the third rule is run, leaving the cell alive,
04:29 and this is the final state of the second frame. Calculating frame three would be done in the same way, but by using frame two as the current state. In the next lesson, I’ll be talking about how to store this data for your program.
04:43 File that away for now and maybe think about how you’d approach the problem yourself.
04:49 One of the things mathematicians find so fascinating about cellular automata is how a few simple rules can create quite complex behavior. Conway’s game of life is popular partially because the rules are so simple. Using the same four rules, but different starting patterns produces drastically different outcomes.
05:08 The example I used to show you how the rules work is known as the blinker pattern. It’s part of a family of patterns known as oscillators, named that way because they loop endlessly through a series of frames.
05:22 Our vertical bar becomes a horizontal one in the next frame and in the following frame goes back to being vertical.
05:30 There is a whole vocabulary behind patterns in cellular automata. There are blobs that do nothing. No matter how many frames go by, they retain the same shape.
05:40 These are known as still lifes. I already showed you the blinker, but there are other types of oscillators as well. One goes through 15 different frames before repeating and is known as Penta decathlon.
05:54 Another family of patterns are known as spaceships. These are oscillating patterns that move, so instead of oscillating in place, they shift along as the pattern changes.
06:05 Our implementation of the game uses a pattern file so you can easily load in new patterns to play with without modifying the code.
06:14 You’ve seen how the game of life works. Let’s briefly think about what it will mean to implement it in Python. You’re going to need to represent the state of the grid as data.
06:24 You’ll need some way of generating the next state based on the current one and some patterns to use as the initial state. Those requirements apply to any implementation of cellular automata.
06:36 Let’s drill down onto some specifics for our program.
06:40 The whole point of visualizing multiple frames is to animate it, so you’ll need a way of displaying the next frame subsequently over the current one. Having initial patterns as part of the code is limiting, so let’s use a data file so the user can insert their own patterns.
06:57 The program is going to have some patterns that the user might want to muck with. At bare minimum, you’re going to need the name of the initial pattern to use, but you might also want to change the size of the grid, how many frames to show, how fast the frames go and other things.
07:12 You can use command line arguments to change the parameters to your code.
07:17
For most programs in your terminal, you run them directly. For Python code, you usually have to type python
then the name of the script. There is a way to make your script more like a direct program though, so let’s make it runnable.
07:31 Of course, it is still Python, so all this needs to be done in a virtual environment.
07:38
Here’s the file structure I’m going to use as I go along. I’m calling the script rp_life
, RP for Real Python.
07:45
Inside the program’s directory, I have a pyproject.toml
file that gets used to specify how the script gets built and ultimately will be how the script becomes a directly runnable program.
07:57
There’s a nested rp_life/
directory inside my rp_life/
directory. As annoying as I find this, it’s common practice. The first level is the name of the package that gets installed, while the second level is the name of the Python module, and in our case also the name of the runnable script hook.
08:15
The __main__
file is the entry point for the script. Once it becomes runable, cli.py
is where I’m going to put command line argument configuration.
08:25
grid.py
stores the data grid patterns. patterns.py
contains the definitions of the data structure for the initial patterns, and views.py
is responsible for displaying content to the screen.
08:38
This module also contains at data file, patterns.toml
. This has some predefined patterns the user can get started with. You can create all these files in your IDE right now, leaving them empty if you like, or you can code the pieces as you go along.
08:53 Don’t forget that source code is provided with this course and available in the supporting material dropdown below the video for this course. The code is divided into lesson directories.
09:03 You can see the desired state at the end of each lesson. As the course progresses, you’re probably itching to write some code, but before getting there, I’m going to spend some time thinking about how to represent the data first.
Become a Member to join the conversation.