solitaire: detect a won board and finish it in one press

A drained, all-face-up board is a guaranteed clear that auto() sweeps home
in a single cascade, but the only way to trigger it was double-clicking
thirty cards home by hand. Add State.Won(), surface it in the view, and
swap the ordinary controls for one pulsing finish button when it's true.
This commit is contained in:
prosolis
2026-07-15 18:50:43 -07:00
parent 8504c4f47a
commit b814f936a8
7 changed files with 115 additions and 3 deletions

View File

@@ -1456,6 +1456,14 @@ html[data-phase="night"] {
100% { box-shadow: 0 0 0 1.4rem rgba(242, 181, 61, 0); }
}
/* The finish button on a won board breathes, so the one press left to make is
the one the eye lands on. */
.pete-finish { animation: pete-finish-pulse 1.6s ease-in-out infinite; }
@keyframes pete-finish-pulse {
0%, 100% { box-shadow: 0 0 0 0 rgba(242, 181, 61, 0.55); }
50% { box-shadow: 0 0 0 0.9rem rgba(242, 181, 61, 0); }
}
/* The rail: the house's rack, what you've banked, the meter. On a wide screen
it's a column down the right of the felt; on a narrow one it lies down and
sits under the board. */
@@ -2130,7 +2138,8 @@ html[data-phase="night"] {
.pete-tile-hit,
.pete-meter[data-hit="1"] { animation: none; }
.pete-nope,
.pete-home-flash { animation: none; }
.pete-home-flash,
.pete-finish { animation: none; }
.pete-card[data-held="1"] { transition: none; }
/* The clock still drains — it is information, not decoration — but it stops
pulsing at you, and a wrong answer stops shaking. */

File diff suppressed because one or more lines are too long

View File

@@ -44,7 +44,10 @@
var playing = root.querySelector("[data-playing]");
var betting = root.querySelector("[data-betting]");
var playControls = root.querySelector("[data-play-controls]");
var wonControls = root.querySelector("[data-won-controls]");
var autoBtn = root.querySelector("[data-auto]");
var finishBtn = root.querySelector("[data-finish]");
var cashBtn = root.querySelector("[data-cash]");
var cashAmountEl = root.querySelector("[data-cash-amount]");
var startBtn = root.querySelector("[data-start]");
@@ -258,6 +261,11 @@
playing.classList.toggle("hidden", !live);
betting.classList.toggle("hidden", live);
if (!live) return;
// A won board has nothing left to decide, so the ordinary controls step aside
// for the one button that finishes it.
var won = !!v.won;
wonControls.classList.toggle("hidden", !won);
playControls.classList.toggle("hidden", won);
autoBtn.disabled = !v.can_auto;
cashAmountEl.textContent = (v.stands || 0).toLocaleString();
}
@@ -545,6 +553,10 @@
autoBtn.addEventListener("click", function () { drop(); send({ kind: "auto" }); });
// The finish button. On a won board a single auto drains every card home in one
// cascade, and the board settles cleared on the far end of it.
finishBtn.addEventListener("click", function () { drop(); send({ kind: "auto" }); });
cashBtn.addEventListener("click", function () {
drop();
send({ kind: "concede" });