上のGUIツールで作ったライフゲーム

エントリの頭に画像はっつけた。
追記:直接このページを訪れた方はこの日のエントリの一つ前のエントリを参照してください。それが"上の"ものです。

#! /bin/env python
# -*- coding: utf-8 -*-
# lifegame_tk.py
from textPrinter import TextPrinter
import copy

ALIVE = True
DEAD = False

class Cell:
    def __init__(self):
        self._state = DEAD
    def state(self):
        return self._state
    def flip(self):
        self._state = not self._state
        return self._state
    def __str__(self):
        return self._state and "@" or "-"

class LifeGame:
    def __init__(self, h, w):
        self.field = [[Cell() for _ in range(w)] for _ in range(h)]
        self.h = h
        self.w = w
    def update(self):
        newfield = copy.deepcopy(self.field)
        for i in range(self.h):
            for j in range(self.w):
                around = self.around(i,j)
                if self.field[i][j].state() is DEAD and around==3:
                    # 死んでいるセルの周囲に3つの生きているセルがあれば誕生
                    newfield[i][j].flip()
                elif self.field[i][j].state() is ALIVE and (around==2 or around==3):
                    # 生きているセルの周囲に2つか3つの生きているセルがあれば次の世代でも生き残る
                    pass
                else:  # 死亡
                    if self.field[i][j].state() is ALIVE:
                        newfield[i][j].flip()
        self.field = newfield
        
    def index(self, x, y):
        # circular access
        if x >= self.h: x = x % self.h
        if y >= self.w: y = y % self.w
        return self.field[x][y]
    def around(self, x, y):
        diff = [[-1,-1], [-1,0], [-1,1],
                [0,-1], [0,1],
                [1,-1], [1,0], [1,1]]
        lst = [self.index(x+d[0], y+d[1]).state() is ALIVE for d in diff]
        return len([x for x in lst if x is True])
    def __str__(self):
        return "\n".join(["".join(map(str, line)) for line in self.field])


def test(h,w,anode):
    tp = TextPrinter(None, "Life Game", font=("courier","10"))
    am = LifeGame(h,w)
    # ランダムに初期化

    import random
    for _ in range(anode):
        x = random.randint(0,h)
        y = random.randint(0,w)
        am.index(x,y).flip()

    # グライダー
    """
    am.index(0,0).flip()
    am.index(0,2).flip()
    am.index(1,1).flip()
    am.index(1,2).flip()
    am.index(2,1).flip()
    """
    
    def callback():
        tp.getText().set( str(am) )
        am.update()
    tp.mainloop(callback, 0.5)

def main():
    import sys
    if sys.argv.__len__() != 4:
        print "usage: %s height width anode" % __file__
        sys.exit()
    h,w,anode = [int(arg) for arg in sys.argv[1:4]]
    test(h, w, anode)
    
if __name__ == '__main__':
    main()