Problem Statement

Modified Blackjack

  1. The game consists of a single player playing against the dealer, played by our program in this example.
  2. Each player is initially dealt two cards from a standard 52 card deck. Each card's value is its face value, with face cards having a value of 10, and aces are valued 11.
  3. The object of the game is to get a higher total value than the other player, without going over 21.
  4. The game consists of several steps:
    1. Both the player and the dealer review the two cards they are dealt. Both the player and the dealer can see the opponent's hand as well.
    2. The player is given the option to draw additional cards. The player may continue to draw cards until she or he chooses to stop, or their total value is greater than 21.
    3. If the player stops before going over 21, the dealer must draw cards to try and beat the player. The dealer stops drawing cards either when their total beats the player, or the dealer's total is greater than 21.
    4. At the end, the participant with the greatest card value that is less than or equal to 21 wins the game. If it is a tie, the dealer wins.

*~*sigh*~*

Image Credit: Giphy

Let's break it down into smaller parts


Use Classes!

Image Credit: Giphy

Let's break it down into classes





class Card:
  

class Card:
# Properties @property def suit(self): return self.__suit
@property def name(self): return self.__name
@property def value(self): return self.__value

class Card:
# Properties ...


class Card:
def __init__(self, a_suit, a_number):
# Properties ...


class Card:
def __init__(self, a_suit, a_number): this.__suit = a_suit
# Properties ...


class Card:
def __init__(self, a_suit, a_number): this.__suit = a_suit this.__name = str(a_number) this.__value = a_number
# Properties ...



class Card:
def __init__(self, a_suit, a_number): this.__suit = a_suit this.__name = str(a_number) this.__value = a_number
# Properties ...


class Card:
def __init__(self, a_suit, a_number): this.__suit = a_suit if:
else: this.__name = str(a_number) this.__value = a_number
# Properties ...



class Card:
def __init__(self, a_suit, a_number): this.__suit = a_suit if a_number == 1:
else: this.__name = str(a_number) this.__value = a_number
# Properties ...

class Card:
def __init__(self, a_suit, a_number): this.__suit = a_suit if a_number == 1: this.__name = "Ace" this.__value = 11 else: this.__name = str(a_number) this.__value = a_number
# Properties ...


class Card:
def __init__(self, a_suit, a_number): this.__suit = a_suit if a_number == 1: this.__name = "Ace" this.__value = 11 elif a_number == 11: this.__name = "Jack" this.__value = 10 elif a_number == 12: this.__name = "Queen" this.__value = 10 elif a_number == 13: this.__name = "King" this.__value = 10 else: this.__name = str(a_number) this.__value = a_number
# Properties ...

class Card:
def __init__(self, a_suit, a_number): this.__suit = a_suit if a_number == 1: this.__name = "Ace" this.__value = 11 elif a_number == 11: this.__name = "Jack" this.__value = 10 elif a_number == 12: this.__name = "Queen" this.__value = 10 elif a_number == 13: this.__name = "King" this.__value = 10 else: this.__name = str(a_number) this.__value = a_number
# Properties ...


class Card:
def __init__(self, a_suit, a_number): if not (a_suit == "Spades" or a_suit == "Hearts" or a_suit == "Clubs" or a_suit == "Diamonds"): raise ValueError("The suit must ...") if a_number < 1 or a_number > 13: raise ValueError("The card number ...") this.__suit = a_suit if a_number == 1: this.__name = "Ace" this.__value = 11 elif a_number == 11: this.__name = "Jack" this.__value = 10 elif a_number == 12: this.__name = "Queen" this.__value = 10 elif a_number == 13: this.__name = "King" this.__value = 10 else: this.__name = str(a_number) this.__value = a_number
# Properties ...


class Card:
def __init__(self, a_suit, a_number): if not (a_suit == "Spades" or a_suit == "Hearts" or a_suit == "Clubs" or a_suit == "Diamonds"): raise ValueError("The suit must ...") if a_number < 1 or a_number > 13: raise ValueError("The card number ...") this.__suit = a_suit if a_number == 1: this.__name = "Ace" this.__value = 11 elif a_number == 11: this.__name = "Jack" this.__value = 10 elif a_number == 12: this.__name = "Queen" this.__value = 10 elif a_number == 13: this.__name = "King" this.__value = 10 else: this.__name = str(a_number) this.__value = a_number
# Properties ...


class Card:
def __init__(self, a_suit, a_number): ...
# Properties ...

