Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cc1b5011a1 |
@@ -184,19 +184,9 @@ const Betting = {
|
||||
|
||||
const nextStreetIndex = this.STREETS.indexOf(state.street || "preflop") + 1;
|
||||
state.street = this.STREETS[nextStreetIndex] || "river";
|
||||
|
||||
if (this.liveSeats(state).length <= 1) {
|
||||
state.actingSeatIndex = null;
|
||||
return;
|
||||
}
|
||||
|
||||
// After the flop the first live player left of the button acts — which heads-up
|
||||
// is the big blind, since the button is the small blind. Naming the big blind
|
||||
// directly also covers a button parked on a seat nobody is sitting in.
|
||||
const { bbIndex, headsUp } = HoldemState.getBlindSeats(state);
|
||||
state.actingSeatIndex = headsUp && bbIndex !== null && !state.seats[bbIndex].folded
|
||||
? bbIndex
|
||||
: this.nextLiveIndex(state, state.dealerSeatIndex);
|
||||
state.actingSeatIndex = this.liveSeats(state).length > 1
|
||||
? this.nextLiveIndex(state, state.dealerSeatIndex)
|
||||
: null;
|
||||
},
|
||||
|
||||
isHandOver(state) {
|
||||
@@ -217,23 +207,15 @@ const Betting = {
|
||||
|
||||
const sb = Number(state.smallBlind) || 0;
|
||||
const bb = Number(state.bigBlind) || 0;
|
||||
const { sbIndex, bbIndex, headsUp } = HoldemState.getBlindSeats(state);
|
||||
const sbIndex = this.seatAt(state, state.dealerSeatIndex, 1);
|
||||
const bbIndex = this.seatAt(state, state.dealerSeatIndex, 2);
|
||||
|
||||
if (sbIndex === null || bbIndex === null) {
|
||||
state.currentBet = 0;
|
||||
state.actingSeatIndex = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (sb > 0) this.putIn(state, sbIndex, sb);
|
||||
if (bb > 0) this.putIn(state, bbIndex, bb);
|
||||
if (sb > 0 && state.seats[sbIndex].inHand) this.putIn(state, sbIndex, sb);
|
||||
if (bb > 0 && state.seats[bbIndex].inHand) this.putIn(state, bbIndex, bb);
|
||||
|
||||
state.currentBet = this.round(Math.max(this.committed(state.seats[sbIndex]), this.committed(state.seats[bbIndex])));
|
||||
state.lastRaiseSize = bb || 0;
|
||||
|
||||
// Heads-up the button is the small blind and acts first before the flop; with
|
||||
// three or more it's the seat after the big blind.
|
||||
state.actingSeatIndex = headsUp ? sbIndex : this.nextLiveIndex(state, bbIndex);
|
||||
state.actingSeatIndex = this.nextLiveIndex(state, bbIndex);
|
||||
},
|
||||
|
||||
// Winners get their share put back in front of them.
|
||||
|
||||
@@ -18,6 +18,7 @@ const PotWizard = {
|
||||
this.playerLabelById = new Map(
|
||||
players.map(p => [p.id, this.labelFor(p, state.seats.indexOf(p))])
|
||||
);
|
||||
this.seatIndexById = new Map(players.map(p => [p.id, state.seats.indexOf(p)]));
|
||||
const contributions = players.map(p => ({
|
||||
id: p.id,
|
||||
contribution: HoldemState.computeContribution(p, state.chipLegend, state.basePotAmount),
|
||||
@@ -49,6 +50,20 @@ const PotWizard = {
|
||||
this.totals.set(id, (this.totals.get(id) || 0) + amount);
|
||||
},
|
||||
|
||||
// A chopped pot rarely divides exactly, and the odd chip goes to the first player
|
||||
// left of the button — not to whoever the dealer happened to tick first. The
|
||||
// calculator hands leftovers out in the order it's given the winners, so ordering
|
||||
// them here is what makes the payout match the rule.
|
||||
orderFromButton(ids) {
|
||||
const distance = new Map();
|
||||
for (let step = 1; step <= this.state.seatCount; step++) {
|
||||
distance.set(HoldemState.nextSeatIndex(this.state, this.state.dealerSeatIndex, step), step);
|
||||
}
|
||||
return [...ids].sort((a, b) =>
|
||||
(distance.get(this.seatIndexById.get(a)) ?? 0) - (distance.get(this.seatIndexById.get(b)) ?? 0)
|
||||
);
|
||||
},
|
||||
|
||||
renderStep() {
|
||||
// Auto-resolve any round where only one player is left standing — nothing to ask.
|
||||
let contenders = PotCalculator.getContenders(this.entries);
|
||||
@@ -127,7 +142,7 @@ const PotWizard = {
|
||||
confirmBtn.addEventListener("click", () => {
|
||||
const selected = Array.from(choices.querySelectorAll("input:checked")).map(i => i.value);
|
||||
if (selected.length === 0) return;
|
||||
const result = PotCalculator.resolveRound(this.entries, selected);
|
||||
const result = PotCalculator.resolveRound(this.entries, this.orderFromButton(selected));
|
||||
this.recordRound(result);
|
||||
this.entries = result.updatedEntries;
|
||||
this.renderStep();
|
||||
|
||||
@@ -163,36 +163,10 @@ const HoldemState = {
|
||||
state.dealerSeatIndex = this.nextSeatIndex(state, state.dealerSeatIndex, 1);
|
||||
},
|
||||
|
||||
// Seats dealt into this hand, in blind order starting from the seat after the
|
||||
// button. Blinds follow the players, not the chairs — the seats immediately left
|
||||
// of the button are empty often enough that counting chairs posts them to nobody.
|
||||
liveOrderFromButton(state) {
|
||||
const order = [];
|
||||
for (let step = 1; step <= state.seatCount; step++) {
|
||||
const index = this.nextSeatIndex(state, state.dealerSeatIndex, step);
|
||||
if (state.seats[index].inHand) order.push(index);
|
||||
}
|
||||
return order;
|
||||
},
|
||||
|
||||
// Who posts what. Heads-up is its own rule: with two players the button posts the
|
||||
// small blind, which is the opposite of the usual order.
|
||||
getBlindSeats(state) {
|
||||
const live = this.liveOrderFromButton(state);
|
||||
const dealerIndex = state.dealerSeatIndex;
|
||||
|
||||
if (live.length < 2) {
|
||||
return { dealerIndex, sbIndex: null, bbIndex: null, headsUp: false };
|
||||
}
|
||||
|
||||
if (live.length === 2) {
|
||||
const buttonIsPlaying = state.seats[dealerIndex].inHand;
|
||||
const sbIndex = buttonIsPlaying ? dealerIndex : live[0];
|
||||
const bbIndex = live.find(i => i !== sbIndex);
|
||||
return { dealerIndex, sbIndex, bbIndex, headsUp: true };
|
||||
}
|
||||
|
||||
return { dealerIndex, sbIndex: live[0], bbIndex: live[1], headsUp: false };
|
||||
const sbIndex = this.nextSeatIndex(state, state.dealerSeatIndex, 1);
|
||||
const bbIndex = this.nextSeatIndex(state, state.dealerSeatIndex, 2);
|
||||
return { dealerIndex: state.dealerSeatIndex, sbIndex, bbIndex };
|
||||
},
|
||||
|
||||
startNextHand(state) {
|
||||
|
||||
Reference in New Issue
Block a user