From 7c647492676e021eb5fe018beff1b54d61c162ca Mon Sep 17 00:00:00 2001 From: JoshHeaps Date: Tue, 1 Sep 2026 00:07:37 -0600 Subject: [PATCH] Let Quick Split handle the pot it used to send people away for Quick Split answered the easy half of the question and printed a footnote for the hard half: if somebody was all-in for less, go set up the full table. That's the moment a dealer least wants to be setting up a table. A second mode takes what each player put in and lists the main pot and each side pot with who can win it, plus anything uncalled that goes back. Rows can be marked folded, so dead money lands in the right pot without its owner being able to win it. The running total is shown so the breakdown can be checked against the chips actually on the table. It reuses the same pot maths as the full table rather than growing a second implementation, which means the two screens can't drift apart and Quick Split inherits the uncalled-bet and everyone-folded handling that was fixed there. Also fixes hiding: these sections carry a `display` declaration, which outranks the browser's own [hidden] rule, so toggling `hidden` on them did nothing and both modes' controls showed at once. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_015bnp7xKUPFFSpwkYNFaPgb --- .../Casino/TexasHoldem/QuickSplit.cshtml | 47 ++++- .../wwwroot/css/casino/quicksplit.css | 171 ++++++++++++++++++ .../wwwroot/js/casino/holdem/quickSplit.js | 121 +++++++++++++ 3 files changed, 333 insertions(+), 6 deletions(-) diff --git a/JoshHeaps.Net/Pages/Casino/TexasHoldem/QuickSplit.cshtml b/JoshHeaps.Net/Pages/Casino/TexasHoldem/QuickSplit.cshtml index 0dfc7a6..0fb0660 100644 --- a/JoshHeaps.Net/Pages/Casino/TexasHoldem/QuickSplit.cshtml +++ b/JoshHeaps.Net/Pages/Casino/TexasHoldem/QuickSplit.cshtml @@ -11,6 +11,11 @@

Chop a pot without setting up a table.

+
+ + +
+
Each player gets
$0.00
@@ -18,7 +23,18 @@
-
+ + + + +
$ @@ -28,12 +44,12 @@
-
+
Split between
-
+
Smallest chip in play
@@ -43,12 +59,30 @@ Full dealer table → -

- Uneven pots — someone all-in for less — need the side-pot walkthrough on the - full table. +

+ If somebody was all-in for less than the others, switch to + Someone's all-in above. +

