メインコンテンツまでスキップ

ライフゲーム

今回は、複雑なプログラムを実際に書いてみましょう。ライフゲームのプログラムを実際に書いていきます。

ライフゲームとは

ライフゲームとは、1970 年に英国の数学者ジョン・ホートン・コンウェイが考案した生命の誕生と死を再現したシミュレーションゲームです。

過疎でも過密でも生命の生存に適さないということをシンプルなモデルで再現しています。

ライフゲームのルール

  • 碁盤の目上のセルの上に一体の生命がいるとする。

  • 各セルには、「生」と「死」の二種類の状態がある。

  • 生きているセルはaliveで、死んでいるセルはdeadで表す。

  • 次の世代は、そのセルの周囲の 8 つのセルの現在の状態によって決定される。

  • 次の世代は、次の 4 つのルールで決定される。

誕生
死んでいるセルの周りに生きたセルが3つある時、誕生する。

birth

生存
生きているセルの周りに生きたセルが2つか3つある時、生存することができる。

survive1

survive2

過疎
生きているセルの周りに生きたセルが1つ以下しかない時、死滅する。

underpopulation1

underpopulation1

過密
生きているセルの周りに生きたセルが4つ以上ある時、死滅する。

overpopulation1

overpopulation2

overpopulation3

overpopulation4

overpopulation5

ライフゲームで遊んでみる

ライフゲームを簡単に遊べる Web アプリを作ってみました。下のマスをクリックまたはタッチすると、マスの色を反転することができます。これで少し遊ぶことでライフゲームの仕組みを理解してください。

速さ

ライフゲームのプログラム

全体

早速、ライフゲームの Python でのプログラムを見てみましょう。この後、詳しく解説するので、分からなくても構いません。Python のプログラムの実行結果をブラウザ上で動かせるようにしてあるので、

ボタンを押して実際に動く様子を確認してみてください。

Open In Colab

それでは、実際にライフゲームのプログラムを作っていきましょう。

盤面の表し方

次のような盤面はプログラム上でどのように表すのが良いでしょうか?

board_example

これに関しては、次のように二次元配列を使うと良さそうです。さらに、生きているセルを 1、死んでいるセルを 0 とするとセルの値を足すだけで簡単に生きたセルの数を計算することができそうです。

board = [[1, 1, 0],
[1, 0, 0],
[0, 0, 0]]

生きたセルをカウント

次に、ある盤面の iijj 列の周りに生きたセルが何個あるのかを求める関数を作りましょう。

関数の引数に boardij があるとしましょう。このとき、i1i-1 行目から i+1i+1 行目でありかつ j1j-1 列目から j+1j+1 列目であるセルの値の和から、iijj 列のセルの値(つまり自分の値)を引けばできそうです。次のようになると思えます。

Open In Colab

しかし、実はこれではセルが端にある時にエラーが出てしまいます。そこで、セルが端にある時も考慮してプログラムを作ると、次のようになります。

Open In Colab

あるセルの生死の判定

次に、次の世代においてあるセルが生きているかを確認する関数を作ってみましょう。先程、あるセルの周りに生きたセルが何個あるのかを求める関数を作ったので、それを使います。関数の引数は、先程のように boardij で良いでしょう。後は、ライフゲームの定義通りにプログラムを書いていけばよいでしょう。

Open In Colab

次の世代の計算

次に、次の世代の盤面を計算する関数を考えます。 引数は board として、次の世代の様子を格納する配列を作ってそこに結果を格納していきましょう。

配列の作り方はいろいろありますが、ここではリスト内包表記と呼ばれる方法で行いましょう。 例えば、[0, 0, 0, 0, 0] のような配列は次のようにして作ることができます。

[0 for _ in range(5)]

つまり、[0 for _ in range(n)] は、[0, 0, 0, ..., 0] のようになります。

さらに、[[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]] のような配列は次のようにして作ります。

[[0 for _ in range(3)] for _ in range(4)]
ita ライブラリの make2d 関数

大学が用意した ita ライブラリでも配列を作ることができます。

次のような構文で新たな一次元配列を作ることができます。

ita.array.make1d(要素数)

さらに、新たな二次元配列を作ることもできます。

ita.array.make2d(行数,列数)

これらを使ってあげると、次のようなプログラムになるはずです。

Open In Colab

すべての盤面の計算

次の世代の盤面を計算することができたので、次は指定した世代までの盤面を計算する関数を作りましょう。

引数を board と世代数 n にすると、次のようにプログラムを書けます。

Open In Colab

アニメーション

後はこれをアニメーションにしてあげれば、完成です。

サンプルデータは次のようにしましょう。これはグライダーと呼ばれるライフゲームにおいて有名なデータで、グライダーが移動していくように見えるものです。

data = [
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 1, 0],
[0, 0, 0, 0, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
]

アニメーションを作るのは、ita ライブラリを使えば簡単です。三次元配列を次のように渡してあげれば、1 のところは黒で 0 のところは白にしてアニメーションをつくってくれます。

ita.plot.animation_show(三次元配列)

今までのをすべて合わせると、次のようになって冒頭のプログラムができました。

Open In Colab