# Simple BlackJack Card Game - First OOP Code

Blackjack card game with hit and stand.

Wasn't allowed to use functions outside of classes in code.

Had some difficulty with __str__ dunder method on Dealer and Player classes (got weird solutions for the time-being)

Would appreciate any feedback on how to improve readability and make code more efficient.

## Code

#Blackjack

#imports
import random
import time
from IPython.display import clear_output

#dictionaries
ranks = ['Ace', 'Two', 'Three', 'Four', 'Five', 'Six', 'Seven', 'Eight', 'Nine', 'Ten', 'Jack', 'Queen', 'King']
suits = ['Diamonds', 'Spades', 'Clubs', 'Hearts']
values = {'Ace':1, 'Two':2, 'Three':3, 'Four':4, 'Five':5, 'Six':6, 'Seven':7, 'Eight':8, 'Nine':9, 'Ten':10, 'Jack':10, 'Queen':10, 'King':10}

#card class
class Card():
def __init__(self, rank, suit):
self.rank = rank
self.suit = suit
self.value = values[rank]

def __str__(self):
return f'{self.rank} of {self.suit}'

#deck class
class Deck():
def __init__(self):
self.deck_cards = []

for rank in ranks:
for suit in suits:
self.deck_cards.append(Card(rank,suit))

def shuffle(self):
random.shuffle(self.deck_cards)

def dealCards(self):
return self.deck_cards.pop(0)

def __str__(self):
for item in self.deck_cards:
print(item)
return 'Joker'

#hand class
class Player():
def __init__(self):
self.hand = []

self.hand.append(card)

def handSum(self):
card_sum = 0
for card in self.hand:
card_sum += card.value
return card_sum

def __str__(self):
print('------------\nPlayer Cards\n------------')
for item in self.hand:
print(item)
print(f"{player_name}'s card sum: {player1.handSum()}")
return('')

#chip class
class Chips():

def __init__(self, player_name):
self.player_name = player_name
self.chip_count = 3

def betChip(self,num):
self.chip_count -= num
return num

self.chip_count += num

def subtractChip(self,num):
self.chip_count -= num

def __str__(self):
if self.chip_count == 1:
return f'{self.player_name} has {self.chip_count} chip!'
else:
return f'{self.player_name} has {self.chip_count} chips!'

#dealer class
class Dealer(Player):

def __str__(self):
print('------------\nDealer Cards\n------------')
for item in self.hand:
if item == self.hand[-1]:
pass
else:
print(item)
print('**********')
return str('')

#variable initialization
player_name = input('What is your name?: ')

running = False
game_on = True
gameDeck = Deck()
gameDeck.shuffle()
player1 = Player()
player1_chips = Chips(player_name)
dealer = Dealer()

#game loop
while game_on:

if player1_chips.chip_count == 0:
time.sleep(3)
clear_output()
print('You ran out of chips\nThanks for playing')
break
else:
pass

gameDeck = Deck()
gameDeck.shuffle()
player1 = Player()
dealer = Dealer()

clear_output()
running = True
clear_output()
print('Thanks for playing!')
break
else:
clear_output()
continue

while running:

#placing bets
bet = input(f'You have {player1_chips.chip_count} chips. How much would you like to bet? ')
clear_output()
if bet.isdigit() == True:
bet = int(bet)
if bet > player1_chips.chip_count:
time.sleep(1)
clear_output()
continue
else:
print(f'You have bet {bet} chips')
time.sleep(1)
clear_output()
else:
print('Your bet is not a number!')
time.sleep(1)
clear_output()
continue

#card initialization
print(f'Distributing card to {player_name}...')
time.sleep(.85)
clear_output()
print('Distributing card to Dealer...')
time.sleep(.85)
clear_output()
print(f'Distributing card to {player_name}...')
time.sleep(.85)
clear_output()
print('Distributing card to Dealer...')
time.sleep(.85)
clear_output()
print('Cards distributed')
clear_output()
print(player1)
print(dealer)

#check for 21:
if player1.handSum() == 21:
print(f'You win and get {bet * 1.5} chips')
time.sleep(2)
clear_output()
running = False
else:
pass

temp_var = True

#gameplay
while temp_var:
choice = input('Hit(H) or Stand(S)? ')
if choice == 'H' or choice == 'h':
clear_output()
print(f'Distributing card to {player_name}...')
time.sleep(1)
temp_var = False
elif choice == 'S' or choice == 's':
temp_var = False
clear_output()
else:
clear_output()
time.sleep(.5)
continue

#printing updated hands
print('Dealer will reveal their cards')
time.sleep(1.3)
clear_output()
print(player1)
print('')

print('------------\nDealer Cards\n------------')
[print(item) for item in dealer.hand[0::]]
print(f"Dealer's card sum: {dealer.handSum()}")
print(' \n \n ')
time.sleep(.9)

