3
\$\begingroup\$

I've decided to learn python as my main language and after watching some tutorial on youtube I decided to write this blackjack game using OOP. Im sure it has a lot of beginner mistakes and might be simply bad. I also don't guarantee that it will always work but i would appreciate any feedback you could give me that could help me write better and cleaner code in the future.

Thanks in advance.

from random import randint
from os import system
class Deck:
 def __init__(self):
 self.deck = [("Ace of Clubs", 1), ("Ace of Diamonds", 1),
 ("Ace of Hearts", 1), ("Ace of Spades", 1),
 ("2 of Clubs", 2), ("2 of Diamonds", 2),
 ("2 of Hearts", 2), ("2 of Spades", 2),
 ("3 of Clubs", 3), ("3 of Diamonds", 3),
 ("3 of Hearts", 3), ("3 of Spades", 3),
 ("4 of Clubs", 4), ("4 of Diamondss", 4),
 ("4 of Hearts", 4), ("4 of Spades", 4),
 ("5 of Clubs", 5), ("5 of Diamonds", 5),
 ("5 of Hearts", 5), ("5 of Spades", 5),
 ("6 of Clubs", 6), ("6 of Diamonds", 6),
 ("6 of Hearts", 6), ("6 of Spades", 6),
 ("7 of Clubs", 7), ("7 of Diamonds", 7),
 ("7 of Hearts", 7), ("7 of Spades", 7),
 ("8 of Clubs", 8), ("8 of Diamonds", 8),
 ("8 of Hearts", 8), ("8 of Spades", 8),
 ("9 of Clubs", 9), ("9 of Diamonds", 9),
 ("9 of Hearts", 9), ("9 of Spades", 9),
 ("10 of Clubs", 10), ("10 of Diamonds", 10),
 ("10 of Hearts", 10), ("10 of Spades", 10),
 ("Jack of Clubs", 10), ("Jack of Diamonds", 10),
 ("Jack of Hearts", 10), ("Jack of Spades", 10),
 ("Queen of Clubs", 10), ("Queen of Diamonds", 10),
 ("Queen of Hearts", 10), ("Queen of Spades", 10),
 ("King of Clubs", 10), ("King of Diamonds", 10),
 ("King of Hearts", 10), ("King of Spades", 10)]
 def get_deck(self):
 return self.deck
 def remove_from_deck(self, index):
 self.deck.pop(index)
 def __len__(self):
 return len(self.deck)
class Tokens:
 def __init__(self, amount):
 self.amount = amount
 def __str__(self):
 return str(self.amount)
 def bet_tokens(self, amount):
 if self.amount - amount >= 0:
 self.amount -= amount
 return True
 print(f"Not enough tokens!")
 return False
 def add_tokens(self, amount_won):
 self.amount += amount_won
 def get_tokens(self):
 return self.amount
class Blackjack:
 def __init__(self,):
 self.tokens = Tokens(100)
 self.second_card_hidden = True
 def deal_a_card(self, hand, deck):
 x = randint(0, len(self.deck) - 1)
 hand.append(deck.get_deck()[x])
 deck.remove_from_deck(x)
 def open(self, bet_amount):
 if self.tokens.bet_tokens(bet_amount):
 self.deal_a_card(self.user_hand, self.deck)
 self.deal_a_card(self.user_hand, self.deck)
 self.deal_a_card(self.dealer_hand, self.deck)
 self.deal_a_card(self.dealer_hand, self.deck)
 return True
 return False
 def get_sum_of_cards(self, hand):
 sum_of_cards = 0
 for card in hand:
 sum_of_cards += card[1]
 for card in hand:
 if card[0] in ["Ace of Spades", "Ace of Hearts", "Ace of Diamonds", "Ace of Clubs"]:
 if sum_of_cards <= 11:
 sum_of_cards += 10
 return sum_of_cards
 def check_for_bust(self, hand):
 return self.get_sum_of_cards(hand) > 21
 def get_cards(self, hand):
 cards = ""
 for card in hand:
 cards += card[0] + ", "
 return cards[:-2]
 def reset_hands_and_deck(self):
 self.deck = Deck()
 self.user_hand = []
 self.dealer_hand = []
 self.second_card_hidden = True
 def clear_screen_print_cards(self):
 system("cls")
 print(self)
 def check_for_win(self):
 user_score = self.get_sum_of_cards(self.user_hand)
 dealer_score = self.get_sum_of_cards(self.dealer_hand)
 if user_score == dealer_score:
 print("Tie!")
 return "tie"
 elif user_score > dealer_score:
 print("You win!")
 return "win"
 elif dealer_score > user_score:
 print("You lose!")
 return "lose"
 def check_for_blackjack(self):
 user_score = self.get_sum_of_cards(self.user_hand)
 dealer_score = self.get_sum_of_cards(self.dealer_hand)
 if user_score == dealer_score == 21:
 print("You both hit a blackjack!")
 return "tie"
 elif user_score == 21:
 print(f"You hit a blackjack!")
 return "blackjack_user"
 elif dealer_score == 21:
 system("cls")
 self.second_card_hidden = False
 print(game)
 print("Dealer hit a blackjack!")
 return "blackjack_dealer"
 return 0
 def hit_or_stand(self):
 decision = input("(hit/stand h/s): ")
 while decision.lower() not in ["hit", "h", "stand", "s"]:
 decision = input("(hit/stand h/s): ")
 if decision in ["hit", "h"]:
 return 1
 return 0
 def token_distributor(self, result, bet_amount):
 if result == "blackjack_user":
 self.tokens.amount += bet_amount + 1.5 * bet_amount
 elif result == "tie":
 self.tokens.amount += bet_amount
 elif result == "win":
 self.tokens.amount += (2 * bet_amount)
 def __str__(self):
 if self.second_card_hidden:
 return f"\tDealer hand({self.dealer_hand[1][1]})\n[{self.dealer_hand[1][0]}, <card hidden>]\n\n[{self.get_cards(self.user_hand)}]\n\tPlayer hand({self.get_sum_of_cards(self.user_hand)})\n"
 else:
 return f"\tDealer hand({self.get_sum_of_cards(self.dealer_hand)})\n[{self.get_cards(self.dealer_hand)}]\n\n[{self.get_cards(self.user_hand)}]\n\tPlayer hand({self.get_sum_of_cards(self.user_hand)})\n"
