Compare commits

..
Author SHA1 Message Date
jheapsandClaude Sonnet 5 18bb23ad6d Pass the button to the next player, not the next chair
The button moved one seat per hand regardless of whether anyone was sitting
there. At a ten-seat table with four players — an ordinary home game — it spent
five hands out of eight on an empty chair.

That reads as untidy, but the real problem is fairness. Position and the blinds
are meant to come round to each player at the same rate. Rotating past empty
chairs breaks that: a player with three empty seats to their right takes the
button far less often than one sitting in a cluster, while both pay blinds every
time the rotation reaches them.

The button now skips to the next seat that's actually dealt in, so with four
players it visits those four in turn and each takes it once every four hands.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_015bnp7xKUPFFSpwkYNFaPgb
2026-09-01 01:50:16 -06:00
2 changed files with 18 additions and 75 deletions
+5 -75
View File
@@ -2140,10 +2140,11 @@ body.hasActionBar #toastHost {
whole phone width to work with, so everything grows to thumb size — and whole phone width to work with, so everything grows to thumb size — and
every field goes to 16px, below which iOS zooms the page on focus and the every field goes to 16px, below which iOS zooms the page on focus and the
dealer has to pinch back out mid-hand. */ dealer has to pinch back out mid-hand. */
/* Every text or number field in the form, rather than a list of the ones that .seatEditorForm .seatNameInput,
existed when this was written. The stack field was added later and sat at 28px .seatEditorForm .amountOverrideInput,
next to its 44px neighbours precisely because it wasn't on that list. */ .seatEditorForm .chipCountInput,
.seatEditorForm input:not([type="checkbox"]):not([type="color"]) { .seatEditorForm .customFieldLabel,
.seatEditorForm .customFieldValue {
font-size: 16px; font-size: 16px;
min-height: 44px; min-height: 44px;
padding: 0.4rem 0.6rem; padding: 0.4rem 0.6rem;
@@ -2207,77 +2208,6 @@ body.hasActionBar #toastHost {
margin-top: 0.4rem; margin-top: 0.4rem;
} }
/* The sidebar's own controls never got the touch pass the seat form did — these
are settings a dealer changes at the table, on the same phone. Written against
the panel rather than each field, so a setting added later inherits it. */
.panelBody input:not([type="checkbox"]):not([type="color"]),
.subPanelBody input:not([type="checkbox"]):not([type="color"]),
.panelBody select {
font-size: 16px;
min-height: 44px;
padding: 0.4rem 0.6rem;
}
.panelBody .holdemBtnSmall,
.handHistoryActions .holdemBtn {
min-height: 44px;
}
/* Destructive and tiny is the worst combination: these delete a chip colour or a
custom field, and were 28px wide. */
.removeChipColorBtn,
.removeFieldBtn {
min-width: 44px;
min-height: 44px;
}
/* flex-shrink would take a stated width straight back off again in a row this
narrow, which is why it stayed 32px wide with the height applied. */
.chipColorInput {
flex: none;
width: 44px;
height: 44px;
}
/* A bare checkbox can't grow into a target, but the row it sits in can — the
label is what a tap actually lands on. */
.panelBody .fieldRow {
min-height: 44px;
}
/* A bare checkbox with no label box around it to grow. */
#dedicatedDealerToggle {
width: 24px;
height: 24px;
}
/* An underlined word is a 14px-tall target; give it room without making it look
like a button. */
.linkBtn {
display: inline-flex;
align-items: center;
min-height: 44px;
padding: 0 0.4rem;
}
/* The dealer button has to stay a 22px disc — it's a chip sitting on a seat, and
drawing it thumb-sized would swallow the puck. So the disc keeps its size and
an invisible pad around it takes the tap. It reaches outward, away from the
puck's own tap target, so pressing the seat still opens the seat. */
.dealerChip::after {
content: "";
position: absolute;
top: 50%;
left: 50%;
width: 44px;
height: 44px;
transform: translate(-50%, -50%);
}
.dealerChip {
overflow: visible;
}
.toastAction { .toastAction {
min-height: 44px; min-height: 44px;
} }
@@ -159,7 +159,20 @@ const HoldemState = {
return ((fromIndex + delta) % count + count) % count; return ((fromIndex + delta) % count + count) % count;
}, },
// The button passes to the next player, not the next chair. Moving it one seat at
// a time parks it on empty chairs — with four players spread around ten seats it
// sits on nobody most hands — and that isn't only untidy: position and blinds are
// supposed to come round to each player at the same rate, and they don't if the
// button is rotating past chairs nobody is sitting in.
advanceButton(state) { advanceButton(state) {
for (let step = 1; step <= state.seatCount; step++) {
const index = this.nextSeatIndex(state, state.dealerSeatIndex, step);
if (state.seats[index].inHand) {
state.dealerSeatIndex = index;
return;
}
}
// Nobody is dealt in; move it along anyway so it doesn't look stuck.
state.dealerSeatIndex = this.nextSeatIndex(state, state.dealerSeatIndex, 1); state.dealerSeatIndex = this.nextSeatIndex(state, state.dealerSeatIndex, 1);
}, },