注解
此笔记本可在此处下载: GameOfLife.ipynb
代码作者:Ludovic Charleux <ludovic.charleux@univ-smb.fr>
生命游戏和其他细胞自动机
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib nbagg
from matplotlib import animation, rc, cm
import IPython, io, urllib
rc('animation', html='html5')
介绍
这本笔记本的灵感来自于大卫·卢亚普在他的YouTube频道上提出的伟大视频。 “科学伊顿南特” :
IPython.display.YouTubeVideo('S-W0NX97DB0')
这个 生活游戏(GOL) 是了解面向对象编程、numpy和matplotlib用法的好方法。它也是一个相互关联的科学和数学问题。GOL属于更广泛的问题组,称为 细胞自动机 .自GOL发明以来,随着时间的推移,已经创建/发现了许多替代的相互关系规则集。在本教程中,我们将介绍一个简单的类,它可以解决所有这些问题 类似生命的细胞自动机(LLCA) .
进一步阅读:
模拟LLCA的泛型类
class LLCA:
"""
A Life Like Cellular Automaton (LLCA)
Inputs:
* C: a binary matrix representing the cells where 1 stands for alive and 0 for dead.
* rule: the rule of the in the format 'BXSY' where X and Y are the birth and survival conditions.
Example: GOL rule is "B3S23".
"""
def __init__(self, C = np.random.rand(50, 50), rule = "B3S23"):
self.C = np.array(C).astype(np.bool)
self.rule = rule
def parse_rule(self):
"""
Parses the rule string
"""
r = self.rule.upper().split("S")
B = np.array([int(i) for i in r[0][1:] ]).astype(np.int64)
S = np.array([int(i) for i in r[1] ]).astype(np.int64)
return B, S
def neighbors(self):
"""
Returns the number of living neigbors of each cell.
"""
C = self.C
N = np.zeros(C.shape, dtype = np.int8) # Neighbors matrix
N[ :-1, : ] += C[1: , : ] # Living cells south
N[ : , :-1] += C[ : ,1: ] # Living cells east
N[1: , : ] += C[ :-1, : ] # Living cells north
N[ : , 1: ] += C[ : , :-1] # Living cells west
N[ :-1, :-1] += C[1: ,1: ] # Living cells south east
N[1: , :-1] += C[ :-1,1: ] # Living cells north east
N[1: , 1: ] += C[ :-1, :-1] # Living cells north west
N[ :-1, 1: ] += C[1: , :-1] # Living cells south west
return N
def iterate(self):
"""
Iterates one time.
"""
B, S = self.parse_rule()
N = self.neighbors()
C = self.C
C1 = np.zeros(C.shape, dtype = np.int8)
for b in B: C1 += ((C == False) & (N == b))
for s in S: C1 += (C & (N == s))
self.C[:] = C1 > 0
生命的原始游戏(规则B3S23)
# INITIAL CONFIGURATION
N = 100
t = np.linspace(0., 1., N+1)
X, Y = np.meshgrid(t, t)
f = 4
C0 = np.sin(2. * np.pi * f * X ) * np.sin(2. * np.pi * 2 * f * Y ) > -.1
g = LLCA(C0, rule = "B3S23")
# ANIMATION
def updatefig(*args):
g.iterate()
im.set_array(g.C)
return im,
fig, ax = plt.subplots()
ax.axis('off')
im = plt.imshow(g.C, interpolation = "nearest", cmap = cm.binary, animated=True)
anim = animation.FuncAnimation(fig, updatefig, frames=200, interval=50, blit=True)
plt.close()
anim
#plt.show()
<IPython.core.display.Javascript object>
替代规则:昼夜(B3678S34678)
N = 100
t = np.linspace(0., 1., N+1)
X, Y = np.meshgrid(t, t)
f = 10
C0 = np.sin(2. * np.pi * f * X ) * np.sin(2. * np.pi * 2 * f * Y ) > 0.
g = LLCA(C0, rule = "B3678S34678")
def updatefig(*args):
g.iterate()
im.set_array(g.C)
return im,
fig, ax = plt.subplots()
ax.axis('off')
im = plt.imshow(g.C, interpolation = "nearest", cmap = cm.binary, animated=True)
anim = animation.FuncAnimation(fig, updatefig, frames=200, interval=50, blit=True)
plt.close()
anim
#plt.show()
<IPython.core.display.Javascript object>
替代规则:分形,如b1s123
N = 200
C0 = np.zeros((N, N))
C0[1,1] = 1
g = LLCA(C0, rule = "B1S123")
def updatefig(*args):
g.iterate()
im.set_array(g.C)
return im,
fig, ax = plt.subplots()
ax.axis('off')
im = plt.imshow(g.C, interpolation = "nearest", cmap = cm.binary, animated=True)
anim = animation.FuncAnimation(fig, updatefig, frames=200, interval=40, blit=True)
plt.close()
anim
#plt.show()
<IPython.core.display.Javascript object>
GOL现有结构
让我们模拟一个现有的河豚:
http://www.conwaylife.com/patterns/hivenudger2_106.lif
def life_parser(path, bottom_margin = 10, top_margin = 10, left_margin = 10, right_margin = 10):
"""
A life 1.06 file parser
http://www.conwaylife.com/wiki/Life_1.06
"""
data = "".join([l for l in open(path).readlines() if not l.startswith("#")])
data = pd.read_csv(io.StringIO(data), header = None, sep = " ").values
xmin, xmax = data[:,0].min(), data[:,0].max()
ymin, ymax = data[:,1].min(), data[:,1].max()
C0 = np.zeros( (xmax - xmin + top_margin + bottom_margin,
ymax - ymin + left_margin + right_margin) )
data[:,0] += -xmin + top_margin
data[:,1] += -ymin + left_margin
C0[data[:,0] , data[:,1]] = 1
return C0
path = "_data/hivenudger2_106.lif"
C0 = life_parser(path, top_margin = 100).T[:, ::-1]
fig, ax = plt.subplots()
plt.imshow(C0, cmap = cm.binary)
ax.axis('off')
plt.show()
<IPython.core.display.Javascript object>
g = LLCA(C0, rule = "B3S23") # B2S23 means Birth if 2 living neighbours and survival if 2 or 3 living neighbours
def updatefig(*args):
g.iterate()
im.set_array(g.C)
return im,
fig, ax = plt.subplots()
im = plt.imshow(g.C, interpolation = "nearest", cmap = cm.binary, animated=True)
anim = animation.FuncAnimation(fig, updatefig, frames=200, interval=50, blit=True)
#ax.axis('off')
plt.close()
anim
#plt.show()
<IPython.core.display.Javascript object>