ライフゲーム(Game of Life)は John Horton Conway が考案したシミュレーションゲーム(セル・オートマトン)である。Conway は2020年4月11日に COVID-19 で亡くなった。
ルールはウィキペディア等に書かれているのでここでは省略する。
次のプログラム例は生の Python または IPython 用である。Google Colab では動かないようだ。Jupyter Notebook では %matplotlib notebook
を付ければ動いた(@CinderellaJapan 先生のご教示感謝!)。
#! /usr/bin/env python3
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
N = 100
x = np.arange(N * N) % N
y = np.arange(N * N) // N
# 初期状態(任意に与える)
a = np.zeros((N, N), dtype="int8")
a[N // 2, N // 2] = 1
a[N // 2 - 1, N // 2] = 1
a[N // 2 + 1, N // 2] = 1
a[N // 2, N // 2 - 1] = 1
a[N // 2 - 1, N // 2 + 1] = 1
a.shape = N * N
fig = plt.figure(figsize=(7, 7))
plt.axis([-1, N, -1, N])
line, = plt.plot(x[a != 0], y[a != 0], ".")
def update(_):
line.set_data(x[a != 0], y[a != 0])
b = a.copy()
for i in range(N + 1, N * N - N - 1):
n = (
b[i - N - 1]
+ b[i - N]
+ b[i - N + 1]
+ b[i - 1]
+ b[i + 1]
+ b[i + N - 1]
+ b[i + N]
+ b[i + N + 1]
)
if n == 3:
a[i] = 1
elif n != 2:
a[i] = 0
ani = FuncAnimation(fig, update, interval=100)
plt.show()
最後を例えば
ani = FuncAnimation(fig, update, interval=100, frames=1000)
ani.save("gameoflife.gif")
とすると1000世代までGIFで保存できる。
難しいところを解説すると,plt.plot()
の戻り値は普通は使わないが,matplotlib.lines.Line2D というもののリストが返される。Google Colab などで plt.plot()
すると [
のような表示が出るのはこのためである。これには図の座標の情報などが入っている。この情報を書き換えることにより図を更新している。
上のコードの line, = ...
まで実行した時点で
line.get_data()
と打ち込むと
(array([50, 51, 49, 50, 50]), array([49, 49, 50, 50, 51]))
のようなグラフを構成する点の座標の配列のタプルが返る。この line, = ...
は要素が一つだけのリストの要素を取り出すための常套句で,lines = ...
としてから line = lines[0]
とするのと同じである。このコンマの用法は
t, u = [1, 2]
とすると t
に 1 が入り u
に 2 が入ることを思い出せば理解しやすくなる。この要素が一つになれば
t, = [1]
とすると t
に 1 が入る。
t = [1]
では t
にリスト [1]
が入ってしまう。
この line
のデータを100ミリ秒ごとに更新するのが FuncAnimation(fig, update, interval=100)
である。第2引数で指定した関数 update()
は,この場合はシーケンス番号 0,1,2,… を引数として100ミリ秒ごとに呼び出される。この中で line.set_data(x[a != 0], y[a != 0])
によってデータだけ取り替え,配列 a
を更新する。
上のコードは難しいと不評だったようだ。次のように毎回普通に描く方法のほうがわかりやすそうだ:
# 前半の準備は上と同じ
fig = plt.figure(figsize=(7, 7))
# plt.axis(...) ← 消す
# line, = ... ← 消す
def update(_):
plt.cla() # 画面クリア (clear current axes)
plt.axis([-1, N, -1, N])
plt.plot(x[a != 0], y[a != 0], ".")
b = a.copy()
# 以下同じ
Last modified: