How DD Poker Manages Player Actions During Each Betting Round: A Deep Dive into TournamentDirector

During each betting round, DD Poker sequentially processes seated players through TournamentDirector.doBetting, routing human decisions to the UI, AI decisions to probabilistic logic, and remote actions over the network via the immutable HandAction object.

Managing player actions during each betting round is the core responsibility of the DD Poker game engine. The open-source repository dougdonohoe/ddpoker implements a deterministic state machine that handles local humans, AI opponents, and remote network players through a unified interface. Understanding how the game manages player actions during each betting round reveals the orchestration between the tournament director, hand state, and action representation objects.

The Betting Round Orchestrator in TournamentDirector

The entire betting flow originates in TournamentDirector.doBetting(), located in code/poker/src/main/java/com/donohoedigital/games/poker/online/TournamentDirector.java. This method implements a sequential processor that examines each player, determines their eligibility to act, and routes the decision to the appropriate handler.

Selecting the Current Player

The engine identifies whose turn it is by invoking HoldemHand.getCurrentPlayerInitIndex(). This method initializes the player order for the first betting round and returns the index of the current actor. According to the source code in lines 45-52 of TournamentDirector.java, this call establishes the rotation sequence that persists throughout the hand.

// From TournamentDirector.doBetting()
PokerPlayer cur = table.getHoldemHand().getCurrentPlayerInitIndex();

Handling Sit-Out and Demo Players

Before presenting action options, the engine checks if the player is marked as sitting out or if a demo user has exhausted their allocated time. When either condition is true, the system automatically generates a HandAction with ACTION_FOLD and processes it via doHandAction(). This automated folding occurs in lines 59-66 of TournamentDirector.java, ensuring inactive players do not stall the game.

if (cur.isSittingOut() || demoExpired) {
    HandAction fold = new HandAction(cur, table.getHoldemHand().getRound(),
                                     HandAction.ACTION_FOLD, 0,
                                     HandAction.FOLD_SITTING_OUT, "sittingout");
    doHandAction(fold, false, false, false);
}

Processing Different Player Types

The engine distinguishes between three player categories during action resolution: local humans, AI-controlled opponents, and remote network participants.

Local Human Players and UI Integration

When the current player is locally controlled and the table represents the active UI window, the engine pauses execution and transfers control to the user interface. This is achieved by setting the next phase to "TD.Bet" via ret.setPhaseToRun("TD.Bet") (lines 71-80). The tournament director remains in this state until the human player clicks a button in the client interface, at which point the resulting HandAction is injected back into the processing loop.

AI Decision Making with PlayerAction

For computer-controlled players on non-current tables, the engine immediately queries the AI for a decision using PokerPlayer.getAction(false). This method returns a HandAction object populated by the lightweight PlayerAction class, which generates probabilistic decisions based on supplied percentage weights.

The PlayerAction constructor (located in code/ddpoker/src/main/java/com/ddpoker/holdem/PlayerAction.java, lines 54-78) implements a random roll mechanism that selects actions based on cumulative probability buckets for fold, check, call, and bet.

// Creating a probabilistic AI action
// 30% chance to bet, 20% to call, 30% to check, 20% to fold
PlayerAction ai = PlayerAction.act(20, 30, 20, 30);
System.out.println("AI selected: " + ai);   // e.g. "Bet (bet 30%):"

The resulting action is immediately applied through doHandAction() without UI intervention, allowing rapid simulation of hands across multiple computer-only tables.

Remote Players in Network Games

When the host runs a networked game, remote opponents trigger a different pathway. The host adds the player to a wait list using table.addWait(cur) and sets ret.setRunOnClient(true) to instruct the client to present its own UI (lines 99-106). The host then pauses execution until the remote client transmits a HandAction back to the server, which is processed identically to local actions.

Representing Actions with the HandAction Class

Every player decision is encapsulated in an immutable HandAction object defined in code/poker/src/main/java/com/donohoedigital/games/poker/HandAction.java (lines 55-66). This data structure records:

  • The player reference
  • The round identifier (preflop, flop, turn, river)
  • The action type (ACTION_FOLD, ACTION_CHECK, ACTION_CALL, ACTION_BET, ACTION_RAISE)
  • The amount and sub-amount (distinguishing between total bet size and call portion of a raise)
  • An optional debug string for tracing
// Manual construction of a HandAction for a human bet
PokerPlayer human = player;                  // player that clicked "Bet $50"
int round = HoldemHand.ROUND_FLOP;
int amount = 50;
HandAction bet = new HandAction(human, round,
                               HandAction.ACTION_BET,
                               amount, 0,
                               "user pressed Bet");
doHandAction(bet, false, false, false);

State Transitions and Round Advancement

After processing the current player's action, doBetting() evaluates whether to continue the current round or transition to the next phase. The method may invoke doBettingAllComputer() to synchronize tables where all participants are AI-controlled, then determines the next table state via nextBettingState() (lines 110-127). Valid transitions include:

  • BETTING – Continue the current betting round with the next player
  • COMMUNITY – Deal community cards (flop, turn, or river)
  • PRE_SHOWDOWN – Prepare for card revelation if only one player remains

The HoldemHand class maintains the internal state machine, automatically advancing the player index after each action until the hand reaches completion.

Summary

  • TournamentDirector.doBetting() serves as the central coordinator for managing player actions during each betting round, iterating through seated players sequentially.
  • Player selection begins with HoldemHand.getCurrentPlayerInitIndex(), which establishes and maintains the betting order throughout the hand.
  • Inactive players are handled automatically through forced fold actions when sitting out or when demo time expires.
  • Local humans trigger UI phases ("TD.Bet"), while AI players receive immediate probabilistic decisions from PlayerAction, and remote players enter a wait state pending network transmission.
  • All actions are represented by immutable HandAction objects that capture player, round, action type, amounts, and debugging metadata.

Frequently Asked Questions

What class manages the betting round flow in DD Poker?

The TournamentDirector class in TournamentDirector.java manages the entire betting round flow. Its doBetting() method implements the main loop that selects players, determines available actions, and routes decisions to the appropriate handlers for humans, AI, or remote participants.

How does DD Poker handle players who are sitting out?

When isSittingOut() returns true or a demo player's time expires, the engine automatically constructs a HandAction with ACTION_FOLD and the FOLD_SITTING_OUT sub-type. This action is immediately processed through doHandAction(), removing the player from the current hand without requiring UI interaction.

What determines whether the UI or AI controls a player's action?

The system checks PokerPlayer.isLocallyControlled() and PokerTable.isCurrent(). If both conditions are true for a human player, the phase is set to "TD.Bet" to trigger the UI. If the player is a computer on a non-current table, getAction(false) invokes the AI logic immediately, bypassing the interface entirely.

How are player actions represented internally in the codebase?

Player actions are represented by the HandAction class, an immutable data structure defined in HandAction.java. It encapsulates the player reference, betting round, action type constants (ACTION_FOLD, ACTION_BET, etc.), monetary amounts, and optional debug strings, providing a serializable record of every decision made during the hand.

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 →