Skip to content

Fix heads-up blind assignment and betting order#83

Open
jianrontan wants to merge 1 commit into
ishikota:masterfrom
jianrontan:fix-heads-up-blind-rules
Open

Fix heads-up blind assignment and betting order#83
jianrontan wants to merge 1 commit into
ishikota:masterfrom
jianrontan:fix-heads-up-blind-rules

Conversation

@jianrontan
Copy link
Copy Markdown

  • Assign the small blind to the button seat in heads-up play; keep the seat left of the button for 3+ player games
  • Detect heads-up via the count of chip-holding players taken before ante zeroing, so a game shrinking from 3 to 2 players switches correctly
  • Apply the fix in both blind code paths: dealer.py and emulator.py
  • Seed postflop action from the seat left of the button (small blind for 3+ players, big blind heads-up)
  • Seed preflop action from the seat left of the big blind (UTG for 3+ players, small blind/button heads-up)
  • Guard the __publish_messages result in play_round before unpacking
  • Update heads-up test expectations that encoded the old behavior; add coverage for a 3-to-2 player transition into a correct heads-up round

Fixes #82

Problem

Heads-up (2-player) games did not follow standard poker rules. The blind
search always assigned the small blind to the seat left of the button, and the
betting order was derived from that assumption. For 2 players this made the
non-button player the small blind and inverted the preflop/postflop action
order.

The blind logic is duplicated in dealer.py and emulator.py, so both code
paths were affected.

Changes

pypokerengine/engine/dealer.py, pypokerengine/api/emulator.py

_steal_money_from_poor_player now selects the small blind from the button
seat in heads-up play, and from the seat left of the button otherwise:

sb_offset = 0 if pre_ante_active == 2 else 1
search_targets = search_targets[table.dealer_btn+sb_offset:table.dealer_btn+sb_offset+len(players)]

pre_ante_active counts players that still hold chips before ante zeroing.
Using a count taken after ante zeroing would drop a 3-player game to 2 and
falsely trigger heads-up mode; counting beforehand also makes a tournament
that genuinely shrinks from 3 players to 2 switch to heads-up rules correctly.

pypokerengine/engine/round_manager.py

Betting order no longer assumes the 3+ player layout:

  • Postflop: first to act is the first active seat left of the button —
    the small blind for 3+ players, the big blind heads-up.
  • Preflop: first to act is the first active seat left of the big blind —
    UTG for 3+ players, the small blind/button heads-up.

These reduce to the previous behavior for 3+ player games (verified
algebraically and by the existing multi-player tests).

Defensive guard in dealer.py

play_round now asserts the __publish_messages result before unpacking it,
documenting the invariant that an ongoing round always ends on an ask message.

Tests

  • Updated heads-up test expectations in game_test.py, dealer_test.py and
    emulator_test.py that had encoded the old (incorrect) behavior — swapped
    blind amounts, wrong first actor, and scripted action lists in the old order.
  • test_exclude_short_of_money_player_when_ante_on and
    test_run_until_game_finish_when_one_player_is_left now also cover a game
    that shrinks from 3 players to a correct heads-up round.
  • Full suite passes (python -m unittest discover -s tests -p "*_test.py"):
    232 tests, OK.

Compatibility / notes

  • 3+ player behavior is unchanged.
  • Heads-up game trees change (correctly). Agents/strategies trained against
    the previous heads-up behavior should be retrained.
  • DataEncoder.__order_histories still orders action_histories seat-wise
    from the small blind. This is a pre-existing display-only approximation and
    is left as-is; every history entry carries a uuid, so no information is
    lost.

  - Assign the small blind to the button seat in heads-up play; keep the
    seat left of the button for 3+ player games
  - Detect heads-up via the count of chip-holding players taken before
    ante zeroing, so a game shrinking from 3 to 2 players switches correctly
  - Apply the fix in both blind code paths: dealer.py and emulator.py
  - Seed postflop action from the seat left of the button (small blind for
    3+ players, big blind heads-up)
  - Seed preflop action from the seat left of the big blind (UTG for 3+
    players, small blind/button heads-up)
  - Guard the __publish_messages result in play_round before unpacking
  - Update heads-up test expectations that encoded the old behavior; add
    coverage for a 3-to-2 player transition into a correct heads-up round
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Heads-up games do not follow standard blind / action-order rules

1 participant