Skip to content

Commit

Permalink
Add ICM calculation
Browse files Browse the repository at this point in the history
  • Loading branch information
AussieSeaweed committed Jun 13, 2024
1 parent cf214e7 commit 57cc656
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Version 0.5.2 (June 13, 2024)
**Added**

- Added ``pokerkit.state.ChipsPushing.pot_index``, ``pokerkit.state.ChipsPushing.board_index``, and ``pokerkit.state.ChipsPushing.hand_type_index`` attributes to provide information on what portion of the pot was pushed.
- Added ICM calculation ``pokerkit.analysis.calculate_icm`` function.

Version 0.5.1 (May 24, 2024)
----------------------------
Expand Down
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
project = 'PokerKit'
copyright = '2023, University of Toronto Computer Poker Student Research Group'
author = 'University of Toronto Computer Poker Student Research Group'
release = '0.5.1'
release = '0.5.2'

# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
Expand Down
2 changes: 2 additions & 0 deletions pokerkit/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
'BringInPosting',
'calculate_equities',
'calculate_hand_strength',
'calculate_icm',
'Card',
'CardBurning',
'CardsLike',
Expand Down Expand Up @@ -105,6 +106,7 @@
from pokerkit.analysis import (
calculate_equities,
calculate_hand_strength,
calculate_icm,
parse_range,
Statistics,
)
Expand Down
40 changes: 40 additions & 0 deletions pokerkit/analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -513,3 +513,43 @@ def payoff_stderr(self) -> float:
:return: The payoff standard error.
"""
return self.payoff_stdev / sqrt(self.sample_count)


def calculate_icm(
payouts: Iterable[float],
chips: Iterable[float],
) -> tuple[float, ...]:
"""Calculate the independent chip model (ICM) values.
>>> calculate_icm([70, 30], [50, 30, 20]) # doctest: +ELLIPSIS
(45.17..., 32.25, 22.57...)
>>> calculate_icm([50, 30, 20], [25, 87, 88]) # doctest: +ELLIPSIS
(25.69..., 37.08..., 37.21...)
>>> calculate_icm([50, 30, 20], [21, 89, 90]) # doctest: +ELLIPSIS
(24.85..., 37.51..., 37.63...)
>>> calculate_icm([50, 30, 20], [198, 1, 1]) # doctest: +ELLIPSIS
(49.79..., 25.10..., 25.10...)
:param payouts: The payouts.
:param chips: The players' chips.
:return: The ICM values.
"""
payouts = tuple(payouts)
chips = tuple(chips)
chip_sum = sum(chips)
chip_percentages = [chip / chip_sum for chip in chips]
icms = [0.0] * len(chips)

for player_indices in permutations(range(len(chips)), len(payouts)):
probability = 1.0
denominator = 1.0

for player_index in player_indices:
chip_percentage = chip_percentages[player_index]
probability *= chip_percentage / denominator
denominator -= chip_percentage

for payout, player_index in zip(payouts, player_indices):
icms[player_index] += payout * probability

return tuple(icms)

0 comments on commit 57cc656

Please sign in to comment.