#!/usr/bin/env python3 ## The Game of Life using pyglet. A quite slow implementation. import pyglet from pyglet.window import key import numpy class Application(pyglet.window.Window): def __init__(self): """Window initialization""" super().__init__(caption="The Game of Life", resizable=True) self.size = 10 self.cells = numpy.zeros((self.width // self.size, self.height // self.size)) self.running = False self.full = False self.frequency = 1 / 120 pyglet.gl.glClearColor(0, 0.13, 0.16, 1.0) def on_mouse_press(self, x, y, button, modifiers): """Turn alive the cell under the pointer""" value = False if modifiers == key.MOD_COMMAND else True if x >= 0 and y >= 0: try: self.cells[x // self.size][y // self.size] = value except IndexError: pass def on_mouse_drag(self, x, y, dx, dy, button, modifiers): """Turn cells alive while dragging""" self.on_mouse_press(x, y, button, modifiers) def on_mouse_scroll(self, x, y, scroll_x, scroll_y): self.size += scroll_y if self.size == 0: self.size += 1 self.resize_space() def on_key_press(self, button, modifiers): # Toggle update if button == key.SPACE: if self.running: pyglet.clock.unschedule(self.update) self.running = False else: pyglet.clock.schedule_interval(self.update, self.frequency) self.running = True # Reset space elif button == key.BACKSPACE: self.cells.fill(0) # Toggle fullscreen elif modifiers == key.MOD_COMMAND and button == key.F: if self.fullscreen: self.set_fullscreen(False) self.full = False else: self.set_fullscreen() self.full = True # Change update frequency if button == key.SLASH: self.frequency += 0.1 if self.running: pyglet.clock.unschedule(self.update) pyglet.clock.schedule_interval(self.update, self.frequency) elif button == key.BRACKETRIGHT: self.frequency -= 0.1 if self.running: pyglet.clock.unschedule(self.update) pyglet.clock.schedule_interval(self.update, self.frequency) def on_resize(self, width, height): super().on_resize(width, height) self.resize_space() def on_draw(self): """Draw the frame""" self.clear() pyglet.gl.glColor3f(0.15, 0.6, 0.5) for x, row in enumerate(self.cells): for y, cell in enumerate(row): if cell: self.draw_cell(x, y) if self.size > 7: self.draw_grid() def resize_space(self): self.cells.resize((self.width // self.size, self.height // self.size)) def draw_grid(self): """Draw the grid""" pyglet.gl.glColor3f(0.06, 0.17, 0.21) for i in range(self.height // self.size): pyglet.graphics.draw(2, pyglet.gl.GL_LINES, ('v2i', (0, i * self.size, self.width, i * self.size))) for j in range(self.width // self.size): pyglet.graphics.draw(2, pyglet.gl.GL_LINES, ('v2i', (j * self.size, 0, j * self.size, self.height))) def draw_cell(self, x, y): """Draw a square""" x, y = x * self.size, y * self.size x1, y1, x2, y2 = x, y, x + self.size, y + self.size pyglet.graphics.draw(4, pyglet.gl.GL_QUADS, ('v2f', (x1, y1, x1, y2, x2, y2, x2, y1))) def update(self, dt): """Calculate the next frame""" copy = numpy.copy(self.cells) for x, row in enumerate(self.cells): for y, cell in enumerate(row): copy[x][y] = self.alive(x, y) self.cells = numpy.copy(copy) def alive(self, x, y): """Calculate if a cell will be alive in the next frame""" livings = 0 for i in (-1, 0, 1): for j in (-1, 0, 1): try: if (self.cells[x + i][y + j] and x + i > 0 and y + j > 0): livings += 1 except IndexError: continue if self.cells[x][y]: livings -= 1 if not self.cells[x][y] and livings == 3: return 1 elif self.cells[x][y] and livings in (2, 3): return 1 else: return 0 app = Application() pyglet.app.run()