-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgame_mechanics.py
171 lines (155 loc) · 5.77 KB
/
game_mechanics.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
import random
class Game:
def __init__(self, players):
self.players = players
self.turn_counter = 0
self.province = 8
self.duchy = 8
self.estate = 8
def game_state(self):
return self.province, self.duchy, self.estate
def check_valid(self, action, player):
coins = sum(player.hand)
if action == "province" and (self.province == 0 or coins < 8):
return False
elif action == "duchy" and (self.duchy == 0 or coins < 5):
return False
elif action == "estate" and (self.estate == 0 or coins < 2):
return False
elif action == "gold" and coins < 6:
return False
elif action == "silver" and coins < 3:
return False
else:
valid_actions = ["none", "copper", "silver", "gold", "estate", "duchy", "province"]
return action in valid_actions
def buy(self, action, player):
if action == "province":
self.province -= 1
elif action == "duchy":
self.duchy -= 1
elif action == "estate":
self.estate -= 1
player.buy(action)
def winner(self):
best_score = max([player.vp for player in self.players])
best_players = [player for player in self.players if player.vp == best_score]
fewest_turns = min([player.turns for player in best_players])
winners = [player for player in best_players if player.turns == fewest_turns]
winner_names = []
for player in winners:
winner_names.append(player.name)
return winner_names
def scores(self):
result = {}
for player in self.players:
result[player.name] = dict(vp=player.vp,
turns=player.turns,
province=player.province,
duchy=player.duchy,
estate=player.estate,
gold=player.gold,
silver=player.silver,
copper=player.copper,
)
# print(f"{player.name} VP: {player.vp}, Turns: {player.turns}, "
# f"P: {player.province}, D: {player.duchy}, E: {player.estate}, "
# f"G: {player.gold}, S: {player.silver}, C: {player.copper}")
return result
def play(self):
while self.province != 0:
self.turn_counter += 1
# print("Turn", self.turn_counter)
if self.turn_counter == 100:
raise Exception("Turn count exceeded")
for player in self.players:
player.draw_hand()
valid_action = False
attempts = 0
while not valid_action:
attempts += 1
action = player.action(self.game_state())
valid_action = self.check_valid(action, player)
if attempts == 10:
raise Exception("Failed to supply valid action")
self.buy(action, player)
player.discard_hand()
# input()
winner_names = self.winner()
scores = self.scores()
return winner_names, scores
class Player:
def __init__(self, name, strategy):
self.name = name
self.strategy = strategy
self.turns = 0
self.vp = 3
self.total_cards = 10
self.victory_cards = 10
self.copper = 7
self.silver = 0
self.gold = 0
self.estate = 3
self.duchy = 0
self.province = 0
self.deck = [0]*3 + [1]*7
random.shuffle(self.deck)
self.hand = []
self.discard_pile = []
def action(self, game_state):
game_province, game_duchy, game_estate = game_state
player_state = dict(hand=self.hand,
game_province=game_province,
game_duchy=game_duchy,
game_estate=game_estate)
return self.strategy(player_state)
def draw_hand(self):
self.turns += 1
for i in range(5):
if len(self.deck) == 0:
self.reshuffle()
self.hand.append(self.deck.pop())
def discard_hand(self):
while len(self.hand) != 0:
self.discard_pile.append(self.hand.pop())
def reshuffle(self):
assert len(self.deck) == 0
self.deck = self.discard_pile.copy()
random.shuffle(self.deck)
self.discard_pile = []
def buy(self, action):
# print(self.name, action, sum(self.hand), self.hand)
if action == "province":
self.discard_pile.append(0)
self.vp += 6
self.total_cards += 1
self.victory_cards += 1
self.province += 1
elif action == "duchy":
self.discard_pile.append(0)
self.vp += 3
self.total_cards += 1
self.victory_cards += 1
self.duchy += 1
elif action == "estate":
self.discard_pile.append(0)
self.vp += 1
self.total_cards += 1
self.victory_cards += 1
self.estate += 1
elif action == "gold":
self.discard_pile.append(3)
self.total_cards += 1
self.gold += 1
elif action == "silver":
self.discard_pile.append(2)
self.total_cards += 1
self.silver += 1
elif action == "copper":
self.discard_pile.append(1)
self.total_cards += 1
self.copper += 1
elif action == "none":
pass
else:
raise Exception("No action implemented")