Files
holdem_poker/assets/cards/back.svg
T
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

88 lines
4.4 KiB
XML

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
version="1.1" width="360" height="540" viewBox="0 0 360 540">
<defs>
<!-- Interlocking lattice, rotated 45deg for the classic diagonal weave -->
<pattern id="lattice" width="36" height="36" patternUnits="userSpaceOnUse"
patternTransform="rotate(45 0 0)">
<rect width="36" height="36" fill="#a81d24"/>
<path d="M 18,0 L 18,36 M 0,18 L 36,18" stroke="#c9545b"
stroke-width="1.5" fill="none"/>
<circle cx="18" cy="18" r="6" fill="none" stroke="#c9545b" stroke-width="1.5"/>
<circle cx="18" cy="18" r="1.8" fill="#c9545b"/>
<g fill="#c9545b">
<circle cx="0" cy="0" r="3.2"/><circle cx="36" cy="0" r="3.2"/>
<circle cx="0" cy="36" r="3.2"/><circle cx="36" cy="36" r="3.2"/>
</g>
</pattern>
<!-- Centre glow so the medallion sits on a lit field -->
<radialGradient id="vignette" cx="50%" cy="50%" r="62%">
<stop offset="0%" stop-color="#c4353d" stop-opacity="0.85"/>
<stop offset="55%" stop-color="#c4353d" stop-opacity="0.20"/>
<stop offset="100%" stop-color="#8f1218" stop-opacity="0.75"/>
</radialGradient>
<clipPath id="panelClip">
<rect x="16" y="16" width="328" height="508" rx="19" ry="19"/>
</clipPath>
<g id="spade"><path d="M 0,-19 C -5,-9 -18,-3 -18,6 C -18,12 -13,15.5 -8.5,15.5 C -5,15.5 -2,13.5 0,10 C 2,13.5 5,15.5 8.5,15.5 C 13,15.5 18,12 18,6 C 18,-3 5,-9 0,-19 Z"/><path d="M -1,8 C -1,14 -4,18 -7.5,19.5 L 7.5,19.5 C 4,18 1,14 1,8 Z"/></g>
<path id="heart" d="M 0,19 C -5,12 -18,3 -18,-7 C -18,-14.5 -12,-18.5 -7,-18.5 C -3,-18.5 -0.5,-15.5 0,-12 C 0.5,-15.5 3,-18.5 7,-18.5 C 12,-18.5 18,-14.5 18,-7 C 18,3 5,12 0,19 Z"/>
<path id="diamond" d="M 0,-20 C 4,-10 9,-4 14,0 C 9,4 4,10 0,20 C -4,10 -9,4 -14,0 C -9,-4 -4,-10 0,-20 Z"/>
<g id="club">
<circle cx="0" cy="-9" r="9"/><circle cx="-10" cy="5" r="9"/>
<circle cx="10" cy="5" r="9"/><path d="M -1.2,4 C -1.2,11 -4,16 -7.5,19 L 7.5,19 C 4,16 1.2,11 1.2,4 Z"/>
</g>
<!-- Corner ornament: a small gold lozenge cluster -->
<g id="ornament" fill="#e3c179">
<path d="M 0,-9 L 5,0 L 0,9 L -5,0 Z"/>
<circle cx="0" cy="-13.5" r="2"/><circle cx="0" cy="13.5" r="2"/>
<circle cx="-9" cy="0" r="2"/><circle cx="9" cy="0" r="2"/>
</g>
</defs>
<!-- Card body: identical geometry to the face cards -->
<rect x="0.5" y="0.5" width="359" height="539" rx="29.944447" ry="29.944447"
fill="#ffffff" stroke="#000000" stroke-width="1"/>
<!-- Patterned panel -->
<g clip-path="url(#panelClip)">
<rect x="16" y="16" width="328" height="508" fill="#8f1218"/>
<rect x="16" y="16" width="328" height="508" fill="url(#lattice)"/>
<rect x="16" y="16" width="328" height="508" fill="url(#vignette)"/>
</g>
<!-- Gold double frame -->
<rect x="16" y="16" width="328" height="508" rx="19" ry="19"
fill="none" stroke="#e3c179" stroke-width="2.5"/>
<rect x="24" y="24" width="312" height="492" rx="13" ry="13"
fill="none" stroke="#e3c179" stroke-width="1" opacity="0.75"/>
<!-- Corner ornaments -->
<use xlink:href="#ornament" x="0" y="0" transform="translate(52,64)"/>
<use xlink:href="#ornament" x="0" y="0" transform="translate(308,64)"/>
<use xlink:href="#ornament" x="0" y="0" transform="translate(52,476)"/>
<use xlink:href="#ornament" x="0" y="0" transform="translate(308,476)"/>
<!-- Central medallion -->
<g>
<ellipse cx="180" cy="270" rx="86" ry="104" fill="#8f1218" opacity="0.55"/>
<ellipse cx="180" cy="270" rx="80" ry="98" fill="#faf4e6"
stroke="#e3c179" stroke-width="3"/>
<ellipse cx="180" cy="270" rx="72" ry="90" fill="none"
stroke="#e3c179" stroke-width="1" opacity="0.8"/>
<!-- Four suits in a diamond arrangement -->
<use xlink:href="#spade" transform="translate(180,206) scale(0.82)" fill="#1a1a1a"/>
<use xlink:href="#diamond" transform="translate(180,334) scale(0.82)" fill="#c8102e"/>
<use xlink:href="#heart" transform="translate(130,270) scale(0.82)" fill="#c8102e"/>
<use xlink:href="#club" transform="translate(230,270) scale(0.82)" fill="#1a1a1a"/>
<!-- Tiny centre pip to tie the arrangement together -->
<circle cx="180" cy="270" r="4.5" fill="#e3c179"/>
<circle cx="180" cy="270" r="1.8" fill="#8f1218"/>
</g>
</svg>