diff --git a/engine/src/commonMain/kotlin/com/jsjdesigns/poker/core/PreflopChart.kt b/engine/src/commonMain/kotlin/com/jsjdesigns/poker/core/PreflopChart.kt index 528cadb..37aa171 100644 --- a/engine/src/commonMain/kotlin/com/jsjdesigns/poker/core/PreflopChart.kt +++ b/engine/src/commonMain/kotlin/com/jsjdesigns/poker/core/PreflopChart.kt @@ -26,7 +26,10 @@ import kotlin.random.Random */ object PreflopChart { - /** 169 entries keyed by [key]; value is percentile where 0.0 is the best hand. */ + /** + * Indexed by [key]. Only 169 of the [TABLE_SIZE] slots are real hand classes; + * the rest stay at 1.0 as an unreachable sentinel. + */ private val percentiles: DoubleArray by lazy { build() } /** Canonical slot for a starting hand: pairs, then suited, then offsuit. */ @@ -46,8 +49,14 @@ object PreflopChart { private const val TABLE_SIZE = 13 + 169 + 169 /** - * Percentile of this starting hand, 0.0 (aces) to 1.0 (worst). - * A player who "plays the top 20%" enters when this is <= 0.20. + * The share of dealt hands ranked strictly stronger than this one, so a + * player who "plays the top 20%" enters when this is `<= 0.20`. + * + * This is the **start** of the class's band, not its end: aces are 0.0, and + * the worst class (72o) begins at `(1326 - 12) / 1326` ≈ 0.991 because its own + * 12 combinations occupy the remainder. The value therefore never reaches 1.0 + * for a real hand — which is correct for gating, since a class is admitted + * when its band starts inside the range. */ fun percentile(hole: IntArray): Double = percentiles[key(hole)]