See still life, glider and spaceship, oscillators, etc. Also see A New Kind of Science.
"""
life.py
J. H. Conway's Game of Life.
The number of rows that you see is self.nrows.
Their index numbers run from 0 to self.nrows - 1 inclusive.
In addition, there are extra additional rows that are not displayed.
Their index numbers run from self.nrows to self.nrows + Life.extra - 1
inclusive.
Finally, there is one more row, at index number self.nrows + Life.extra,
that is always empty.
Ditto for the columns.
"""
import tkinter
import time
class Life(object):
extra = 5 #how many extra rows or columns of boxes along each edge
def __init__(self, picture):
picture = picture.splitlines()
self.nrows = len(picture)
self.ncols = len(picture[0])
self.b = self.emptyBoard()
for row in range(self.nrows):
self.b[Life.extra + row][Life.extra:Life.extra + self.ncols] = \
[picture[row][col] == "X" for col in range(self.ncols)]
def get(self, x, y):
"Return the value at row y, column x."
assert 0 <= x < self.ncols and 0 <= y < self.nrows
return self.b[Life.extra + y][Life.extra + x]
def emptyBoard(self):
"Return a two-dimensional list of Bools (all False)."
return [(self.ncols + 2 * Life.extra) * [False]
for i in range(self.nrows + 2 * Life.extra)]
def next(self):
b1 = self.emptyBoard()
for y in range(1, 2 * Life.extra + self.nrows - 1):
for x in range(1, 2 * Life.extra + self.ncols - 1):
#How many of the 8 neighbors of (x, y) are occupied?
listOf8Neighbors = [
self.b[y1][x1]
for y1 in range(y - 1, y + 2)
for x1 in range(x - 1, x + 2)
if x1 != x or y1 != y
]
count = listOf8Neighbors.count(True)
if count == 2:
b1[y][x] = self.b[y][x] #Law of Survival
else:
b1[y][x] = count == 3 #Laws of Birth and Death
self.b = b1
def _test():
import tkinter
picture = """\
...........
.X......X..
..XX....X..
.XX.....X..
...........
...........
...........
...........
.XX........
.XX........
...........
"""
life = Life(picture)
boxSide = 12 #pixels
root = tkinter.Tk()
root.title("Conway's Game of Life")
#dimensions in pixels
root.geometry(f"{life.ncols * boxSide}x{life.nrows * boxSide}")
canvas = tkinter.Canvas(root, highlightthickness = 0)
canvas.pack(expand = tkinter.YES, fill = "both")
while True:
draw(life, canvas, boxSide)
life.next()
root.update()
time.sleep(0.5)
def draw(life, canvas, boxSide):
canvas.delete(tkinter.ALL)
for y, row in enumerate(life.b[Life.extra:Life.extra + life.nrows]):
for x, box in enumerate(row[Life.extra:Life.extra + life.ncols]):
left = x * boxSide
top = y * boxSide
canvas.create_rectangle(
left,
top,
left + boxSide,
top + boxSide,
width = 1, #width of border
outline = "white", #color of border
fill = "black" if box else "gray"
)
if __name__ == '__main__':
_test()
Test the module:
python3 -m life
This program imports the above module.
"""
lifeimporter.py
Run J. H. Conway's Game of Life on a tkinter Canvas widget.
"""
import tkinter
import time
import life #the module life.py that we wrote
#Gosper glider gun.
picture = """\
......................................
.........................X............
.......................X.X............
.............XX......XX............XX.
............X...X....XX............XX.
.XX........X.....X...XX...............
.XX........X...X.XX....X.X............
...........X.....X.......X............
............X...X.....................
.............XX.......................
......................................
......................................
......................................
......................................
......................................
......................................
......................................
......................................
......................................
......................................
......................................
......................................
......................................
......................................
......................................
......................................
"""
game = life.Life(picture)
boxSize = 12 #in pixels
def draw(game, canvas):
canvas.delete(tkinter.ALL)
for y in range(game.nrows):
for x in range(game.ncols):
left = x * boxSize
top = y * boxSize
canvas.create_rectangle(
left,
top,
left + boxSize,
top + boxSize,
width = 1, #width of border
outline = "white", #color of border
fill = "black" if game.get(x, y) else "gray"
)
root = tkinter.Tk()
root.title("Conway's Game of Life")
#dimensions in pixels
root.geometry(f"{boxSize * game.ncols}x{boxSize * game.nrows}")
canvas = tkinter.Canvas(root, highlightthickness = 0)
canvas.pack(expand = tkinter.YES, fill = "both")
while True:
draw(game, canvas)
game.next()
root.update()
time.sleep(0.25)