pythonblackjack

Python Blackjack Drawing a Card from a Deck Problem


Question: I am attempting to make a blackjack game. I am at the part where I am trying to make a player class with a hand size which contains an empty list. My intuition tells me that I need to be targeting the deck where the cards are and to use the append and the pop methods. I have already written a function in another class called the deal cards method. Am I able to use functions from other classes inside a class? Or do I have to come up with some way of my class targeting the deck and getting the cards?

# Work on the player class give them the ability to have a hand and to deal the 
# cards into that hand 

from random import shuffle

class Card:
    def __init__(self, rank, suit): 
        self.rank = rank
        self.suit = suit 
    
    def __str__(self):
        return str(self.rank) + " of " + self.suit

class Deck:
    deck = []
    def __init__(self):
    
        suits = "Hearts", "Diamonds", "Clubs", "Spades"
        ranks = 2,3,4,5,6,7,8,9,10,"J","Q","K","A"
        for suit in suits:
            for rank in ranks:
                card= Card(rank,suit)
                self.deck.append(card)
    # need to be able to deal cards
    def deal_card(self):
        dealt_card = self.deck.pop()
        return dealt_card # return gives back the value to whomever called it.  

    # needs to be able to shuffle
    def shuffle(self):
        shuffle(self.deck)
    # display the deck
    def display(self):
        for card in self.deck:
            print(card)

class Player:
    def __init__(self, name, isdealer):
        self.name = name
        self.hand = []
        self.isdealer = isdealer
    
    def draw_cards(self):
        player_cards = dealt_card(); 
#scratchpad thinking area
# self.hand is an empty list. I want to get cards from the deck and put them in that list! SO I need to target
# the deck somehow. 
# maybe with pop?
# I would use append to add the result to my hand. 


    
# Work on the player class give them the ability to have a hand and to deal the 
# cards into that hand 

def main(): # main can be called blackjack or gameplay
    
    # Welcome the player and explain the rules
    print("""Welcome to Blackjack! Here are the Rules
      Try to get as close to 21 without going over.
      Kings, Queens, and Jacks are worth 10 points.
      Aces are worth 1 or 11 points.
      Cards 2 through 10 are worth their face value.
      (H)it to take another card.
      (S)tand to stop taking cards.
      The dealer stops hitting at 17""")

    # Run a game of blackjack
    # create a deck of cards outside of the main. 
    deck = Deck()
    deck.shuffle()
    deck.display()

    # Make player 1 and the dealer

#    while True:

        # return cards to the deck
        # Shuffle the deck of cards close to the start to start a new game. 
        # Deal 2 cards to the players

        # Loop: display hands and scores 
        # Ask them to hit or stand. 
        # Determine Winner

# If the program is run (instead of imported), run the game:
if __name__ == '__main__':
    main()

I have tried using the function from the deck class but I am unsure I can use methods from other classes. I know that append can be used to add to strings. I know I need to target the deck somehow but it is in another class.


Solution

  • Am I able to use functions from other classes inside a class? Or do I have to come up with some way of my class targeting the deck and getting the cards?

    There are several ways to approach this dilemma:

    In below code I have taken the first approach in the deal method.

    I also took some other decisions:

    I also implemented the game loop with hitting/standing/quitting, and reporting the winner

    Maybe some of this might not be acceptable for the code challenge you might be taking, but I thought these were the right thing to do:

    from random import shuffle
    
    class Card:
        def __init__(self, rank, suit): 
            self.rank = rank
            self.suit = suit 
            # Add a value to use in the blackjack scoring
            self.value = rank if isinstance(rank, int) else (1 if rank == "A" else 10) 
        
        def __str__(self):
            return f"{self.rank} of {self.suit}"
    
    class Deck(list):  # Inherit from list as a deck is mostly a list
        def __init__(self):
            suits = "Hearts", "Diamonds", "Clubs", "Spades"
            ranks = 2,3,4,5,6,7,8,9,10,"J","Q","K","A"
            for suit in suits:
                for rank in ranks:
                    card = Card(rank, suit)
                    self.append(card)
    
        def deal(self, player):  # Pass player as argument so to act on deck & player
            player.append(self.pop())
            return player[-1]
    
        def collect(self, player):
            self.extend(player)
            player.clear()
        
        def __str__(self):
            return ", ".join(map(str, self))
    
    
    class Player(Deck):  # Inherit from Deck, as a player really is a deck with a name
        def __init__(self, name, isdealer):
            self.name = name
            self.isdealer = isdealer
    
        def score(self):
            total = 0
            hasAce = False
            for card in self:
                total += card.value
                hasAce = hasAce or card.value == 1
            return total + 10 if hasAce and total < 12 else total
        
        def __str__(self):
            return f"{self.name} has {self.score()} ({super().__str__()})"
    
    
    def main():
        
        # Welcome the player and explain the rules
        print("""Welcome to Blackjack! Here are the Rules
          Try to get as close to 21 without going over.
          Kings, Queens, and Jacks are worth 10 points.
          Aces are worth 1 or 11 points.
          Cards 2 through 10 are worth their face value.
          (H)it to take another card.
          (S)tand to stop taking cards.
          The dealer stops hitting at 17
          """)
    
        deck = Deck()
    
        # Make player 1 and the dealer
        player = Player(input("What's your name? "), False)
        dealer = Player("Dealer", True)
    
        while True:
            # return cards to the deck
            deck.collect(player)
            deck.collect(dealer)
            
            shuffle(deck)
            
            # Deal 2 cards to the players
            deck.deal(player)
            deck.deal(player)
            deck.deal(dealer)
            deck.deal(dealer)
    
            # Loop: display hands and scores
            print()
            print("New game:")
            print(dealer)
            print(player)
            
            # Ask them to hit or stand.
            while player.score() <= 21:
                choice = input(f"{player.name}, do you want to [h]it, [s]tand or [q]uit? ").upper()
                if choice == "Q":
                    return
                if choice == "S":
                    break
                if choice == "H":
                    print(f"{player.name}, you receive {deck.deal(player)}")
                    print(player)
        
            while dealer.score() <= 16:
                print(f"{dealer.name} receives {deck.deal(dealer)}")
                print(dealer)
                
            # Determine Winner
            if player.score() > 21 or player.score() <= dealer.score() <= 21:
                print(f"{dealer.name} won this round")
            else:
                print(f"{player.name}, you won this round!")
    
    
    if __name__ == '__main__':
        main()