LIFEGAME

LIFEGAME

Python, Numpy, Curses の組み合わせでライフゲームを製作した。練習問題ですね。

cursesでconsoleのwindowサイズを取得、それに合わせてnumpy.arrayを作成しbufferとする。初期画面はnumpyのrandomで生成、世代更新はnumpyのsumを利用した。画面更新はbufferをスキャンして1つ1つ書き換え。ここは改良の余地がありそう。

#!/usr/bin/env python3

import numpy as np
import curses as cs
import time

class lifegame:
    def __init__(self, ny, nx):
        self.field = np.zeros([ny, nx]).astype(np.int)
        self.ny = ny
        self.nx = nx

    def fill_random(self, duty=0.5):
        f = np.random.rand(self.ny, self.nx)
        self.field = np.floor(f + duty).astype(np.int)

    def update_generation(self):
        f = self.field
        next = np.zeros([self.ny, self.nx]).astype(np.int)
        f = np.r_[f[[self.ny - 1], :], f, f[[0], :]]
        f = np.c_[f[:, [self.nx - 1]], f, f[:, [0]]]
        for i in range(0, self.ny):
            for j in range(0, self.nx):
                area = f[i:i + 3, j:j + 3]
                life = np.sum(area) - area[1, 1]
                if area[1, 1] == 1:
                    if life == 2 or life == 3:
                        next[i, j] = 1
                else:
                    if life == 3:
                        next[i, j] = 1
        self.field = next

def display(win, buff, ny, nx):
    for i in range(0, ny):
        for j in range(0, nx):
            win.addch(i, j, int(buff[i, j]))
    win.refresh()

def main(scr):
    mark = ord('*')
    blank = ord(' ')
    tc = 0.5
    scr.clear()
    ny, nx = scr.getmaxyx()
    win = scr.subwin(ny, nx, 0, 0)
    ny -= 1
    nx -= 1
    lg = lifegame(ny, nx)
    lg.fill_random(0.5)
    buff = lg.field * (mark - blank) + blank
    display(win, buff, ny, nx)
    scr.nodelay(1)
    time.sleep(0.5)
    tz1 = time.time()
    while(True):
        c = scr.getch()
        if c == -1:
            lg.update_generation()
            buff = lg.field * (mark - blank) + blank
            display(win, buff, ny, nx)
            tz0 = time.time()
            t = tz0 - tz1
            if t < tc:
                time.sleep(tc - t)
            tz1 = tz0
        elif 0 < c <= 255:
            c = chr(c)
            if c in 'Qq\n':
                break

if __name__ == '__main__':
    cs.wrapper(main)

動作例 Movie

コメントを残す

メールアドレスが公開されることはありません。