IACS Computes! High School summer camp
Day 1
Day 2
Day 3
Day 4
Day 5
Day 6
Day 7
Day 8
Day 9
Modelling life is hard. In science, when we want to model something complex, we begin by breaking it down into something simpler until it becomes easy enough to us to understand.
This is the principle behind a cellular automaton. A collection of objects (or cells) can have each have two possible states: alive or dead. We model the objects as living on some sort of grid. The objects are then evolved over a series of timesteps. At each new timestep, the new state of each cell depends on its previous state and on the states of its immediate neighbors.
Let’s begin by looking at a 1d cellular automaton.
# this is the initial state of the cells
initial_cells = [0, 0, 0, 0, 1, 0, 0, 0, 0]
# this defines the behavior of the automaton. Each entry in the dictionary
# describes a cell and its two neighbors, and returns the what the new value of the
# cell should be for each possible state
rules = {(0,0,0): 0, (0,0,1): 1, (0,1,0): 0, (0,1,1): 1, (1,0,0):1, (1,0,1): 0, (1,1,0): 1, (1,1,1): 0}
# evolve the cells through a single step
def step(cells, rules):
new_cells = [0] * len(cells)
# do the inner cells
for i in range(1, len(cells)-1):
# update the ith cell using the rules dictionary
# note that I'm casting the list as a tuple
# (remember how lists are mutable so we can't use them for indexing?)
new_cells[i] = rules[tuple(cells[i-1:i+2])]
# we must deal with the first and last cells separately as they do not have both neighbors
# instead, we shall pretend that the cells wrap around, so the cell at the end becomes the
# cell to the left of the first cell, and the first cell becomes the cell to the right of the
# last cell
new_cells[0] = rules[tuple([cells[-1]] + cells[:2])]
new_cells[-1] = rules[tuple(cells[-2:] + [cells[0]])]
return new_cells
# evolve the cells through n steps
def evolve(cells, rules, nsteps):
print(cells)
for i in range(nsteps):
cells = step(cells, rules)
print(cells)
evolve(initial_cells, rules, 15)
[0, 0, 0, 0, 1, 0, 0, 0, 0]
[0, 0, 0, 1, 0, 1, 0, 0, 0]
[0, 0, 1, 0, 0, 0, 1, 0, 0]
[0, 1, 0, 1, 0, 1, 0, 1, 0]
[1, 0, 0, 0, 0, 0, 0, 0, 1]
[1, 1, 0, 0, 0, 0, 0, 1, 1]
[0, 1, 1, 0, 0, 0, 1, 1, 0]
[1, 1, 1, 1, 0, 1, 1, 1, 1]
[0, 0, 0, 1, 0, 1, 0, 0, 0]
[0, 0, 1, 0, 0, 0, 1, 0, 0]
[0, 1, 0, 1, 0, 1, 0, 1, 0]
[1, 0, 0, 0, 0, 0, 0, 0, 1]
[1, 1, 0, 0, 0, 0, 0, 1, 1]
[0, 1, 1, 0, 0, 0, 1, 1, 0]
[1, 1, 1, 1, 0, 1, 1, 1, 1]
[0, 0, 0, 1, 0, 1, 0, 0, 0]
Take a look at this code and try and see if you can follow what it’s doing by comparing the cells at each step (if you don’t, ask one of the instructors!).
For example, look at the central cell in the first row. It starts off as a 1, with 0s on either side. This means that we need to look up the 010
pattern in the rules
dictionary, which tells us that at the next step the cell should be a 0. Sure enough, if you look at the central cell in the next step, it has now turned into a 0.
Ok cool. But how does this relate to life? Well you can think of the cells as living things (e.g. bacteria, or maybe even some actual organic cells). Living things need certain things to be alive: food, warmth, oxygen, room to move etc. So we can think of the rules of the automaton as describing these rules. If too many cells are alive in a certain area, then they shall not have enough resources and so they shall die (111
-> 0). If all cells are dead, then it’s not possible for them to spontaneously come back to life (000
-> 0). However, if the balance is just right (the cell has a single alive neighbor), then the cell shall have enough food and warmth to survive (e.g. 110
-> 1).
For this project, you’re going to build The Game of Life. This is a 2d cellular automaton. It has the following rules:
Your project is to write a code that plays the game of life. To give you some hints on how to get started, here is suggested list of functions/bits of code that you could write:
When you’ve got your code working, try running it with different grid sizes and different starting configurations. You can read about all the crazy patterns that can be created on the Game of Life wikipedia page.
If you manage to get through all of that, then great! This project is not easy, so getting to the point where you have a working game of life would be a very impressive achievement. However, if you do complete all of the above, then here are a few suggestions for extra things you can do:
imshow
from matplotlib
(see below). Instead of printing the cells at each timestep, output them using imshow
.FuncAnimation
here# Use imshow to print a grid
import matplotlib.pyplot as plt
%matplotlib inline
img = plt.imshow([[0,0,1,0],
[1,1,0,1]])
plt.axis('off')
img
<matplotlib.image.AxesImage at 0x7f239498d1d0>