-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathidiots_delight.py
112 lines (94 loc) · 3.6 KB
/
idiots_delight.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
from collections import defaultdict
import operator
class Idiots_Delight(object):
def __init__(self, deck=None, print_steps=False):
self.piles = defaultdict(list)
self.deck = deck
if self.deck.__class__.__name__ != 'Deck':
print 'The deck should be of type "Deck"'
self.num_piles = deck.num_suits
self.print_steps = print_steps
def play_game(self):
while len(self.deck.card_pool) > 0:
self.add_layer()
if self.print_steps:
print 'New layer:'
print self.piles
print ''
self.eliminate()
num_cards_remaining = 0
for pile, cards in self.piles.iteritems():
num_cards_remaining += len(cards)
return num_cards_remaining
def add_layer(self):
for pile_num in range(self.num_piles):
self.piles[pile_num].append(self.deck.card_pool.pop())
def eliminate(self):
something_changed = False
cards_showing = self.get_cards_showing()
# Find high card for each suit
high_card_per_suit = dict(zip(self.deck.suit_labels,
[None] * self.num_piles))
for pile, card in cards_showing.iteritems():
if len(card) > 0:
if card[1] > high_card_per_suit[card[0]]:
high_card_per_suit[card[0]] = card[1]
# Remove cards
for pile, card in cards_showing.iteritems():
if len(card) > 0:
if card[1] < high_card_per_suit[card[0]]:
something_changed = True
self.piles[pile].pop()
if something_changed:
if self.print_steps:
print 'Cards removed:'
print self.piles
print ''
self.eliminate()
else:
reorg = self.is_reorganizable()
if reorg:
self.reorganize()
self.eliminate()
def get_cards_showing(self):
cards_showing = dict()
for pile_num in range(self.num_piles):
pile_size = len(self.piles[pile_num])
if pile_size == 0:
cards_showing[pile_num] = []
if pile_size > 0:
cards_showing[pile_num] = self.piles[pile_num][pile_size - 1]
return cards_showing
def is_reorganizable(self):
has_zero = False
has_many = False
for pile, cards in self.piles.iteritems():
if len(cards) == 0:
has_zero = True
if len(cards) > 1:
has_many = True
if has_zero and has_many:
return True
else:
return False
def reorganize(self):
# move pile that has more than one card with largest sum
# to pile with zero
pile_sums = defaultdict(int)
for pile, cards in self.piles.iteritems():
if len(cards) > 1:
for card_num in range(len(cards)):
pile_sums[pile] += cards[card_num][1]
if ((card_num == len(cards) - 1) and
(cards[card_num][1] == max(self.deck.card_values))):
pile_sums[pile] += float('inf')
if len(cards) == 0:
pile_to_receive = pile
pile_to_move = max(pile_sums.iteritems(),
key=operator.itemgetter(1))[0]
card_to_move = self.piles[pile_to_move].pop()
self.piles[pile_to_receive].append(card_to_move)
if self.print_steps:
print 'Reorganized:'
print self.piles
print ''