pythonpython-3.xruntime-errorpoker

Python appears to be passing then wrong object into a function


Here is my code I am trying to run

# -*- coding: utf-8 -*-
import pydealer
from pokerlib import HandParser
from pokerlib.enums import Value, Suit


class Player:
    def __init__(self, name: str, chips=500):
        self.name = name
        self.hand = pydealer.Stack()
        self.fold = False
        self.matching_pot = True
        self.hand_rank = None
        if name == "AI":
            self.chips = 500
        else:
            self.chips = chips

    def __str__(self):
        return self.name


class PokerGame:
    def __init__(self, players):
        self.deck = pydealer.Deck()
        self.discard_pile = pydealer.Stack()
        self.table = pydealer.Stack()
        self.players = players
        self.pot = 0
        """
        TLDR: (bet_pot=starting ante) --> pots right --> (pot=bet_pot) and bet_pot is reset --> someone raises -->repeat
        Pot and bet pot work as described, pot starts at zero and bet_pot has the initial buy in, the betting round and 
        pots right make sure that players either fold or match, at the end of that round, then bet_pot is transferred to
        pot and cleared for the next round.  Bet_pot is updated only when players raise and at the beginning.
        In addition, when a player matches his chips go to the pot not bet_pot.
        """
        self.bet_pot = 0  # Add starting bet
        self.stage = 0
        self.stage_dict = {
            0: "Pre-flop",
            1: "Post-flop/Pre-turn",
            2: "Post-turn/Pre-river",
            3: "Post-river/Final Betting round",
        }
        print("Created a game with {} players.".format(len(self.players)))

    def poker(self):
        self.deck.shuffle()
        self.deal()
        self.flop()
        self.turn()
        self.river()
        self.rank_hands()
        self.award_pot()

    def deal(self):
        for player in self.players:
            new_card = self.deck.deal(2)
            player.hand.add(new_card)

    def flop(self):
        self.discard_pile = self.deck.deal(1)
        self.table = self.deck.deal(3)
        self.stage += 1
        print("The flop is\n", self.table, "\n")

    def turn(self):
        self.discard_pile = self.deck.deal(1)
        turn_card = self.deck.deal(1)
        self.table += turn_card
        self.stage += 1
        print("The turn adds\n", turn_card)
        print("The table is\n", self.table, "\n")

    def river(self):
        self.discard_pile = self.deck.deal(1)
        river_card = self.deck.deal(1)
        self.table += river_card
        self.stage += 1
        print("The river adds\n", river_card)
        print("The table is\n", self.table, "\n")

    def convert_cards(self, convert_what, player=None):
        values = {2: Value.TWO, 3: Value.THREE, 4: Value.FOUR, 5: Value.FIVE, 6: Value.SIX, 7: Value.SEVEN,
                  8: Value.EIGHT, 9: Value.NINE, 10: Value.TEN, "Jack": Value.JACK, "Queen": Value.QUEEN,
                  "King": Value.KING, "Ace": Value.ACE}
        suits = {"Hearts": Suit.HEART, "Spades": Suit.SPADE, "Diamonds": Suit.DIAMOND, "Clubs": Suit.CLUB}
        if convert_what == "hand":
            stack = player.hand
        elif convert_what == "table":
            stack = self.table
        else:
            raise Exception("In Convert_cards, convert_what is either empty, or is an invalid option(Not hand or table")
        converted_cards = []
        for card in stack:
            card = str(card)
            temp_list = ["value", "suit"]
            for value in values.keys():
                if card.find(str(value)) == -1:
                    continue
                else:
                    temp_list[0] = values[value]
                    break
            for suit in suits.keys():
                if card.find(suit) == -1:
                    continue
                else:
                    temp_list[1] = suits[suit]
                    break
            temp_list = tuple(temp_list)
            converted_cards.append(temp_list)
        return converted_cards

    def rank_hands(self):
        for player in self.players:
            cards_to_rank = list(self.convert_cards("hand", player)) + list(self.convert_cards("table"))
            player.hand_rank = HandParser(cards_to_rank)

    def find_winner(self):
        winning_hand = HandParser([(Value.TWO, Suit.HEART)])  # Might need object to compare - I would try None
        winning_hand.parse()
        temp_winner = []
        dual_winners = False
        for player in self.players:
            player.hand_rank.parse()
            if player.hand_rank > winning_hand:
                winning_hand = player.hand
                temp_winner.append(player)
                print(player.hand_rank.handenum)
            elif player.hand_rank == winning_hand:
                dual_winners = True
                print(player.hand_rank.handenum)
        winner = temp_winner
        return winner, winning_hand, dual_winners

    def award_pot(self):
        winner, winning_hand, dual_winners = self.find_winner()
        if dual_winners:
            winnings = self.pot / 2
            winner[0].chips = winnings
            winner[1].chips = winnings
            print(f"The winners are {winner[0]}, and {winner[1]} with {winning_hand}.  They each win {winnings}")
            quit()
        else:
            winner[0].chips = self.pot
            print(f"The winner is {winner}, who won the pot of {self.pot} with {winning_hand}")
            quit()

class PokerAi(PokerGame):
    def __init__(self, name):
        super().__init__(name)

    def ai_poker(self):
        self.poker()


if __name__ == "__main__":
    game_type = "ai"  # Defaults
    user_name = "default_name"
    if game_type == "ai":
        game = PokerAi([Player(user_name, 600), Player("AI")])  # Ai player index is 1
        game.ai_poker()

And after inputing nothing(by pressing return) until the end, I get the error:

Traceback (most recent call last):
  File "/Users/jchampeau/PycharmProjects/CP2-Final-Project/main.py", line 319, in <module>
    game.ai_poker()
  File "/Users/jchampeau/PycharmProjects/CP2-Final-Project/main.py", line 306, in ai_poker
    self.poker()
  File "/Users/jchampeau/PycharmProjects/CP2-Final-Project/main.py", line 63, in poker
    self.award_pot()
  File "/Users/jchampeau/PycharmProjects/CP2-Final-Project/main.py", line 270, in award_pot
    winner, winning_hand, dual_winners = self.find_winner()
  File "/Users/jchampeau/PycharmProjects/CP2-Final-Project/main.py", line 259, in find_winner
    if player.hand_rank > winning_hand:
  File "/Users/jchampeau/Library/Python/3.8/lib/python/site-packages/pokerlib/_handparser.py", line 69, in __gt__
    if self.handenum != other.handenum:
AttributeError: 'Stack' object has no attribute 'handenum'

Based on my understanding of the error, the function is receiving the wrong class/object which I don't know why it is happening. Which is interesting because the if statement works because I can see the handenum of the winning hand.

I have tried debugging it but the variable look fine in the debugger and the code prints the print(player.handenums) I am not expecting to get an error, instead I am expecting the code to run/move on to and display the award pot print statements.


Solution

  • I believe this is your problem.

    class Player:
        def __init__(self, name: str, chips=500):
            self.name = name
            self.hand = pydealer.Stack()
            ...
    
    class PokerGame:
        ...
        def find_winner(self):
            winning_hand = HandParser([(Value.TWO, Suit.HEART)])
            ...
            for player in self.players:
                ...
                if player.hand_rank > winning_hand:
                    winning_hand = player.hand
    

    winning_hand and player.hand_rank both start as HandParser objects.

    But then inside the loop, when player.hand_rank > winning_hand is true, winning_hand is reassigned to player.hand, which is a Stack object.

    So on the next loop iteration, you try to compare a HandParser object to a Stack object, and you get the error.