class Card:
def __init__(self, a_suit, a_number): ...
# Properties ...
def __str__(self): return "{} of {}".format(this.__name, this.__suit)






class Deck:


from Card import *
class Deck:


from Card import *
class Deck:
def __init__(self):


from Card import *
class Deck:
def __init__(self): self.__card_deck = []


from Card import *
class Deck:
def __init__(self): self.__card_deck = [] suits = ["Spades", "Hearts", "Diamonds", "Clubs"] for suit in suits:



from Card import *
class Deck:
def __init__(self): self.__card_deck = [] suits = ["Spades", "Hearts", "Diamonds", "Clubs"] for suit in suits: for i in range(1, 14): self.__card_deck.append(Card(suit, i))



from Card import *
class Deck:
def __init__(self): self.__card_deck = [] suits = ["Spades", "Hearts", "Diamonds", "Clubs"] for suit in suits: for i in range(1, 14): self.__card_deck.append(Card(suit, i))



from Card import *
class Deck:
def __init__(self): self.__card_deck = [] suits = ["Spades", "Hearts", "Diamonds", "Clubs"] for suit in suits: for i in range(1, 14): self.__card_deck.append(Card(suit, i))
def __str__(self): output = "" for a_card in self.__card_deck: output += str(a_card) + "\n" return output


Let's Test It!



from Deck import *
class Main:
@staticmethod def main(): a_deck = Deck() print(a_deck)
if __name__ == "__main__": Main.main()


from Deck import *
class Main:
@staticmethod def main(): a_deck = Deck() print(a_deck)
if __name__ == "__main__": Main.main()

from Card import *
class Deck:
def __init__(self): ... def __str__(self): ...



from Card import *
class Deck:
def __init__(self): ... def __str__(self): ...
def shuffle(self, times):



from Card import *
class Deck:
def __init__(self): ... def __str__(self): ...
def shuffle(self, times): for i in range(0, times):



import random
from Card import *
class Deck:
def __init__(self): ... def __str__(self): ...
def shuffle(self, times): for i in range(0, times): first = random.randint(0, 52) second = random.randint(0, 52)

import random
from Card import *
class Deck:
def __init__(self): ... def __str__(self): ...
def shuffle(self, times): for i in range(0, times): first = random.randint(0, 52) second = random.randint(0, 52) if first != second: temp = self.__card_deck[first] self.__card_deck[first] = self.__card_deck[second] self.__card_deck[second] = temp



import random
from Card import *
class Deck:
def __init__(self): ... def __str__(self): ...
def shuffle(self, times): if times <= 0: raise ValueError("The deck must ...") for i in range(0, times): first = random.randint(0, 52) second = random.randint(0, 52) if first != second: temp = self.__card_deck[first] self.__card_deck[first] = self.__card_deck[second] self.__card_deck[second] = temp


import random
from Card import *
class Deck:
def __init__(self): ... def __str__(self): ...
def shuffle(self, times): if times <= 0: raise ValueError("The deck must ...") for i in range(0, times): first = random.randint(0, 52) second = random.randint(0, 52) if first != second: temp = self.__card_deck[first] self.__card_deck[first] = self.__card_deck[second] self.__card_deck[second] = temp


Let's Test It!



from Deck import *
class Main:
@staticmethod def main(): a_deck = Deck() a_deck.shuffle(1000) print(a_deck)
if __name__ == "__main__": Main.main()


from Deck import *
class Main:
@staticmethod def main(): a_deck = Deck() a_deck.shuffle(1000) print(a_deck)
if __name__ == "__main__": Main.main()


import random
from Card import *
class Deck:
def __init__(self): ... def __str__(self): ... def shuffle(self, times): ...


import random
from Card import *
class Deck:
def __init__(self): ... def __str__(self): ... def shuffle(self, times): ...
def draw(self):


import random
from Card import *
class Deck:
def __init__(self): ... def __str__(self): ... def shuffle(self, times): ...
def draw(self): output = self.__card_deck[self.__card_position] self.__card_position += 1 return output


import random
from Card import *
class Deck:
def __init__(self): self.__card_position = 0 ...
def __str__(self): ... def shuffle(self, times): ...
def draw(self): output = self.__card_deck[self.__card_position] self.__card_position += 1 return output

import random
from Card import *
class Deck:
def __init__(self): self.__card_position = 0 ...
def __str__(self): ... def shuffle(self, times): ...
def draw(self): output = self.__card_deck[self.__card_position] self.__card_position += 1 return output



