@alexjamesmalcolm/poker-odds-machine

Poker odds machine (calculator)

Usage no npm install needed!

<script type="module">
  import alexjamesmalcolmPokerOddsMachine from 'https://cdn.skypack.dev/@alexjamesmalcolm/poker-odds-machine';
</script>

README

poker-odds-machine

Uses Monte Carlo simulation to estimate win probability of any poker hand.
Check it out in action at https://emileindik.com/projects/poker.html (Heroku will probably be sleepy and need to wake up, so give it a minute)

Install

npm install poker-odds-machine

Usage

const Calculator = require('poker-odds-machine').Calculator;
const input = {
    /**
     * Hands of players, following the syntax below.
     * A player can have a partial hand (one card specified) in order
     * to have their next card randomly selected.
     * If hands option not supplied, then numPlayers must be provided.
     */
    hands: ['Ac,Kc', '2h,7d', 'Js'],
    /**
     * If not supplied, defaults to length of hands array.
     * For every player above the length of hands array,
     * a NPC will be created and dealt random cards.
     */
    numPlayers: 4,
    /**
     * Defaults to empty board, which is populated with number of
     * cards specified in boardSize option.
     */
    board: 'Td,2d,Qc',
    /**
     * Defaults to 5.
     */
    boardSize: 5,
    /**
     * Defaults to 2.
     */
    handSize: 2,
    /**
     * Defaults to 1.
     */
    numDecks: 1,
    /**
     * If true, returns additional data containing stats on each player's winning hands.
     * Defaults to false.
     */
    returnHandStats: true,
    /**
     * If true, returns additional data containing stats on each player's tied hands.
     * Defaults to false.
     */
    returnTieHandStats: true,
    /**
     * Number of iterations in the Monte Carlo simulation to perform.
     * The more iterations, the more accurate the returned probabilities,
     * but the longer the calculation takes.
     * Defaults to 1000.
     */
    iterations: 1000000,
};

