Commit Graph

2 Commits

Author SHA1 Message Date
thejayman77 7382bc8638 Fix the fold experience: honest actions, matched state, action identity
Reported as "folding looks broken". It was five separate defects.

1. Fold silently became Check. sanitise() rewrote FOLD to CHECK whenever
   checking was free, so a UI showing a Fold button folded nothing and the
   player kept being asked to act. Folding is legal at any turn — it simply
   mucks — so FOLD is now honoured literally. The engine must never substitute a
   different action than the caller asked for. The reverse rewrite (an illegal
   CHECK facing a bet becoming FOLD) is legitimate and stays.

   Safe by construction: no bot emits FOLD when it can check, and the 20k-hand
   simulation reproduces byte-identical numbers (289.12 / 113.19 / -195.64).

2. Snapshot and offer could describe different moments. The 32-deep frame
   channel let the engine race far ahead of the animation, so the action on
   offer could belong to a later street, or another hand. The channel is now
   RENDEZVOUS, capping the engine at one frame ahead, and UiState.liveOffer()
   only surfaces an offer whose hand and street match the table on screen.

3. Stale and double taps could act on a later decision. DecisionOffer now
   carries a token; submit() requires it and rejects anything stale, so a second
   tap is dropped rather than applied to whatever comes next.

4. A real fold was invisible. The hero kept normal cards and no folded state, so
   a correctly processed fold looked like a bug. Cards now dim, FOLDED shows in
   red, and the action bar explains the player is sitting out.

5. Non-atomic UiState updates from two coroutines now use update {}.

Also: Fold is hidden when checking is free (folding a free hand is never
correct, and offering it invites an accidental muck), and onCleared no longer
calls human.cancel() — viewModelScope is already cancelled by then so the launch
never ran; scope cancellation already propagates into act()'s finally.

The delivery tests were weak as charged: no slow consumer, and not the app's
capacity. Replaced with a genuinely slow consumer measuring how far the engine
runs ahead — asserting <= 1 on RENDEZVOUS, and > 1 on a 32-deep buffer to
document why the buffer was removed.

Verified on the emulator (physical device untouched): folded facing a bet, hero
showed FOLDED, was never asked again that hand, and play advanced to hand 2.

Tests: 55 -> 62, green on jvmTest and testAndroidHostTest.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-25 21:04:44 -04:00
thejayman77 479be1f6b9 Initial commit: Hold'em engine, bots, and simulation harness
Kotlin Multiplatform engine (JVM target only for now; androidTarget and
iosArm64 slot in without touching commonMain).

Core:
- HandEvaluator: single-pass 5-7 card evaluation, ~24M evals/sec. Verified
  exhaustively against published frequencies for all 2,598,960 five-card hands.
- Equity: Monte Carlo with ties split. PreflopChart ranks the 169 starting
  hands using all-in equity plus an explicit playability adjustment, so
  looseness means "plays the top N%".
- Table: no-limit betting rounds, side pots, odd-chip splits, uncalled-bet
  refunds, and incomplete (short all-in) raises that correctly do not reopen
  betting.

Bots:
- SkillLevel and PlayStyle are orthogonal axes. Skill drives decision quality
  (rollout accuracy, pot-odds discipline, position awareness, error rate);
  style drives bluffing, sandbagging, aggression, tightness.
- BotMood gives tilt that persists between hands and decays.
- OpponentModel lets Advanced/Expert exploit habitual bettors.
- MathBot emits a DecisionTrace of the numbers behind each decision, which the
  coach will later hand to an LLM to narrate. The LLM never does poker maths.

Simulator:
- 2,200-3,400 hands/sec. Deck RNG is separate from bot RNGs so rollout counts
  cannot shift the deal.
- Controlled skill-ladder test asserts the difficulty gradient is monotonic:
  73.9 / 53.9 / 27.6 / -155.4 bb/100 over 50k hands.

Assets: 52 CC0 English-pattern card faces plus generated backs.

Tests: 30 passing (evaluator, table rules, pre-flop chart).

Known open: win-rate magnitudes ~10x realistic and several profiles looser
than their labels. Tuning, not correctness.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-25 04:36:03 -04:00