Source code for maverick.utils.holding_strength
from typing import TYPE_CHECKING, Optional
from functools import partial
if TYPE_CHECKING: # pragma: no cover
from ..card import Card
from .scoring import find_highest_scoring_hand
__all__ = ["estimate_holding_strength"]
[docs]
def estimate_holding_strength(
holding: list["Card"],
*,
community_cards: Optional[list["Card"]] = None,
n_simulations: int = 1000,
n_players: int = 8,
n_private: int = 0,
n_community_cards_total: int = 5,
) -> float:
"""
Estimate the holding strength as the relative linelihood of winning against
n_players - 1 opponents.
If you are pre-flop, provide only your two hole cards in `holding`.
If you are post-flop, provide your hole cards plus the community cards on the
table in `community_cards`.
Parameters
----------
holding : list[Card]
The player's holding cards.
n_simulations : int, optional
The number of Monte Carlo simulations to run (default is 1000).
n_players : int, optional
The total number of players at the table including the player (default is 8).
community_cards : list[Card], optional
The community cards already on the table. If provided, these will be used in the
simulations.
n_community_cards_total : int, optional
The total number of community cards in the game (default is 5).
n_private : int, optional
The number of private cards that must be included in the hand (default is 0).
A value of 0 means any number of private cards can be used.
Returns
-------
float
The relative linelihood of winning as a value in the unit interval [0, 1].
Notes
-----
The estimated strength is only as accurate as the number of simulations run. Also, it is
only the relative linelihood of winning mathematically, and does not take into account
betting strategies, player tendencies, or other psychological factors.
"""
from maverick import Deck
community_cards = community_cards or []
n_opponents = n_players - 1
n_holding_cards = len(holding)
n_community_cards = len(community_cards)
n_community_cards_req = n_community_cards_total - n_community_cards
n_wins = 0
scorer = partial(find_highest_scoring_hand, n_private=n_private)
# run simulations
for _ in range(n_simulations):
# start a new deck for each simulation
deck_sim = Deck.standard_deck().shuffle()
# remove known cards
deck_sim.remove_cards(holding + community_cards)
# deal opponent holdings
opponent_holdings = [deck_sim.deal(n_holding_cards) for _ in range(n_opponents)]
# deal missing community cards
if n_community_cards_req > 0:
community_cards_full = community_cards + deck_sim.deal(
n_community_cards_req
)
else:
community_cards_full = community_cards
# compare scores
score = scorer(holding, community_cards_full)[-1]
if all(score >= scorer(h, community_cards_full)[-1] for h in opponent_holdings):
n_wins += 1
return n_wins / n_simulations