uoftcprg / pokerkit

An open-source Python library for poker game simulations, hand evaluations, and statistical analysis
https://pokerkit.readthedocs.io/
MIT License
247 stars 29 forks source link

game.actor.showdown() throws IndexError for 2nd player at the end of a hand #1

Closed Tenoke closed 2 years ago

Tenoke commented 2 years ago
from pokerface import *
from random import random

evaluator = StandardEvaluator()
deck = StandardDeck()
stakes = (0,(1,2))
stacks = [100,100]

def random_action(p):
    if p.can_fold() and p.check_call_amount > 0 and random()<0.25:
        p.fold()
        return
    r = random()
    if r < 0.33:
        p.check_call()
    elif r<0.6:
        if p.can_bet_raise():
            p.bet_raise(max(p.bet_raise_min_amount, p.stack/5))
    elif r<0.75:
        if p.can_bet_raise():
            p.bet_raise(max(p.bet_raise_min_amount, p.stack/3))
    elif r<0.9:
        if p.can_bet_raise():
            p.bet_raise(max(p.bet_raise_min_amount, p.stack/5))
    elif r<0.9:
        if p.can_bet_raise():
            p.bet_raise(p.stack)

def hand():
    deck = StandardDeck()
    game = NoLimitTexasHoldEm(Stakes(0, (1, 2)), stacks)
    game.nature.deal_hole()
    game.nature.deal_hole()
    while game.is_terminal() == False and game.actor != game.nature:
        random_action(game.actor)

    if game.is_terminal() == False:
        game.nature.deal_board()
        if game.actor != game.nature:
            game.actor.check_call()
            game.actor.check_call()
        game.nature.deal_board()
        if game.actor != game.nature:
            game.actor.check_call()
            game.actor.check_call()
        game.nature.deal_board()
        if game.actor != game.nature and game.is_terminal() == False:
            game.actor.check_call()
            game.actor.check_call()
        print(game.players, '____')
        for p in game.players:
             if game.is_terminal() == False:
                print(game.players)
                print(game.actor)
                print(game.actor.can_showdown(), game.actor.is_showdown_necessary())
                game.actor.showdown()
    # print(dir(game))
    # print(dir(game.nature))
    print(game.players, 'end')
    stacks.clear()
    stacks.append(game.players[1].stack)
    stacks.append(game.players[0].stack)
    return 

while 0 not in stacks:
    hand()

results in

SequenceView([PokerPlayer(0, 101, ????), PokerPlayer(0, 99)]) end
SequenceView([PokerPlayer(0, 79.0, ????), PokerPlayer(0, 81.0, ????)]) ____
SequenceView([PokerPlayer(0, 79.0, ????), PokerPlayer(0, 81.0, ????)])
PokerPlayer(0, 79.0, ????)
True True
SequenceView([PokerPlayer(0, 79.0, 2cJs), PokerPlayer(0, 81.0, ????)])
PokerPlayer(0, 81.0, ????)
True True
SequenceView([PokerPlayer(0, 79.0, 2cJs), PokerPlayer(0, 121.0, QhAd)]) end
Traceback (most recent call last):
  File "/home/tenoke/.local/lib/python3.8/site-packages/pokerface/game.py", line 270, in _update
    while self.stages[index]._is_done():
IndexError: tuple index out of range

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "create_data.py", line 67, in <module>
    hand()
  File "create_data.py", line 35, in hand
    random_action(game.actor)
  File "create_data.py", line 11, in random_action
    p.fold()
  File "/home/tenoke/.local/lib/python3.8/site-packages/pokerface/game.py", line 708, in fold
    self._get_fold_action().act()
  File "/home/tenoke/.local/lib/python3.8/site-packages/pokerface/_actions.py", line 16, in act
    self.game._update()
  File "/home/tenoke/.local/lib/python3.8/site-packages/pokerface/game.py", line 275, in _update
    self._distribute()
  File "/home/tenoke/.local/lib/python3.8/site-packages/pokerface/game.py", line 283, in _distribute
    for side_pot in self._side_pots:
  File "/home/tenoke/.local/lib/python3.8/site-packages/pokerface/game.py", line 187, in _side_pots
    cur = players[-1]._put
IndexError: list index out of range

despite needing to showdown to finish the hand

AussieSeaweed commented 2 years ago

Line 18, 21, and 24 in your script sometimes make non-integer raises which causes non-integer stack values. You should use floor division '//' instead of true division '/' to ensure the quotient value is always integral. I should have made it clear somewhere in the doc, but float stack values will cause some issues during chip distribution after the game ends. If you insist on using non-integer values, then you should give decimals a try. I am pretty sure that will work fine...

As for your remark about "despite needing to showdown to finish the hand," showdown is only necessary if two or more people remain in hand after all betting rounds. If everyone folded except one person, a showdown is not necessary. You can check whether or not the showdown should be done using "not game.is_terminal()" and "game.actor.can_showdown()" (kind of confusing I know).

Tenoke commented 2 years ago

Thanks, it must be the non-integer raises. I'll fix that.

You can check whether or not the showdown should be done using "not game.is_terminal()" and "game.actor.can_showdown()"

I do check it

   if game.is_terminal() == False:
                print(game.players)
                print(game.actor)
                print(game.actor.can_showdown(), game.actor.is_showdown_necessary())
SequenceView([PokerPlayer(0, 79.0, 2cJs), PokerPlayer(0, 81.0, ????)])
PokerPlayer(0, 81.0, ????)
True True