"""
「「移動付繰り返し囚人ゲーム・シミュレーション」」
<<世界>>
NUM_COL 横の数
NUM_ROW 縦の数
世界 NUM_COL × NUM_ROWのテーブル。pythonの入れ子リスト構造で表現。
self.field 今回の世界
<<生物>>
生物のリスト構造
0=x 1=y 2=asset 3=hist 4=win or loose last time, 5=strategy
lives = [x:, y:, assets10, hist:10, win/loose:1/-1, strategy:0-4] 生物のリスト、ゲーム内の生物の辞書構造と標準値
assetは、自分の資産。エネルギー残量。
histは、0だと死んでる。1以上だと生きてる。
win/loose -1だと負けた(裏切られた)後、1だと勝った後。
strategy @:お人好し、 1:裏切り者、 2:経歴重視(histが小さくなると裏切る)、 3:前回勝てば同意、負ければ裏切り、 4:ランダム
<<囚人ゲーム>>
gamet_tabel 二つのセルの間の演算(対戦)の結果それぞれのセルが受け取る値。囚人のジレンマゲームのテーブル。
戦略は同意か、裏切りの二つ。結果は以下の通り。
相手 同意=0 裏切=1
自分
同意 1/1 -6 / 0
裏切 0/ -6 -3/-3
"""
import pygame
from pygame.locals import *
import random
import sys
SCR_RECT = Rect(0, 0, 800, 600)
CS = 10
NUM_ROW = SCR_RECT.height / CS
NUM_COL = SCR_RECT.width / CS
DEAD, ALIVE = -1, 0
NUM_LIVES = 100
NUM_STRATEGY = 4
TABLE_GAME = [[[1, 1,1,1],[-6,0,-1,1]],[[0,-6,1,-1],[-3,-3,-1,-1]]]
TABLE_MOVE = [[-1,-1],[-1,0],[-1,1],[0,-1],[0,1],[1,-1],[1,0],[1,1]]
class PrisonerGame:
def __init__(self):
global SCR_RECT, CS, NUM_ROW, NUM_COL, DEAD, ALIVE, NUM_LIVES, TABLE_GAME, TABLE_MOVE, table_rand
pygame.init()
screen = pygame.display.set_mode(SCR_RECT.size)
pygame.display.set_caption(u"Prisoner Game")
self.font = pygame.font.SysFont(None, 16)
self.num_lives_c = NUM_LIVES
self.std_assets=10
self.std_hist=10
self.std_wl=0
self.std_strategy=0
self.generation = 0
self.run = False
self.cursor = [NUM_COL/2, NUM_ROW/2]
self.clear()
self.table_rand()
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
elif event.key == K_RIGHT:
self.cursor[0] += 1
if self.cursor[0] > NUM_COL-1: self.cursor[0] = NUM_COL-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
self.add(x,y)
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.clear()
self.table_rand()
elif event.type == MOUSEBUTTONDOWN and event.button == 1:
px, py = event.pos
x, y = px/CS, py/CS
self.cursor = [x, y]
self.add(x,y)
def add(self,x,y):
global NUM_LIVES
if self.field[y][x] == DEAD:
self.field[y][x] = self.num_lives_c
self.lives.append({"x":x,"y":y,"assets":self.std_assets,"hist":self.std_hist,"wl":self.std_wl,"strategy":random.randint(0, NUM_STRATEGY)})
self.num_lives_c = self.num_lives_c + 1
elif self.field[y][x] >= ALIVE:
self.lives[self.field[y][x]]["assets"] = 0
self.field[y][x] = DEAD
def clear(self):
"""ゲームを初期化"""
self.generation = 0
self.num_lives_c = NUM_LIVES
self.field = [[DEAD for x in range(NUM_COL)] for y in range(NUM_ROW)]
self.lives=[]
self.num_lives_c = 0
def table_rand(self):
self.num_lives_c = NUM_LIVES
self.lives = [{"x":0,"y":0,"assets":self.std_assets,"hist":self.std_hist,"wl":self.std_wl,"strategy":self.std_strategy} for x in range(self.num_lives_c)]
for i in range(self.num_lives_c):
finish_flag=0
while finish_flag==0 :
x=random.randint(1, NUM_COL - 1)
y=random.randint(1, NUM_ROW - 1)
if self.field[y][x] == DEAD :
self.field[y][x]=i
self.lives[i]["x"]=x
self.lives[i]["y"]=y
self.lives[i]["strategy"]=random.randint(0, NUM_STRATEGY)
finish_flag=1
def update(self):
"""フィールドを更新"""
if self.run:
self.step()
def step(self):
for j in range(len(self.lives)):
if self.lives[j]["assets"] > 0 :
a_round = self.around(self.lives[j]["x"], self.lives[j]["y"])
if a_round >= 0 :
self.table_trade(j,a_round)
else :
self.field_move(j, random.randint(0,7))
self.generation += 1
print "Generation %d th " % self.generation
def field_move(self, live_num, direction) :
x = self.lives[live_num]["x"]
y = self.lives[live_num]["y"]
new_x = x+TABLE_MOVE[direction][0]
new_y = y+TABLE_MOVE[direction][1]
a_round=self.around(x,y)
if not (a_round >= 0 or new_x < 1 or new_y < 1 or new_x > NUM_COL-1 or new_y > NUM_ROW - 1) :
self.field[y][x] = DEAD
self.field[new_y][new_x]=live_num
self.lives[live_num]["x"]=new_x
self.lives[live_num]["y"]=new_y
def table_trade(self, num1, num2):
assets_num1 = self.lives[num1]["assets"]
assets_num2 = self.lives[num2]["assets"]
decision_num1 = self.trade_strategy(num1)
decision_num2 = self.trade_strategy(num2)
self.die_or_suv(num1, decision_num1, TABLE_GAME[decision_num1][decision_num2][0], TABLE_GAME[decision_num1][decision_num2][2])
self.die_or_suv(num2, decision_num2, TABLE_GAME[decision_num1][decision_num2][1], TABLE_GAME[decision_num1][decision_num2][3])
print
def trade_strategy(self, num):
hist_status=self.lives[num]["hist"]
last_w_l = self.lives[num]["wl"]
strategy_type=self.lives[num]["strategy"]
if strategy_type==1 :
return 1
elif strategy_type == 2 and hist_status <= 7 :
return 1
elif strategy_type == 3 and last_w_l == -1 :
return 1
elif strategy_type == 4 and random.random() < .3 :
return 1
else :
return 0
def die_or_suv(self, num, decision, trade, wl) :
if (self.lives[num]["assets"] + trade) <= ALIVE :
self.dead_lives(num)
else:
self.lives[num]["assets"] = self.lives[num]["assets"] + trade
self.lives[num]["hist"] = self.lives[num]["hist"] + wl
self.lives[num]["wl"] = wl
a_print = "num: %d x: %d y: %d " % (num, self.lives[num]["x"], self.lives[num]["y"])
a_print = a_print + "asset: %d hist: %d w/l %d strategy: %d " % (self.lives[num]["assets"], self.lives[num]["hist"], self.lives[num]["wl"], self.lives[num]["strategy"])
a_print = a_print + "decision: %d result %d" % (decision, trade)
print a_print
def dead_lives(self,num):
self.field[self.lives[num]["y"]][self.lives[num]["x"]]=DEAD
self.lives[num]["assets"] = 0
def draw(self, screen):
"""フィールドを描画"""
for y in range(NUM_ROW):
for x in range(NUM_COL):
s_num = self.field[y][x]
if s_num > ALIVE:
s_color = self.lives[s_num]["assets"]
s_strategy = self.lives[s_num]["strategy"]
if s_color > 255 :
s_color = 255
if s_color < 255 :
s_color = 0
if s_strategy == 0:
pygame.draw.rect(screen, (int(s_color/2), 0, 255), Rect(x*CS,y*CS,CS,CS))
elif s_strategy == 1 :
pygame.draw.rect(screen, (255, 0 , int(s_color/2)), Rect(x*CS,y*CS,CS,CS))
elif s_strategy == 2 :
pygame.draw.rect(screen, (0, 255, int(s_color/2)), Rect(x*CS,y*CS,CS,CS))
elif s_strategy == 3 :
pygame.draw.rect(screen, (int(s_color/4), 125, 125), Rect(x*CS,y*CS,CS,CS))
else :
pygame.draw.rect(screen, (int(s_color/4), 0, 180), Rect(x*CS,y*CS,CS,CS))
elif s_num == 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("space : 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):
"""(x,y)の周囲8マスの生きているセルの数を返す"""
if x < 2 or x > (NUM_COL - 2) or y < 2 or y > (NUM_ROW - 2) :
return DEAD
else:
for i in [-1, 0, 1]:
for j in [-1, 0, 1]:
if not (i==0 and j==0):
a = self.field[y+j][x+i]
if a > ALIVE:
return a
return DEAD
if __name__ == "__main__":
PrisonerGame()