-
Notifications
You must be signed in to change notification settings - Fork 0
/
run.py
321 lines (296 loc) · 10.3 KB
/
run.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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
from pyfiglet import Figlet
import random
import time
# How many options each face card will give the next player
FACE_CARD_VALUES = {
'J': 2,
'Q': 3,
'K': 4
}
# Suit representations to their symbols
SUIT_SYMBOLS = {
'D': '♦',
'C': '♣',
'H': '♥',
'S': '♠'
}
# Seconds for program to sleep when dealing and before a dramatic reveal in game
DEAL_SLEEP = .8
SUSPENSE_SLEEP = 1
# How ranks and suits are represented
RANKS = ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K']
SUITS = ['D', 'C', 'H', 'S']
# Ways people might enter rank and suit names
RANKS_ACCEPTED_INPUT = {
'ACE': 'A',
'TWO': '2',
'THREE': '3',
'FOUR': '4',
'FIVE': '5',
'SIX': '6',
'SEVEN': '7',
'EIGHT': '8',
'NINE': '9',
'TEN': '10',
'JACK': 'J',
'QUEEN': 'Q',
'KING': 'K',
}
SUITS_ACCEPTED_INPUT = {
'DIAMONDS': 'D',
'DIAMOND': 'D',
'DI': 'D',
'D': 'D',
'CLUBS': 'C',
'CLUB': 'C',
'CL': 'C',
'C': 'C',
'HEARTS': 'H',
'HEART': 'H',
'HE': 'H',
'H': 'H',
'SPADES': 'S',
'SPADE': 'S',
'SP': 'S',
'S': 'S'
}
def print_big(phrase, font_type='standard'):
f = Figlet(font=font_type)
print(f.renderText(phrase))
def welcome():
clear_window()
welcome_phrase = 'WELCOME TO HYDR-ACE-TION!!'
print_big(welcome_phrase)
time.sleep(DEAL_SLEEP)
print('Please refer to the README to learn the rules if you haven\'t played before!\n')
time.sleep(DEAL_SLEEP)
def parse_card_input(inp):
inp = inp.strip().upper()
cleaned_suit = ''
rank = None
suit = None
ranks_accepted_input_list = list(RANKS_ACCEPTED_INPUT.keys())
for r in (ranks_accepted_input_list + RANKS):
# Look for rank in user input
if inp.find(r) == 0:
if r in ranks_accepted_input_list:
rank = RANKS_ACCEPTED_INPUT[r]
else:
rank = r
words = inp.split()
# Look for suit in user input
if len(words) == 1:
# Input contains just one word, just check back of word for a suit
cleaned_suit = inp[len(r):]
else:
# With multiple words, just check the last word for suit
cleaned_suit = words[-1]
if cleaned_suit in SUITS_ACCEPTED_INPUT:
suit = SUITS_ACCEPTED_INPUT[cleaned_suit]
return rank, suit
def get_card_input():
rank = None
suit = None
while True:
inp = input()
rank, suit = parse_card_input(inp)
if suit is not None and rank is not None:
break
else:
print('Please enter a card in the format specified in the README!')
return (rank, suit)
def get_players():
num_players = 2
while True:
try:
# User must specify an integer
num_players = int(input('How many players?\n'))
if num_players >= 2 and num_players <= 8:
break
else:
print('There needs to be between 2 and 8 players.')
except:
print('Enter an integer between 2 and 8.')
players = []
# Get player names
for i in range(num_players):
while True:
player = input('What is player {}\'s name?\n'.format(i + 1))
if player in players:
print('Choose a different name from other players!')
elif len(player) < 1:
print('Player\'s name must be at least one character long!')
else:
break
players.append(player)
return players
def create_full_deck():
deck = []
for rank in RANKS:
for suit in SUITS:
deck.append((rank, suit))
return deck
# Returns the random card dealt and the remaining deck
def deal_random_card(avail_cards):
if len(avail_cards) < 1:
return (), avail_cards
rand = random.randint(0, len(avail_cards) - 1)
rand_card = avail_cards[rand]
del avail_cards[rand]
return rand_card, avail_cards
def show_cards(cards):
space = ' '
num_per_row = 4
top, rank_top, padding_top, suit, padding_bottom, rank_bottom, bottom = [''], [''], [''], [''], [''], [''], ['']
for i in range(len(cards)):
# Fill in cards in a row
top[-1] += '┌───────┐' + space
rank_top[-1] += '| {:<2} |'.format(cards[i][0]) + space
padding_top[-1] += '| |' + space
suit[-1] += '| {} |'.format(SUIT_SYMBOLS[cards[i][1]]) + space
padding_bottom[-1] += '| |' + space
rank_bottom[-1] += '| {:>2} |'.format(cards[i][0]) + space
bottom[-1] += '└───────┘' + space
if (i+1) % num_per_row == 0 and i != len(cards) - 1:
# Make a new row of cards
top.append('')
rank_top.append('')
padding_top.append('')
suit.append('')
padding_bottom.append('')
rank_bottom.append('')
bottom.append('')
if len(cards) > 0:
# Print all rows
for i in range(len(top)):
print(top[i])
print(rank_top[i])
print(padding_top[i])
print(suit[i])
print(padding_bottom[i])
print(rank_bottom[i])
print(bottom[i])
def get_face_card_choice(avail_cards, face_card_rank, player, players):
num = FACE_CARD_VALUES[face_card_rank]
prev_player = players[players.index(player) - 1]
choices = []
for i in range(num):
# Gather options
rand_card, avail_cards = deal_random_card(avail_cards)
choices.append(rand_card)
print('Thanks to {} for getting a face card [{}] last turn! {}, pick one card from the following:'.format(prev_player, face_card_rank, player))
time.sleep(DEAL_SLEEP)
show_cards(choices)
print('Enter your choice:')
while True:
card_choice = get_card_input()
if card_choice in choices:
# Append unchosen cards back to avail_cards
for c in choices:
if c != card_choice:
avail_cards.append(c)
return card_choice
print('That\'s not listed above! Try again.')
def sort_by_rank(hand):
def sort_by_rank_helper(card):
rank = card[0]
return RANKS.index(rank)
hand.sort(key=sort_by_rank_helper)
def get_drinker(player, players):
drinker = 0
while True:
drinker = input('Who would you like to hydrate?\n')
if drinker in players:
return drinker
print('Please enter a player\'s name with correct spelling and caps! Other players\' names are:', )
for p in players:
if player != p:
print(p)
def handle_hydrate(player, hand, players):
last_card = hand[-1]
# Check if ace
if last_card[0] == 'A':
print_hydrate_message(player, players, 'GOT AN ACE!', 'TAKE ONE DRINK!', [])
# Check if the last card creates a new pair, which means 1 drink for 1 pair or
# two drinks if 2 pairs
last_card_rank = last_card[0]
same_rank = 0
same_rank_cards = []
for card in hand:
if card[0] == last_card_rank:
same_rank_cards.append(card)
same_rank += 1
if same_rank == 2:
#TODO: show the double or quad
print_hydrate_message(player, players, 'GOT A DOUBLE!', 'TAKE ONE DRINK!', same_rank_cards)
if same_rank == 4:
print_hydrate_message(player, players, 'GOT A QUAD!', 'TAKE TWO DRINKS!', same_rank_cards)
show_cards(same_rank_cards)
def print_hydrate_message(player, players, alert_msg, drink_msg, same_rank_cards):
time.sleep(SUSPENSE_SLEEP)
print_big('{} {}'.format(player, alert_msg), font_type='slant')
show_cards(same_rank_cards)
drinker = get_drinker(player, players)
print_big('{} - {}'.format(drinker, drink_msg))
def clear_window():
# print ANSI sequence to clear screen
print('\033[H\033[J')
def end():
time.sleep(SUSPENSE_SLEEP)
clear_window()
print_big('NO MORE CARDS - THANKS FOR PLAYING!')
input('Press Enter to terminate.')
def play_game():
welcome()
players = get_players()
num_players = len(players)
curr_deck = create_full_deck()
iter = 0
present_options = False
face_card_rank = 1
hands = {}
input('Press Enter to start the game!')
while len(curr_deck) > 1:
clear_window()
curr_player = players[iter % num_players]
# This is curr_player's turn!
print_big('{}\'s turn!'.format(curr_player))
if curr_player in hands:
print('{}, your current hand looks like:'.format(curr_player))
show_cards(hands[curr_player])
else:
print('{}, your current hand is empty.'.format(curr_player))
time.sleep(DEAL_SLEEP)
card_taken = ()
if present_options and len(curr_deck) < FACE_CARD_VALUES[face_card_rank]:
# Out of cards because last player drew face card
break
elif not present_options:
# Last player did not draw face card, give one card as normal
rand_card, deck = deal_random_card(curr_deck)
card_taken = rand_card
print('This card was drawn and added to your hand:'.format(curr_player))
elif present_options:
# Last player drew a face card, so current player gets options
card_taken = get_face_card_choice(curr_deck, face_card_rank, curr_player, players)
print('Your chosen card below has been added to your hand.'.format(curr_player))
show_cards([card_taken])
if curr_player in hands:
hands[curr_player].append(card_taken)
else:
hands[curr_player] = [card_taken]
handle_hydrate(curr_player, hands[curr_player], players)
sort_by_rank(hands[curr_player])
if card_taken[0] in FACE_CARD_VALUES:
print('Yep, that\'s a face card! Next player will get {} choices.'.format(FACE_CARD_VALUES[card_taken[0]]))
present_options = True # Indicate that the next player should get options
face_card_rank = card_taken[0] # Indicates what options next player should get
else:
present_options = False
face_card_rank = 1
iter += 1
time.sleep(DEAL_SLEEP)
input('Press Enter to continue!')
end()
if __name__ == '__main__':
play_game()