class Hand:


from Card import *
class Hand:


from Card import *
class Hand:
def __init__(self): self.__card_hand = []


from Card import *
class Hand:
def __init__(self): self.__card_hand = []
@property def value(self): value = 0 for card in self.__card_hand: value += card.value return value
def __str__(self): output = "" for card in self.__card_hand: output += str(card) + "\n" return output


from Card import *
class Hand:
def __init__(self): self.__card_hand = []
@property def value(self): value = 0 for card in self.__card_hand: value += card.value return value
def __str__(self): output = "" for card in self.__card_hand: output += str(card) + "\n" return output
def add_card(self, input): if not isinstance(input, Card): raise ValueError("Input must be a Card object") self.__card_hand.append(input)




class Dealer:


from Hand import *
class Dealer:
def __init__(self, a_hand): if not isinstance(a_hand, Hand): raise ValueError("A_hand must be a Hand object") self.__my_hand = a_hand


from Hand import *
class Dealer:
def __init__(self, a_hand): if not isinstance(a_hand, Hand): raise ValueError("A_hand must be a Hand object") self.__my_hand = a_hand
def __str__(self): output = "The dealer currently holds: \n" output += str(self.__my_hand) output += "for a total of {}".format(self.__my_hand.value) return output

from Hand import *
class Dealer:
def __init__(self, a_hand): ... def __str__(self): ...

from Hand import *
class Dealer:
def __init__(self, a_hand): ... def __str__(self): ...
def make_moves(self, player_value):


from Hand import *
class Dealer:
def __init__(self, a_hand): ... def __str__(self): ...
def make_moves(self, player_value): while self.__my_hand.value < player_value and self.__my_hand.value <= 21: # we need to draw a card here!

from Hand import *
class Dealer:
def __init__(self, a_hand): ... def __str__(self): ...
def make_moves(self, player_value): while self.__my_hand.value < player_value and self.__my_hand.value <= 21: # we need to draw a card here!

Option 1: Make Deck Static

Pros:

  • Requires few code changes
  • Can use deck from anywhere

Cons:

  • Can only have one deck
  • Not standard

Option 2: Pass Deck to Dealer

Pros:

  • No modification to deck
  • More object-oriented

Cons:

  • Have to manage deck instance
  • Easy to lose objects in code

from Hand import *
class Dealer:
def __init__(self, a_hand): ... def __str__(self): ...
def make_moves(self, player_value): while self.__my_hand.value < player_value and self.__my_hand.value <= 21: # we need to draw a card here!

from Hand import *
class Dealer:
def __init__(self, a_hand, a_deck): if not isinstance(a_hand, Hand): raise ValueError("A_hand must be a Hand object") if not isinstance(a_deck, Deck): raise ValueError("A_deck must be a Hand object") self.__my_hand = a_hand self.__the_deck = a_deck
def __str__(self): ...
def make_moves(self, player_value): while self.__my_hand.value < player_value and self.__my_hand.value <= 21: # we need to draw a card here!


from Hand import *
class Dealer:
def __init__(self, a_hand, a_deck): if not isinstance(a_hand, Hand): raise ValueError("A_hand must be a Hand object") if not isinstance(a_deck, Deck): raise ValueError("A_deck must be a Hand object") self.__my_hand = a_hand self.__the_deck = a_deck
def __str__(self): ...
def make_moves(self, player_value): while self.__my_hand.value < player_value and self.__my_hand.value <= 21: new_card = self.__the_deck.draw() print("The dealer draws a {}".format(str(new_card))) self.__my_hand.add_card(new_card)


from Hand import *
class Dealer:
def __init__(self, a_hand, a_deck): if not isinstance(a_hand, Hand): raise ValueError("A_hand must be a Hand object") if not isinstance(a_deck, Deck): raise ValueError("A_deck must be a Hand object") self.__my_hand = a_hand self.__the_deck = a_deck
def __str__(self): ...
def make_moves(self, player_value): while self.__my_hand.value < player_value and self.__my_hand.value <= 21: new_card = self.__the_deck.draw() print("The dealer draws a {}".format(str(new_card))) self.__my_hand.add_card(new_card)


from Hand import *
from Deck import *
class Dealer:
def __init__(self, a_hand, a_deck): if not isinstance(a_hand, Hand): raise ValueError("A_hand must be a Hand object") if not isinstance(a_deck, Deck): raise ValueError("A_deck must be a Hand object") self.__my_hand = a_hand self.__the_deck = a_deck
def __str__(self): output = "The dealer currently holds: \n" output += str(self.__my_hand) output += "for a total of {}".format(self.__my_hand.value) return output


