ライフゲーム / Python / 1世代だけ進める函数

実質1行だけで現世代から次世代へ変換できる。

import numpy as np
from scipy.signal import convolve2d

class LifeGame:
    def __init__(self, mat):
        self.mat   = np.asarray(mat, dtype="uint8") # 現世代排列を取り込んで、念のためndarrayにしておく。
        self.Rules = np.array([[0,0,0,1,0,0,0,0,0], [0,0,1,1,0,0,0,0,0]], dtype="uint8") # 生死ルール排列を定義しておく。

    def update(self):
        # この1行だけで次世代排列が求まる。
        # たとえば現世代排列が0、そのムーア近傍の和が6ならルール排列の[0, 6]を検索して次世代の生死を決定する。
        self.mat = self.Rules[self.mat, convolve2d(self.mat, [[1,1,1], [1,0,1], [1,1,1]], mode="same", boundary="wrap")]

########
# test #
########
if __name__ == "__main__":

    # グライダーで確かめてみる。   
    glider = np.array([[0,0,0,0,0,0,0],
                       [0,0,1,0,0,0,0],
                       [0,0,0,1,0,0,0],
                       [0,1,1,1,0,0,0],
                       [0,0,0,0,0,0,0]], dtype="uint8")

    life = LifeGame(glider)
    
    for i in range(100):
        print("第%d世代: " % (i))
        print(life.mat)
        life.update()

実行結果:
f:id:ti-nspire:20181017090326p:plain

ライフゲーム / Python / 全セルのムーア近傍の和を求める / scipy.signal.convolve2d()

scipy.signal.convolve2d()boundary=オプションで境界条件を指定すればわざわざ一回り大きい排列を作る必要はなかった。

import numpy as np
from scipy.signal import convolve2d

# この排列aを現世代排列とする。
numOfRows, numOfCols = 5, 10
a = np.random.randint(0, 2, [numOfRows, numOfCols], dtype="uint8")

# 現世代排列の全セルのムーア近傍の和を求める。境界条件は上下左右のつながったトーラスとする。
moore = convolve2d(a, [[1,1,1],
                       [1,0,1],
                       [1,1,1]], boundary="wrap", mode="same")
    
print(a)
print(moore)

実行結果:
f:id:ti-nspire:20181015194254p:plain:w300