# Blackjack OOP logic in Python

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:
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')

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')


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 ;)

• Thanks.. I have progressed somewhat and no doubt be back with more questions soon:) – johnashu Feb 18 '18 at 4:42