Pythonによるライフゲーム
そうだ、ブログを書こう!
ということでブログを新設しました。
RやPythonによるデータマイニングやその他雑記、備忘録を適当に載せる予定です。
取り合えず日記でも。
今日はPythonでライフゲームを作りました。pygameの練習として作ったのですが、結構面白いです。
参考にしたのは以下のサイトです。
http://aidiary.hatenablog.com/entry/20080507/1269694935
ライフゲームが何かという所から、Pythonによる実装まで超詳しく載ってます。
その他の記事も機械学習とか勉強している身からすると非常に面白いのでお勧めです。
作成したPythonのコードは以下の通り。
#!/usr/bin/python # -*- coding: utf-8 -*- import pygame from pygame.locals import * import random import sys reload(sys) sys.setdefaultencoding("utf-8") SCR_RECT = Rect(0,0,800,600) CS = 10 NUM_ROW = SCR_RECT.height / CS NUM_COL = SCR_RECT.width / CS DEAD, ALIVE = 0, 1 RAND_LIFE = 0.1 RATE_SUDDEN_ALIVE = 0.01 RATE_SUDDEN_DETH = 0.01 BC = 1 class LifeGame: def __init__(self): pygame.init() screen = pygame.display.set_mode(SCR_RECT.size) self.font = pygame.font.SysFont(None, 16) self.field = [[DEAD for x in range(NUM_COL)] for y in range(NUM_ROW)] self.generation = 0 self.run = False self.cursor = [NUM_COL/2, NUM_ROW/2] self.clear() clock = pygame.time.Clock() while True: clock.tick(60) self.update() self.draw(screen) pygame.display.update() for event in pygame.event.get(): if event.type == QUIT: pygame.quit() sys.exit() elif event.type == KEYDOWN: if event.key == K_ESCAPE: pygame.quit() sys.exit() elif event.key == K_LEFT: self.cursor[0] -= 1 if self.cursor[0] < 0: self.cursor[0] = 0 print self.cursor elif event.key == K_RIGHT: self.cursor[0] += 1 if self.cursor[0] > NUM_COL-1: self.cursor[0] - 1 elif event.key == K_UP: self.cursor[1] -= 1 if self.cursor[1] < 0: self.cursor[1] = 0 elif event.key == K_DOWN: self.cursor[1] += 1 if self.cursor[1] > NUM_ROW-1: self.cursor[1] = NUM_ROW-1 elif event.key == K_SPACE: x, y = self.cursor if self.field[y][x] == DEAD: self.field[y][x] = ALIVE elif self.field[y][x] == ALIVE: self.field[y][x] = DEAD elif event.key == K_s: self.run = not self.run elif event.key == K_n: self.step() elif event.key == K_c: self.clear() elif event.key == K_r: self.rand() elif event.type == MOUSEBUTTONDOWN and event.button == 1: px, py = event.pos x, y = px/CS, py/CS self.cursor = [x,y] if self.field[y][x] == DEAD: self.field[y][x] = ALIVE elif self.field[y][x] == ALIVE: self.field[y][x] = DEAD def clear(self): self.generation = 0 for y in range(NUM_ROW): for x in range(NUM_COL): self.field[y][x] = DEAD def rand(self): for y in range(NUM_ROW): for x in range(NUM_COL): if random.random() < RAND_LIFE: self.field[y][x] = ALIVE def update(self): if self.run: self.step() def step(self): next_field = [[False for x in range(NUM_COL)] for y in range(NUM_ROW)] for y in range(NUM_ROW): for x in range(NUM_COL): num_alive_cells = self.around(x,y) if num_alive_cells == 2: next_field[y][x] = self.field[y][x] elif num_alive_cells == 3: next_field[y][x] = ALIVE elif num_alive_cells > 0: next_field[y][x] = DEAD if num_alive_cells >= 2: if self.field[y][x] == ALIVE and random.random() <= RATE_SUDDEN_DETH: next_field[y][x] = DEAD elif self.field[y][x] == DEAD and random.random() <= RATE_SUDDEN_ALIVE: next_field[y][x] = ALIVE self.field = next_field self.generation += 1 def draw(self,screen): for y in range(NUM_ROW): for x in range(NUM_COL): if self.field[y][x] == ALIVE: pygame.draw.rect(screen,(255,255,0),Rect(x*CS,y*CS,CS,CS)) elif self.field[y][x] == DEAD: pygame.draw.rect(screen,(0,0,0),Rect(x*CS,y*CS,CS,CS)) pygame.draw.rect(screen,(50,50,50),Rect(x*CS,y*CS,CS,CS),1) pygame.draw.line(screen,(255,0,0),(0,SCR_RECT.height/2),(SCR_RECT.width,SCR_RECT.height/2)) pygame.draw.line(screen,(255,0,0),(SCR_RECT.width/2,0),(SCR_RECT.width/2,SCR_RECT.height)) pygame.draw.rect(screen,(0,0,255),Rect(self.cursor[0]*CS,self.cursor[1]*CS,CS,CS),1) screen.blit(self.font.render("generation:%d" % self.generation, True, (0,255,0)),(0,0)) screen.blit(self.font.render("spase : birth/kill", True, (0,255,0)),(0,12)) screen.blit(self.font.render("s : start/stop",True, (0,255,0)),(0,24)) screen.blit(self.font.render("n : next",True, (0,255,0)),(0,36)) screen.blit(self.font.render("r : random", True, (0,255,0)),(0,48)) def around(self, x, y): if BC == 0: if x == 0 or x == NUM_COL-1 or y == 0 or y == NUM_ROW-1: return 0 elif BC == 1: sum = 0 sum += self.field[(y-1+NUM_ROW)%NUM_ROW][(x-1+NUM_COL)%NUM_COL] sum += self.field[(y-1+NUM_ROW)%NUM_ROW][x] sum += self.field[(y-1+NUM_ROW)%NUM_ROW][(x+1)%NUM_COL] sum += self.field[y][(x-1+NUM_COL)%NUM_COL] sum += self.field[y][(x+1)%NUM_COL] sum += self.field[(y+1)%NUM_ROW][(x-1+NUM_COL)%NUM_COL] sum += self.field[(y+1)%NUM_ROW][x] sum += self.field[(y+1)%NUM_ROW][(x+1)%NUM_COL] return sum if __name__ == "__main__": LifeGame()
今度ブログにコードを載せる方法を調べよう。。。
基本は参考サイトの丸パクリだけど、周期的境界条件と突然死(と自然発生)の部分を追加しています。
突然死と自然発生はパラメータを調整することで、ユニバーサリティを持つのがわかるので面白いです。