Skip to content

Commit 7957f8e

Browse files
authored
Add files via upload
1 parent 4cadb85 commit 7957f8e

File tree

2 files changed

+172
-0
lines changed

2 files changed

+172
-0
lines changed

game_of_life5.py

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
# Conway's Game of Life
2+
# ---------------------
3+
#
4+
# from Wikipedia:
5+
# ************************************
6+
# Rules
7+
#
8+
# The universe of the Game of Life is an infinite, two-dimensional orthogonal grid of square cells,
9+
# each of which is in one of two possible states, live or dead (or populated and unpopulated, respectively).
10+
# Every cell interacts with its eight neighbours, which are the cells that are horizontally,
11+
# vertically, or diagonally adjacent. At each step in time, the following transitions occur:
12+
#
13+
# Any live cell with fewer than two live neighbours dies, as if by underpopulation.
14+
# Any live cell with two or three live neighbours lives on to the next generation.
15+
# Any live cell with more than three live neighbours dies, as if by overpopulation.
16+
# Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.
17+
#
18+
# The initial pattern constitutes the seed of the system.
19+
# The first generation is created by applying the above rules simultaneously to every cell in the seed,
20+
# live or dead; births and deaths occur simultaneously,
21+
# and the discrete moment at which this happens is sometimes called a tick.
22+
# [nb 1] Each generation is a pure function of the preceding one.
23+
# The rules continue to be applied repeatedly to create further generations.
24+
# *************************************
25+
#
26+
# Rules for Game of life per number of neighbours
27+
# alive = True; dead = False
28+
# neigbours action if True action if False
29+
# 0 False False
30+
# 1 False False
31+
# 2 True False
32+
# 3 True True
33+
# 4 False False
34+
# 5 False False
35+
# 6 False False
36+
# 7 False False
37+
# 8 False False
38+
39+
40+
import tkinter as tk
41+
import numpy as np
42+
43+
# make new tkinter and canvas objects
44+
def generate_tk_canvas(height, width):
45+
print("make tkinter and canvas objects")
46+
new_tk_root = tk.Tk()
47+
new_tk_root.title(txt)
48+
new_tk_canvas = tk.Canvas(new_tk_root, background = "black",
49+
height = height, width = width)
50+
new_tk_canvas.pack()
51+
return new_tk_canvas, new_tk_root
52+
53+
# counts the number of neighbours at location row,col in field
54+
# handles wrap around when at a border of the field
55+
def neighbours2(field, row, col):
56+
# all the row and col indexes to be checked
57+
rows = [(row-1)%Nrow, row, (row+1)%Nrow]
58+
cols = [(col-1)%Ncol, col, (col+1)%Ncol]
59+
# make 3x3 arrays containing row and col indexes
60+
R,C = np.meshgrid(rows,cols)
61+
# sum the elements equal to True, do not count the row,col element itself
62+
n = np.sum(field[R,C]) - field[row, col]
63+
return n
64+
65+
# fill field "target" with new values according to the rules
66+
# and based on values in field "source"
67+
def update_field(source, target, gen_count):
68+
for row in range(Nrow):
69+
for col in range(Ncol):
70+
n = neighbours2(source, row, col)
71+
if n == 2:
72+
target[row, col] = source[row, col]
73+
elif n == 3:
74+
target[row, col] = True
75+
else:
76+
target[row, col] = False
77+
return gen_count+1
78+
79+
# draw graphical representations of "field" on tkinter canvas "cvs"
80+
def drawfield(field, cvs):
81+
# delete previous
82+
cvs.delete('all')
83+
# draw vertical grid lines
84+
x = 0
85+
for col in range(Ncol):
86+
cvs.create_line(x, 0, x, screen_height, fill = grid_color)
87+
x += dx
88+
# draw horizontal grid lines
89+
y = 0
90+
for row in range(Nrow):
91+
cvs.create_line(0, y, screen_width, y, fill = grid_color)
92+
y += dy
93+
# get row and column indexes of elements in array field equal to True
94+
rows, cols = np.where(field == True)
95+
# draw rectangles at locations in grid given by indexes in rows, cols
96+
for row, col in zip(rows, cols):
97+
x = col * dx; y = row * dy
98+
cvs.create_rectangle(x, y, x+dx, y+dy, fill = cell_color, outline = grid_color)
99+
cvs.create_text(100, 40, text = f"{txt}\nGeneration: {gen_count}",
100+
anchor = "nw", font = ("TkFixedFont",18,"normal"), fill = text_color)
101+
cvs.update()
102+
103+
# this functions performs update on one of the field arrays
104+
# and shows new data on the tkinter canvas
105+
# this funtion calls itself after delay "dt"
106+
def update_generation():
107+
global gen_count, field1, field2 # these global vars have to be modified in this function
108+
drawfield(field1, canvas1)
109+
gen_count = update_field(field1, field2, gen_count)
110+
field1, field2 = field2, field1 # swap arrays, latest one becomes source to calc next one
111+
root1.after(dt, update_generation)
112+
113+
# stops program after mouse click
114+
def click_handler(event):
115+
# event also has x & y attributes
116+
if event.num == 1:
117+
root1.destroy()
118+
119+
120+
# parameters
121+
Nrow = 50; Ncol = 75 # number of cells in 2 dimensions
122+
screen_width = 1500; screen_height = 1000 # image size in pixels
123+
dx = int(screen_width / Ncol); dy = int(screen_height / Nrow)
124+
dt = 75 # time delay between steps in milliseconds
125+
txt = "Conway's Game of Life using Python, tkinter and numpy"
126+
grid_color = "#505050"
127+
text_color = "#808080"
128+
cell_color = "red"
129+
130+
# initialise fields
131+
# the fields are numpy arrays of booleans
132+
field1 = np.full((Nrow, Ncol), False, dtype = np.bool_)
133+
field2 = np.full((Nrow, Ncol), False, dtype = np.bool_)
134+
135+
# patterns
136+
# some known patters are defined here as 2 numpy arrays containing
137+
# their row and column index values
138+
# a "blinker", stationary
139+
blinker_rows = np.array((0,1,2))
140+
blinker_cols = np.array((0,0,0))
141+
# a "toad", stationary
142+
toad_rows = np.array((1,1,1,0,0,0))
143+
toad_cols = np.array((0,1,2,1,2,3))
144+
# a "glider", moves diagonally
145+
glider_rows = np.array((1,2,2,1,0))
146+
glider_cols = np.array((0,1,2,2,2))
147+
# a "gosper's gun", complicated machine which generates moving "gliders"
148+
gosper_gun_rows = np.array((5,5,6,6, 5, 6, 7, 4, 8, 3, 9, 3, 9, 6, 4, 8, 5, 6, 7, 6, 3, 4, 5, 3, 4, 5, 2, 6, 1, 2, 6, 7, 3, 4, 3, 4))
149+
gosper_gun_cols = np.array((1,2,1,2,11,11,11,12,12,13,13,14,14,15,16,16,17,17,17,18,21,21,21,22,22,22,23,23,25,25,25,25,35,35,36,36))
150+
151+
# insert patters in field
152+
# adding the patterns to field1 by setting correct elements to True
153+
# adding values to the row or column vectors defines the location in the field
154+
# subtracting a number with the vector flips the orietation of the pattern
155+
field1[gosper_gun_rows+15, gosper_gun_cols+5] = True
156+
157+
# make tkinter root and canvas objects
158+
canvas1, root1 = generate_tk_canvas(screen_height, screen_width)
159+
160+
# define event handler for mouse click
161+
root1.bind("<Button>", click_handler)
162+
163+
# global variable keeps track of number of generations calculated
164+
gen_count = 0
165+
166+
# call this function for the first time, will call itself from then on with time delay
167+
update_generation()
168+
169+
# tkinter main loop
170+
tk.mainloop()
171+
172+

game_of_life_recording.gif

1.59 MB
Loading

0 commit comments

Comments
 (0)