// Dealing around a player who busted and hasn't bought back in. // // A home game produces one of these about once an hour. The table used to deal them // in anyway, promise a blind from a seat with nothing to post it with, take it from // nobody, and then sit on a hand that could never finish. const test = require("node:test"); const assert = require("node:assert"); const { Betting, HoldemState, makeTable, chipsOnTable } = require("./load"); const postedBy = state => state.seats .map((player, index) => (player.committed > 0 ? { seat: index + 1, amount: player.committed } : null)) .filter(Boolean); test("a seat with no chips and nothing in the pot is broke", () => { const state = makeTable({ seatCount: 6, seated: [0, 1, 2], stack: 100 }); state.seats[2].stack = 0; assert.deepEqual(Betting.brokeSeats(state), [2]); }); test("an all-in player is not broke — they have money riding on the hand", () => { const state = makeTable({ seatCount: 6, seated: [0, 1, 2], stack: 100 }); state.seats[2].stack = 12; Betting.beginHand(state); Betting.allIn(state, 2); assert.equal(Betting.stackOf(state, state.seats[2]), 0); assert.equal(Betting.isAllIn(state, state.seats[2]), true); assert.deepEqual(Betting.brokeSeats(state), []); }); test("a seat with no stack recorded falls back to the table's and isn't broke", () => { const state = makeTable({ seatCount: 6, seated: [0, 1, 2], stack: 100 }); state.defaultStack = 200; state.seats[2].stack = null; assert.deepEqual(Betting.brokeSeats(state), []); }); test("a chair nobody is sitting in isn't broke, it's empty", () => { const state = makeTable({ seatCount: 6, seated: [0, 1, 2], stack: 100 }); assert.deepEqual(Betting.brokeSeats(state), []); }); test("dealing sits the broke seat out and leaves everything else about it alone", () => { const state = makeTable({ seatCount: 6, seated: [0, 1, 2, 3], stack: 100 }); state.seats[2].stack = 0; state.seats[2].name = "Cal"; state.seats[2].buyIns = 100; Betting.beginHand(state); assert.equal(state.seats[2].inHand, false); assert.equal(state.seats[2].folded, false, "sat out, not folded — they didn't muck anything"); assert.equal(state.seats[2].name, "Cal"); assert.equal(state.seats[2].buyIns, 100); }); test("the blinds skip the broke seat and land on players who can post", () => { // Button on seat 1, so the blinds would be seats 2 and 3. Seat 2 is busted. const state = makeTable({ seatCount: 6, seated: [0, 1, 2, 3], stack: 100, dealerSeatIndex: 0 }); state.seats[1].stack = 0; Betting.beginHand(state); assert.deepEqual(postedBy(state), [ { seat: 3, amount: state.smallBlind }, { seat: 4, amount: state.bigBlind }, ]); }); test("the preview promises what the deal produces", () => { // The fault this whole step exists to prevent: the preview once read a table the // deal was about to change underneath it. const state = makeTable({ seatCount: 6, seated: [0, 1, 2, 3], stack: 100, dealerSeatIndex: 0 }); state.seats[1].stack = 0; state.bettingOpen = false; const preview = Betting.blindPreview(state); assert.deepEqual(preview.satOut, [1]); Betting.beginHand(state); const posted = postedBy(state); assert.equal(posted.find(p => p.amount === state.smallBlind).seat, preview.sbIndex + 1); assert.equal(posted.find(p => p.amount === state.bigBlind).seat, preview.bbIndex + 1); }); test("asking for the preview doesn't sit anybody out on its own", () => { const state = makeTable({ seatCount: 6, seated: [0, 1, 2], stack: 100 }); state.seats[1].stack = 0; Betting.blindPreview(state); assert.equal(state.seats[1].inHand, true, "the preview is a view, not a change"); }); test("with only one player left holding chips there is nothing to preview", () => { const state = makeTable({ seatCount: 6, seated: [0, 1, 2], stack: 100 }); state.seats[1].stack = 0; state.seats[2].stack = 0; assert.equal(Betting.blindPreview(state), null); }); test("no chips move when the broke seats are dealt around", () => { const state = makeTable({ seatCount: 6, seated: [0, 1, 2, 3], stack: 100 }); state.seats[2].stack = 0; const before = chipsOnTable(state); Betting.beginHand(state); assert.equal(chipsOnTable(state), before); }); test("the board isn't running out before the hand is dealt", () => { // Two busted players and one with chips looks exactly like a table of all-ins to // the run-out test, and the bar was announcing one over an empty felt. const state = makeTable({ seatCount: 6, seated: [0, 1, 2], stack: 100 }); state.seats[1].stack = 0; state.seats[2].stack = 0; state.bettingOpen = false; assert.equal(Betting.isRunningOut(state), false); }); test("buying back in puts them in the next hand", () => { const state = makeTable({ seatCount: 6, seated: [0, 1, 2], stack: 100 }); state.seats[2].stack = 0; Betting.beginHand(state); assert.equal(state.seats[2].inHand, false); // What the dealer does when they hand over cash: chips, and back in. state.seats[2].stack = 100; state.seats[2].inHand = true; HoldemState.startNextHand(state); Betting.beginHand(state); assert.equal(state.seats[2].inHand, true); assert.equal(Betting.liveSeats(state).length, 3); }); test("the table dealt around them counts the right number of players", () => { const state = makeTable({ seatCount: 6, seated: [0, 1, 2, 3], stack: 100 }); state.seats[3].stack = 0; assert.equal(Betting.liveSeats(state).length, 4); assert.equal(Betting.liveSeats(Betting.tableAsDealt(state)).length, 3); assert.equal(state.seats[3].inHand, true, "the view didn't touch the table"); });