def play_blackjack(game):
 game.reset_hands_and_deck()
 system("cls")
 print(f"Welcome to Blackjack!, Your tokens: {game.tokens.get_tokens()}")
 bet_amount = input(
 f"How much do u want to bet? max({game.tokens.get_tokens()}): ")
 while (not bet_amount.isdigit()) or (int(bet_amount) not in range(1, game.tokens.get_tokens() + 1)):
 system("cls")
 bet_amount = input(
 f"How much do u want to bet? max({game.tokens.get_tokens()}): ")
 bet_amount = int(bet_amount)
 system("cls")
 if game.open(bet_amount):
 print(game)
 check = game.check_for_blackjack()
 if check:
 game.token_distributor(check, bet_amount)
 return 1
 elif not check:
 while game.hit_or_stand():
 game.deal_a_card(game.user_hand, game.deck)
 if game.get_sum_of_cards(game.user_hand) == 21:
 game.token_distributor("win", bet_amount)
 if game.check_for_bust(game.user_hand):
 game.clear_screen_print_cards()
 print("Bust!")
 return 1
 game.clear_screen_print_cards()
 game.second_card_hidden = False
 while game.get_sum_of_cards(game.dealer_hand) < 17:
 game.deal_a_card(game.dealer_hand, game.deck)
 if game.check_for_bust(game.dealer_hand):
 game.clear_screen_print_cards()
 print("Dealer bust!")
 game.tokens.amount += bet_amount * 2
 return 1
 game.clear_screen_print_cards()
 check = game.check_for_win()
 if check:
 game.token_distributor(check, bet_amount)
 return 1
game = Blackjack()
play_again = True
while play_again:
 play_blackjack(game)
 play_again = True if input(
 f"You have {game.tokens.get_tokens()} tokens left\nPlay again? (y/n): ").lower() == "y" else False
system("cls")
print(f"Game over!, your ended up with {game.tokens.get_tokens()} tokens")
Ben A
10.7k5 gold badges37 silver badges101 bronze badges
asked Jul 14, 2020 at 19:32
\$\endgroup\$
1
  • 1
    \$\begingroup\$ What quickly jumps into my mind is that the play_blackjack method is very long and complex. Try breaking that down into other functions. Also change the sequence of functions so that it reads from top to bottom. eg. play_game (which seems to be the game loop) first and it then jumps down to each function in the sequence they are getting called. Otherwise it's pretty easy to read. Great Job on that. \$\endgroup\$ Commented Jul 17, 2020 at 11:50

1 Answer 1

1
\$\begingroup\$

Blackjack.hit_or_stand

This function can be shortened to the following

def hit_or_stand(self):
 while decision := input("(hit/stand h/s): ").lower()[0]:
 if decision in 'hs':
 return decision == 'h'

using python 3.8's new assignment expressions, and instead of returning true or false, returning the comparison. This evaluates to a boolean, so it does the same thing but looks a lot nicer.

Blackjack.get_sum_of_cards

This function can be shortened to the following

def get_sum_of_cards(self, hand):
 sum_of_cards = sum(card[1] for card in hand)
 aces = ["Ace of Spades", "Ace of Hearts", "Ace of Diamonds", "Ace of Clubs"]
 extra_sum = sum(10 for card in hand if card[0] in aces and sum_of_cards <= 11)
 
 return sum_of_cards + extra_sum

using pythons built in sum function. Also, putting all the aces into their own list makes it a bit clearer.

Blackjack.get_cards

This function can be shortened to the following

def get_cards(self, hand):
 return ', '.join(card[0] for card in hand)

using pythons string function join. This also removes the need to remove the last two characters.

Portability

Currently, clearing the screen only works on Windows, as cls is an invalid command on macOS/unix. Something like this will work fine:

import os
def clear_screen_print_cards(self):
 os.system('cls' if os.name == 'nt' else 'clear')
 print(self)
answered Jul 14, 2020 at 21:31
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.