文章目录
一、生命游戏是什么
生命游戏(Game of Life)是由英国数学家约翰·何顿·康威在1970年发明的一种细胞自动机(Cellular Automaton),也可以称为生命棋或零玩家游戏。生命游戏的特点主要体现在以下几个方面:
- 游戏背景
生命游戏在一个二维的网格上进行,每个网格(或称为格子、细胞)都可以处于"生"或"死"的状态。网格可以是无穷大的,也可以是一个有限大的矩形。 - 游戏规则
一个细胞的生死状态完全取决于它周围八个相邻细胞的状态。具体规则如下:
当前状态 | 下一代状态 |
---|---|
存活 | 如果周围恰好有2个或3个活细胞,则它在下一代仍然存活;如果周围有0个、1个或超过3个的活细胞,则它在下一代死去(因孤独或过度拥挤) |
死去 | 如果周围有恰好3个活细胞,则它在下一代复活(模拟繁殖) |
- 游戏特性
生命游戏是一个零玩家游戏,即没有玩家的干预或输入,所有变化都遵循预设的规则。
随着游戏的进行,杂乱无序的细胞会逐渐演化出各种精致、有形的结构,有时这些结构会保持稳定,有时会因为无序细胞的"入侵"而被破坏。生命游戏的规则简单,但能够产生出复杂且富有变化的模式,这体现了从简单规则中产生复杂性的原理。 - 应用场景
生命游戏不仅在数学和计算机科学领域具有研究价值,也常被用于演示元胞自动机的原理和特性。在艺术和设计领域,生命游戏也被用于生成独特的纹理和图案。生命游戏是一个简单但强大的模型,它展示了从简单规则中涌现出复杂性和多样性的能力,对理解自然界和社会现象提供了有趣的视角。
二、生命游戏规则解释
1.相邻细胞
对于如下3×3的9宫格, i i i号细胞的周围八个相邻细胞分别是 a 、 b 、 c 、 d 、 e 、 f 、 g 、 h a、b、c、d、e、f、g、h a、b、c、d、e、f、g、h
[ a b c d i e f g h ] \left[ \begin{matrix} a & b & c \\ d & i & e \\ f & g & h \\ \end{matrix} \right] adfbigceh
2.细胞状态
1表示细胞存活状态,0表示细胞死去状态。
- 当前状态为存活,下一代继续存活
假设当前细胞 i i i为存活状态,如果相邻细胞的状态如下所示,则细胞 i i i下一代继续存活,因为其周围有3个活细胞。
[ 0 0 1 0 1 1 1 0 0 ] \left[ \begin{matrix} 0 & 0 & 1 \\ 0 & 1 & 1 \\ 1 & 0 & 0 \\ \end{matrix} \right] 001010110 - 当前状态为存活,下一代不能存活
假设当前细胞 i i i为存活状态,如果相邻细胞的状态如下所示,则细胞 i i i下一代不能存活,因为其周围有4个活细胞,拥挤死去。
[ 0 0 1 1 1 1 1 0 0 ] \left[ \begin{matrix} 0 & 0 & 1 \\ 1 & 1 & 1 \\ 1 & 0 & 0 \\ \end{matrix} \right] 011010110 - 当前状态为死去,下一代复活
假设当前细胞 i i i为死去状态,如果相邻细胞的状态如下所示,则细胞 i i i复活,因为其周围恰有3个活细胞。
[ 1 0 0 1 0 0 0 0 1 ] \left[ \begin{matrix} 1 & 0 & 0 \\ 1 & 0 & 0 \\ 0& 0 & 1 \\ \end{matrix} \right] 110000001 - 当前状态为死去,下一代继续为死去状态
假设细胞 i i i为死去状态, 如果相邻细胞的状态如下所示,则细胞 i i i继续为死去状态,因为其周围有1个活细胞。
[ 0 0 0 1 0 0 0 0 0 ] \left[ \begin{matrix} 0 & 0 & 0 \\ 1 & 0 & 0 \\ 0& 0 & 0 \\ \end{matrix} \right] 010000000
三、代码实现
1.邻居细胞
针对邻居8个细胞,分别进行判断,这里采用的是一个有限大的矩形。
python
#判断每一代邻居生存状态
def cal(i, j):
count = 0
if i-1 >= 0 and j-1>= 0:
count = count + earth_init[i-1][j-1]
if i-1 >= 0:
count = count + earth_init[i-1][j]
if i-1 >= 0 and j+1< grid_size:
count = count + earth_init[i-1][j+1]
if j-1>= 0:
count = count + earth_init[i][j-1]
if j+1< grid_size:
count = count + earth_init[i][j+1]
if i+1 < grid_size and j-1>= 0:
count = count + earth_init[i+1][j-1]
if i+1 < grid_size:
count = count + earth_init[i+1][j]
if i+1 < grid_size and j+1< grid_size:
count = count + earth_init[i+1][j+1]
return count
2.更新状态
根据细胞的存活、死去状态进行更新。
python
#更新新一代earth
def new_earth(earth_init):
earth = copy.deepcopy(earth_init)
for i in range(grid_size):
for j in range(grid_size):
#活细胞
if earth[i][j] == 1:
if cal(i, j) <= 1 or cal(i, j) >= 4:
earth[i][j] = 0
#死细胞
else:
if cal(i, j) == 3:
earth[i][j] = 1
return earth
四、整体代码
完整代码如下所示。
python
import copy
import matplotlib.pyplot as plt
import numpy as np
import random
#生命游戏二维空间大小
grid_size = 30
#init生命数量
counts = 100
def grid_init(input):
#手动输入关注型态
care_init = [[10,10], [11,10], [12,10],[13,10]]
#随机生成
labels = []
random.randint(0,grid_size-1)
for i in range(counts):
labels.append([random.randint(0,grid_size-1), random.randint(0,grid_size-1)])
#初始化
earth_init = np.zeros((grid_size, grid_size))
if input != 'random':
labels = care_init
for label in labels:
earth_init[label[0]][label[1]] = 1
return earth_init
#判断每一代邻居生存状态
def cal(i, j):
count = 0
if i-1 >= 0 and j-1>= 0:
count = count + earth_init[i-1][j-1]
if i-1 >= 0:
count = count + earth_init[i-1][j]
if i-1 >= 0 and j+1< grid_size:
count = count + earth_init[i-1][j+1]
if j-1>= 0:
count = count + earth_init[i][j-1]
if j+1< grid_size:
count = count + earth_init[i][j+1]
if i+1 < grid_size and j-1>= 0:
count = count + earth_init[i+1][j-1]
if i+1 < grid_size:
count = count + earth_init[i+1][j]
if i+1 < grid_size and j+1< grid_size:
count = count + earth_init[i+1][j+1]
return count
#更新新一代earth
def new_earth(earth_init):
earth = copy.deepcopy(earth_init)
for i in range(grid_size):
for j in range(grid_size):
if earth[i][j] == 1:
if cal(i, j) <= 1 or cal(i, j) >= 4:
earth[i][j] = 0
else:
if cal(i, j) == 3:
earth[i][j] = 1
return earth
#作图
def pplot(earth):
# 创建一个grid_size x grid_size的网格
x = np.linspace(0, 1, grid_size)
y = np.linspace(0, 1, grid_size)
X, Y = np.meshgrid(x, y)
# 绘制九宫格
fig, ax = plt.subplots()
for i in range(grid_size):
for j in range(grid_size):
if earth[i][j] == 1:
#白色
color = [1, 1, 1]
else:
#黑色
color = [0, 0, 0]
# 绘制每个格子,使用颜色数组中的对应颜色
ax.add_patch(plt.Rectangle(
(x[i], y[j]), # 左下角坐标
x[1] - x[0], # 宽度
y[1] - y[0], # 高度
#color=colors[i, j], # 颜色
color=color,
edgecolor='black' # 边框颜色
))
# 设置坐标轴范围
ax.set_xlim(0, 1)
ax.set_ylim(0, 1)
# 关闭坐标轴的刻度显示
ax.set_xticks([])
ax.set_yticks([])
ax.set_aspect('equal', adjustable='box')
# 显示图形
plt.show(block=False)
plt.pause(1)
plt.close()
earth_init = grid_init('random')
pplot(earth_init)
#迭代代数
iters = 100
for i in range(iters):
earth = new_earth(earth_init)
#没有生命存活则停止
if sum(sum(earth)) == 0:
break
pplot(earth)
plt.close('all')
print('='*20, i)
print(sum(sum(earth)))
earth_init = copy.deepcopy(earth)
附上一张实验图。