How the DD Poker Hand Simulator Analyzes Hand Ranges: Full Enumeration vs. Monte Carlo

The DD Poker hand simulator evaluates hole cards against opponent ranges using either exhaustive enumeration or Monte Carlo sampling, depending on the board state, to calculate exact or approximate equity percentages.

DD Poker is an open-source Java engine for Texas Hold'em that includes sophisticated tools for poker hand analysis. The HoldemSimulator class in code/poker/src/main/java/com/donohoedigital/games/poker/engine/HoldemSimulator.java serves as the core hand range analyzer. It processes millions of combinations to determine win probabilities against specific opponent ranges or random hands while remaining responsive through the DDProgressFeedback interface.

Three Simulation Modes in HoldemSimulator.java

The simulator selects its execution strategy based on the number of known community cards. This adaptive approach balances mathematical precision with computational feasibility.

Full Enumeration for Late Streets

When the board contains four or five known cards (turn or river), the simulator uses the iterate(...) method to perform full enumeration. This mode loops over every possible opponent hand that matches the defined range and iterates through all remaining board cards (three or fewer). Because the deck has limited remaining combinations at this stage, the simulator can calculate exact win-loss-tie statistics without approximation.

Statistical Simulation for Early Streets

When the board has three or fewer cards (preflop or flop), the simulator switches to simulate(...), a Monte Carlo method. This mode randomly draws opponent hands and completes the board for a configurable number of trials (defaulting to approximately 4,000 iterations based on DEFAULT_PRECISION). This statistical approach avoids the combinatorial explosion that would make exhaustive enumeration prohibitively expensive on early streets.

All-Hands Random Sampling

For ad-hoc analysis without a specific range defined, the simulator falls back to an all-hands (random) mode. It generates a large random sample of opponent hands from the entire remaining deck, providing a "quick-look" equity calculation against an unspecified opponent holding.

Core Workflow and Execution Path

The simulation process follows a rigorous pipeline defined in HoldemSimulator.java:

  1. Deck Initialization – Creates a fresh Deck object (52 cards) and removes known hole cards and community cards using removeCards().

  2. Range Selection – Calls HandGroup.getProfileList() to retrieve predefined range profiles (e.g., "premium hands", "suited connectors").

  3. Path Selection – Evaluates board length to choose between simulate() (statistical) for ≥3 cards or iterate() (enumeration) for ≥4 cards.

  4. Hand Evaluation – Uses HandInfoFaster.getScore(...) to obtain numeric hand strength values. This optimized engine leverages pre-computed lookup tables for rapid evaluation.

  5. Result Aggregation – Collects outcomes in StatResult objects mapped by range name, returning a final StatResults collection to the caller.

  6. Progress Updates – Calls perc(...) and msg(...) on the DDProgressFeedback interface every N iterations (capped at 50,000 for UI responsiveness), allowing real-time progress bars and cancellation.

Key Classes Supporting Hand Range Analysis

Several specialized classes work together to enable accurate hand range simulation:

  • HandGroup (HandGroup.java) – Defines named hand-range profiles and expands compact notation (e.g., "AQs+", "KQs") into concrete Hand lists using HandList.

  • HandInfoFaster (HandInfoFaster.java) – A fast hand-evaluation engine that returns numeric scores for hand-plus-board combinations, enabling the score(...) comparisons that determine win/loss/tie outcomes.

  • Deck (Deck.java) – Manages the 52-card deck state during simulation, providing nextCard(), removeCards(), and addRandom() methods to handle card removal and random drawing.

  • UI IntegrationSimulatorDialog.java and PokerSimulatorPanel.java instantiate HoldemSimulator and provide concrete DDProgressFeedback implementations for interactive use.

  • AI IntegrationV2Player.java demonstrates programmatic usage, calling the simulator to evaluate opponent ranges during automated decision-making.

Practical Implementation: Running the Simulator

Below is a concrete example of invoking the statistical simulation directly:

// Build a hole hand (e.g., Ace of spades + King of hearts)
Hand hole = new Hand(Card.ACE_SPADES, Card.KING_HEARTS);

// Community board: flop only (three cards)
Hand community = new Hand(Card.TEN_DIAMONDS, Card.JACK_CLUBS, Card.QUEEN_SPADES);

// Optional UI progress listener (null = silent)
DDProgressFeedback progress = null;

// Run a statistical simulation with default precision (≈ 4,000 trials)
StatResults results = HoldemSimulator.simulate(hole, community, progress);

// Retrieve the outcome for a specific hand-range profile, e.g., "All Hands"
StatResult allHands = results.get(HoldemSimulator.ALL_HANDS);
System.out.printf("Win: %.2f%%, Lose: %.2f%%, Tie: %.2f%%%n",
    allHands.getWinPct(), allHands.getLosePct(), allHands.getTiePct());

When called from the UI layer, the progress parameter receives live updates that drive the progress bar in SimulatorDialog.

Range Definition: From Compact Notation to Concrete Hands

The simulator handles hand ranges through a two-phase resolution process. First, HandGroup contains a HandList that expands compact range descriptions (e.g., "AA", "Broadway", "Suited A-K") into concrete lists of Hand objects.

For iteration mode, the simulator removes each hand's cards from the deck and enumerates all remaining board cards, yielding exact counts. For sampling mode, it randomly selects hands from this pre-expanded list (or generates completely random hands if the list is null), then completes the board randomly. The handCount parameter derives from the range size multiplied by a precision factor, ensuring statistically significant results without unnecessary computation.

Summary

  • Adaptive Strategy: The simulator switches between exhaustive iterate() for late streets (≥4 cards) and Monte Carlo simulate() for early streets (≤3 cards).
  • Performance Optimization: HandInfoFaster provides sub-millisecond hand strength calculations via lookup tables.
  • Range Handling: HandGroup translates human-readable range notation into processable hand lists.
  • UI Integration: The DDProgressFeedback interface enables real-time progress reporting and cancellation in SimulatorDialog.
  • Dual API: The engine supports both interactive UI usage and programmatic AI integration (as demonstrated in V2Player.java).

Frequently Asked Questions

How does the simulator decide between enumeration and sampling?

The decision is based entirely on the number of known community cards. As implemented in HoldemSimulator.java, if the board has four or five cards, the code invokes iterate(...) for full enumeration. For three or fewer cards, it calls simulate(...) to use statistical Monte Carlo sampling, avoiding the billions of combinations that would result from exhaustive preflop calculations.

What role does HandInfoFaster play in the simulation?

HandInfoFaster is the evaluation engine that converts a seven-card hand (two hole cards plus five board cards) into a numeric score representing hand strength. According to the source, it uses pre-computed lookup tables to generate scores rapidly, allowing the simulator to evaluate millions of hands per second when iterating or sampling.

Can the hand simulator run without a graphical interface?

Yes. The HoldemSimulator.simulate() and iterate() methods accept a DDProgressFeedback parameter that can be set to null for silent execution. The V2Player AI class demonstrates this headless usage, calling the simulator programmatically to analyze opponent ranges during game play without any UI dependencies.

How are specific hand ranges like "AQs+" or "suited connectors" defined in the code?

Ranges are defined in HandGroup.java, which stores predefined profiles (e.g., "premium", "broadway", "suited connectors"). The class expands compact notation into concrete Hand objects stored in a HandList. When the simulator runs, it iterates over or samples from these pre-expanded lists to represent the opponent's possible holdings accurately.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →