-
Notifications
You must be signed in to change notification settings - Fork 0
/
table.py
139 lines (109 loc) · 4.03 KB
/
table.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
from card import *
from collections import OrderedDict as ordereddict
import numpy as np
np.random.seed(1)
# Flip debug to True to test all cards.
DEBUG = False
FIXED = True
class Table:
def __init__(self, num_players):
"""
A table is a collection of card piles.
"""
# Choose 10 cards without replacement from set of all kingdom cards
kingdom = np.random.choice(KINGDOM_CARDS, size=10, replace=False)
if DEBUG:
kingdom = KINGDOM_CARDS
if FIXED:
kingdom = [CHAPEL, BANDIT, WITCH, MARKET, VILLAGE, SMITHY, MINE, MERCHANT, WORKSHOP, CELLAR]
self.kingdom = kingdom
# Use a ordered dict to allow indexing with a number
self.table = ordereddict({
COPPER: 60 - (num_players * 7),
SILVER: 40,
GOLD: 30,
ESTATE: 8 if num_players == 2 else 12,
DUTCHY: 8 if num_players == 2 else 12,
PROVINCE: 8 if num_players == 2 else 12,
CURSE: 10 * (num_players - 1),
})
for card in kingdom:
self.table[card] = 10
def __str__(self):
"""
Returns a string representation of the table.
"""
s = '{:<4}{:<14}{:<5}{:<7}{:<}\n'.format('', 'Name', 'Left', 'Cost', 'Description')
for i, (card, left) in enumerate(self.table.items()):
s += '{:>2}. {!s:<23} [{:>2}] ({:>2}) | {}\n'.format(i, card, left, card.cost, card.description)
return s
@property
def cards(self):
"""
Returns the list of cards on the table.
"""
return list(self.table.keys())
@property
def num_empty_piles(self):
"""
Returns the number of empty piles
"""
empty_piles = [v for v in self.table.values() if v == 0]
return len(empty_piles)
def can_purchase(self, idx, treasures, card_type_only=None):
"""
A card is available for purcase if there is more in the pile, and the
cost is at most the amount of treasures available.
"""
card, left = list(self.table.items())[idx]
if card_type_only and card.type != card_type_only:
return False
return card.cost <= treasures and left >= 1
def can_purchase_card(self, card, worth):
"""
A card is available for purcase if there is more in the pile, and the
cost is at most the amount of treasures available.
"""
left = self.table[card]
return card.cost <= worth and left >= 1
def get_purchasable_cards(self, worth, card_type_only=None):
"""
Return the set of cards available for purchase as a list of indexes.
"""
purchasable = []
for idx, (card, left) in enumerate(list(self.table.items())):
if card_type_only and card.type != card_type_only:
continue
if card.cost <= worth and left >= 1:
purchasable.append(idx)
return purchasable
def buy_idx(self, idx):
"""
When passed an index of a card, perform a purchase of the card, removing
one count of it from the table and returning a shared instance of it to
the player.
"""
card, _ = list(self.table.items())[idx]
self.table[card] -= 1
return card
def get_card(self, card):
"""
If a specific card is desired, just pull one of it from the table. If there
are no cards left in the pile, returns False.
"""
if self.table[card] >= 1:
self.table[card] -= 1
return True
return False
def reached_end(self):
"""
Returns true if the end of the game is reached. This can happen when:
- There are no more provinces
- 3 piles are empty (4 in a four player game)
"""
if self.table[PROVINCE] == 0:
return True
n_piles_empty = len([v for v in self.table.values() if v == 0])
if n_piles_empty >= 3:
return True
return False