const c = new Calculator(input);
const s = c.simulate();
console.log(s);
Super verbose sample output
{
  'Ac,Kc': {
    winCount: 280171,
    tieCount: 6678,
    handStats: {
      highCard: { count: 0, percent: 0 },
      pair: { count: 95106, percent: 9.5106 },
      twoPair: { count: 30744, percent: 3.0744 },
      trips: { count: 5180, percent: 0.518 },
      straight: { count: 104479, percent: 10.4479 },
      flush: { count: 43626, percent: 4.3626 },
      fullHouse: { count: 0, percent: 0 },
      quads: { count: 0, percent: 0 },
      straightFlush: { count: 1036, percent: 0.1036 }
    },
    tieHandStats: {
      highCard: { count: 0, percent: 0 },
      pair: { count: 775, percent: 0.0775 },
      twoPair: { count: 1603, percent: 0.1603 },
      trips: { count: 19, percent: 0.0019 },
      straight: { count: 4281, percent: 0.4281 },
      flush: { count: 0, percent: 0 },
      fullHouse: { count: 0, percent: 0 },
      quads: { count: 0, percent: 0 },
      straightFlush: { count: 0, percent: 0 }
    },
    winPercent: 28.0171,
    tiePercent: 0.6678
  },
  '2h,7d': {
    winCount: 284788,
    tieCount: 17209,
    handStats: {
      highCard: { count: 0, percent: 0 },
      pair: { count: 39160, percent: 3.916 },
      twoPair: { count: 140578, percent: 14.0578 },
      trips: { count: 48312, percent: 4.8312 },
      straight: { count: 0, percent: 0 },
      flush: { count: 32751, percent: 3.2751 },
      fullHouse: { count: 22944, percent: 2.2944 },
      quads: { count: 1043, percent: 0.1043 },
      straightFlush: { count: 0, percent: 0 }
    },
    tieHandStats: {
      highCard: { count: 0, percent: 0 },
      pair: { count: 2544, percent: 0.2544 },
      twoPair: { count: 11370, percent: 1.137 },
      trips: { count: 1840, percent: 0.184 },
      straight: { count: 0, percent: 0 },
      flush: { count: 0, percent: 0 },
      fullHouse: { count: 1455, percent: 0.1455 },
      quads: { count: 0, percent: 0 },
      straightFlush: { count: 0, percent: 0 }
    },
    winPercent: 28.4788,
    tiePercent: 1.7209
  },
  Js: {
    winCount: 191810,
    tieCount: 11826,
    handStats: {
      highCard: { count: 0, percent: 0 },
      pair: { count: 54926, percent: 5.4926 },
      twoPair: { count: 33710, percent: 3.371 },
      trips: { count: 11381, percent: 1.1381 },
      straight: { count: 81774, percent: 8.1774 },
      flush: { count: 4881, percent: 0.4881 },
      fullHouse: { count: 4907, percent: 0.4907 },
      quads: { count: 231, percent: 0.0231 },
      straightFlush: { count: 0, percent: 0 }
    },
    tieHandStats: {
      highCard: { count: 0, percent: 0 },
      pair: { count: 464, percent: 0.0464 },
      twoPair: { count: 4559, percent: 0.4559 },
      trips: { count: 366, percent: 0.0366 },
      straight: { count: 5835, percent: 0.5835 },
      flush: { count: 0, percent: 0 },
      fullHouse: { count: 602, percent: 0.0602 },
      quads: { count: 0, percent: 0 },
      straightFlush: { count: 0, percent: 0 }
    },
    winPercent: 19.181,
    tiePercent: 1.1826
  },
  'NPC 1': {
    winCount: 213260,
    tieCount: 24612,
    handStats: {
      highCard: { count: 0, percent: 0 },
      pair: { count: 66905, percent: 6.6905 },
      twoPair: { count: 76426, percent: 7.6426 },
      trips: { count: 21628, percent: 2.1628 },
      straight: { count: 10761, percent: 1.0761 },
      flush: { count: 24377, percent: 2.4377 },
      fullHouse: { count: 12442, percent: 1.2442 },
      quads: { count: 671, percent: 0.0671 },
      straightFlush: { count: 50, percent: 0.005 }
    },
    tieHandStats: {
      highCard: { count: 0, percent: 0 },
      pair: { count: 3783, percent: 0.3783 },
      twoPair: { count: 10083, percent: 1.0083 },
      trips: { count: 1645, percent: 0.1645 },
      straight: { count: 7976, percent: 0.7976 },
      flush: { count: 0, percent: 0 },
      fullHouse: { count: 1125, percent: 0.1125 },
      quads: { count: 0, percent: 0 },
      straightFlush: { count: 0, percent: 0 }
    },
    winPercent: 21.326,
    tiePercent: 2.4612
  }
}

Disclaimer:
I do not bound the value of most of the options, such as handSize and boardSize, on purpose. So have fun messin some shiz up with totally crazy options values, but know I haven't tested this library with outlier options values.

Setup

npm install
npm run build
npm test
┌─────────┬─────────────────┬───────────┬─────────────┬─────────┐
│ (index) │      hand       │  % hypo   │ % estimated │ % error │
├─────────┼─────────────────┼───────────┼─────────────┼─────────┤
│    0    │   'highCard'    │ 17.41192  │   17.4821   │ 0.4031  │
│    1    │     'pair'      │ 43.822546 │   43.8405   │  0.041  │
│    2    │    'twoPair'    │ 23.495536 │   23.4381   │ -0.2445 │
│    3    │     'trips'     │  4.82987  │    4.815    │ -0.3079 │
│    4    │   'straight'    │ 4.619382  │   4.6163    │ -0.0667 │
│    5    │     'flush'     │ 3.025494  │   3.0321    │ 0.2183  │
│    6    │   'fullHouse'   │ 2.596102  │   2.5828    │ -0.5124 │
│    7    │     'quads'     │ 0.168067  │   0.1623    │ -3.4314 │
│    8    │ 'straightFlush' │ 0.031083  │   0.0308    │ -0.9105 │
└─────────┴─────────────────┴───────────┴─────────────┴─────────┘

The test calculates estimated probability for all hands and compares them against their true hypothetical value (% hypo).