Hold'em dealer: 55 polish rounds, one merge #101
@@ -143,7 +143,9 @@ button,
|
|||||||
}
|
}
|
||||||
|
|
||||||
.unevenCurrency {
|
.unevenCurrency {
|
||||||
color: #777;
|
/* Was #777 — 4.11:1 on this background, under the 4.5:1 small text needs. It sits
|
||||||
|
against every amount a dealer types, so it is read constantly. */
|
||||||
|
color: #8f8f8f;
|
||||||
}
|
}
|
||||||
|
|
||||||
.unevenAmount {
|
.unevenAmount {
|
||||||
@@ -184,7 +186,9 @@ button,
|
|||||||
height: 44px;
|
height: 44px;
|
||||||
border: none;
|
border: none;
|
||||||
background: none;
|
background: none;
|
||||||
color: #6a6a6a;
|
/* Was #6a6a6a — 3.66:1, the worst on the page, on a control that deletes a
|
||||||
|
player's entry. A destructive action should not be the faintest thing in view. */
|
||||||
|
color: #9a9a9a;
|
||||||
font-size: 0.85rem;
|
font-size: 0.85rem;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
@@ -209,11 +213,86 @@ button,
|
|||||||
.unevenPot {
|
.unevenPot {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: baseline;
|
align-items: baseline;
|
||||||
|
/* Wraps so a chop opens underneath its own pot rather than squeezing in beside the
|
||||||
|
eligible-players list and pushing it off the row. */
|
||||||
|
flex-wrap: wrap;
|
||||||
gap: 0.6rem;
|
gap: 0.6rem;
|
||||||
padding: 0.3rem 0;
|
padding: 0.3rem 0;
|
||||||
font-size: 0.85rem;
|
font-size: 0.85rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.unevenChopToggle {
|
||||||
|
flex: none;
|
||||||
|
order: 3;
|
||||||
|
/* 44px on touch: it moves money, like everything else that does. */
|
||||||
|
min-height: 32px;
|
||||||
|
padding: 0.2rem 0.6rem;
|
||||||
|
border: 1px solid rgba(216, 180, 106, 0.45);
|
||||||
|
border-radius: 999px;
|
||||||
|
background: rgba(216, 180, 106, 0.1);
|
||||||
|
color: #e3c887;
|
||||||
|
font: inherit;
|
||||||
|
font-size: 0.74rem;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.unevenChopToggle:hover {
|
||||||
|
background: rgba(216, 180, 106, 0.18);
|
||||||
|
}
|
||||||
|
|
||||||
|
.unevenChopToggle:focus-visible {
|
||||||
|
outline: 2px solid #d8b46a;
|
||||||
|
outline-offset: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.unevenChopDetail {
|
||||||
|
order: 4;
|
||||||
|
flex: 0 0 100%;
|
||||||
|
/* Or the padding is added on top of the 100% basis and the panel sits wider than
|
||||||
|
the row it belongs to — measured 328px inside a 309px row on a phone. */
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin: 0.15rem 0 0.2rem;
|
||||||
|
padding: 0.45rem 0.6rem;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: rgba(255, 255, 255, 0.04);
|
||||||
|
}
|
||||||
|
|
||||||
|
.unevenChopWays {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.45rem;
|
||||||
|
margin-bottom: 0.3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.unevenChopWaysLabel {
|
||||||
|
color: #cfcfcf;
|
||||||
|
font-size: 0.78rem;
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
|
}
|
||||||
|
|
||||||
|
.unevenChopEach {
|
||||||
|
margin: 0;
|
||||||
|
color: #f2f2f2;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.unevenChopNote {
|
||||||
|
margin: 0.2rem 0 0;
|
||||||
|
color: #9a9a9a;
|
||||||
|
font-size: 0.76rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.unevenChopDust {
|
||||||
|
color: #e0b169;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 700px), (pointer: coarse) {
|
||||||
|
.unevenChopToggle {
|
||||||
|
min-height: 44px;
|
||||||
|
padding: 0.4rem 0.9rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.unevenPot + .unevenPot {
|
.unevenPot + .unevenPot {
|
||||||
border-top: 1px solid rgba(255, 255, 255, 0.06);
|
border-top: 1px solid rgba(255, 255, 255, 0.06);
|
||||||
}
|
}
|
||||||
@@ -510,7 +589,9 @@ button,
|
|||||||
|
|
||||||
.splitFootnote {
|
.splitFootnote {
|
||||||
margin-top: 1.5rem;
|
margin-top: 1.5rem;
|
||||||
color: #6f6f6f;
|
/* Was #6f6f6f — 3.94:1. It carries the instruction for what to do with the pot
|
||||||
|
list, which is not a decorative line. */
|
||||||
|
color: #8d8d8d;
|
||||||
font-size: 0.78rem;
|
font-size: 0.78rem;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|||||||
@@ -197,6 +197,80 @@ const QuickSplit = {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Chopping one of the pots listed above, without leaving the screen that worked it
|
||||||
|
// out. Starts closed and at as many ways as there are players who can win the pot,
|
||||||
|
// which is the common case; the stepper covers a chop between fewer of them, which
|
||||||
|
// is the other one.
|
||||||
|
//
|
||||||
|
// The per-pot ways live on the row rather than in `this.ways`, so opening a chop on
|
||||||
|
// the main pot doesn't change what the side pot below it is saying.
|
||||||
|
addChopControl(row, amount, contenderCount) {
|
||||||
|
let ways = contenderCount;
|
||||||
|
let open = false;
|
||||||
|
|
||||||
|
const toggle = document.createElement("button");
|
||||||
|
toggle.type = "button";
|
||||||
|
toggle.className = "unevenChopToggle";
|
||||||
|
|
||||||
|
const detail = document.createElement("div");
|
||||||
|
detail.className = "unevenChopDetail";
|
||||||
|
detail.hidden = true;
|
||||||
|
|
||||||
|
const draw = () => {
|
||||||
|
toggle.textContent = open ? "Hide chop" : "Chop";
|
||||||
|
toggle.setAttribute("aria-expanded", String(open));
|
||||||
|
detail.hidden = !open;
|
||||||
|
if (!open) return;
|
||||||
|
|
||||||
|
const result = SplitCalculator.split(amount, ways, this.chip);
|
||||||
|
detail.innerHTML = "";
|
||||||
|
|
||||||
|
const stepper = document.createElement("div");
|
||||||
|
stepper.className = "unevenChopWays";
|
||||||
|
stepper.appendChild(this.makeStepButton("−", () => {
|
||||||
|
if (ways > 2) { ways -= 1; draw(); }
|
||||||
|
}));
|
||||||
|
const label = document.createElement("span");
|
||||||
|
label.className = "unevenChopWaysLabel";
|
||||||
|
label.textContent = `${ways} ways`;
|
||||||
|
stepper.appendChild(label);
|
||||||
|
stepper.appendChild(this.makeStepButton("+", () => {
|
||||||
|
if (ways < Math.max(contenderCount, this.MAX_WAYS)) { ways += 1; draw(); }
|
||||||
|
}));
|
||||||
|
detail.appendChild(stepper);
|
||||||
|
|
||||||
|
const each = document.createElement("p");
|
||||||
|
each.className = "unevenChopEach";
|
||||||
|
each.textContent = `${Money.format(result.each)} each`;
|
||||||
|
detail.appendChild(each);
|
||||||
|
|
||||||
|
// Same wording as the main split, because it is the same rule and a dealer
|
||||||
|
// shouldn't have to notice they're reading a different screen.
|
||||||
|
if (result.valid && result.oddChips > 0) {
|
||||||
|
const odd = document.createElement("p");
|
||||||
|
odd.className = "unevenChopNote";
|
||||||
|
odd.textContent = result.oddChips === 1
|
||||||
|
? `plus one odd ${Money.format(result.chip)} chip to the first player left of the button`
|
||||||
|
: `plus ${result.oddChips} odd ${Money.format(result.chip)} chips — one each to the ` +
|
||||||
|
`first ${result.oddChips} players left of the button`;
|
||||||
|
detail.appendChild(odd);
|
||||||
|
}
|
||||||
|
if (result.valid && result.dust > 0) {
|
||||||
|
const dust = document.createElement("p");
|
||||||
|
dust.className = "unevenChopNote unevenChopDust";
|
||||||
|
dust.textContent =
|
||||||
|
`${Money.format(result.dust)} doesn't divide into ${Money.format(result.chip)} chips — ` +
|
||||||
|
`pick a smaller denomination.`;
|
||||||
|
detail.appendChild(dust);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
toggle.addEventListener("click", () => { open = !open; draw(); });
|
||||||
|
draw();
|
||||||
|
row.appendChild(toggle);
|
||||||
|
row.appendChild(detail);
|
||||||
|
},
|
||||||
|
|
||||||
updateUneven() {
|
updateUneven() {
|
||||||
const players = this.entries
|
const players = this.entries
|
||||||
.map((entry, index) => ({ id: `P${index + 1}`, contribution: Number(entry.amount) || 0, folded: entry.folded }))
|
.map((entry, index) => ({ id: `P${index + 1}`, contribution: Number(entry.amount) || 0, folded: entry.folded }))
|
||||||
@@ -218,7 +292,7 @@ const QuickSplit = {
|
|||||||
}
|
}
|
||||||
empty.hidden = true;
|
empty.hidden = true;
|
||||||
|
|
||||||
const addRow = (label, amount, who, className) => {
|
const addRow = (label, amount, who, className, chopWays) => {
|
||||||
const row = document.createElement("div");
|
const row = document.createElement("div");
|
||||||
row.className = `unevenPot ${className || ""}`;
|
row.className = `unevenPot ${className || ""}`;
|
||||||
const name = document.createElement("span");
|
const name = document.createElement("span");
|
||||||
@@ -234,9 +308,19 @@ const QuickSplit = {
|
|||||||
row.appendChild(value);
|
row.appendChild(value);
|
||||||
row.appendChild(eligible);
|
row.appendChild(eligible);
|
||||||
host.appendChild(row);
|
host.appendChild(row);
|
||||||
|
|
||||||
|
// Two players tying for a side pot is ordinary, and working out each one's
|
||||||
|
// share meant copying the amount into the other mode by hand — retyping a
|
||||||
|
// number the screen had just worked out, which is a transcription error
|
||||||
|
// waiting to happen with money on it. The chop happens here instead.
|
||||||
|
//
|
||||||
|
// Only offered where it means something: a pot with at least two people
|
||||||
|
// who can win it. Not the uncalled row, which goes back to one player, and
|
||||||
|
// not the total.
|
||||||
|
if (chopWays >= 2) this.addChopControl(row, amount, chopWays);
|
||||||
};
|
};
|
||||||
|
|
||||||
pots.forEach(pot => addRow(pot.label, pot.amount, pot.eligible.join(", ")));
|
pots.forEach(pot => addRow(pot.label, pot.amount, pot.eligible.join(", "), "", pot.eligible.length));
|
||||||
returns.forEach(ret => addRow("Uncalled", ret.amount, `back to ${ret.id}`, "unevenPotReturn"));
|
returns.forEach(ret => addRow("Uncalled", ret.amount, `back to ${ret.id}`, "unevenPotReturn"));
|
||||||
|
|
||||||
const total = players.reduce((sum, p) => sum + p.contribution, 0);
|
const total = players.reduce((sum, p) => sum + p.contribution, 0);
|
||||||
|
|||||||
Reference in New Issue
Block a user