misc/python/life.py
2018-08-05 18:53:07 +02:00

139 lines
3.7 KiB
Python
Executable File

#!/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()