Skip to content

Instantly share code, notes, and snippets.

@shiracamus
Created January 7, 2021 22:33
Show Gist options
  • Save shiracamus/80b8b236bc177416940c80eeb4be81a6 to your computer and use it in GitHub Desktop.
Save shiracamus/80b8b236bc177416940c80eeb4be81a6 to your computer and use it in GitHub Desktop.
import random
import time
DEPOP = 1 # 過疎条件
OVERCROW = 4 # 過密条件
ALIVE_LOWER = 3 # 発生条件(下限)
ALIVE_UPPER = 3 # 発生条件(上限)
ETERNAL = False # セルの永続化フラグ
INITIALIZE_ALIVE_RATE = 20 # 初期セルの生存率(%)
class LifeGame:
def __init__(self, width, height):
self.width = width
self.height = height
self.cells = self.generate(self.init_life)
def next_generation(self):
"""世代交代"""
self.cells = self.generate(self.next_life)
def __iter__(self):
"""生命体セルのイテレータを返す(for文のinで使用)"""
return iter(self.cells)
def generate(self, life):
"""生命体セルを生成する"""
return tuple(tuple(life(x, y) for x in range(self.width))
for y in range(self.height))
def init_life(self, x, y):
"""初期の生命体の値"""
if random.randint(1, 100) <= INITIALIZE_ALIVE_RATE:
return random.randint(0, 9)
return 0
def next_life(self, x, y):
"""次世代の生命体の値"""
life = self.cells[y][x]
neighbor_alives = self.count_neighbor_alives(x, y)
if life == 0:
if ALIVE_LOWER <= neighbor_alives <= ALIVE_UPPER:
life = 1
elif life == 9:
if not ETERNAL:
life = 0 # 寿命で死亡
else:
if DEPOP < neighbor_alives < OVERCROW:
life += 1
else:
life = 0
return life
def count_neighbor_alives(self, x, y):
"""周囲のセルの生存数を数える"""
return sum(1
for ny in (y - 1, y, y + 1)
if 0 <= ny < self.height
for nx in (x - 1, x, x + 1)
if 0 <= nx < self.width
if (ny, nx) != (y, x)
if self.cells[ny][nx] != 0)
def main():
lifegame = LifeGame(79, 23)
for _ in range(100):
print('\033[2J\033[H')
for cells in lifegame:
print(*cells, sep='')
time.sleep(1)
lifegame.next_generation()
if __name__ == '__main__':
main()
import time
import matplotlib.pyplot as plt
from lifegame_model import LifeGame
# 各変数の設定
# グラフの描画サイズ
WIDTH = HEIGHT = 1000
# 描画時のセルの間隔
# 各軸のセルの数は描画サイズ÷セルの間隔で求められます。
SPACE = 5
# セル描画時の大きさ係数
SIZE_FACTOR = 5
class LifeGameView:
def __init__(self):
# インタラクティブモード オン
plt.ion()
# 描画領域の初期化
fig, ax = plt.subplots()
ax.set_xlim(0, WIDTH + SPACE)
ax.set_ylim(0, HEIGHT + SPACE)
ax.set_aspect('equal')
ax.grid(False)
# マウスクリックで終了するためのイベントの設定
fig.canvas.mpl_connect('button_press_event', stop)
# scatter(散布図)オブジェクトの作成
width = WIDTH // SPACE
height = HEIGHT // SPACE
x = [*range(1, WIDTH + 1, SPACE)] * height
y = [y for y in range(1, HEIGHT + 1, SPACE) for x in range(width)]
color = ['b'] * width * height
scale = [0] * width * height
self.sc = ax.scatter(x, y, c=color, s=scale, alpha=0.3, edgecolors='none')
def draw(self, lifegame):
scale = []
color = []
# セルの状態を元に描画設定を作成
for cells in lifegame:
for life in cells:
scale.append(life * SIZE_FACTOR)
color.append('bbbbbggggr'[life])
# 描画の設定と再描画
self.sc.set_sizes(scale)
self.sc.set_color(color)
self.sc.figure.canvas.draw_idle()
self.sc.figure.canvas.flush_events()
def stop(event):
print('Program is over.')
main.loop = False
def main():
view = LifeGameView()
lifegame = LifeGame(WIDTH // SPACE, HEIGHT // SPACE)
main.loop = True
while main.loop:
lifegame.next_generation()
view.draw(lifegame)
# 処理が早すぎて困る場合のスリープ(秒)
# time.sleep(0.01)
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment