From ae591e42124be192528f1bfc3417df55457284d9 Mon Sep 17 00:00:00 2001 From: JoshHeaps Date: Tue, 1 Sep 2026 01:37:19 -0600 Subject: [PATCH] Stop asking all-in players to act MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A player who is all-in is still in the hand and still wins pots, but has nothing left to decide. The engine didn't know that: it picked the next player to act by walking to whoever was still in the hand, chips or no chips. So a dealer with three players all-in pre-flop was asked to check for each of them on the flop, the turn and the river — nine taps to say nothing — and the action could land mid-street on someone who'd already pushed their last chip in. Now the action passes over players who are all-in, and once fewer than two people have chips left the betting is simply over: the bar runs Deal Flop, Turn, River, Showdown straight through, and says "All-in — running out the board" so the absence of a question reads as deliberate rather than as a stuck screen. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_015bnp7xKUPFFSpwkYNFaPgb --- JoshHeaps.Net/wwwroot/css/casino/holdem.css | 6 +++ .../wwwroot/js/casino/holdem/actionBar.js | 10 +++++ .../wwwroot/js/casino/holdem/betting.js | 45 ++++++++++++++++--- 3 files changed, 56 insertions(+), 5 deletions(-) diff --git a/JoshHeaps.Net/wwwroot/css/casino/holdem.css b/JoshHeaps.Net/wwwroot/css/casino/holdem.css index 8d9ca2e..f7bfe3a 100644 --- a/JoshHeaps.Net/wwwroot/css/casino/holdem.css +++ b/JoshHeaps.Net/wwwroot/css/casino/holdem.css @@ -1480,6 +1480,12 @@ body.hasActionBar #holdemSidebar { font-variant-numeric: tabular-nums; } +.actionRunout { + margin-left: auto; + color: #d8b46a; + font-size: 0.74rem; +} + .actionWho { margin-left: auto; color: #9c9c9c; diff --git a/JoshHeaps.Net/wwwroot/js/casino/holdem/actionBar.js b/JoshHeaps.Net/wwwroot/js/casino/holdem/actionBar.js index d440315..3673f21 100644 --- a/JoshHeaps.Net/wwwroot/js/casino/holdem/actionBar.js +++ b/JoshHeaps.Net/wwwroot/js/casino/holdem/actionBar.js @@ -74,6 +74,16 @@ const ActionBar = { players.textContent = `${remaining} ${remaining === 1 ? "player" : "players"}`; row.appendChild(players); + // Nobody is being asked to act because nobody can — say so, or the bar just + // looks like it's waiting for something. + if (Betting.isRunningOut(this.state) && !Betting.isHandOver(this.state)) { + const runout = document.createElement("span"); + runout.className = "actionRunout"; + const stillIn = Betting.liveSeats(this.state).length; + runout.textContent = `All-in — running out the board (${stillIn} players)`; + row.appendChild(runout); + } + const index = this.state.actingSeatIndex; if (index !== null && index !== undefined && !Betting.isHandOver(this.state)) { const player = this.state.seats[index]; diff --git a/JoshHeaps.Net/wwwroot/js/casino/holdem/betting.js b/JoshHeaps.Net/wwwroot/js/casino/holdem/betting.js index bb2f628..97b34fd 100644 --- a/JoshHeaps.Net/wwwroot/js/casino/holdem/betting.js +++ b/JoshHeaps.Net/wwwroot/js/casino/holdem/betting.js @@ -70,7 +70,19 @@ const Betting = { for (let step = 1; step <= count; step++) { const index = this.seatAt(state, fromIndex, step); const player = state.seats[index]; - if (player.inHand && !player.folded && this.stackOf(state, player) >= 0) return index; + if (player.inHand && !player.folded) return index; + } + return null; + }, + + // Who the dealer asks next. A player who is all-in is still in the hand and still + // wins pots, but has no decision left, so the action passes over them. + nextToAct(state, fromIndex) { + const count = state.seatCount; + for (let step = 1; step <= count; step++) { + const index = this.seatAt(state, fromIndex, step); + const player = state.seats[index]; + if (player.inHand && !player.folded && this.stackOf(state, player) > this.EPSILON_CHIPS) return index; } return null; }, @@ -156,7 +168,7 @@ const Betting = { }, passAction(state, index) { - state.actingSeatIndex = this.isStreetComplete(state) ? null : this.nextLiveIndex(state, index); + state.actingSeatIndex = this.isStreetComplete(state) ? null : this.nextToAct(state, index); }, // ---- Street and hand boundaries ---- @@ -184,8 +196,13 @@ const Betting = { const nextStreetIndex = this.STREETS.indexOf(state.street || "preflop") + 1; state.street = this.STREETS[nextStreetIndex] || "river"; - state.actingSeatIndex = this.liveSeats(state).length > 1 - ? this.nextLiveIndex(state, state.dealerSeatIndex) + + // It takes two players with chips to have a bet. Once everyone left is all-in + // — or only one player still has anything behind — the rest of the board is + // just dealt out, and asking someone to check when they have nothing to check + // with only slows the dealer down. + state.actingSeatIndex = this.canStillBet(state) + ? this.nextToAct(state, state.dealerSeatIndex) : null; }, @@ -193,6 +210,24 @@ const Betting = { return this.liveSeats(state).length <= 1; }, + // Players still in the hand who have chips left to put in. Fewer than two of them + // means the betting is finished even though the hand isn't. + seatsWithChips(state) { + return this.liveSeats(state).filter(s => this.stackOf(state, s.player) > this.EPSILON_CHIPS); + }, + + EPSILON_CHIPS: 0.004, + + canStillBet(state) { + return this.liveSeats(state).length > 1 && this.seatsWithChips(state).length > 1; + }, + + // True when the hand is still live but nobody can bet again — the dealer is just + // running the board out. + isRunningOut(state) { + return this.liveSeats(state).length > 1 && !this.canStillBet(state); + }, + // Deals a fresh betting round: blinds posted, action to the seat after the big // blind, which is where a dealer expects to be looking when the cards go out. beginHand(state) { @@ -215,7 +250,7 @@ const Betting = { state.currentBet = this.round(Math.max(this.committed(state.seats[sbIndex]), this.committed(state.seats[bbIndex]))); state.lastRaiseSize = bb || 0; - state.actingSeatIndex = this.nextLiveIndex(state, bbIndex); + state.actingSeatIndex = this.nextToAct(state, bbIndex); }, // Winners get their share put back in front of them.