康威生命游戏
康威生命游戏(Conway’s Game of Life)是康威发明的细胞自动机。
生命游戏有几个简单的规则:
细胞有两种状态,存活或死亡,每个细胞以自身为中心与周围的八格细胞互动。
对于存活的细胞:
- 当周围的细胞过少(<2)或过多(>3)时,细胞死亡。
- 周围细胞数量适中(2或3)时,细胞保持存活。
对于死亡的细胞(空白区域):
- 周围有3个细胞时,该区域生成细胞。(模拟繁殖)
参考:中文维基百科-康威生命游戏
康威生命游戏通过上述几条简单的规则,加上不同的初始状态,就可以演化出各种复杂的模式:
Python实现
由于生命游戏的规则非常简单,我们可以很容易的用Python实现。
可以用二维数组表示细胞状态,并根据生命游戏的规则计算下一次的细胞状态进行更新。
(当规模变大时,更新细胞会变得困难。可以考虑并行)
下面是一个简单的实现,使用pygame
显示动画,借助numpy
操作数组。
效果如下:
代码参考:https://www.youtube.com/watch?v=cRWg2SWuXtM完整代码:
import pygame import numpy as np import time # 定义颜色和细胞大小 COLOR_BG = (10, 10, 10) # 背景,黑色 COLOR_GRID = (40, 40, 40) # 网格,黑灰色 COLOR_DIE_NEXT = (170, 170, 170) # 下一代死亡细胞,灰色 COLOR_ALIVE_NEXT = (255, 255, 255) # 下一代存活细胞,白色 SIZE = 10 # 更新细胞状态 def update(screen, cells, size, with_progress=False): '''更新细胞状态 screen: pygame.Surface 对象 cells: 细胞状态矩阵 size: 细胞大小 with_progress: 是否显示下一代细胞状态。 有时候我们只想(通过鼠标点击)修改当前细胞状态,而不想立即显示下一代细胞状态 ''' updated_cells = np.zeros_like(cells) # 遍历每一个细胞 for row, col in np.ndindex(cells.shape): # 统计周围细胞的存活数量 alive = np.sum(cells[row-1:row+2, col-1:col+2]) - cells[row, col] # 设置格子颜色,如果当前细胞处于死亡状态,颜色为背景色;否则为存活细胞颜色 color = COLOR_BG if not cells[row, col] else COLOR_ALIVE_NEXT # 如果当前细胞处于存活状态 if cells[row, col]: if alive < 2 or alive > 3: if with_progress: color = COLOR_DIE_NEXT elif 2 <= alive <= 3: updated_cells[row, col] = 1 if with_progress: color = COLOR_ALIVE_NEXT # 如果当前细胞处于死亡状态 else: if alive == 3: updated_cells[row, col] = 1 if with_progress: color = COLOR_ALIVE_NEXT # 在屏幕的(row, col)位置绘制细胞。size-1是为了留出边界 pygame.draw.rect(screen, color, (col*size, row*size, size-1, size-1)) return updated_cells def main(): pygame.init() screen = pygame.display.set_mode((800, 600)) cells = np.zeros((60, 80)) screen.fill(COLOR_GRID) update(screen, cells, SIZE) pygame.display.update() ruuning = False while True: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() return if event.type == pygame.KEYDOWN: # 空格键控制游戏暂停/继续 if event.key == pygame.K_SPACE: ruuning = not ruuning update(screen, cells, SIZE) pygame.display.update() # 鼠标左键点击,添加活细胞 if pygame.mouse.get_pressed()[0]: x, y = pygame.mouse.get_pos() cells[y//SIZE, x//SIZE] = 1 update(screen, cells, SIZE) pygame.display.update() screen.fill(COLOR_GRID) if ruuning: cells = update(screen, cells, SIZE, with_progress=True) pygame.display.update() time.sleep(0.1) if __name__ == '__main__': main()