+ + + + @section Styles { } @@ -56,5 +90,6 @@ @section Scripts { + } diff --git a/JoshHeaps.Net/wwwroot/css/casino/quicksplit.css b/JoshHeaps.Net/wwwroot/css/casino/quicksplit.css index 0f15fd8..157f9c9 100644 --- a/JoshHeaps.Net/wwwroot/css/casino/quicksplit.css +++ b/JoshHeaps.Net/wwwroot/css/casino/quicksplit.css @@ -45,6 +45,171 @@ body { font-size: 0.85rem; } +/* ---------- Mode toggle ---------- */ + +#modeToggle { + margin-bottom: 1.1rem; +} + +/* ---------- Uneven amounts ---------- */ + +#unevenRows { + display: flex; + flex-direction: column; + gap: 0.45rem; + margin-bottom: 0.6rem; +} + +.unevenRow { + display: flex; + align-items: center; + gap: 0.45rem; +} + +.unevenRowLabel { + flex: none; + width: 2rem; + color: #8f8f8f; + font-size: 0.8rem; + font-weight: 600; +} + +.unevenAmountWrap { + flex: 1; + min-width: 0; + display: flex; + align-items: center; + gap: 0.3rem; + background: #141414; + border: 1px solid #3a3a3a; + border-radius: 10px; + padding: 0 0.6rem; +} + +.unevenAmountWrap:focus-within { + border-color: #d8b46a; +} + +.unevenCurrency { + color: #777; +} + +.unevenAmount { + flex: 1; + min-width: 0; + background: none; + border: none; + outline: none; + color: #f2f2f2; + font-family: inherit; + font-size: 16px; + font-variant-numeric: tabular-nums; + padding: 0.6rem 0; +} + +.unevenFoldBtn { + flex: none; + min-height: 44px; + padding: 0 0.6rem; + border-radius: 9px; + border: 1px solid #3a3a3a; + background: #232323; + color: #8f8f8f; + font-family: inherit; + font-size: 0.72rem; + cursor: pointer; +} + +.unevenFoldBtn.selected { + background: linear-gradient(180deg, #3d1f1f, #2c1515); + border-color: #5b2626; + color: #ffd6d6; +} + +.unevenRemoveBtn { + flex: none; + width: 30px; + height: 44px; + border: none; + background: none; + color: #6a6a6a; + font-size: 0.85rem; + cursor: pointer; +} + +.unevenRemoveBtn:disabled { + opacity: 0.3; + cursor: not-allowed; +} + +#unevenResult { + background: linear-gradient(160deg, #1f2a21, #161c17); + border: 1px solid #2c3a2f; + border-radius: 14px; + padding: 0.9rem 1rem; + margin-bottom: 1.5rem; +} + +#unevenResult[hidden] { + display: none; +} + +.unevenPot { + display: flex; + align-items: baseline; + gap: 0.6rem; + padding: 0.3rem 0; + font-size: 0.85rem; +} + +.unevenPot + .unevenPot { + border-top: 1px solid rgba(255, 255, 255, 0.06); +} + +.unevenPotLabel { + flex: none; + color: #d8b46a; + font-weight: 600; +} + +.unevenPotAmount { + flex: none; + color: #f2f2f2; + font-weight: 600; + font-variant-numeric: tabular-nums; +} + +.unevenPotWho { + flex: 1; + min-width: 0; + text-align: right; + color: #9a9a9a; + font-size: 0.78rem; +} + +.unevenPotReturn .unevenPotLabel, +.unevenPotReturn .unevenPotAmount { + color: #9a9a9a; + font-weight: 500; +} + +.unevenPotTotal { + margin-top: 0.15rem; + border-top: 1px solid rgba(255, 255, 255, 0.14) !important; +} + +.unevenPotTotal .unevenPotLabel { + color: #8f9d92; + font-weight: 500; +} + +.unevenEmpty { + margin: 0; + color: #8f9d92; + font-size: 0.82rem; + line-height: 1.45; +} + /* ---------- The answer ---------- */ #splitResult { @@ -104,6 +269,12 @@ body { margin-bottom: 1.35rem; } +/* A `display` declaration outranks the browser's own [hidden] rule, so anything + given one has to opt back out explicitly or toggling `hidden` does nothing. */ +[hidden] { + display: none !important; +} + .splitLabel { display: block; margin-bottom: 0.5rem; diff --git a/JoshHeaps.Net/wwwroot/js/casino/holdem/quickSplit.js b/JoshHeaps.Net/wwwroot/js/casino/holdem/quickSplit.js index aa4c164..2cf84f6 100644 --- a/JoshHeaps.Net/wwwroot/js/casino/holdem/quickSplit.js +++ b/JoshHeaps.Net/wwwroot/js/casino/holdem/quickSplit.js @@ -15,12 +15,28 @@ const QuickSplit = { ways: 2, chip: 1, + // "even" is the common case — one pot, everyone matched. "uneven" is the one this + // screen used to send people back to the full table for: somebody all-in for less, + // so the money splits into a main pot and side pots. + mode: "even", + entries: [], + mount() { this.potInput = document.getElementById("potInput"); this.clearPotBtn = document.getElementById("clearPotBtn"); + this.entries = [{ amount: "", folded: false }, { amount: "", folded: false }, { amount: "", folded: false }]; this.renderWayChoices(); this.renderChipChoices(); + this.renderUnevenRows(); + + document.getElementById("modeEvenBtn").addEventListener("click", () => this.setMode("even")); + document.getElementById("modeUnevenBtn").addEventListener("click", () => this.setMode("uneven")); + document.getElementById("addPlayerBtn").addEventListener("click", () => { + this.entries.push({ amount: "", folded: false }); + this.renderUnevenRows(); + this.update(); + }); this.potInput.addEventListener("input", () => { this.sanitizePotInput(); @@ -127,7 +143,112 @@ const QuickSplit = { }); }, + setMode(mode) { + this.mode = mode; + document.getElementById("modeEvenBtn").classList.toggle("selected", mode === "even"); + document.getElementById("modeUnevenBtn").classList.toggle("selected", mode === "uneven"); + + document.querySelectorAll(".evenOnly").forEach(el => { el.hidden = mode !== "even"; }); + document.querySelectorAll(".unevenOnly").forEach(el => { el.hidden = mode !== "uneven"; }); + document.getElementById("splitResult").hidden = mode !== "even"; + document.getElementById("unevenResult").hidden = mode !== "uneven"; + + this.update(); + }, + + renderUnevenRows() { + const host = document.getElementById("unevenRows"); + const template = document.getElementById("unevenRowTemplate"); + host.innerHTML = ""; + + this.entries.forEach((entry, index) => { + const row = template.content.firstElementChild.cloneNode(true); + row.querySelector(".unevenRowLabel").textContent = `P${index + 1}`; + + const amount = row.querySelector(".unevenAmount"); + amount.value = entry.amount; + amount.setAttribute("aria-label", `Player ${index + 1} amount`); + amount.addEventListener("input", () => { + entry.amount = amount.value.replace(/[^0-9.]/g, "").replace(/(\..*)\./g, "$1"); + if (entry.amount !== amount.value) amount.value = entry.amount; + this.update(); + }); + + // Folded money stays in the pot as dead money, but its owner can't win any + // of it — which is exactly the distinction that makes side pots tricky. + const fold = row.querySelector(".unevenFoldBtn"); + fold.classList.toggle("selected", entry.folded); + fold.setAttribute("aria-pressed", String(entry.folded)); + fold.addEventListener("click", () => { + entry.folded = !entry.folded; + this.renderUnevenRows(); + this.update(); + }); + + const remove = row.querySelector(".unevenRemoveBtn"); + remove.disabled = this.entries.length <= 2; + remove.addEventListener("click", () => { + this.entries.splice(index, 1); + this.renderUnevenRows(); + this.update(); + }); + + host.appendChild(row); + }); + }, + + updateUneven() { + const players = this.entries + .map((entry, index) => ({ id: `P${index + 1}`, contribution: Number(entry.amount) || 0, folded: entry.folded })) + .filter(p => p.contribution > 0); + + const pots = PotCalculator.layers(players); + const returns = PotCalculator.uncalledReturns(players); + + const host = document.getElementById("unevenPots"); + const empty = document.getElementById("unevenEmpty"); + host.innerHTML = ""; + + if (pots.length === 0 && returns.length === 0) { + empty.hidden = false; + empty.textContent = players.length === 0 + ? "Enter what each player put in." + : "Nobody left who can win — un-fold whoever should take it."; + return; + } + empty.hidden = true; + + const addRow = (label, amount, who, className) => { + const row = document.createElement("div"); + row.className = `unevenPot ${className || ""}`; + const name = document.createElement("span"); + name.className = "unevenPotLabel"; + name.textContent = label; + const value = document.createElement("span"); + value.className = "unevenPotAmount"; + value.textContent = Money.format(amount); + const eligible = document.createElement("span"); + eligible.className = "unevenPotWho"; + eligible.textContent = who; + row.appendChild(name); + row.appendChild(value); + row.appendChild(eligible); + host.appendChild(row); + }; + + pots.forEach(pot => addRow(pot.label, pot.amount, pot.eligible.join(", "))); + returns.forEach(ret => addRow("Uncalled", ret.amount, `back to ${ret.id}`, "unevenPotReturn")); + + const total = players.reduce((sum, p) => sum + p.contribution, 0); + addRow("On the table", Math.round(total * 100) / 100, "", "unevenPotTotal"); + }, + update() { + if (this.mode === "uneven") { + this.updateUneven(); + return; + } + const potValue = Number(this.potInput.value); const pot = Number.isNaN(potValue) ? 0 : potValue; this.clearPotBtn.hidden = this.potInput.value === "";