-
Notifications
You must be signed in to change notification settings - Fork 4
/
game.py
120 lines (100 loc) · 4.63 KB
/
game.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
import random
import copy
from constants import DIESIDE, MAX_HEALTH, VICTORY_PTS_WIN, DIE_COUNT, PlayerState
class Game:
def __init__(self, player_strategies=[], start_idx=0):
self.players = [PlayerState() for _ in range(2)]
self.player_strategies = player_strategies
assert len(self.player_strategies) == len(self.players)
self.winner = -1
self.current_player_idx = start_idx
@property
def n_players(self):
return len(self.players)
@property
def current_player(self):
return self.players[self.current_player_idx]
@property
def other_player_idx(self):
return (self.current_player_idx + 1) % self.n_players
@property
def other_player(self):
return self.players[self.other_player_idx]
@property
def tokyo_player_idx(self):
players_in_tokyo = [player.in_tokyo for player in self.players]
return players_in_tokyo.index(True)
def other_player_yields_tokyo(self, dice):
return self.player_strategies[self.other_player_idx].yield_tokyo(copy.deepcopy(self.other_player), copy.deepcopy(self.current_player), copy.deepcopy(dice))
def start_turn(self):
if self.current_player.in_tokyo:
self.current_player.victory_points += 2
def roll_n_dice(self, n):
return [random.choice([DIESIDE.ATTACK, DIESIDE.HEAL, DIESIDE.ONE, DIESIDE.TWO, DIESIDE.THREE]) for _ in range(n)]
def roll_dice(self):
dice_results = self.roll_n_dice(DIE_COUNT)
for i in range(2):
keep_mask = self.player_strategies[self.current_player_idx].keep_dice(copy.deepcopy(self.current_player), copy.deepcopy(self.other_player), copy.deepcopy(dice_results), reroll_n=i)
dice_results = [dice_results[i] for i in range(DIE_COUNT) if keep_mask[i]] + self.roll_n_dice(DIE_COUNT - sum(keep_mask))
return dice_results
def resolve_victory_point_dice(self, dice):
for dieside in [DIESIDE.ONE, DIESIDE.TWO, DIESIDE.THREE]:
cnt = sum([x == dieside for x in dice])
if cnt >= 3:
self.current_player.victory_points += int(dieside)
self.current_player.victory_points += cnt - 3
def resolve_health_dice(self, dice):
heals = sum([x == DIESIDE.HEAL for x in dice])
if not self.current_player.in_tokyo:
self.current_player.health = min(MAX_HEALTH, self.current_player.health + heals)
def resolve_attack_dice(self, dice):
attack = sum([x == DIESIDE.ATTACK for x in dice])
if self.current_player.in_tokyo:
self.other_player.health = self.other_player.health - attack
elif self.other_player.in_tokyo:
self.other_player.health = self.other_player.health - attack
if attack > 0 and self.other_player_yields_tokyo(dice):
self.current_player.in_tokyo = True
self.other_player.in_tokyo = False
else:
self.current_player.in_tokyo = True
self.current_player.victory_points += 1
def resolve_dice(self, dice):
self.resolve_victory_point_dice(dice)
self.resolve_health_dice(dice)
self.resolve_attack_dice(dice)
def check_winner(self):
for i, player in enumerate(self.players):
if player.health <= 0:
self.winner = (i + 1) % self.n_players
if player.victory_points >= VICTORY_PTS_WIN:
self.winner = i
def step(self):
self.start_turn()
dice = self.roll_dice()
self.resolve_dice(dice)
self.check_winner()
self.current_player_idx = (self.current_player_idx + 1) % self.n_players
def __str__(self):
return (f'GAME STATE: player {self.tokyo_player_idx} is in tokyo \n' +
f'Players 0 has {self.players[0].health} health and {self.players[0].victory_points} victory points \n' +
f'Players 1 has {self.players[1].health} health and {self.players[1].victory_points} victory points')
if __name__ == '__main__':
import importlib
import sys
if len(sys.argv) != 3:
print('Example usage: python game.py random_agent random_agent')
sys.exit(1)
_, strategy_one, strategy_two =sys.argv
module_one = importlib.import_module(strategy_one)
module_two = importlib.import_module(strategy_two)
GAMES_N = 100
winners = []
for i in range(GAMES_N):
game = Game(player_strategies=[module_one.PlayerStrategy(), module_two.PlayerStrategy()],
start_idx=i%2)
while game.winner == -1:
game.step()
winners.append(game.winner)
player_0_wins = sum([x == 0 for x in winners])
print(f'{strategy_one} won {player_0_wins}/{GAMES_N} games against {strategy_two}')