Skip to content

Commit df557b7

Browse files
authored
Move Card defaults to read time (#578)
* Re-order card classes so Card.type can have a python type hint * make Card.get_total_cost not static * Refactor card count tracking to move default to read time
1 parent de866f9 commit df557b7

File tree

5 files changed

+122
-100
lines changed

5 files changed

+122
-100
lines changed

src/domdiv/cards.py

Lines changed: 92 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,53 @@
55
from reportlab.lib.units import cm
66

77

8+
class CardType(object):
9+
@staticmethod
10+
def decode_json(obj):
11+
return CardType(**obj)
12+
13+
def __init__(
14+
self,
15+
card_type,
16+
card_type_image,
17+
group_global_type=None,
18+
group_cost=None,
19+
defaultCardCount=10,
20+
tabTextHeightOffset=0,
21+
tabCostHeightOffset=-1,
22+
):
23+
self.typeNames = tuple(card_type)
24+
self.tabImageFile = card_type_image
25+
self.group_global_type = group_global_type
26+
self.group_cost = group_cost
27+
self.defaultCardCount = defaultCardCount
28+
self.tabTextHeightOffset = tabTextHeightOffset
29+
self.tabCostHeightOffset = tabCostHeightOffset
30+
31+
def getTypeDefaultCardCount(self):
32+
return self.defaultCardCount
33+
34+
def getTypeNames(self):
35+
return self.typeNames
36+
37+
def getTabImageFile(self):
38+
if not self.tabImageFile:
39+
return None
40+
return self.tabImageFile
41+
42+
def getGroupGlobalType(self):
43+
return self.group_global_type
44+
45+
def getGroupCost(self):
46+
return self.group_cost
47+
48+
def getTabTextHeightOffset(self):
49+
return self.tabTextHeightOffset
50+
51+
def getTabCostHeightOffset(self):
52+
return self.tabCostHeightOffset
53+
54+
855
class Card(object):
956
sets = None
1057
types = None
@@ -31,7 +78,7 @@ def __init__(
3178
potcost=0,
3279
debtcost=0,
3380
extra="",
34-
count=-1,
81+
count=None,
3582
card_tag="missing card_tag",
3683
cardset_tags=None,
3784
group_tag="",
@@ -61,32 +108,48 @@ def __init__(
61108
self.cardset_tags = cardset_tags
62109
self.group_tag = group_tag
63110
self.group_top = group_top
64-
self.image = image
111+
self.image = image # used for promo cards with unique "set" images
65112
self.text_icon = text_icon
66113
self.cardset_tag = cardset_tag
67-
self.setCardCount(count)
68114
self.randomizer = randomizer
69115

70-
def getCardCount(self):
71-
return sum(i for i in self.count)
116+
if count is not None:
117+
if isinstance(count, int):
118+
self._counts = [count]
119+
elif isinstance(count, str) and count.isdigit():
120+
self._counts = [int(count)]
121+
else:
122+
raise TypeError(
123+
f"{name or card_tag}: Count must be int or str: {count} has type {type(count)}"
124+
)
125+
else:
126+
self._counts = None
127+
128+
def getCardCount(self) -> int:
129+
return sum(self.getCardCounts())
130+
131+
def getCardCounts(self) -> list[int]:
132+
if self._counts is None:
133+
return [self.getType().getTypeDefaultCardCount()]
134+
return self._counts
72135

73136
def setCardCount(self, value):
74-
value = int(value)
75-
if value < 0:
76-
self.count = [self.getType().getTypeDefaultCardCount()]
77-
elif value == 0:
78-
self.count = []
137+
if value == 0:
138+
self._counts = []
79139
else:
80-
self.count = [value]
140+
self._counts = [int(value)]
81141

82-
def addCardCount(self, value):
83-
self.count.extend(value)
142+
def mergeCardCount(self, value: list):
143+
if self._counts is None:
144+
self._counts = value
145+
else:
146+
self._counts.extend(value)
84147

85148
def getStackHeight(self, thickness):
86-
# return height of the stacked cards in cm. Using hight in cm of a stack of 60 Copper cards as thickness.
149+
# return height of the stacked cards in cm. Using height in cm of a stack of 60 Copper cards as thickness.
87150
return self.getCardCount() * cm * (thickness / 60.0) + 2
88151

89-
def getType(self):
152+
def getType(self) -> CardType:
90153
return Card.types[tuple(self.types)]
91154

92155
def getBonusBoldText(self, text):
@@ -169,35 +232,28 @@ def get_GroupGlobalType(self):
169232
def get_GroupCost(self):
170233
return self.getType().getGroupCost()
171234

172-
def get_total_cost(self, c):
173-
# Return a tuple that represents the total cost of card c
174-
# Hightest cost cards are in order:
175-
# - Types with group cost of "" sort at the very end
176-
# - cards with * since that can mean anything
177-
# - cards with numeric errors
178-
# convert cost (a string) into a number
179-
if c.get_GroupCost() == "":
235+
def cost_sort_key(self):
236+
"""Return a tuple that represents the total cost of this card in (coins, potions, debt)
237+
used for sorting cards by cost.
238+
Highest cost cards are in order:
239+
- Types with group cost of "" sort at the very end
240+
- cards with * since that can mean anything
241+
- cards with numeric errors
242+
convert cost (a string) into a number
243+
"""
244+
if self.get_GroupCost() == "":
180245
c_cost = 999
181-
elif not c.cost:
246+
elif not self.cost:
182247
c_cost = 0 # if no cost, treat as 0
183-
elif "*" in c.cost:
248+
elif "*" in self.cost:
184249
c_cost = 998 # make it a really big number
185250
else:
186251
try:
187-
c_cost = int(c.cost)
252+
c_cost = int(self.cost)
188253
except ValueError:
189254
c_cost = 997 # can't, so make it a really big number
190255

191-
return c_cost, c.potcost, c.debtcost
192-
193-
def set_lowest_cost(self, other):
194-
# set self cost fields to the lower of the two's total cost
195-
self_cost = self.get_total_cost(self)
196-
other_cost = self.get_total_cost(other)
197-
if other_cost < self_cost:
198-
self.cost = other.cost
199-
self.potcost = other.potcost
200-
self.debtcost = other.debtcost
256+
return c_cost, self.potcost, self.debtcost
201257

202258
def setImage(self, use_set_icon=False):
203259
setImage = None
@@ -235,50 +291,3 @@ def __init__(self, num):
235291

236292
def isBlank(self):
237293
return True
238-
239-
240-
class CardType(object):
241-
@staticmethod
242-
def decode_json(obj):
243-
return CardType(**obj)
244-
245-
def __init__(
246-
self,
247-
card_type,
248-
card_type_image,
249-
group_global_type=None,
250-
group_cost=None,
251-
defaultCardCount=10,
252-
tabTextHeightOffset=0,
253-
tabCostHeightOffset=-1,
254-
):
255-
self.typeNames = tuple(card_type)
256-
self.tabImageFile = card_type_image
257-
self.group_global_type = group_global_type
258-
self.group_cost = group_cost
259-
self.defaultCardCount = defaultCardCount
260-
self.tabTextHeightOffset = tabTextHeightOffset
261-
self.tabCostHeightOffset = tabCostHeightOffset
262-
263-
def getTypeDefaultCardCount(self):
264-
return self.defaultCardCount
265-
266-
def getTypeNames(self):
267-
return self.typeNames
268-
269-
def getTabImageFile(self):
270-
if not self.tabImageFile:
271-
return None
272-
return self.tabImageFile
273-
274-
def getGroupGlobalType(self):
275-
return self.group_global_type
276-
277-
def getGroupCost(self):
278-
return self.group_cost
279-
280-
def getTabTextHeightOffset(self):
281-
return self.tabTextHeightOffset
282-
283-
def getTabCostHeightOffset(self):
284-
return self.tabCostHeightOffset

src/domdiv/db.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ def read_card_data(options) -> list[Card]:
250250

251251
# Add correct card counts to Start Deck prototype. This will be used to make copies.
252252
cards[StartDeck_index].setCardCount(STARTDECK_COPPERS)
253-
cards[StartDeck_index].addCardCount([int(STARTDECK_ESTATES)])
253+
cards[StartDeck_index].mergeCardCount([int(STARTDECK_ESTATES)])
254254

255255
# Make new Start Deck Dividers and adjust the corresponding card counts
256256
for x in range(0, STARTDECK_NUMBER):

src/domdiv/draw.py

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1245,16 +1245,26 @@ def add_inline_text(self, card, text, emWidth):
12451245

12461246
return text.strip().strip("\n")
12471247

1248-
def drawCardCount(self, card, x, y, offset=-1):
1249-
# Note that this is right justified.
1250-
# x represents the right most for the image (image grows to the left)
1251-
if card.getCardCount() < 1:
1248+
def drawCardCount(self, card, x, y) -> int:
1249+
"""Draw the card counts for this card. (x, y) is the bottom right corner of the images,
1250+
which are right aligned.
1251+
1252+
Returns the width used in points.
1253+
"""
1254+
1255+
card_counts = card.getCardCounts()
1256+
if sum(card_counts) < 1:
12521257
return 0
12531258

1254-
# draw_list = [(card.getCardCount(), 1)]
1255-
draw_list = sorted([(i, card.count.count(i)) for i in set(card.count)])
1259+
# make a list of all the (num cards in pile, num piles with that size) pairs for each unique pile size
1260+
draw_list = sorted(
1261+
[
1262+
(pile_size, card_counts.count(pile_size))
1263+
for pile_size in set(card_counts)
1264+
]
1265+
)
12561266

1257-
cardIconHeight = y + offset
1267+
cardIconHeight = y
12581268
countHeight = cardIconHeight - 4
12591269
width = 0
12601270

src/domdiv/main.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ def by_cost_sort_key(self, card):
131131
return (
132132
card.cardset,
133133
int(card.isExpansion()),
134-
str(card.get_total_cost(card)),
134+
str(card.cost_sort_key()),
135135
self.get_card_name_sort_key(card.name),
136136
)
137137

@@ -247,7 +247,9 @@ def combine_cards(cards, old_card_type, new_card_tag, new_cardset_tag, new_type)
247247
filteredCards = []
248248
for c in cards:
249249
if c.isType(old_card_type):
250-
holder.addCardCount(c.count) # keep track of count and skip card
250+
holder.mergeCardCount(
251+
c.getCardCounts()
252+
) # keep track of count and skip card
251253
else:
252254
filteredCards.append(c) # Not the right type, keep card
253255

@@ -354,8 +356,8 @@ def filter_sort_cards(cards: list[Card], options) -> list[Card]:
354356
cards_in_group.setdefault(
355357
(card.group_tag, card.cardset_tag), []
356358
).append(card)
357-
group_holders[(card.group_tag, card.cardset_tag)].addCardCount(
358-
card.count
359+
group_holders[(card.group_tag, card.cardset_tag)].mergeCardCount(
360+
card.getCardCounts()
359361
)
360362
if card.group_top:
361363
# this is a designated card to represent the group, so update important data

tests/selection_tests.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ def test_group_special():
1313
]
1414
assert len(empires_event_cards) == 1
1515
empires_events = empires_event_cards[0]
16-
assert empires_events.count == [1] * 13
16+
assert empires_events.getCardCounts() == [1] * 13
1717
assert empires_events.name == "Events: Empires"
1818
assert empires_events.types == ["Event"]
1919

@@ -23,7 +23,7 @@ def test_group_special():
2323
gladiator_fortune = gladiator_matches[0]
2424
gladiator_fortune.name.startswith("Gladiator")
2525
assert "Fortune" in gladiator_fortune.name
26-
assert gladiator_fortune.count == [5, 5]
26+
assert gladiator_fortune.getCardCounts() == [5, 5]
2727
assert gladiator_fortune.types == ["Action"]
2828
assert gladiator_fortune.cost == "3"
2929

@@ -32,8 +32,9 @@ def test_group_special():
3232
joust_rewards = joust_matches[0]
3333
assert joust_rewards.name.startswith("Joust")
3434
assert "Rewards" in joust_rewards.name
35-
joust_rewards.count.sort()
36-
assert joust_rewards.count == 6 * [2] + [10]
35+
counts = joust_rewards.getCardCounts()
36+
counts.sort()
37+
assert counts == 6 * [2] + [10]
3738
assert joust_rewards.types == ["Action"]
3839

3940
allies_ally_cards = [
@@ -42,4 +43,4 @@ def test_group_special():
4243
assert len(allies_ally_cards) == 1
4344
allies_allies = allies_ally_cards[0]
4445
assert allies_allies.name == "Allies: Allies"
45-
assert allies_allies.count == [1] * 23
46+
assert allies_allies.getCardCounts() == [1] * 23

0 commit comments

Comments
 (0)