对于使用Python和pyglet进行Conway的《生命游戏》的简单且可扩展的实现,我有以下代码。
import numpy as np
import pyglet
from pyglet import shapes
COLOURS = [(255, 255, 255), (0, 0, 155)]
class Board(np.ndarray):
def __new__(cls, box=10, *args, **kwargs):
return np.ndarray.__new__(cls, (box, box), *args, dtype=int, **kwargs)
def __init__(self, box, *args, **kwargs):
self.box = box
self.conditions = np.array([
[0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 1, 1, 0, 0, 0, 0, 0]
])
self.PIXEL = kwargs.get('pixel_size', 10)
def populate(self, array : np.ndarray):
self[:, :] = array[:, :]
def neighbours(self, i : int, j : int) -> int:
return sum([
self[i-1 % self.box - 1, j-1 % self.box - 1],
self[i % self.box - 1, j-1 % self.box - 1],
self[i+1 % self.box - 1, j-1 % self.box - 1],
self[i-1 % self.box - 1, j % self.box - 1],
self[i+1 % self.box - 1, j % self.box - 1],
self[i-1 % self.box - 1, j+1 % self.box - 1],
self[i % self.box - 1, j+1 % self.box - 1],
self[i+1 % self.box - 1, j+1 % self.box - 1],
])
def next(self):
new = Board(self.box)
for i, row in enumerate(self):
for j, idx in enumerate(row):
neighbours = self.neighbours(i, j)
new[i, j] = self.conditions[self[i, j], neighbours]
return new
def run(self, n):
result = self.next()
for i in range(n-1):
result = result.next()
return result
def render(self, dt, window=None):
if not window:
window = pyglet.window.Window()
@window.event
def on_draw():
window.clear()
for i, row in enumerate(self):
for j, state in enumerate(row):
shapes.Rectangle(
x=self.PIXEL * i,
y=self.PIXEL * j,
width=self.PIXEL,
height=self.PIXEL,
color=COLOURS[state]
).draw()
if not window:
pyglet.app.run()
if window:
self[:, :] = self.next()
def animate(self):
window = pyglet.window.Window(
width=self.PIXEL*self.shape[0],
height=self.PIXEL*self.shape[1]
)
pyglet.clock.schedule_interval(self.render, 1./60., window)
pyglet.app.run()
if __name__ == '__main__':
import sys
try:
size = sys.argv[1]
except IndexError:
size = 50
board = Board(size)
board.populate(np.random.randint(2, size=board.shape))
board.animate()
我想知道如何提高性能(因为目前动画对于大尺寸动画来说要慢得多)。
我的主要想法是向Board.next()
方法添加并行性,并可能在on_draw()
中添加Board.render()
函数,以消除double for循环。此功能的主要任务是创建Board
的新实例(基本上只是一个新的np.ndarray
)并更新每个单元格:
def next(self):
new = Board(self.box)
for i, row in enumerate(self):
for j, idx in enumerate(row):
neighbours = self.neighbours(i, j)
new[i, j] = self.conditions[self[i, j], neighbours]
return new
...
@window.event
def on_draw():
window.clear()
for i, row in enumerate(self):
for j, state in enumerate(row):
shapes.Rectangle(
x=self.PIXEL * i,
y=self.PIXEL * j,
width=self.PIXEL,
height=self.PIXEL,
color=COLOURS[state]
).draw()
我完全确定,由于我们创建了一个新数组,因此可以并行完成此操作,因此我有以下问题: