Deal around a player who busted and hasn't rebought #65

Closed
jheaps wants to merge 1 commits from fix/casino-holdem-deal-around-broke into fix/casino-holdem-settle-up
Owner

The most ordinary thing that happens in a home game: somebody stacks off, and they don't buy back in that second. The table dealt them in anyway, and the result was a hand nobody could finish. Stacked on #64.

Three players, two of them busted:

bar before dealing:
  Pot $0 | 3 players | All-in — running out the board (3 players)
  | Cal posts $1, Ann posts $2 | Post blinds & deal

after dealing:
  Cal posted nothing — no chips to post with
  Ann posted $2 and was asked to check or bet against her own money
  liveSeats 3, isStreetComplete false, isHandOver false

Every line of that is wrong. It announced a board being run out over a felt with no cards on it, promised a small blind from a seat that couldn't post one, took it from nobody, and then sat on a hand with no way forward.

Dealt around instead

A seat with no chips and nothing in the pot is dealt around. Seat, name and buy-in record untouched — sat out, not folded, because they didn't muck anything — and adding chips puts them straight back in the next hand.

four players, Ben busted, button on Ann:
  3 players | Cal posts $1, Dee posts $2
  | Ben has no chips — sitting out this hand. | Post blinds & deal

  -> Ben inHand false, folded false; blinds exactly as promised; Ann to act

Said before it happens, for the same reason the button move is: a dealer shouldn't find out from the felt. And the preview computes it on a view of the table rather than by changing it, so the promise and the deal ask the same question — the exact fault these two lines exist to prevent.

When it can't be dealt at all, it says who has to buy in rather than pretending it's a seating problem:

Only Ann has chips — Ben and Cal need to buy in.

Nobody at the table has chips left. Add a buy-in to deal.

Two smaller things fall out

  • The run-out banner is gated on the betting actually being open. Before the deal, a table of busted players is indistinguishable from a table of all-ins to that test.
  • The bar's player count reads the table as it will be dealt, so someone waiting on a rebuy isn't announced as one of the players. Read-only — the sitting-out happens when the hand is dealt, not while the bar is drawn.

Broke is deliberately not the same as all-in, and the code says so: an all-in player has money riding on the hand. A seat with no stack recorded isn't broke either — those fall back to the table's starting stack.

Validation

13 tests (198 total), and 5 of them fail with the sit-out and the run-out guard taken back out.

Driven through Playwright at seven viewports in both states (dealt-around and blocked): layout and contrast clean everywhere except the landscape phone already documented in #63, and no console errors. Verified the buy-back-in path puts them in the next hand.

Left alone deliberately: a sat-out seat shows dimmed with a blank stack line rather than a "no chips" label. The dimming already reads as out-of-hand and the deal prompt gives the reason; labelling it would change how every manually sat-out seat draws, which is a bigger change than this fix needs.

