What you should be doing instead of your own while loop is using tkinters mainloop().
What you do is define a single frame and then tell it to recall that after a certain amount of time.
Examine both the
main
and
Life.frame
functions in the following:
try:
import Tkinter as tk
except ImportError:
import tkinter as tk
#Declare cellular automata rules here.
BIRTH = (3,) #Neighbors an empty cell needs to be born.
SURVIVE = (2, 3) #Neighbors a living cell needs to survive.
#Seed for a 'Gosper Glider Gun' in set form.
SEED = {(22, 3),(17, 5),(16, 8),( 2, 6),(35, 3),(16, 4),(36, 4),(14, 3),(25, 7),
(22, 4),(21, 4),(18, 6),( 1, 6),(25, 1),(36, 3),(13, 9),( 2, 5),(35, 4),
(14, 9),(17, 7),(11, 7),(17, 6),(13, 3),(11, 5),(25, 6),(23, 2),(21, 3),
( 1, 5),(15, 6),(12, 4),(21, 5),(25, 2),(22, 5),(23, 6),(11, 6),(12, 8)}
#Convenient constant for looking at adjacent neighbors.
ADJACENTS = {(-1, 1),(0, 1),(1,1 ),(-1, 0),(1, 0),(-1,-1),(0,-1),(1,-1)}
class Life(tk.Canvas):
def __init__(self, root, *args, **kwargs):
tk.Canvas.__init__(self, root, *args, **kwargs)
self.root = root
self.pack()
self.live = SEED.copy() #Set of all living cells.
self.pop = len(self.live) #Population counter.
self.gen = 0 #Generation counter.
self.speed = 60 #FPS of animation
self.sz = 10 #Size of a cell.
self.w = int(self.cget("width"))//self.sz #Canvas width in cells.
self.h = int(self.cget("height"))//self.sz #Canvas height in cells.
def draw(self):
for x,y in self.live:
rect = (x*self.sz, y*self.sz, (x+1)*self.sz, (y+1)*self.sz)
##self.create_oval(rect, outline="black")
##self.create_oval(rect, outline="yellow", fill="blue")
self.create_rectangle(rect, outline="green", fill="purple", width=2)
##self.create_rectangle(rect, fill="orange")
def stats(self):
gen = "Generation: {}".format(self.gen)
pop = "Population: {}".format(self.pop)
self.create_text((700,20), text=gen, fill="red", anchor="w")
self.create_text((700,35), text=pop, fill="red", anchor="w")
def frame(self):
self.process()
self.delete(tk.ALL)
self.draw()
self.stats()
self.root.after(1000//self.speed, self.frame)
def process(self):
# Count everyone's neighbors.
neighbors = {}
for x,y in self.live:
for i,j in ADJACENTS:
check = ((x+i)%self.w, (y+j)%self.h) #Wrap-around.
neighbors[check] = neighbors.get(check, 0)+1
# Make changes accordingly.
next_live = set()
for guy in neighbors:
if neighbors[guy] in BIRTH and guy not in self.live:
next_live.add(guy)
elif neighbors[guy] in SURVIVE and guy in self.live:
next_live.add(guy)
self.live = next_live
self.pop = len(self.live)
self.gen += 1
def main():
root = tk.Tk()
root.title("Conway's Game of Life")
live = Life(root, width=800, height=600,
highlightthickness=0, bd=0, bg='grey')
live.frame()
root.mainloop()
if __name__ == "__main__":
main()