やること
ライフゲームには様々なバリエーションがあります。今回は重み付きのルールを試してみましょう。
参考文献
こちらの論文を参考にさせていただきました。
http://www.kurims.kyoto-u.ac.jp/~kyodo/kokyuroku/contents/pdf/0853-10.pdf
基本ルールと重み付きルール
17-1で用いた基本ルールでは、各セルは周りの8マス(=ムーア近傍)にある生存セルの影響を一様に受けていました。
ここで、隣り合う4マス(=ノイマン近傍)の影響を2倍受けることにするのが今回のルールです。
生存ルールは、まずは23/45ルールとします。
次のステップでの生存条件 | |
生存セル | 隣接する8セルのうち生存セルが2、3個 |
死セル | 隣接する8セルのうち生存セルが4、5個 |
実行環境
どちらかを用いますが、WinPythonをおすすめします。WinPythonでは図が紙芝居のようにパラパラ流れて見やすいですが、Colabではスクロールする必要があり見づらいです。
Colabにも対応しました!(推奨)
WinPython3.6をおすすめしています。
WinPython - Browse /WinPython_3.6/3.6.7.0 at SourceForge.net
Portable Scientific Python 2/3 32/64bit Distribution for Windows
Google Colaboratoryが利用可能です。
Google Colab
ソースコード
基本的には17-1の記事のソースコードのうち、周囲のマスを足し込む部分と、セルの生存条件の部分を書き換えました。
↓WinPythonコード
import numpy as np
import numpy.random as nr
import matplotlib.pyplot as plt
#============================
#初期状態の設定
#============================
#高さ、幅
h, w = 16, 16
#任意の状態を用意
state = np.array([[0,1,1,0],
[1,0,0,1],
[0,0,0,0],
[0,1,1,0]])
#フィールドのどこに置くか(左上点を指定)
p = (12, 6)
#終了ステップ数
max_step = 30
#============================
#メイン処理
#============================
#フィールドの生成
f = np.zeros((h, w), dtype=bool)
#任意の状態を置く
f[p[0]:p[0]+len(state), p[1]:p[1]+len(state[0])] = state
#初期状態の表示
plt.imshow(f, cmap='inferno')
#plt.savefig('save/{}.png'.format(0), bbox_inches='tight', pad_inches=0)
plt.show(), print()
#状態の更新
for i in range(1, max_step + 1):
#周囲の生存マス数を記録するための配列
mask = np.zeros((h, w))
#周囲の生存マスを足し込む
mask[1:, :] += f[:-1, :] * 2 #上 #ここ
mask[:-1, :] += f[1:, :] * 2 #下 #ここ
mask[:, 1:] += f[:, :-1] * 2 #左 #ここ
mask[:, :-1] += f[:, 1:] * 2 #右 #ここ
mask[1:, 1:] += f[:-1, :-1] #左上
mask[1:, :-1] += f[:-1, 1:] #右上
mask[:-1, 1:] += f[1:, :-1] #左下
mask[:-1, :-1] += f[1:, 1:] #右下
#未来のフィールド(すべて死状態)
future = np.zeros((h, w), dtype=bool)
#生きているマスが生きる条件(=生存)
future[mask*f==2] = 1
future[mask*f==3] = 1
#死んでいるマスが生きる条件(=誕生)
future[mask*~f==4] = 1
future[mask*~f==5] = 1
#フィールドの更新(浅いコピーに注意)
f = future
#表示
plt.imshow(f, cmap='inferno')
#plt.savefig('save/{}.png'.format(i), bbox_inches='tight', pad_inches=0)
plt.show(), print()
↓Colabコード
import numpy as np
import numpy.random as nr
import matplotlib.pyplot as plt
from matplotlib import animation, rc
#============================
#初期状態の設定
#============================
#高さ、幅
h, w = 16, 16
#任意の状態を用意
state = np.array([[0,1,1,0],
[1,0,0,1],
[0,0,0,0],
[0,1,1,0]])
#フィールドのどこに置くか(左上点を指定)
p = (12, 6)
#終了ステップ数
max_step = 30
#============================
#メイン処理
#============================
#フィールドの生成
f = np.zeros((h, w), dtype=bool)
#任意の状態を置く
f[p[0]:p[0]+len(state), p[1]:p[1]+len(state[0])] = state
#画像をスタックする配列の準備
fig = plt.figure()
#fig = plt.figure(figsize=(10, 10))
ims = []
#初期状態の表示(スタック)
im = plt.imshow(f, cmap='inferno')
ims.append([im])
#状態の更新
for i in range(1, max_step + 1):
#周囲の生存マス数を記録するための配列
mask = np.zeros((h, w))
#周囲の生存マスを足し込む
mask[1:, :] += f[:-1, :] * 2 #上 #ここ
mask[:-1, :] += f[1:, :] * 2 #下 #ここ
mask[:, 1:] += f[:, :-1] * 2 #左 #ここ
mask[:, :-1] += f[:, 1:] * 2 #右 #ここ
mask[1:, 1:] += f[:-1, :-1] #左上
mask[1:, :-1] += f[:-1, 1:] #右上
mask[:-1, 1:] += f[1:, :-1] #左下
mask[:-1, :-1] += f[1:, 1:] #右下
#未来のフィールド(すべて死状態)
future = np.zeros((h, w), dtype=bool)
#生きているマスが生きる条件(=生存)
future[mask*f==2] = 1
future[mask*f==3] = 1
#死んでいるマスが生きる条件(=誕生)
future[mask*~f==4] = 1
future[mask*~f==5] = 1
#フィールドの更新(浅いコピーに注意)
f = future
#表示(スタック)
im = plt.imshow(f, cmap='inferno')
ims.append([im])
#アニメーション表示の準備
print('making animation......')
print('len(ims) = ' + str(len(ims)))
ani = animation.ArtistAnimation(fig, ims, interval=50, blit=True)
#ここにアニメを表示する場合はこちらを有効に
rc('animation', html='jshtml')
ani
#.gifや.mp4を保存する場合はこちらを有効に
#ani.save('aaa.gif', writer='imagemagick',fps=40)
#ani.save('bbb.mp4', writer="ffmpeg")
グライダーを実行してみる
ソースコードをそのまま実行すると、独特のグライダーが飛び始めます。
26周期振動子
#============================
#初期状態の設定
#============================
#高さ、幅
h, w = 10, 11
#任意の状態を用意
state = np.array([[0,1,1],
[1,0,0],
[0,0,1],
[1,1,0]])
#フィールドのどこに置くか(左上点を指定)
p = (3, 4)
#終了ステップ数
max_step = 30
他のルールを試してみる
重み付けはそのままで、3456/4ルールに変えてみます。コードは適切に書き換えてください。
次のステップでの生存条件 | |
生存セル | 隣接する8セルのうち生存セルが3、4、5、6個 |
死セル | 隣接する8セルのうち生存セルが4個 |
#============================
#初期状態の設定
#============================
#高さ、幅
h, w = 10, 10
#任意の状態を用意
state = np.array([[1,1,1,1],
[1,0,0,1]])
#フィールドのどこに置くか(左上点を指定)
p = (8, 3)
#終了ステップ数
max_step = 30
シュシュポッポ列車
#============================
#初期状態の設定
#============================
#高さ、幅
h, w = 12, 40
#任意の状態を用意
state = np.array([[0,1,0,0],
[0,1,1,0],
[1,0,0,1],
[1,0,0,1],
[0,1,1,0],
[0,1,0,0]])
#フィールドのどこに置くか(左上点を指定)
p = (3, 0)
#終了ステップ数
max_step = 110
まとめ
楽しい(中毒)。皆さんも実装できたらぜひSlackで報告してください。または、Twitterでこの記事のURLを添付してつぶやいていただけたら嬉しいです。