The most ordinary thing that happens in a home game: somebody stacks off, and they don't buy back in that second. The table dealt them in anyway, and the result was **a hand nobody could finish**. Stacked on #64. Three players, two of them busted: ``` bar before dealing: Pot $0 | 3 players | All-in — running out the board (3 players) | Cal posts $1, Ann posts $2 | Post blinds & deal after dealing: Cal posted nothing — no chips to post with Ann posted $2 and was asked to check or bet against her own money liveSeats 3, isStreetComplete false, isHandOver false ``` Every line of that is wrong. It announced a board being run out over a felt with no cards on it, promised a small blind from a seat that couldn't post one, took it from nobody, and then sat on a hand with no way forward. ## Dealt around instead A seat with no chips and nothing in the pot is dealt around. Seat, name and buy-in record untouched — **sat out, not folded**, because they didn't muck anything — and adding chips puts them straight back in the next hand. ``` four players, Ben busted, button on Ann: 3 players | Cal posts $1, Dee posts $2 | Ben has no chips — sitting out this hand. | Post blinds & deal -> Ben inHand false, folded false; blinds exactly as promised; Ann to act ``` Said *before* it happens, for the same reason the button move is: a dealer shouldn't find out from the felt. And the preview computes it on a **view** of the table rather than by changing it, so the promise and the deal ask the same question — the exact fault these two lines exist to prevent. When it can't be dealt at all, it says who has to buy in rather than pretending it's a seating problem: > Only Ann has chips — Ben and Cal need to buy in. > > Nobody at the table has chips left. Add a buy-in to deal. ## Two smaller things fall out - The **run-out banner** is gated on the betting actually being open. Before the deal, a table of busted players is indistinguishable from a table of all-ins to that test. - The bar's **player count** reads the table as it will be dealt, so someone waiting on a rebuy isn't announced as one of the players. Read-only — the sitting-out happens when the hand is dealt, not while the bar is drawn. Broke is deliberately not the same as all-in, and the code says so: an all-in player has money riding on the hand. A seat with no stack *recorded* isn't broke either — those fall back to the table's starting stack. ## Validation **13 tests (198 total)**, and 5 of them fail with the sit-out and the run-out guard taken back out. Driven through Playwright at seven viewports in both states (dealt-around and blocked): layout and contrast clean everywhere except the landscape phone already documented in #63, and no console errors. Verified the buy-back-in path puts them in the next hand. Left alone deliberately: a sat-out seat shows dimmed with a blank stack line rather than a "no chips" label. The dimming already reads as out-of-hand and the deal prompt gives the reason; labelling it would change how every manually sat-out seat draws, which is a bigger change than this fix needs.
jheaps added 1 commit 2026-09-01 13:08:49 -06:00
The most ordinary thing that happens in a home game: somebody stacks off, and they
don't buy back in that second. The table dealt them in anyway, and the result was a
hand nobody could finish.

Three players, two of them busted:

  bar before dealing:
    "Pot $0 | 3 players | All-in - running out the board (3 players)
     | Cal posts $1, Ann posts $2 | Post blinds & deal"
  after dealing:
    Cal posted nothing -- no chips to post with
    Ann posted $2 and was asked to check or bet against her own money
    liveSeats 3, isStreetComplete false, isHandOver false

Every line of that is wrong. It announced a board being run out over a felt with no
cards on it, promised a small blind from a seat that couldn't post one, took it from
nobody, and then sat on a hand with no way forward.

So a seat with no chips and nothing in the pot is dealt around. Their seat, name and
buy-in record are untouched -- sat out, not folded, because they didn't muck anything
-- and adding chips puts them straight back in the next hand.

  four players, Ben busted, button on Ann:
    "3 players | Cal posts $1, Dee posts $2
     | Ben has no chips - sitting out this hand. | Post blinds & deal"
    -> Ben inHand false, folded false; blinds exactly as promised; Ann to act

Said before it happens, for the same reason the button move is: a dealer shouldn't
find out from the felt. And the preview computes it on a view of the table rather
than by changing it, so the promise and the deal ask the same question -- the fault
these two lines exist to prevent.

When it can't be dealt at all, it says who has to buy in rather than pretending it's
a seating problem:

  "Only Ann has chips - Ben and Cal need to buy in."
  "Nobody at the table has chips left. Add a buy-in to deal."

Two smaller things fall out. The run-out banner is now gated on the betting actually
being open -- before the deal, a table of busted players is indistinguishable from a
table of all-ins to that test. And the bar's player count reads the table as it will
be dealt, so someone waiting on a rebuy isn't announced as one of the players.

Not the same as all-in, and the code says so: an all-in player has money riding on
the hand. A seat with no stack recorded isn't broke either -- those fall back to the
table's starting stack.

13 tests (198 total), and 5 of them fail with the sit-out and the run-out guard taken
back out.

Driven through the UI at seven viewports in both states: layout and contrast clean
everywhere but the landscape phone already known from #63, and no console errors.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_015bnp7xKUPFFSpwkYNFaPgb
jheaps closed this pull request 2026-09-02 09:58:34 -06:00

Pull request closed

Please reopen this pull request to perform a merge.
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: jheaps/JoshHeaps.Net#65