uoftcprg/pokerkit

Error Calculating Hand Strength for OmahaEightOrBetterLowHand

Closed this issue · 4 comments

I was trying to use this to calculate Omaha High Low hand strengths but I think I ran into a bug:

import pokerkit as pk

pk.calculate_hand_strength(
    3,
    pk.parse_range('AsAd3d2s'),
    pk.Card.parse('4s8c3s'),
    4,
    5,
    pk.Deck.STANDARD,
    (pk.hands.OmahaEightOrBetterLowHand,),
    sample_count=700,
)

results in this error:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Users\pdw\code\bp\Lib\site-packages\pokerkit\analysis.py", line 403, in calculate_hand_strength
    equities = calculate_equities(
               ^^^^^^^^^^^^^^^^^^^
  File "C:\Users\pdw\code\bp\Lib\site-packages\pokerkit\analysis.py", line 324, in calculate_equities
    for i, equity in chain.from_iterable(map(enumerate, mapper(fn, indices))):
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\pdw\code\bp\Lib\site-packages\pokerkit\analysis.py", line 208, in __calculate_equities_1
    return __calculate_equities_0(
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\pdw\code\bp\Lib\site-packages\pokerkit\analysis.py", line 182, in __calculate_equities_0
    hands = list(
            ^^^^^
  File "C:\Users\pdw\code\bp\Lib\site-packages\pokerkit\hands.py", line 542, in from_game
    raise ValueError(
ValueError: No valid ABCMeta hand can be formed from the hole and board cards.

It seems like the evaluation for low hands isn't properly calculating the "max_hand" as best as I can tell from digging in the code. But I have no idea what to test next - none of my attempts to fix it have worked so far. Any suggestions or am I just doing something wrong?

It works great for OmahaHoldemHand, so thank you for that!

Ah, I think I'm on to something - the problem may be with what happens when the random hands generated can't create a valid low hand:

pk.calculate_equities(
    (pk.parse_range('3d2sAsAd'),
     pk.parse_range('5dJcQcKd'),
    ),
    pk.Card.parse('8c4s3s'),
    4,
    5,
    pk.Deck.STANDARD,
    (pk.hands.OmahaEightOrBetterLowHand,),
    sample_count=700,
)

fails but this one works:

pk.calculate_equities(
    (pk.parse_range('3d2sAsAd'),
     pk.parse_range('5d3cAcKd'),
    ),
    pk.Card.parse('8c4s3s'),
    4,
    5,
    pk.Deck.STANDARD,
    (pk.hands.OmahaEightOrBetterLowHand,),
    sample_count=700,
)

This is the most direct route to triggering the error:

pk.OmahaEightOrBetterLowHand.from_game('5dJcQcKd','8c4s3s')

For my purposes, I managed to work around it by modifying hands.py BoardCombinationHand and HoleBoardCombinationHand to go from:

            except ValueError:
                pass
            else:
                if max_hand is None or hand > max_hand:
                    max_hand = hand

        if max_hand is None:
            raise ValueError(
                (
                    f'No valid {type(cls).__qualname__} hand can be formed'
                    ' from the hole and board cards.'
                ),
            )

        return max_hand

to this:

            except ValueError:
                pass
            else:
                #if max_hand is None or hand > max_hand:
                if hand is not None and (max_hand is None or hand > max_hand): # added by PDW
                    max_hand = hand

        #if max_hand is None:
        if max_hand is None and not cls.low: # added by PDW
            raise ValueError(
                (
                    f'No valid {type(cls).__qualname__} hand can be formed'
                    ' from the hole and board cards.'
                ),
            )

        return max_hand

I'm sure this isn't a valid permanent fix but I'm sharing what I found as the root cause - EightOrBetterLookup adds no entries for non-qualifying hands because it generates a ValueError it tries to create an instance of the Hand class and the init fails on the self.lookup.has_entry(self.cards) call on line 90 of hands.py.

Hi,

Sorry for the late response. Thanks for sharing this!

Also, I find the error message containing 'ABCMeta' to be problematic. It should be the actual hand class.

I will think of ways to fix this... I think the change can be isolated to pokerkit/analysis.py.

I don't have the bandwidth to work on this right now, but will aim to get this done by early November.

Thanks!

No worries! My fix is working for my purposes but I'm mainly using it for the equities/hand strength anyway, so I'm not worried about side effects (yet...). Thanks for your work on this!

This is now fixed in the new alpha release 0.6.0a0.