from Hand import *
from Deck import *
class Dealer:
def __init__(self, a_hand, a_deck): if not isinstance(a_hand, Hand): raise ValueError("A_hand must be a Hand object") if not isinstance(a_deck, Deck): raise ValueError("A_deck must be a Hand object") self.__my_hand = a_hand self.__the_deck = a_deck
def __str__(self): output = "The dealer currently holds: \n" output += str(self.__my_hand) output += "for a total of {}".format(self.__my_hand.value) return output


from Hand import *
from Deck import *
class Player:
def __init__(self, a_hand, a_deck): if not isinstance(a_hand, Hand): raise ValueError("A_hand must be a Hand object") if not isinstance(a_deck, Deck): raise ValueError("A_deck must be a Hand object") self.__my_hand = a_hand self.__the_deck = a_deck
def __str__(self): output = "The player currently holds: \n" output += str(self.__my_hand) output += "for a total of {}".format(self.__my_hand.value) return output


from Hand import *
from Deck import *
class Player:
def __init__(self, a_hand, a_deck): if not isinstance(a_hand, Hand): raise ValueError("A_hand must be a Hand object") if not isinstance(a_deck, Deck): raise ValueError("A_deck must be a Hand object") self.__my_hand = a_hand self.__the_deck = a_deck
def __str__(self): output = "The player currently holds: \n" output += str(self.__my_hand) output += "for a total of {}".format(self.__my_hand.value) return output


from Hand import *
from Deck import *
class Player:
def __init__(self, a_hand, a_deck): ... def __str__(self): ...



from Hand import *
from Deck import *
class Player:
def __init__(self, a_hand, a_deck): ... def __str__(self): ...
def make_moves(self):


import sys
from Hand import *
from Deck import *
class Player:
def __init__(self, a_hand, a_deck): ... def __str__(self): ...
def make_moves(self): with sys.stdin as reader:


import sys
from Hand import *
from Deck import *
class Player:
def __init__(self, a_hand, a_deck): ... def __str__(self): ...
def make_moves(self): with sys.stdin as reader: while self.__my_hand.value <= 21:

import sys
from Hand import *
from Deck import *
class Player:
def __init__(self, a_hand, a_deck): ... def __str__(self): ...
def make_moves(self): with sys.stdin as reader: while self.__my_hand.value <= 21: print("You currently have a value of {}".format( self.__my_hand.value)) print("Would you like to draw another card (y/n)?: ") input = reader.readline().strip()



import sys
from Hand import *
from Deck import *
class Player:
def __init__(self, a_hand, a_deck): ... def __str__(self): ...
def make_moves(self): with sys.stdin as reader: while self.__my_hand.value <= 21: print("You currently have a value of {}".format( self.__my_hand.value)) print("Would you like to draw another card (y/n)?: ") input = reader.readline().strip() if input == "y" or input == "Y": new_card = self.__the_deck.draw() print("The dealer draws a {}".format(str(new_card))) self.__my_hand.add_card(new_card) elif input == "n" or input == "N": break; else: print("Invalid input!")

import sys
from Hand import *
from Deck import *
class Player:
def __init__(self, a_hand, a_deck): ... def __str__(self): ...
def make_moves(self): with sys.stdin as reader: while self.__my_hand.value <= 21: print("You currently have a value of {}".format( self.__my_hand.value)) print("Would you like to draw another card (y/n)?: ") input = reader.readline().strip() if input == "y" or input == "Y": new_card = self.__the_deck.draw() print("The dealer draws a {}".format(str(new_card))) self.__my_hand.add_card(new_card) elif input == "n" or input == "N": break; else: print("Invalid input!") print("You end your turn with a value of {}".format( self.__my_hand.value))

import sys
from Hand import *
from Deck import *
class Player:
def __init__(self, a_hand, a_deck): ... def __str__(self): ...
def make_moves(self): with sys.stdin as reader: while self.__my_hand.value <= 21: print("You currently have a value of {}".format( self.__my_hand.value)) print("Would you like to draw another card (y/n)?: ") input = reader.readline().strip() if input == "y" or input == "Y": new_card = self.__the_deck.draw() print("The dealer draws a {}".format(str(new_card))) self.__my_hand.add_card(new_card) elif input == "n" or input == "N": break; else: print("Invalid input!") print("You end your turn with a value of {}".format( self.__my_hand.value))



from Deck import *
from Hand import *
from Dealer import *
from Player import *
class Main:
@staticmethod def main():
if __name__ == "__main__": Main.main()


from Deck import *
from Hand import *
from Dealer import *
from Player import *
class Main:
@staticmethod def main(): the_deck = Deck()
if __name__ == "__main__": Main.main()


from Deck import *
from Hand import *
from Dealer import *
from Player import *
class Main:
@staticmethod def main(): the_deck = Deck() the_deck.shuffle(1000)
if __name__ == "__main__": Main.main()

from Deck import *
from Hand import *
from Dealer import *
from Player import *
class Main:
@staticmethod def main(): the_deck = Deck() the_deck.shuffle(1000) player_hand = Hand() player_hand.add_card(the_deck.draw()) player_hand.add_card(the_deck.draw()) a_player = Player(player_hand, the_deck)
if __name__ == "__main__": Main.main()

from Deck import *
from Hand import *
from Dealer import *
from Player import *
class Main:
@staticmethod def main(): the_deck = Deck() the_deck.shuffle(1000) player_hand = Hand() player_hand.add_card(the_deck.draw()) player_hand.add_card(the_deck.draw()) a_player = Player(player_hand, the_deck) dealer_hand = Hand() dealer_hand.add_card(the_deck.draw()) dealer_hand.add_card(the_deck.draw()) a_dealer = Dealer(dealer_hand, the_deck)
if __name__ == "__main__": Main.main()


from Deck import *
from Hand import *
from Dealer import *
from Player import *
class Main:
@staticmethod def main(): the_deck = Deck() the_deck.shuffle(1000) player_hand = Hand() player_hand.add_card(the_deck.draw()) player_hand.add_card(the_deck.draw()) a_player = Player(player_hand, the_deck) dealer_hand = Hand() dealer_hand.add_card(the_deck.draw()) dealer_hand.add_card(the_deck.draw()) a_dealer = Dealer(dealer_hand, the_deck) a_player.make_moves()
if __name__ == "__main__": Main.main()


from Deck import *
from Hand import *
from Dealer import *
from Player import *
class Main:
@staticmethod def main(): the_deck = Deck() the_deck.shuffle(1000) player_hand = Hand() player_hand.add_card(the_deck.draw()) player_hand.add_card(the_deck.draw()) a_player = Player(player_hand, the_deck) dealer_hand = Hand() dealer_hand.add_card(the_deck.draw()) dealer_hand.add_card(the_deck.draw()) a_dealer = Dealer(dealer_hand, the_deck) a_player.make_moves() a_dealer.make_moves(player_hand.value)
if __name__ == "__main__": Main.main()


from Deck import *
from Hand import *
from Dealer import *
from Player import *
class Main:
@staticmethod def main(): the_deck = Deck() the_deck.shuffle(1000) player_hand = Hand() player_hand.add_card(the_deck.draw()) player_hand.add_card(the_deck.draw()) a_player = Player(player_hand, the_deck) dealer_hand = Hand() dealer_hand.add_card(the_deck.draw()) dealer_hand.add_card(the_deck.draw()) a_dealer = Dealer(dealer_hand, the_deck) a_player.make_moves() a_dealer.make_moves(player_hand.value)
if player_hand.value <= 21 and dealer_hand.value > 21: print("The player wins!") elif player_hand.value <= 21 and player_hand.value > dealer_hand.value: print("The player wins!") elif dealer_hand.value <= 21: print("The dealer wins!") else: print("There is no winner")
if __name__ == "__main__": Main.main()


from Deck import *
from Hand import *
from Dealer import *
from Player import *
class Main:
@staticmethod def main(): the_deck = Deck() the_deck.shuffle(1000) player_hand = Hand() player_hand.add_card(the_deck.draw()) player_hand.add_card(the_deck.draw()) a_player = Player(player_hand, the_deck) dealer_hand = Hand() dealer_hand.add_card(the_deck.draw()) dealer_hand.add_card(the_deck.draw()) a_dealer = Dealer(dealer_hand, the_deck) a_player.make_moves() a_dealer.make_moves(player_hand.value)
if player_hand.value <= 21 and dealer_hand.value > 21: print("The player wins!") elif player_hand.value <= 21 and player_hand.value > dealer_hand.value: print("The player wins!") elif dealer_hand.value <= 21: print("The dealer wins!") else: print("There is no winner")
if __name__ == "__main__": Main.main()