/
life.py
181 lines (151 loc) · 4.64 KB
/
life.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# Exemplar implementation of the Conway's Life Project
from ggame import CircleAsset, Color, LineStyle, Sprite
from ggame import App
red = Color(0xff0000, 1.0)
blue = Color(0x0000ff, 1.0)
black = Color(0,1.0)
CELLDIAMETER = 10
redcircle = CircleAsset(CELLDIAMETER/2, LineStyle(0, black), red)
bluecircle = CircleAsset(CELLDIAMETER/2, LineStyle(0, black), blue)
deadcells = []
livecells = {}
neighborsof = {}
killlist = []
birthlist = []
# logical screen shift
screenoffset = (0,0)
# physical coordinates from logical
pfroml = lambda p: (p[0]*CELLDIAMETER, p[1]*CELLDIAMETER)
# logical coordinates from physical
lfromp = lambda p: (p[0]//CELLDIAMETER, p[1]//CELLDIAMETER)
adjacentdelta = [(-1,-1), (0,-1), (1,-1), (-1,0), (1,0), (-1,1), (0,1), (1,1)]
adjacentcoords = lambda pos, delta: [(pos[0]+x[0], pos[1]+x[1]) for x in delta]
def GetAdjacent(coords):
# build a list of adjacentcoordinates
try:
neighbors = neighborsof[coords]
except:
# build a list of adjacent coordinates
neighbors = adjacentcoords(coords, adjacentdelta)
neighborsof[coords] = neighbors
return neighbors
def NewCellAt(coords):
global screenoffset
if not coords in livecells:
try:
newcell = deadcells.pop()
except:
newcell = (Sprite(redcircle,(0,0)), Sprite(bluecircle,(0,0)))
livecells[coords] = newcell
newcell[0].position = newcell[1].position = pfroml((coords[0]+screenoffset[0], coords[1]+screenoffset[1]))
newcell[0].visible = True
newcell[1].visible = False
# return number of live neighbors and list of empty neighbors
def ScanCell(coords):
neighbors = GetAdjacent(coords)
count = 0
empties = []
for n in neighbors:
if n in livecells:
count = count + 1
else:
empties.append(n)
return count, empties
def step():
global killlist
global birthlist
global running
if not running:
return
allempties = set()
# scan living cells
for p, val in livecells.items():
# change reds to blue
if val[0].visible:
val[0].visible = False
val[1].visible = True
n, empties = ScanCell(p)
if n > 3 or n < 2:
killlist.append(p)
allempties.update(empties)
# scan all neighboring empty cells to find newbies
for p in allempties:
n, empties = ScanCell(p)
if n == 3:
birthlist.append(p)
# process deaths
for p in killlist:
c = livecells.pop(p)
c[0].visible = c[1].visible = False
deadcells.append(c)
# process births
for p in birthlist:
NewCellAt(p)
# clean up
killlist = []
birthlist = []
"""
def MakeAGlider(pos):
deltas = [(0,0), (1,1), (2,1), (2,0), (2,-1)]
for p in deltas:
NewCellAt((pos[0]+p[0],pos[1]+p[1]))
for i in range(5):
MakeAGlider((i*6, i*2))
"""
mousedown = None
running = False
def MouseDown(event):
global mousedown
global screenoffset
mousedown = True
pos = lfromp((event.x, event.y))
NewCellAt((pos[0]-screenoffset[0], pos[1]-screenoffset[1]))
def MouseUp(event):
global mousedown
mousedown = False
def MouseMove(event):
global screenoffset
if mousedown:
pos = lfromp((event.x, event.y))
NewCellAt((pos[0]-screenoffset[0], pos[1]-screenoffset[1]))
def Spacebar(event):
global running
if running:
running = False
else:
running = True
def Left(event):
global screenoffset
screenoffset = (screenoffset[0]-1, screenoffset[1])
Move()
def Right(event):
global screenoffset
screenoffset = (screenoffset[0]+1, screenoffset[1])
Move()
def Up(event):
global screenoffset
screenoffset = (screenoffset[0], screenoffset[1]-1)
Move()
def Down(event):
global screenoffset
screenoffset = (screenoffset[0], screenoffset[1]+1)
Move()
def Move():
global screenoffset
for p, val in livecells.items():
pphys = pfroml((p[0]+screenoffset[0],p[1]+screenoffset[1]))
val[0].position = pphys
val[1].position = pphys
App.listenMouseEvent('mousedown', MouseDown)
App.listenMouseEvent('mouseup', MouseUp)
App.listenMouseEvent('mousemove', MouseMove)
App.listenKeyEvent('keypress', 'space', Spacebar)
App.listenKeyEvent('keydown', 'left arrow', Left)
App.listenKeyEvent('keydown', 'right arrow', Right)
App.listenKeyEvent('keydown', 'up arrow', Up)
App.listenKeyEvent('keydown', 'down arrow', Down)
print("Press <space> to start and stop.")
print("Use mouse to set initial living cells.")
print("Use cursor keys to move the screen.")
myapp = App()
myapp.run(step)