-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstate.py
184 lines (151 loc) · 4.32 KB
/
state.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# Copyright 2009-2011 Ram Rachum.
# This program is distributed under the LGPL2.1 license.
'''
A simulation package for a repeating game of prisoner's dillema between a
population of players with different strategies.
'''
### @export "imports"
import copy
import random
random.seed()
import garlicsim.data_structures
from garlicsim.misc import StepCopy
### @export "init"
ROUNDS = 7
NUMBER_OF_PLAYERS = 70
class State(garlicsim.data_structures.State):
def __init__(self, round, match, player_pool):
self.round = round
self.match = match
self.player_pool = player_pool
### @export "create-root"
@staticmethod
def create_root():
global player_types
state = State(
round=-1,
match=0,
player_pool=[
player_types[i % len(player_types)]() for \
i in xrange(NUMBER_OF_PLAYERS)
]
)
state.prepare_for_new_match()
return state
### @export "create-messy-root"
@staticmethod
def create_messy_root():
global player_types
state = State(
round=-1,
match=0,
player_pool=[
random_strategy_player() for \
i in xrange(NUMBER_OF_PLAYERS)
]
)
state.prepare_for_new_match()
return state
### @export "step"
def step(self):
state = copy.deepcopy(self, StepCopy())
state.clock += 1
state.round += 1
if state.round == ROUNDS:
state.round = -1
state.match += 1
state.prepare_for_new_match()
return state
for pair in state.pairs:
play_game(pair, state.round)
return state
### @export "prepare-for-new-match"
def prepare_for_new_match(self):
'''
Note: this function is not strictly a "step function":
it manipulates the state that is given to it and then returns it.
'''
pool = self.player_pool
loser = player_with_least_points(pool)
pool.remove(loser)
pool.append(random_strategy_player())
self.pairs = pair_pool(self.player_pool)
### @export "pair-pool"
def pair_pool(player_pool):
'''
Takes a player pool and returns a list of random pairs of players.
Every player will be a member of exactly one pair.
'''
assert len(player_pool) % 2 == 0
result = []
pool = player_pool[:]
while len(pool) > 0:
pair = random.sample(pool, 2)
result.append(pair)
pool.remove(pair[0])
pool.remove(pair[1])
return result
### @export "play-game"
def play_game((x, y), round):
x_move = x.play(round)
y_move = y.play(round)
assert x_move in [True, False]
assert y_move in [True, False]
if x_move == True and y_move == True:
x.points += 1
y.points += 1
elif x_move == True and y_move == False:
x.points += -4
y.points += 2
elif x_move == False and y_move == True:
x.points += 2
y.points += -4
elif x_move == False and y_move == False:
x.points += -1
y.points += -1
x.other_guy_played(y_move)
y.other_guy_played(x_move)
### @export "random-strategy-player"
def random_strategy_player():
player = random.choice(player_types)
return player()
### @export "player"
class Player(object):
def __init__(self):
self.points = 0
def play(self, *args, **kwargs):
raise NotImplementedError
def other_guy_played(self,move):
pass
### @export "angel"
class Angel(Player):
def play(self, round):
return True
### @export "devil"
class Devil(Player):
def play(self, round):
return False
### @export "tit-for-tat"
class TitForTat(Player):
def play(self, round):
if round == 0:
return True
else:
return self.last_play
def other_guy_played(self, move):
self.last_play = move
### @end
player_types=[Angel, Devil, TitForTat]
def how_many_players_of_certain_type(pool, type):
n = 0
for player in pool:
if isinstance(player, type):
n += 1
return n
def player_with_least_points(pool):
assert len(pool) > 0
loser = pool[0]
for player in pool:
if player.points < loser.points:
loser = player
return loser