In a continuation of understanding models of life, one of the most interesting cellular automatons is a two dimensional "life-like" automaton. The first life-like automaton was created by John Conway in 1970, and was published in the October 1970 release of Scientific American. The intrigue that surrounds the automaton comes from the emergence and self-organization of highly complex patterns as the simulation evolves. As a result, these automata have attracted the interest of computer scientists, mathematicians, biologists, and physicists.
Let's examine the rules of Conway's cellular automaton and see if we can implement a simple life-like cellular automaton in python.
Four basic rules define the spatial interactions that determine how life in the world evolve:
- Any live cell with fewer than two live neighbors dies.
- Any live cell with two or three live neighbors lives.
- Any live cell with more than three live neighbors dies.
- Any dead cell with exactly three live neighbors becomes a live cell.
Based on these rules, underpopulated and overpopulated cells die, existing communities survive, and cells can be populated through migration. In our implementation, we are going to use a Moore neighborhood to examine relationships, and all cells will be evaluated simultaneously each tick of discrete time.
We can start by defining how we want our simulation to work. In general, we must create a world, populate the world with life, and then let the world evolve and output its new state each tick. In the abstract, this only requires a world and functions to manipulate the world. We can take these basic steps and implement them as classes and functions.
Now we can flesh out exactly what the world is. In our case, the world is a two-dimensional array with width and height that stores if a cell is dead or alive. Additionally, we don't want to lose information as out cells migrate across borders, so we must treat the world as a torus, which we will get to in a bit.
First, let's define our world object, and specify what happens when we make a new one. We must determine the width and height of the terminal, and then create a multidimensional array to fit the dimensions.
We can then take the world that we created, and populate it with life. For our purposes we are not interested in testing specific geometries, so we can instead pseudo-randomly assign life to each cell. For the sake of simplicity a uniform distribution can be applied.
We now have the simple task of outputting the current state of the world. To that end all we need to do is iterate through each row and concatenate the characters into a string.
Last but certainly not least, we must evaluate the cells and generate the state of the world for the next tick. For each tick, we must evaluate each cell by counting its neighbors, and following Conway's rules determine if the cell will survive into the next generation. The next generation cannot interfere with the current state of the world, and each cell must remain within our torus world.
With our class and functions defined, we can put all of our code together and run our own life-like cellular automaton. Due to the initial stochastic distribution of life, each run will be unique with its own still lifes, oscillators, and spaceships.
The complete script is freely available on github. Happy simulating!