#!/usr/bin/python3 """Really simple hacky interactive UI for the Game of Life.""" import tkinter import life def main(): tk = tkinter.Tk() tk.title("Life") w = tkinter.Canvas(tk, width=512, height=512, background='#f7f7f7') w.pack() scales = [32] boards = [{(8,7), (9,7), (7,8), (8,8), (8,9)}] # Default to R-pentomino history = [] origin = [(0, 0)] running = [] def zoom(factor): scale, = scales newscale = scale * factor if newscale > 512: return scales[0] = newscale dx = 128//scale if factor > 1 else -128//newscale scroll(dx, dx) def redraw(): w.delete(tkinter.ALL) scale, = scales margin = scale / 16 for x, y in boards[0]: x0 = (x - origin[0][0]) * scale + margin y0 = (y - origin[0][1]) * scale + margin xmax = x0 + scale - margin ymax = y0 + scale - margin w.create_oval(x0, y0, xmax, ymax) def step(*a): history.append(boards[0]) if len(history) > 1024: history.pop(0) boards[0] = life.succ(boards[0]) redraw() def back(*a): if not history: return boards[0] = history.pop() w.after_idle(redraw) def run(): if running: running[:] = [] b.configure(text='Run') else: b.configure(text='Stop') running.append(1) keep_running() def keep_running(): if running: step() tk.after(17, keep_running) def scroll(dx, dy): origin[0] = [origin[0][0] + dx, origin[0][1] + dy] redraw() b = tkinter.Button(tk, text='Run', command=run) s = tkinter.Button(tk, text='Step', command=step) back_b = tkinter.Button(tk, text='Back', command=back) zout = lambda *a: zoom(.5) zin = lambda *a: zoom(2) zout_b = tkinter.Button(tk, text='Zoom out', command=zout) zin_b = tkinter.Button(tk, text='Zoom in', command=zin) # XXX TODO scrollbars left = lambda *a: scroll(-(256 // scales[0]), 0) up = lambda *a: scroll(0, -(256 // scales[0])) down = lambda *a: scroll(0, (256 // scales[0])) right = lambda *a: scroll(256 // scales[0], 0) left_b = tkinter.Button(tk, text='←', command=left) up_b = tkinter.Button(tk, text='↑', command=up) down_b = tkinter.Button(tk, text='↓', command=down) right_b = tkinter.Button(tk, text='→', command=right) for bi in b, s, back_b, zout_b, zin_b, left_b, up_b, down_b, right_b: bi.pack(side='left') def clicker(ev): scale, = scales bx = ev.x // scale + origin[0][0] by = ev.y // scale + origin[0][1] if (bx, by) in boards[0]: boards[0].remove((bx, by)) else: boards[0].add((bx, by)) w.focus_set() redraw() for k, v in {'': clicker, '': zin, '': zin, '': zin, '': zout, '': zout, '': zout, '': left, '': left, '': right, '': right, '': up, '': up, '': up, '': up, '': down, '': down, '': down, '': down, '': step, '': back, }.items(): w.bind(k, v) w.focus_set() redraw() tkinter.mainloop() if __name__ == '__main__': main()