I am attempting to write a game of blackjack using classes in Python. Any advice on keeping it DRY?
I seem to be creating too many lists in lists. Should I name the keys in the dictionary or just use integers? How can I get the deck, shuffle and deal logic into a class that will link with the Player class?
import random
import itertools as it
number_players = 2 #input('Enter Number of Players here: ')
number_cards = 2 #input('Enter Number of Cards here: ')
# create the deck of cards
deck = list(it.product("♠♣♥♦", [str(x) for x in range(2, 11)] + list("JQKA")))
times_to_shuffle_deck = 5
for x in range(times_to_shuffle_deck):
random.shuffle(deck)
# print(len(deck))
# print(deck)
# init the memo
memo = set()
def set_shuffle(n):
for i in range(n):
k = random.choice(deck)
if k not in memo:
memo.add(k)
else:
set_shuffle(1)
return memo #sorted(memo)
i = set_shuffle(52)
def deal(deck, number_players, number_cards):
"""
Deals n amount of cards to n amount of players.
"""
player_dict = {'Player' + str(k + 1): [i.pop() for x in range(number_cards)] for k in range(number_players)}
dealer_hand = [i.pop() for x in range(number_cards)]
player_dict['Dealer'] = dealer_hand
return player_dict
players = deal(deck, number_players, number_cards)
def print_current_cards(player_dict):
""" pretty prints the current hands """
for k, v in player_dict.items():
print('{} hand:'.format(k))
for u in v:
print(u[1], u[0])
print('\n')
print_current_cards(players)
class Player:
"""Takes in a players cards for processing"""
def __init__(self, cards, player):
self.cards = cards
self.player = player
def pic_to_int(self, card):
"""takes in a card and converts it to an integer of 10 for JQK or 10 and 11 for A """
card_list = ['J', 'Q', 'K', '10']
if card in card_list:
return 10
elif card == 'A':
return 11
if card not in card_list and card != 'A':
return int(card)
def current_score(self):
""" Evaluates the current list of cards and returns a total integer value"""
total = 0
if self.is_blackjack() == True:
return
else:
for c in self.cards:
for c1 in c:
for c2 in c1[1:]:
if c2.isdigit():
total += int(c2)
elif 'A' == c2:
total += 11
else:
total += 10
print('Current card total: ', total, '\n')
return total
def is_blackjack(self):
""" Takes in 2 cards and returns True if the cards contain only 1x Ace and either 10, J, Q or K
"""
if len(self.cards[0]) == 2:
c1 = self.pic_to_int(self.cards[0][0][1])
c2 = self.pic_to_int(self.cards[0][1][1])
total = c1 + c2 if c1 or c2 else 0
if total == 21:
print('BLACKJACK!!!!')
return
else:
return False
else:
return False
def check_if_bust(self):
score = self.current_score()
bust = False
if score > 21:
bust = True
print("Bust!")
return bust
return bust
def stick_or_twist(self, twist=False):
""" Takes in current hand and processes a new card
returns ok or bust
"""
score = self.current_score()
cards = self.cards
if self.player == 'Dealer':
if score < 17:
cards[0].append(i.pop())
self.check_if_bust()
else:
print('Dealer must stand on 17')
elif self.player != 'Dealer':
cards[0].append(i.pop())
self.check_if_bust()
def split_pair(self):
""" splits a pair of the same cards into 2 games """
pass
player1 = Player([v for k, v in players.items() if 'Player1' == k], 'Player1')
player2 = Player([v for k, v in players.items() if 'Player2' == k], 'Player2')
dealer = Player([v for k, v in players.items() if 'Dealer' == k], 'Dealer')
player_list = [player1, player2, dealer]
for p in player_list:
print(p.player, ':')
p.is_blackjack()
p.current_score()
p.check_if_bust()
p.stick_or_twist(twist=True)
print(len(i), 'cards left')
print_current_cards(players)
# for x in range(3):
# j = i.pop()
# print(j)
# print(len(i), 'cards left')
1 Answer 1
In response to your question, a Deck
class may look like this
class Deck():
def __init__(self, times_to_shuffle_deck = 5):
# create the deck of cards
...
self.times_to_shuffle_deck = times_to_shuffle_deck
def shuffle(self):
# Here you can place code to shuffle
def set_shuffle(self, n):
# Here you can place function to set shuffle
def deal(self, player, number_cards):
# Here you could set a method to deal cards to a player
# Probably less complex and easier to follow
Some minor recomendations:
-The class Player is doing a lot of work, you may consider extracting some methods outside, likepic_to_int
or is_blackjack
may go outside (not necessary in a class)
-The deal method I'd do shorter, since in that method you are creating something bigger than just dealing cards
When you pick this project in 3 months, and you want to create a player, you have to ask yourself which of this options is easier to remember:
player1 = Player([v for k, v in players.items() if 'Player1' == k], 'Player1') player1 = Player('Player1')
So may be better to put fireworks with dict comprehensions inside the constructor
Regarding lists on lists and efficiency
In a blackjack game, roughly, you want to store
A list of all possible cards
A list of cards per player
A list of available cards (possible cards - player cards)
Then you can perform checks any way you want to discern player's points
You may want to try to design your app to have:
- 1 possible_cards list + 1 available_cards list + n player_cards lists
If you think you're creating way too many lists, compare it with the minimum required and check where are you doing extra work
That was long.. Hope you spend some more time working on it
Don't hesitate to come back with more questions ;)
-
\$\begingroup\$ Thanks.. I have progressed somewhat and no doubt be back with more questions soon:) \$\endgroup\$johnashu– johnashu2018年02月18日 04:42:34 +00:00Commented Feb 18, 2018 at 4:42
Explore related questions
See similar questions with these tags.