{"_id":"@creatiosoft/poker-odds-calculator","name":"@creatiosoft/poker-odds-calculator","dist-tags":{"latest":"1.0.0"},"versions":{"1.0.0":{"name":"@creatiosoft/poker-odds-calculator","version":"1.0.0","description":"Monte Carlo poker odds calculator for NLH, PLO4, PLO5, and PLO6","main":"dist/index.js","types":"dist/index.d.ts","author":{"name":"Creatiosoft"},"scripts":{"build":"tsc","test":"jest","test:coverage":"jest --coverage","prepublishOnly":"npm run build"},"keywords":["poker","odds","calculator","nlh","plo","omaha","monte-carlo"],"license":"MIT","dependencies":{"poker-evaluator":"^2.1.1"},"devDependencies":{"@types/jest":"^29.5.0","@types/node":"^20.0.0","jest":"^29.5.0","ts-jest":"^29.1.0","typescript":"^5.0.0"},"_id":"@creatiosoft/poker-odds-calculator@1.0.0","gitHead":"0a9db1144235de30f0e641f2b3a6e722816b1fd2","_nodeVersion":"20.18.0","_npmVersion":"10.8.2","dist":{"integrity":"sha512-nKw2avqymfAKnDeayWSawNUX7OLdNYpxpKnEhZTV5g/I68Z6Kx9Qud3Hcsm05dWedi2s4bzLQccRPpfnT4MfiQ==","shasum":"f2e548e9ce2e71a38bdbd4d47d41355ef3c48c66","tarball":"https://registry.npmjs.org/@creatiosoft/poker-odds-calculator/-/poker-odds-calculator-1.0.0.tgz","fileCount":52,"unpackedSize":39619,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDbW9LOrC0J8meL1pYOh0NwS8HB3LHxYCxTRXlDwJo8nAIgchr56LUDEceyTfUELpscTq8cxdaqDM7yIJLWGC1mVNQ="}]},"_npmUser":{"name":"creatiosoft-dev","email":"mayank@creatiosoft.com"},"directories":{},"maintainers":[{"name":"creatiosoft-dev","email":"mayank@creatiosoft.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/poker-odds-calculator_1.0.0_1781728245993_0.33534435647436567"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-17T20:30:45.780Z","1.0.0":"2026-06-17T20:30:46.143Z","modified":"2026-06-17T20:30:46.472Z"},"maintainers":[{"name":"creatiosoft-dev","email":"mayank@creatiosoft.com"}],"description":"Monte Carlo poker odds calculator for NLH, PLO4, PLO5, and PLO6","keywords":["poker","odds","calculator","nlh","plo","omaha","monte-carlo"],"author":{"name":"Creatiosoft"},"license":"MIT","readme":"# @creatiosoft/poker-odds-calculator\n\nA TypeScript package that calculates winning probability for poker hands across all major variants using **Monte Carlo simulation**.\n\nSupports **NLH**, **PLO4**, **PLO5**, and **PLO6**.\n\n---\n\n## Table of Contents\n\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [API Reference](#api-reference)\n- [Understanding the Result](#understanding-the-result)\n- [What is Monte Carlo Simulation?](#what-is-monte-carlo-simulation)\n- [How We Use It](#how-we-use-it)\n- [Why Not Use poker-evaluator's Built-in Odds?](#why-not-use-poker-evaluators-built-in-odds)\n- [Supported Variants](#supported-variants)\n- [Card Format](#card-format)\n- [Accuracy vs Iterations](#accuracy-vs-iterations)\n\n---\n\n## Installation\n\n```bash\nnpm install @creatiosoft/poker-odds-calculator\n```\n\n---\n\n## Quick Start\n\n```typescript\nimport { calculateOdds, calculateTableOdds } from '@creatiosoft/poker-odds-calculator';\n\n// How likely am I to win with pocket Aces against 2 unknown opponents?\nconst result = calculateOdds({\n  variant: 'NLH',\n  holeCards: ['Ah', 'As'],\n  communityCards: [],\n  playerCount: 3,\n  iterations: 5000\n});\n\nconsole.log(result.winRate);      // e.g. 0.73  → 73% chance to win outright\nconsole.log(result.splitRates);   // e.g. [{ rate: 0.01, ways: 2 }] → 1% chance to split with 1 player\n```\n\n---\n\n## API Reference\n\n### `calculateOdds(input)` — Single Player\n\nUse this when **only your cards are known** and opponents' cards are random (the most common real-time table scenario).\n\n```typescript\ncalculateOdds({\n  variant:        'PLO4',          // game variant (see Supported Variants)\n  holeCards:      ['Ah','As','Kh','Kd'],  // your hole cards\n  communityCards: ['2c','7h','Jd'],       // board cards dealt so far (0–5)\n  playerCount:    3,               // total players including you\n  iterations:     5000             // Monte Carlo cycles (optional, default 1000)\n}): PlayerOdds\n```\n\n**Returns:** `PlayerOdds` — your odds only (player 0).\n\n---\n\n### `calculateTableOdds(input)` — All Players Known\n\nUse this when **all hole cards are visible** — e.g. a run-it-out, a showdown analysis, or a training tool.\n\n```typescript\ncalculateTableOdds({\n  variant:        'NLH',\n  hands: [\n    ['Ah', 'As'],   // player 0\n    ['Kh', 'Kd'],   // player 1\n    ['Qh', 'Qd'],   // player 2\n  ],\n  communityCards: ['2c', '7h', 'Jd'],\n  iterations:     5000\n}): TableOdds\n```\n\n**Returns:** `TableOdds` — an array of `PlayerOdds`, one per player, in the same order as `hands`.\n\n---\n\n## Understanding the Result\n\n### `PlayerOdds`\n\n```typescript\n{\n  winRate:    0.72,   // fraction of simulated games this player wins outright\n  splitRates: [\n    { rate: 0.03, ways: 2 },   // 3% of games end in a 2-way split\n    { rate: 0.01, ways: 3 },   // 1% of games end in a 3-way split\n  ]\n}\n```\n\n#### `winRate`\nThe fraction of iterations where **this player won the entire pot outright** — no ties, no splits. A value of `0.72` means the player wins 72 out of every 100 simulated hands.\n\n#### `splitRates`\nAn array describing **how often the pot is split** and **how many players share it**.\n\n| Field | Type | Meaning |\n|---|---|---|\n| `rate` | `number` | Fraction of iterations where the pot was split this way |\n| `ways` | `number` | How many players split the pot (2 = heads-up tie, 3 = three-way tie, …) |\n\n**Example — reading a split result:**\n```\nwinRate:    0.68\nsplitRates: [{ rate: 0.04, ways: 2 }]\n```\nThis means:\n- 68% of the time → you win the whole pot\n- 4% of the time → you and exactly one other player tie (split 50/50)\n- 28% of the time → you lose\n\n**Expected pot share formula:**\n```\nexpectedShare = winRate + Σ (splitRate.rate / splitRate.ways)\n             = 0.68 + (0.04 / 2)\n             = 0.68 + 0.02\n             = 0.70   →  you expect 70% of the pot on average\n```\n\n#### `TableOdds`\n```typescript\n{\n  players: [PlayerOdds, PlayerOdds, ...]  // same order as the hands[] you passed in\n}\n```\n\nThe `winRate` values across all players **do not sum to 1** — splits account for the remainder. But `winRate + splitContribution` summed across all players **does** equal 1 (the whole pot is always distributed).\n\n---\n\n## What is Monte Carlo Simulation?\n\nMonte Carlo simulation is a technique for estimating probabilities by **running a scenario thousands of times with random inputs** and counting outcomes.\n\nIn poker, the number of possible combinations of cards is astronomically large. For example, dealing 2 unknown opponents on a blank board has over 1 billion possible runouts. Calculating exact probabilities by enumerating every combination would take too long for real-time use.\n\n**Monte Carlo solves this by sampling:**\n\n> Instead of checking all 1 billion possibilities, deal out the remaining cards randomly 5,000 times. Count how often you win. 5,000 samples gives you a result accurate to within ~1%.\n\n### Analogy\n\nImagine you want to know the probability of rolling two dice and getting a sum of 7. You could:\n- **Exact method:** list all 36 combinations, count the 6 that sum to 7 → 6/36 = 16.7%\n- **Monte Carlo:** roll the dice 10,000 times, count the 7s → you'll get roughly 16.7%\n\nFor poker, the \"exact method\" is too slow for real-time use. Monte Carlo gives us a fast, accurate-enough answer.\n\n---\n\n## How We Use It\n\nHere is exactly what happens inside each call to `calculateOdds`:\n\n### Step 1 — Build the Remaining Deck\n\nWe start with a full 52-card deck and remove every card that is already known (your hole cards + any community cards already dealt).\n\n```\nFull deck (52 cards)\n− your hole cards (2–6 cards)\n− community cards already on board (0–5 cards)\n= remaining deck (41–50 cards)\n```\n\n### Step 2 — Run N Iterations\n\nFor each iteration:\n\n**1. Shuffle** the remaining deck using the Fisher-Yates algorithm (the same unbiased shuffle used in `poker-evaluator`).\n\n**2. Deal** cards to fill in the unknowns:\n- Each opponent gets hole cards dealt from the top of the shuffled deck\n- The community cards are completed to 5 if not already\n\n**3. Evaluate** each player's best hand using the correct rule for the variant (see below).\n\n**4. Find the winner** — the player with the highest hand value wins. If multiple players have equal values, the pot is split.\n\n**5. Record** the result — increment that player's win or split counter.\n\n### Step 3 — Calculate Rates\n\nAfter all iterations:\n```\nwinRate  = wins[player] / totalIterations\nsplitRate = splits[player][ways-2] / totalIterations\n```\n\n### Hand Evaluation per Variant\n\nThis is where our package differs from `poker-evaluator`'s built-in odds calculator:\n\n| Variant | Rule | How we evaluate |\n|---|---|---|\n| NLH | Best 5 from any 7 cards | Pass all 7 cards to `evalHand` — it picks the best 5 |\n| PLO4 | Exactly 2 hole + 3 board | Generate all C(4,2)=6 hole pairs × C(5,3)=10 board triples = **60 combinations**, evaluate each, take the best |\n| PLO5 | Exactly 2 hole + 3 board | C(5,2)=10 × C(5,3)=10 = **100 combinations** per player |\n| PLO6 | Exactly 2 hole + 3 board | C(6,2)=15 × C(5,3)=10 = **150 combinations** per player |\n\nFor NLH the library's own `evalHand` does the work. For PLO we enumerate every legal 2+3 combination ourselves, call `evalHand` on each 5-card hand, and take the highest value.\n\n### Visual Walkthrough — One Iteration (PLO4, 2 Players)\n\n```\nYour hand : [Ah, As, Kh, Kd]      (known)\nBoard     : [2c, 7h, Jd]          (known, flop)\nDeck left : 45 cards\n\nShuffle deck → [Qc, 3h, 9s, Tc, 6d, ...]\n\nDeal opponent: Qc, 3h  (first 2 from shuffled deck)\nComplete board: 9s, Tc  (next 2 cards → board = [2c,7h,Jd,9s,Tc])\n\nEvaluate YOUR hand (PLO4 — must use exactly 2 hole + 3 board):\n  Ah+As + 2c+7h+Jd → evalHand([Ah,As,2c,7h,Jd]) → one pair aces\n  Ah+As + 2c+7h+9s → evalHand([Ah,As,2c,7h,9s]) → one pair aces\n  Ah+As + 2c+7h+Tc → evalHand([Ah,As,2c,7h,Tc]) → one pair aces\n  Ah+Kh + 2c+7h+Jd → evalHand([Ah,Kh,2c,7h,Jd]) → high card\n  Ah+As + Jd+9s+Tc → evalHand([Ah,As,Jd,9s,Tc]) → one pair aces\n  ... (60 total combos)\n  Best value for you → one pair aces (value: 3553)\n\nEvaluate OPPONENT hand [Qc, 3h] (PLO4):\n  Qc+3h + 2c+7h+Jd → high card queen\n  ... (60 combos)\n  Best value for opponent → high card queen (value: 1210)\n\n3553 > 1210 → YOU WIN this iteration\nwins[0]++\n```\n\nRepeat 5000 times → `winRate = wins[0] / 5000`\n\n---\n\n## Why Not Use poker-evaluator's Built-in Odds?\n\n`poker-evaluator` ships `winningOddsForPlayer` and `winningOddsForTable` but they are **NLH-only**. Two lines in their source code make this impossible to reuse for PLO:\n\n```javascript\n// poker-evaluator source — hardcoded 2 hole cards, no way to change\nvar card1 = numHands[p][0] ?? startingDeck[deckPosition++];\nvar card2 = numHands[p][1] ?? startingDeck[deckPosition++];\nholeCards.push([card1, card2]);  // ← always 2 cards, PLO needs 4/5/6\n\n// NLH rule: best 5 from any 7\nevalHand([...hand, ...communityCards]).value  // ← wrong for PLO\n// PLO rule: must use exactly 2 from hole + 3 from board\n```\n\nWe **reuse** `evalHand` (the fast O(1) lookup table) and write our own loop around it that correctly handles variable hole card counts and the PLO 2+3 constraint.\n\n---\n\n## Supported Variants\n\n| Variant | Hole Cards | Evaluation Rule |\n|---|---|---|\n| `NLH` | 2 | Best 5 from any 7 (hole + board) |\n| `PLO4` | 4 | Exactly 2 from hole + exactly 3 from board |\n| `PLO5` | 5 | Exactly 2 from hole + exactly 3 from board |\n| `PLO6` | 6 | Exactly 2 from hole + exactly 3 from board |\n\n---\n\n## Card Format\n\n```\n<rank><suit>\n\nRanks : A  K  Q  J  T  9  8  7  6  5  4  3  2\nSuits : s (spades)  h (hearts)  d (diamonds)  c (clubs)\n\nExamples:\n  'As' → Ace of Spades\n  'Kh' → King of Hearts\n  'Td' → Ten of Diamonds\n  '2c' → Two of Clubs\n```\n\n---\n\n## Accuracy vs Iterations\n\nBoth `winRate` and `splitRates` become more accurate as you increase `iterations`. More iterations = smaller margin of error but slower response.\n\n| Iterations | Typical error | Time (NLH) | Time (PLO4) | Recommended for |\n|---:|---:|---:|---:|---|\n| 1 000 | ±2–3% | ~13 ms | ~200 ms | Development / unit tests |\n| 5 000 | ±1% | ~44 ms | ~990 ms | Real-time display at the table |\n| 10 000 | ±0.5% | ~100 ms | ~2 000 ms | High-accuracy analysis |\n| 100 000 | ±0.1% | ~1 s | ~20 s | Pre-computation / batch jobs |\n\nFor **real-time use** in a running game, 5 000 iterations is the recommended balance — fast enough to feel instant for NLH, and accurate to within 1%.\n\nFor PLO at real-time speed, consider running the simulation in a **Node.js worker thread** so it does not block the main event loop.\n\n---\n\n## Full Example\n\n```typescript\nimport { calculateOdds, calculateTableOdds } from '@creatiosoft/poker-odds-calculator';\n\n// ── Example 1: Your hand only (most common) ──────────────────────────────────\n\nconst myOdds = calculateOdds({\n  variant: 'PLO4',\n  holeCards: ['Ah', 'As', 'Kh', 'Kd'],   // double-suited aces and kings\n  communityCards: ['2c', '7h', 'Jd'],     // flop is out\n  playerCount: 3,                          // you + 2 opponents\n  iterations: 5000\n});\n\nconsole.log(`Win rate   : ${(myOdds.winRate * 100).toFixed(1)}%`);\nmyOdds.splitRates.forEach(s =>\n  console.log(`${s.ways}-way split: ${(s.rate * 100).toFixed(1)}%`)\n);\n\n// ── Example 2: Full table (all hands known) ──────────────────────────────────\n\nconst table = calculateTableOdds({\n  variant: 'NLH',\n  hands: [\n    ['Ah', 'As'],   // player 0 — pocket aces\n    ['Kh', 'Kd'],   // player 1 — pocket kings\n  ],\n  communityCards: [],   // preflop\n  iterations: 10000\n});\n\ntable.players.forEach((p, i) =>\n  console.log(`Player ${i}: ${(p.winRate * 100).toFixed(1)}% win`)\n);\n// Player 0: 81.2% win\n// Player 1: 17.8% win\n```\n","readmeFilename":"README.md","_rev":"1-d47db8f30f0847debd5afef358362585"}