diff --git a/JoshHeaps.Net/Pages/Casino/TexasHoldem.cshtml b/JoshHeaps.Net/Pages/Casino/TexasHoldem.cshtml index 617e5ff..64c9b18 100644 --- a/JoshHeaps.Net/Pages/Casino/TexasHoldem.cshtml +++ b/JoshHeaps.Net/Pages/Casino/TexasHoldem.cshtml @@ -110,8 +110,9 @@ Player In Won - Net - Cash out + Net + Chips + Up/down
@@ -270,6 +271,7 @@ + diff --git a/JoshHeaps.Net/wwwroot/css/casino/holdem.css b/JoshHeaps.Net/wwwroot/css/casino/holdem.css index eabcf70..fe8e893 100644 --- a/JoshHeaps.Net/wwwroot/css/casino/holdem.css +++ b/JoshHeaps.Net/wwwroot/css/casino/holdem.css @@ -1816,31 +1816,44 @@ button, white-space: nowrap; } -/* The per-hand columns are detail: how the night's swings happened. They're the - first thing to go when there isn't room, because Net and Cash out are what the - banker is actually reading. */ +/* The per-hand columns are detail: how the night's swings happened. They're the first + to go when there isn't room, and Net goes with them — it only moves when a pot is + resolved through the wizard, so on a table where the dealer settles pots by hand it + reads $0 all night beside two columns that don't. + + What survives at every width is the pair the banker actually works from: what the + player is holding, and whether that leaves them up or down. */ .standingsIn, .standingsWon, +.standingsNet, .standingsInHead, -.standingsWonHead { +.standingsWonHead, +.standingsNetHead { display: none; } @container (min-width: 30rem) { .standingsRow { - grid-template-columns: minmax(5rem, 1fr) auto auto auto auto; + grid-template-columns: minmax(5rem, 1fr) auto auto auto auto auto; } .standingsIn, .standingsWon, + .standingsNet, .standingsInHead, - .standingsWonHead { + .standingsWonHead, + .standingsNetHead { display: block; } } -/* The settle-up column is the one a banker reads while counting out cash, so it - carries the weight the per-hand columns don't. */ +/* The chips column is the one a banker's hands follow while counting money onto the + table, so it carries the weight. Up/down is read once, at the end. */ +.standingsChips { + font-weight: 600; + color: #e6e6e6; +} + .standingsCashOut { font-weight: 600; } diff --git a/JoshHeaps.Net/wwwroot/js/casino/holdem/render.js b/JoshHeaps.Net/wwwroot/js/casino/holdem/render.js index 836d0bd..5a2755f 100644 --- a/JoshHeaps.Net/wwwroot/js/casino/holdem/render.js +++ b/JoshHeaps.Net/wwwroot/js/casino/holdem/render.js @@ -818,9 +818,15 @@ const Render = { netEl.classList.toggle("netUp", row.net > 0); netEl.classList.toggle("netDown", row.net < 0); - // What they'd actually be handed if the night ended now: chips in front of - // them less the cash they gave the banker. This was computed and written to - // the CSV all along, but never shown to the person doing the paying out. + // The cash to count out, which is a plain amount and never signed — this + // is the one the banker's hands follow. It sat only in the CSV: on screen + // the column headed "Cash out" held the difference against their buy-in + // instead, so a player up $140 on a $340 stack read as "$140" at the exact + // moment somebody was counting money onto the table. + node.querySelector(".standingsChips").textContent = Money.format(row.chipsInFront); + + // And whether that leaves them up or down, which is the question the rest + // of the table asks and the one the old column was actually answering. const cashEl = node.querySelector(".standingsCashOut"); cashEl.textContent = Money.formatSigned(row.cashPosition); cashEl.classList.toggle("netUp", row.cashPosition > 0); diff --git a/JoshHeaps.Net/wwwroot/js/casino/holdem/state.js b/JoshHeaps.Net/wwwroot/js/casino/holdem/state.js index a950af9..01b4b80 100644 --- a/JoshHeaps.Net/wwwroot/js/casino/holdem/state.js +++ b/JoshHeaps.Net/wwwroot/js/casino/holdem/state.js @@ -683,6 +683,14 @@ const HoldemState = { net: Money.round(t.won - t.in), boughtIn, chipsNow, + // Everything still theirs: the stack in front of them plus whatever + // is out in the middle for the hand in progress. This is the number + // a banker counts out when somebody leaves, and it was the one + // figure the standings never showed — the column called "Cash out" + // held the difference against their buy-in, so a player up $140 on + // a $340 stack read as "$140" at the exact moment cash changed + // hands. + chipsInFront: Money.round(chipsNow + inFrontOfThem), cashPosition: Money.round(chipsNow + inFrontOfThem - boughtIn), notes, }; diff --git a/tests/holdem/bankAudit.test.js b/tests/holdem/bankAudit.test.js index eb2f2b2..9223d5b 100644 --- a/tests/holdem/bankAudit.test.js +++ b/tests/holdem/bankAudit.test.js @@ -167,3 +167,58 @@ describe("does the cash box cover the chips on the table", () => { assert.equal(HoldemState.bankReconciliation(state).balanced, true); }); }); + +describe("the number the banker counts out", () => { + // The standings had two signed columns and neither was an amount to pay. A player + // up $140 on a $340 stack read "$140" under a heading saying "Cash out", at the + // exact moment somebody was counting money onto the table. + test("chips in front is what they are holding, not what they are up", () => { + const state = makeTable({ seatCount: 6, seated: [0, 1], stack: 340 }); + state.seats[0].name = "Ann"; + state.seats[0].buyIns = 200; + state.seats[1].buyIns = 200; + state.seats[1].stack = 60; + + const rows = HoldemState.sessionStandings(state); + const ann = rows.find(r => r.name === "Ann"); + assert.equal(ann.chipsInFront, 340, "the cash to count out"); + assert.equal(ann.cashPosition, 140, "and separately, that they are up $140"); + }); + + test("a player who is down still has chips to be handed", () => { + const state = makeTable({ seatCount: 6, seated: [0, 1], stack: 60 }); + state.seats[0].name = "Cal"; + state.seats.forEach(p => { p.buyIns = 200; }); + + const cal = HoldemState.sessionStandings(state).find(r => r.name === "Cal"); + assert.equal(cal.chipsInFront, 60, "they leave with $60 of chips"); + assert.equal(cal.cashPosition, -140, "having lost $140 of the $200 they brought"); + }); + + test("chips still out in the middle are counted as theirs", () => { + // Cashing out mid-hand isn't a thing, but the panel is read mid-hand constantly + // and a stack that drops by the size of a bet looks like money going missing. + const state = makeTable({ seatCount: 6, seated: [0, 1], stack: 200 }); + state.seats[0].name = "Dee"; + state.seats.forEach(p => { p.buyIns = 200; }); + Betting.beginHand(state); + Betting.raiseTo(state, 0, 50); + + const dee = HoldemState.sessionStandings(state).find(r => r.name === "Dee"); + assert.equal(dee.chipsInFront, 200, "stack plus what's in the middle for them"); + assert.equal(dee.cashPosition, 0, "so they are still level"); + }); + + test("chips and up/down always differ by exactly the buy-in", () => { + const state = makeTable({ seatCount: 9, seated: [0, 1, 2, 3], stack: 100 }); + [340, 150, 60, 250].forEach((chips, i) => { + state.seats[i].stack = chips; + state.seats[i].buyIns = 200 + i * 50; + }); + + HoldemState.sessionStandings(state).forEach(row => { + assert.equal(Money.round(row.chipsInFront - row.boughtIn), row.cashPosition, + `${row.name}'s two columns should tell one story`); + }); + }); +});