The poker game follows a well-defined state machine:
WAITING → PREFLOP → FLOP → TURN → RIVER → SHOWDOWN → COMPLETE
- Initial state before hand starts
- Players can sit down/stand up
- No active hand
- Hand has started
- Blinds posted
- Hole cards dealt (server-only)
- Betting round active
- First three community cards dealt
- Betting round active
- Fourth community card dealt
- Betting round active
- Fifth community card dealt
- Final betting round
- All betting complete
- Hands evaluated
- Pots distributed
- Hand finished
- Winners determined
- Ready for next hand
- Trigger:
StartHandcommand - Conditions:
- At least 2 active players
- Street == WAITING
- Events:
HandStarted
- Trigger: Betting round complete (auto-advance)
- Conditions:
- All active players acted
- All committed equally
- Action returned to last aggressor
- Events:
BettingRoundComplete,StreetDealt(FLOP)
- Trigger: Betting round complete (auto-advance)
- Events:
BettingRoundComplete,StreetDealt(TURN)
- Trigger: Betting round complete (auto-advance)
- Events:
BettingRoundComplete,StreetDealt(RIVER)
- Trigger: Betting round complete (auto-advance)
- Events:
BettingRoundComplete - Actions: Hand evaluation, pot splitting
- Trigger: Pots distributed
- Events:
ShowdownResolved,HandEnded
- Trigger: Only one active player remains
- Transition: Current street → COMPLETE
- Events:
ShowdownResolved,HandEnded(reason="FOLD")
- Trigger: All players all-in
- Action: Deal remaining streets immediately
- Events: Multiple
StreetDealtevents, thenShowdownResolved
OUT → ACTIVE → FOLDED
↓
ALL_IN
- OUT: Not in hand (not seated or sitting out)
- ACTIVE: In hand, can act
- FOLDED: Folded this hand
- ALL_IN: All chips committed
Each street has a betting round with states:
No Bet → Bet Placed → Action Rotation → Round Complete
- No Bet:
current_bet == 0 - Bet Placed:
current_bet > 0,last_raiser_seatset - Action Rotation: Players act in order
- Round Complete: All acted, committed equally
At all times, the following invariants must hold:
- No negative stacks
- Chip conservation:
sum(stack + committed_total)constant - Pot correctness: At terminal state,
sum(pots) == sum(committed_total) - Player status consistency:
stack == 0→status == ALL_IN(if in hand)