思考ノイズ

無い知恵を絞りだす。無理はしない。

ライフゲームをコーディング

モチベーション

この本読んでます。知っていることから知らないこと、新しい知識がいっぱいつまっていて読み応えは十分。 そのなかでライフゲームというゲーム?があることを初めて知りました。ルールは以下の通りです。

大きなグリッド内で一マスの生物が生きている、もしくは死んでいる状態で存在している。 隣り合う8つのマスの状態でそのマスの次の生存状態がきまる - 死んでいるマスの周りで3つの生きているマスがいると、次にそのますは生きている状態になる - 生きているマスの周りで生きているマスが1つ以下だと、次にそのマスは過疎で死ぬ - 生きているマスの周りで生きているますが4つ以上だと、次にそのますは過密で死ぬ

それ、Pythonでやってみましょう!

コーディング

import numpy as np
import random
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import matplotlib.patches as patches
%matplotlib inline

from IPython.display import HTML

class Seizon():
    def __init__(self):
        self.h = 50
        self.v = 50
        self.space = [[0 for i in range(self.h)] for j in range(self.v)]
        self.cycles=15
        self.start_val = 0
        
        self.rectPtrn = []
        
        
    def nextage(self, x, y):
        a_cell = 0
        for i in [-1, 0, 1]:
            for j in [-1, 0, 1]:
                if x+i < 0 or x+i > self.h - 1 or \
                   y+j < 0 or y+j > self.v - 1 or (i==0 and j==0):
                    pass
                elif self.space[x+i][y+j] == 1:
                    a_cell += 1
                    

        if self.space[x][y]==0:
            if a_cell == 3:
                return 1
            return 0
        if self.space[x][y]==1:
            if a_cell == 2:
                return 1
            return 0
    
    def check_life(self):
        for i in range(self.v):
            for j in range(self.h):
                test = self.nextage(i,j)
                self.space[i][j] = test
                
    def random_set(self, d=2):
        c = 0
        for i in range(self.v):
            for j in range(self.h):
                self.space[i][j] = random.randint(0,99) % 2
                c += self.space[i][j]
        self.start_val = c

    def calc_alives(self):
        c = 0
        for i in self.space:
            for j in i:
                c += j
        return c

    
    def pickRect(self):
        
        h = 0
        v = 0
        getRect = []
        for i in self.space:
            v = 0
            h += 1
            for j in i:
                v += 1
                if j == 1:
                    getRect.append([v,h])
        
        self.rectPtrn.append(getRect) 
    
    def __main__(self):
        self.random_set()

        for t in range(self.cycles):
            val = self.calc_alives()
            print str(t) + " : trial ",
            print val * 1.0 /self.start_val, val
            self.pickRect()
            self.check_life()            
        
        print len(self.rectPtrn)

sz = Seizon()
sz.__main__()

出力

0 : trial  1.0 1236
1 : trial  0.532362459547 658
2 : trial  0.366504854369 453
3 : trial  0.25 309
4 : trial  0.155339805825 192
5 : trial  0.0873786407767 108
6 : trial  0.0647249190939 80
7 : trial  0.0493527508091 61
8 : trial  0.0404530744337 50
9 : trial  0.0364077669903 45
10 : trial  0.037216828479 46
11 : trial  0.0380258899676 47
12 : trial  0.037216828479 46
13 : trial  0.0355987055016 44
14 : trial  0.0364077669903 45

ランダムで50%程度のマスカラ始めた場合、10回前後で大体3.5%で生き残り続けるようですね。この値は最初の配置で変わるようですが、3~4%ぐらいのようです。では実際どんな感じで生きているんでしょうか。アニメーションを使ってみてみましょう。

アニメーションをつかって可視化

fig = plt.figure()
ax = plt.gca()
ax.set_xlim(1,50)
ax.set_ylim(1,50)
#ax.set_aspect(1)

def init():
    return []

def animated(i):
    plt.cla()
    patches = []
    print i, len(sz.rectPtrn[i])
    for r in sz.rectPtrn[i]:
    #for r in [[1, 1], [2,2], [3,3]]:
        patches.append(ax.add_patch(plt.Rectangle((r[0],r[1]), 1, 1, fc="Blue")))
    return patches  
    

ani = animation.FuncAnimation(fig, animated, frames=sz.cycles, init_func=init, interval=1000, blit=True)

HTML(ani.to_html5_video())

こんなんが出ました。面白いですね。きまった型になってそのままキープしている様子がうかがえます。 f:id:bython-chogo:20170603085548g:plain