pythonfunctionclassmethodsblackjack

Python Blackjack Project Type Error: Chips.place_bet() missing 1 required positional argument


I am trying to write my first python project blackjack. I was advised to write the program with each class and its methods in a different file so that the code would be more manageable. I divided my code up into smaller files and used import statements.

When I run my code I get the following error message:

Chips.place_bet() missing 1 required positional argument. self.

I thought self was self explanatory. I do not need to put a value for self. I am wondering if this is an import issue.

I am trying to get my place_bet function to activate so that I can ask the user to input the number of chips for a bet. Can anyone advise me on how to do this?

I feel this question is different from

My code is spread over these files:

blackjack.py

import random

from player import Player
from hand import Hand
from chips import Chips
from deck import Deck
from card import Card
# import helper_functions

# Blackjack/
# ├── app/
# │   ├── card.py
# │   ├── chips.py
# │   ├── deck.py
# │   ├── hand.py
# │   ├── player.py
# │   ├── main.py
# │   ├── helper_functions.py

# Gameplay and Outline of Project

# Welcome message and rules
print("Welcome to Blackjack! The rules for blackjack can be found here. https://www.youtube.com/watch?v=PljDuynF-j0")
print("The object of this blackjack game is to make it to 100 chips. You will start with 25 chips.")

# Establish player name
print("Please insert your player name: ")
player_name = input()
print('Please insert your player name ' + player_name)
print("Lets get started" + player_name + "please place your bet!")
# Place the bets BEFORE the cards are dealt. Pure risk.
place_bet()
# .  Deal 2 cards to user and dealer
# . print a message explaining the total hand value of the user. ask player to hit/stay?
# . If the player busts print player busts. if the player is under 21 ask them again to hit or stay.
# . If stay, move on to dealers turn.
# . If the hand is less than 17 have him hit, if it is over 17 have the dealer stay.
# . If the dealer stays print the dealers hand total. IF the dealers hand total is greater than the player the dealer wins.
# . if the dealer busts print the message he busts and the player wins and the player gets the chips.

# 1. Ask dealer to hit/stay?
# 2. If hit, deal 2 cards
# 3. If broke or blackjack deliver message
# 4. If stay, compare hands
# 5. If users hand is closer to 21, (user wins)
# 6. If dealers hand is closer to 21, (user loses)


def main():
    player = Player('strikeouts27', 500,)
    dealer = Player()

    player_chips = Chips()
    dealer_chips = Chips()

    cards = Card()
    deck = Deck()


if __name__ == '__main__':
    main()

card.py

class Card:
    """Card class"""

    def __init__(self, rank, suit):
        self.rank = rank
        self.suit = suit

    def __repr__(self):
        return f'{self.__class__.__name__}(rank={self.rank}, suit={self.suit})'

class Chips:
    """Chip class manages chip balance"""

    def __init__(self, balance):
        self.balance = balance
        self.bet = 0

    def place_bet(self):
        while True:
            total = input(f'How much do you bet? (1-{self.balance}):\n> ')
            # return True if a digit string. false otherwise. hover over the method for visual studio code to show you.
            if not total.isdigit():
                continue
            total = int(total)
            if total > self.balance:
                print('You do not have enough')
                continue
            return total

    def add_value(self, value):
        """Add value to chip total"""
        self.balance += value

    def deduct_value(self, value):
        """Deduct value from chip total"""
        self.balance -= value

    def display_chips(player, dealer):
        print(f'player chips: ${player.chips.balance}')
        print(f'dealer chips: ${dealer.chips.balance}')
            # Displays player and dealer chip count

class.py

class Card:
    #"""Card class"""

    def __init__(self, rank, suit):
        self.rank = rank
        self.suit = suit

    def __repr__(self):
        return f'{self.__class__.__name__}(rank={self.rank}, suit={self.suit})'

deck.py

class Deck:
    """Deck class, represents 52 cards"""

    def __init__(self):
        self.ranks = [str(n) for n in range(2, 11)] + list('jqka')
        self.suits = ["hearts", "diamonds", "clubs", "spades"]
        self.cards = [Card(rank, suit)
                      for suit in self.suits for rank in self.ranks]
        random.shuffle(self.cards)

    # dunder method rewrites what pythons default method to show better information about itself.
    def __repr__(self):
        return f'{self.__class__.__name__}({self.cards})'

    def __len__(self):
        return len(self.cards)

    def __getitem__(self, item):
        return self.cards[item]

    def shuffle(self):
        """shuffles deck of cards"""
        random.shuffle(self.cards)