#no more user input/game continues
if player1.handSum() == 21:
if dealer.handSum() == 21:
print('You have tied with the dealer')
time.sleep(1)
print('You won no chips. Your total remains the same')
break
else:
print('You win!')
time.sleep(.9)
print(f'You have won {bet} chips. Bringing your total up to {player1_chips.chip_count} chips')
break
elif player1.handSum() > 21:
print('You have BUSTED\nYou Lose!')
time.sleep(1)
player1_chips.subtractChip(bet)
print(f'You lost {bet} chips. Bringing your total down to {player1_chips.chip_count} chips')
break
elif dealer.handSum() <= 16:
print('Dealer is adding a card to their hand as they have a 16 or less....')
time.sleep(3)
clear_output()
if dealer.handSum() > 21:

#printing hands
##################################################
print(player1)

print('------------\nDealer Cards\n------------')
[print(item) for item in dealer.hand[0::]]
print(f"Dealer's card sum: {dealer.handSum()}")
time.sleep(1)
##################################################

print('You win! Dealer Busts!')
time.sleep(.9)
print(f'You have won {bet} chips. Bringing your total up to {player1_chips.chip_count} chips')
break
elif dealer.handSum() > player1.handSum():

#printing hands
##################################################
print(player1)

print('------------\nDealer Cards\n------------')
[print(item) for item in dealer.hand[0::]]
print(f"Dealer's card sum: {dealer.handSum()}")
time.sleep(1)
##################################################

print('You Lose! Dealer got a higher sum of cards!')
time.sleep(.9)
player1_chips.subtractChip(bet)
print(f'You lost {bet} chips. Bringing your total down to {player1_chips.chip_count} chips')
break
else:
if dealer.handSum() > player1.handSum():
print('You Lose! Dealer got a higher sum of cards!')
time.sleep(1)
player1_chips.subtractChip(bet)
print(f'You lost {bet} chips. Bringing your total down to {player1_chips.chip_count} chips')
break
else:
print('You win! Dealer got a lesser sum of cards!')
time.sleep(1)
print(f'You have won {bet} chips. Bringing your total up to {player1_chips.chip_count} chips')
break

• Is this homework? (in other words, is it your prof that restricted your library use?) Oct 10, 2022 at 23:06
• No not homework. Im doing this for my self using udemy. The objective was understanding OOP better, as to why I was restricted in what I was allowed to use. Oct 11, 2022 at 4:41

# Don't print in __str__

Your Card class does things correctly:

>>> card = Card("Ace", "Spades")
>>> s = str(card)
>>> print(s)


Notice that str(card) doesn't print anything. It just silently returns the string for the card.

Where this is useful is the print() function. It automatically turns everything passed to it into a string. This means you don't have to str(card) yourself; it is automatic.

>>> print(card)
Ace of Spaces


In contrast, stringifying a dealer produces strange results. First of all, it has a side effect of printing. Second, it returns an empty string!

>>> dealer = Dealer()
>>> s = str(dealer)
------------
Dealer Cards
------------
**********

>>> print(repr(s))
''


This is not the correct behaviour. s = str(something) should never cause any side effects, including printing. It must simply return a string.

# Not referencing self

>>> player_name = "Anna"
>>> player1 = Player()
>>> player_name = "Bob"
>>> player2 = Player()
>>> player_name = "Chris"
>>> print(player1, player2)


What do you think the output is, and why?

After you've tried it out, can you explain why both players appear to have the same name, and the same score despite having a different card?

The section title gives it away, I suppose. You're using player1.handSum(), not self.handSum(). You should also be storing the player's name inside the Player object, and using self.player_name.

# Hidden Dealer's Card

        for item in self.hand:
if item == self.hand[-1]:
pass
else:
print(item)


Here, you loop through all the cards in the dealer's hand, compare them with the last card, and if different, they get printed out.

This is too much code, and may cause a subtle bug down the road.

First, the subtle bug: Imagine upgrading the program to use a shoe with 5 decks. Since the Seven of Diamonds will exist 5 times, the dealer's hand could be two Seven of Diamonds. The loop runs with the first card, and compares it with the last card. Are they the same card? Will it print the first card? Maybe not, depending on exactly how you've implemented things.

We can avoid the problem all together, by looping over all but the last card, eliminating the need to compare the current card with the last one:

        for item in self.hand[:-1]:
print(item)


The magic here is self.hand[:-1], which is a sliced copy of the self.hand, starting at the beginning and stopping just before the end. Since the sliced copy doesn't include last item, we don't have to test if we've reached it and handle it separately anymore.

# PEP 8

The Style Guide for Python Code has many recommendations that all Python programmers should follow. It includes things like naming conventions. addCard is a member function and should be written in snake_case, instead of as a bumpyWord.

There is much more to review feedback to give here, but I'm out of time for now.

• Appreciate the feedback, will take your advice into account moving forward Oct 11, 2022 at 19:48