logo

Babylon.js Market

PokerAI

tabletop-casino · poker-ai

PokerAI

Listens toPokerBetting
Talks toPokerBetting
1
Unlock

Install with the CLI:

bjs download PokerAI

PokerAI

The shared poker-AI substrate — hand equity, starting-hand tiers, weighted action choice, and card formatting — that the personality strategies build on.

What it does

PokerAI is the base library a poker NPC reasons over. It sits on top of two siblings: PokerHandEval ranks the cards, PokerBetting owns the chips and the turn machine. PokerAI turns those into the four numbers a brain reads before it acts.

  • Equity. estimateEquity(holeCards, communityCards) reads the made-hand rank off the evaluator and maps it to a rough win chance (0–1). Pre-flop (no community cards) it returns 0 — a two-card hand has no made rank yet, so use the tier read instead. equityForRank(rank) is the underlying lookup, from 0.10 for High Card to 1.0 for a Royal Flush.
  • Pot odds. potOdds(pot, costToCall) returns the fraction of the resulting pot a call would cost. Compare it against equity: ahead of the odds is a value spot, behind them is a fold.
  • Starting-hand tier. classifyStartingHand([a, b]) sorts a two-card hand into premium | strong | moderate | weak | trash with Sklansky-like groupings — pocket pairs, ace- and king-high combos, suited connectors. Fewer than two cards is trash.
  • Action choice. pickAction(available, preferred) returns the first preferred action that's on the menu, falling back to the first available. weightedPick(available, weights, rng?) is a weighted random draw over the actions that are both offered and weighted.

Card ids use the deck-asset format "<rank>_of_<suit>". shortCard("queen_of_spades")"Q♠"; shortHand(["ace_of_spades", "king_of_hearts"])"A♠K♥".

The core is deterministic against its inputs. The one source of randomness, weightedPick, takes its generator as the rng parameter — pin it in a test, seed it from a personality — and only falls back to Math.random when a caller omits it.

PokerAISystem is the dependency-free default brain. It listens for the betting director's poker.actionRequired menu, runs a baseline strategy assembled from the helpers above (tier pre-flop, equity vs. pot odds post-flop, scaled by aggression), writes its reasoning back onto the context for a HUD, and emits poker.turnAction. A scene can run NPCs with no concrete personality wired in.

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 PokerAI

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 PokerAI
    bjs download PokerAI

    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
{
  "Brain": {
    "components": {
      "PokerAI": {
        "seatIds": ["npc0", "npc1"],
        "aggression": 0.5
      }
    }
  }
}

The example scene pairs it with PokerHandEval and PokerBetting: the director offers a menu on poker.actionRequired, PokerAI answers with poker.turnAction, the director applies the chip effect. Or call the core directly to build your own personality:

TypeScript
import { classifyStartingHand, weightedPick } from './PokerAI'

const seeded = makeSeededRng(42)
function tightAggressive(available, ctx) {
  const tier = classifyStartingHand(ctx.holeCards)
  if (tier === 'trash') return 'fold'
  return weightedPick(available, [
    { action: 'raise', weight: 3 },
    { action: 'call', weight: 1 },
  ], seeded)
}

Props

PropTypeDefaultMeaning
seatIdsstring[][]Seats this brain plays. Empty means it answers for every NPC seat offered a menu.
aggressionnumber0.50–1 dial that scales the post-flop weights toward bets and raises.

Events

DirectionNameConstPayload
inpoker.actionRequiredPokerAIInputEvents.ACTION_REQUIRED{ playerId, actions, context? }
outpoker.turnActionPokerAIEvents.TURN_ACTION{ playerId, action }

poker.turnAction is the same name PokerBetting accepts as a human's raw action, so the director applies PokerAI's pick exactly as it would a HUD click. With no context on the menu, the System falls back to the check / call / fold preference; with one, it runs the full baseline strategy.

Dependencies

  • PokerHandEval — supplies evaluateHand, parseCard, and HandRank, which equity reads.
  • PokerBetting — supplies ActionType, NpcStrategy, NpcContext, and StrategyReasoning, re-exported here so a personality imports the whole vocabulary from one entry point.

Notes

  • One brain per scene: the System routes a menu into the first entity carrying a PokerAI instance.
  • weightedPick returns the first available action when nothing weighted is on the menu, and the last valid bucket if the running total never crosses zero (an rng that returns 1) — so a personality never crashes on a thin menu.
  • The reasoning the System writes ({ hand, tier }) mutates the context passed in; pass a fresh context per turn if a HUD reads it back.
  • Card ids must match the deck-asset format exactly. shortCard returns the id verbatim when it isn't in <rank>_of_<suit> form, and passes through an unknown rank or suit token unchanged.

More like this

PokerBetting
PokerHandEval
AIGoalSeek
AIKick
AIZone
AiPilot
BallPossession
BallPursuit
CardFan
DeckDealer
Enemy
EnemySpawner
FreighterChain
LineOfSight
PokerAIBill
PokerAICali
PokerAIRandy
PokerAIShark
PokerAISurge
PokerAITilt
PokerHUD
PokerInput
PokerMultiplayer
PokerSeating
PokerTableCards
PokerTableDirector
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