hand.py

class Hand:
    """Hand class to hold the cards for the player and the dealer"""

    def __init__(self, cards=None):
        self.cards = [] if cards is None else cards
        self.value = 0
        self.aces = 0

    def add_to_hand(self, card):
        """Adds a cards to self.cards."""
        self.cards.append(card)

    def display_hand(self):
        hashtable = {'hearts': 9829, 'diamonds': 9830,
                     'spades': 9824, 'clubs': 9827}
        return [[i.rank, chr(hashtable.get(i.suit))] for i in self.cards]

    def display_hand_two(player, dealer):
        # Displays player and dealer hand
        print(
            f'players Hand: {player.hand.display_hand()} -->  total {player.total}')
        print(
            f'dealer Hand: {dealer.hand.display_hand()} -->  total {dealer.total}')

player.py

class Player:
    """Player class"""

    def __init__(self, name, chips, hand):
        self.name = name
        self.chips = chips
        self.hand = hand

    @property
    def total(self):
        """Returns the value of the cards. Face cards equal 10, aces can equal
        11 or 1, this function picks best case"""

        value = 0
        aces_count = 0
        # Each card is a tuple in a list:
        cards = [card for card in self.hand.cards]

        for card in cards:
            if card.rank == 'a':
                aces_count += 1
            elif card.rank in 'kqj':
                # Face cards are worth 10 points
                value += 10
            else:
                # Numbered cards are worth their value.
                value += int(card.rank)
        # Add value of aces - 1 per ace
        value += aces_count
        for i in range(aces_count):
            # If another 10 can be added,then do it!
            if value + 10 <= 21:
                value += 10

        return value

    @staticmethod
    def get_move():
        """returns player choice to hit or stand"""
        move = input('>>> (H)it, (S)tand ?:\n> ').lower()
        return move


def main():
    # Instantiate Deck
    deck = Deck()

    # shuffle deck
    deck.shuffle()

    # Instantiate player and dealer chips
    player_chips = Chips(500)
    dealer_chips = Chips(500)

    while True:
        # Instantiate player and dealer hand
        player_hand = Hand()
        dealer_hand = Hand()

        # Instantiate player and dealer
        player = Player('seraph', player_chips, player_hand)
        dealer = Player('codecademy', dealer_chips, dealer_hand)

        # Check if player has enough money
        if player_chips.balance <= 0:
            print('need more money')

        # Then place bet
        bet = player_chips.place_bet()

        # player draws 2 cards
        player.hand.add_to_hand(deck.cards.pop())
        player.hand.add_to_hand(deck.cards.pop())

        # Dealer draws cards
        dealer.hand.add_to_hand(deck.cards.pop())
        dealer.hand.add_to_hand(deck.cards.pop())

        # display player ann dealers hand
        display_hand(player, dealer)

        # Begin game
        while True:
            if player.total > 21:
                break

            #  Get the player's moves
            player_move = player.get_move()
            if player_move == 'h':
                new_card = deck.cards.pop()
                rank, suit = new_card.rank, new_card.suit
                player.hand.add_to_hand(new_card)
                print(f'You drew a {rank} of {suit}')
                display_hand(player, dealer)
                if player.total > 21:
                    print('You busted...')
                    # Busted
                    continue
            if player_move == 's':
                break

        # Get the dealer's moves
        if dealer.total <= 21 and not player.total > 21:
            while dealer.total <= 17:
                print('Dealer hits...')
                new_card = deck.cards.pop()
                dealer.hand.add_to_hand(new_card)
                if dealer.total > 21:
                    break

        if dealer.total > 21:
            print('Dealer Busted - You win!')
            display_hand(player, dealer)
            player.chips.add_value(bet)
            dealer.chips.deduct_value(bet)
            display_chips(player, dealer)

        elif player.total > 21 or player.total < dealer.total:
            print('You lost!')
            display_hand(player, dealer)
            player.chips.deduct_value(bet)
            dealer.chips.add_value(bet)
            display_chips(player, dealer)

        elif player.total == dealer.total:
            print("It's a tie! Money is returned")


if __name__ == '__main__':
    main()

I feel that this question is different than this referenced article because we are dealing with multiple files and the article that I am referencing here is only talking about one file.

referenced article: Why do I get "TypeError: Missing 1 required positional argument: 'self'" trying to call a method from the class directly?


Solution

  • A few issues:

    If you implement all those changes, your code will run.