logo

Babylon.js Market

PokerHandEval

tabletop-casino · poker

PokerHandEval

1
Unlock

Install with the CLI:

bjs download PokerHandEval

PokerHandEval

Ranks poker hands and resolves a showdown to winner(s) — the evaluator every other poker component reads.

What it does

PokerHandEval is the ranking math for a poker table, kept apart from the dealing, betting, and card art. The core takes card ids in the deck-asset format "<rank>_of_<suit>" (queen_of_spades, 10_of_diamonds) and answers four questions: what is this card (parseCard), how good are these exact five (classifyFive), what's the best five out of seven (evaluateHand), and who won the table (evaluateShowdown). Ranking covers High Card through Royal Flush with full tie-breaking — kickers, the ace-low wheel (A-2-3-4-5 counts as a Five-high straight), and a base-15 packed score so any higher hand always outscores a lower one. evaluateShowdown adds a hole-card tiebreaker, so two players with the same five-card hand are split by their highest hole card, then the next.

Each result is deterministic: the same cards always produce the same rank, score, and describeHand label, so a hand can be replayed or asserted in a test with no table running.

The PokerHandEvalSystem is the bus seam. It listens for poker.showdown.request — the seated group ranges, the flat dealt-card array, and which groups folded — runs evaluateShowdown, and emits poker.showdown.resolved with the per-group results and the winner list. A deal sequencer or pot component asks for a showdown and listens for the answer instead of calling the evaluator itself.

Use it in a scene

A scene is just data — a list of entities, each with its components. At startup the SceneLoader turns this JSON into a live world; edit the file and reload to rebuild it.

Fastest path

bjs download scene PokerHandEval

Pulls this exact scene into your project and runs it — no copy-paste. Add --all to grab the components and assets it needs too.

Or build it from scratch with the bjs CLI:

  1. 1Scaffold a project
    npm create @babylonjsmarket/arcade@latest my-game

    World, renderer, and dev server — ready to run.

  2. 2Install dependencies
    cd my-game && npm install
  3. 3Add PokerHandEval
    bjs download PokerHandEval

    Copies its source into src/ so the scene resolves.

    First time? Run bjs login once.

  4. 4Paste the scene into src/scenes/arcade-room.ts and run
    npm run dev

    SceneLoader builds the world from the JSON; reload to rebuild.

JSON
{
  "Evaluator": {
    "components": {
      "PokerHandEval": {
        "emitResults": true
      }
    }
  }
}

Then resolve a showdown from any system:

TypeScript
import { PokerHandEvalInputEvents, PokerHandEvalEvents } from './PokerHandEval'

eventBus.emit(PokerHandEvalInputEvents.REQUEST, {
  groups: {
    player: { start: 0, count: 2 },
    npc0:   { start: 2, count: 2 },
    river:  { start: 4, count: 5 },
  },
  cardIds: [
    'ace_of_spades', 'ace_of_hearts',
    '2_of_clubs', '2_of_diamonds',
    '7_of_hearts', '8_of_clubs', '9_of_diamonds', 'jack_of_spades', 'king_of_clubs',
  ],
  foldedIds: [],
})

eventBus.on(PokerHandEvalEvents.RESOLVED, ({ winners, results }) => {
  // winners → ['player']; results['player'].description → 'Pair of Aces, …'
})

Or skip the bus and call the core directly for a single hand:

TypeScript
import { evaluateHand } from './PokerHandEval'

evaluateHand(
  ['ace_of_hearts', 'king_of_hearts'],
  ['queen_of_hearts', '9_of_hearts', '4_of_hearts', '4_of_clubs', '2_of_spades'],
).rank // HandRank.Flush

Props

  • emitResults (boolean, default true) — echo the full per-group result map on the resolved event. Set false to send only the winners list, a lighter payload for pot-only flows.

Events

  • Emits poker.showdown.resolved (PokerHandEvalEvents.RESOLVED) after each request — { results, winners }. results is keyed by group id ({ name, description, winner }), or {} when emitResults is false; winners lists the winning group ids (several on a tie).
  • Listens for poker.showdown.request (PokerHandEvalInputEvents.REQUEST) — { groups, cardIds, foldedIds? }. groups maps each group id to its { start, count } range in cardIds; the river group is the shared community cards. Requests missing groups or cardIds are dropped.

Core surface

  • parseCard(id){ rank, suit } — rank is 2–14 (ace high).
  • classifyFive(cards){ rank, score } for exactly five Cards.
  • describeHand(cards, rank) → label, e.g. "Full House, Tens over Fours".
  • evaluateHand(holeCards, riverCards) → best-five HandResult from any total of five or more ids (fewer than five returns a degenerate High Card).
  • evaluateShowdown(groups, cardIds, foldedIds)Record<groupId, { name, description, winner }>.

Dependencies

None. The evaluator is the base other poker components build on; it needs no sibling component.

Notes

  • One evaluator per scene: the System routes a request into the first entity carrying a PokerHandEval instance.
  • The river group id is reserved — its cards are the shared community cards added to every seated group, and it is never evaluated as a hand of its own.
  • Ace plays both high and low: an ace-high Broadway straight outranks the ace-low wheel, and the wheel's describeHand label reports Five high, not Ace high.
  • Card ids must match the deck-asset format exactly; an unrecognized rank string parses to an undefined rank.

More like this

PokerTableDirector
BallReset
CardFan
DeckDealer
GameConfig
Goal
MissionDirector
PokerAI
PokerAIBill
PokerAICali
PokerAIRandy
PokerAIShark
PokerAISurge
PokerAITilt
PokerBetting
PokerHUD
PokerInput
PokerMultiplayer
PokerSeating
PokerTableCards
SoccerDirector
TurnPacer
WaveDirector

Was this page helpful?

We read every note — tell us what's working and what isn't.

↑↓ NavigateEnter SelectEsc CloseCtrl+K Open Search