@journey-to-code/games 0.0.0-stage → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/backgammon.d.ts +146 -0
- package/dist/backgammon.js +1221 -0
- package/dist/backgammon.js.map +1 -0
- package/dist/blackjack.d.ts +66 -0
- package/dist/blackjack.js +452 -0
- package/dist/blackjack.js.map +1 -0
- package/dist/bluff.d.ts +60 -0
- package/dist/bluff.js +239 -0
- package/dist/bluff.js.map +1 -0
- package/dist/board.d.ts +387 -0
- package/dist/board.js +105 -0
- package/dist/board.js.map +1 -0
- package/dist/bridge.d.ts +86 -0
- package/dist/bridge.js +494 -0
- package/dist/bridge.js.map +1 -0
- package/dist/canasta.d.ts +88 -0
- package/dist/canasta.js +646 -0
- package/dist/canasta.js.map +1 -0
- package/dist/checkers.d.ts +108 -0
- package/dist/checkers.js +756 -0
- package/dist/checkers.js.map +1 -0
- package/dist/chess.d.ts +162 -0
- package/dist/chess.js +904 -0
- package/dist/chess.js.map +1 -0
- package/dist/chesscore.d.ts +136 -0
- package/dist/chesscore.js +1121 -0
- package/dist/chesscore.js.map +1 -0
- package/dist/combat.d.ts +102 -0
- package/dist/combat.js +772 -0
- package/dist/combat.js.map +1 -0
- package/dist/contractrummy.d.ts +77 -0
- package/dist/contractrummy.js +430 -0
- package/dist/contractrummy.js.map +1 -0
- package/dist/crazy8.d.ts +65 -0
- package/dist/crazy8.js +366 -0
- package/dist/crazy8.js.map +1 -0
- package/dist/cribbage.d.ts +75 -0
- package/dist/cribbage.js +428 -0
- package/dist/cribbage.js.map +1 -0
- package/dist/cuckoo.d.ts +43 -0
- package/dist/cuckoo.js +216 -0
- package/dist/cuckoo.js.map +1 -0
- package/dist/drinkingpyramid.d.ts +54 -0
- package/dist/drinkingpyramid.js +213 -0
- package/dist/drinkingpyramid.js.map +1 -0
- package/dist/drinks.d.ts +25 -0
- package/dist/drinks.js +40 -0
- package/dist/drinks.js.map +1 -0
- package/dist/dropfour.d.ts +103 -0
- package/dist/dropfour.js +577 -0
- package/dist/dropfour.js.map +1 -0
- package/dist/durak.d.ts +58 -0
- package/dist/durak.js +332 -0
- package/dist/durak.js.map +1 -0
- package/dist/euchre.d.ts +80 -0
- package/dist/euchre.js +453 -0
- package/dist/euchre.js.map +1 -0
- package/dist/fivedraw.d.ts +50 -0
- package/dist/fivedraw.js +289 -0
- package/dist/fivedraw.js.map +1 -0
- package/dist/fivehundred.d.ts +90 -0
- package/dist/fivehundred.js +504 -0
- package/dist/fivehundred.js.map +1 -0
- package/dist/freecell.d.ts +50 -0
- package/dist/freecell.js +327 -0
- package/dist/freecell.js.map +1 -0
- package/dist/fruitsalad.d.ts +69 -0
- package/dist/fruitsalad.js +427 -0
- package/dist/fruitsalad.js.map +1 -0
- package/dist/gin.d.ts +72 -0
- package/dist/gin.js +393 -0
- package/dist/gin.js.map +1 -0
- package/dist/go.d.ts +132 -0
- package/dist/go.js +659 -0
- package/dist/go.js.map +1 -0
- package/dist/goboard.d.ts +218 -0
- package/dist/goboard.js +880 -0
- package/dist/goboard.js.map +1 -0
- package/dist/gofish.d.ts +37 -0
- package/dist/gofish.js +235 -0
- package/dist/gofish.js.map +1 -0
- package/dist/golf.d.ts +64 -0
- package/dist/golf.js +343 -0
- package/dist/golf.js.map +1 -0
- package/dist/handfoot.d.ts +86 -0
- package/dist/handfoot.js +515 -0
- package/dist/handfoot.js.map +1 -0
- package/dist/hearts.d.ts +65 -0
- package/dist/hearts.js +390 -0
- package/dist/hearts.js.map +1 -0
- package/dist/holdem.d.ts +45 -0
- package/dist/holdem.js +286 -0
- package/dist/holdem.js.map +1 -0
- package/dist/horserace.d.ts +49 -0
- package/dist/horserace.js +207 -0
- package/dist/horserace.js.map +1 -0
- package/dist/index.d.ts +65 -0
- package/dist/index.js +66 -0
- package/dist/index.js.map +1 -0
- package/dist/kingscorner.d.ts +59 -0
- package/dist/kingscorner.js +374 -0
- package/dist/kingscorner.js.map +1 -0
- package/dist/kingscup.d.ts +44 -0
- package/dist/kingscup.js +185 -0
- package/dist/kingscup.js.map +1 -0
- package/dist/kit.d.ts +283 -0
- package/dist/kit.js +73 -0
- package/dist/kit.js.map +1 -0
- package/dist/klondike.d.ts +57 -0
- package/dist/klondike.js +314 -0
- package/dist/klondike.js.map +1 -0
- package/dist/liarspoker.d.ts +61 -0
- package/dist/liarspoker.js +298 -0
- package/dist/liarspoker.js.map +1 -0
- package/dist/memory.d.ts +36 -0
- package/dist/memory.js +181 -0
- package/dist/memory.js.map +1 -0
- package/dist/minigolf.d.ts +104 -0
- package/dist/minigolf.js +724 -0
- package/dist/minigolf.js.map +1 -0
- package/dist/minigolfcourse.d.ts +127 -0
- package/dist/minigolfcourse.js +470 -0
- package/dist/minigolfcourse.js.map +1 -0
- package/dist/offers.d.ts +136 -0
- package/dist/offers.js +279 -0
- package/dist/offers.js.map +1 -0
- package/dist/ohhell.d.ts +66 -0
- package/dist/ohhell.js +331 -0
- package/dist/ohhell.js.map +1 -0
- package/dist/oldmaid.d.ts +40 -0
- package/dist/oldmaid.js +186 -0
- package/dist/oldmaid.js.map +1 -0
- package/dist/pinochle.d.ts +94 -0
- package/dist/pinochle.js +466 -0
- package/dist/pinochle.js.map +1 -0
- package/dist/pitch.d.ts +77 -0
- package/dist/pitch.js +362 -0
- package/dist/pitch.js.map +1 -0
- package/dist/poker.d.ts +79 -0
- package/dist/poker.js +268 -0
- package/dist/poker.js.map +1 -0
- package/dist/president.d.ts +56 -0
- package/dist/president.js +339 -0
- package/dist/president.js.map +1 -0
- package/dist/pyramid.d.ts +39 -0
- package/dist/pyramid.js +200 -0
- package/dist/pyramid.js.map +1 -0
- package/dist/registry.d.ts +17 -0
- package/dist/registry.js +70 -0
- package/dist/registry.js.map +1 -0
- package/dist/reversi.d.ts +69 -0
- package/dist/reversi.js +584 -0
- package/dist/reversi.js.map +1 -0
- package/dist/ridethebus.d.ts +48 -0
- package/dist/ridethebus.js +257 -0
- package/dist/ridethebus.js.map +1 -0
- package/dist/rummy500.d.ts +89 -0
- package/dist/rummy500.js +474 -0
- package/dist/rummy500.js.map +1 -0
- package/dist/sevens.d.ts +48 -0
- package/dist/sevens.js +221 -0
- package/dist/sevens.js.map +1 -0
- package/dist/slapjack.d.ts +42 -0
- package/dist/slapjack.js +224 -0
- package/dist/slapjack.js.map +1 -0
- package/dist/speed.d.ts +44 -0
- package/dist/speed.js +201 -0
- package/dist/speed.js.map +1 -0
- package/dist/spider.d.ts +51 -0
- package/dist/spider.js +320 -0
- package/dist/spider.js.map +1 -0
- package/dist/spite.d.ts +75 -0
- package/dist/spite.js +372 -0
- package/dist/spite.js.map +1 -0
- package/dist/sport.d.ts +266 -0
- package/dist/sport.js +48 -0
- package/dist/sport.js.map +1 -0
- package/dist/switch.d.ts +69 -0
- package/dist/switch.js +393 -0
- package/dist/switch.js.map +1 -0
- package/dist/table.d.ts +284 -0
- package/dist/table.js +67 -0
- package/dist/table.js.map +1 -0
- package/dist/talk.d.ts +17 -0
- package/dist/talk.js +44 -0
- package/dist/talk.js.map +1 -0
- package/dist/thirtyone.d.ts +66 -0
- package/dist/thirtyone.js +372 -0
- package/dist/thirtyone.js.map +1 -0
- package/dist/tictactoe.d.ts +68 -0
- package/dist/tictactoe.js +541 -0
- package/dist/tictactoe.js.map +1 -0
- package/dist/tricks.d.ts +21 -0
- package/dist/tricks.js +48 -0
- package/dist/tricks.js.map +1 -0
- package/dist/war.d.ts +44 -0
- package/dist/war.js +185 -0
- package/dist/war.js.map +1 -0
- package/dist/whist.d.ts +52 -0
- package/dist/whist.js +218 -0
- package/dist/whist.js.map +1 -0
- package/dist/yacht.d.ts +96 -0
- package/dist/yacht.js +653 -0
- package/dist/yacht.js.map +1 -0
- package/package.json +41 -4
- package/README.md +0 -3
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
import { clone, FULL, GameError, makeDeck, markReady, nextRandom, rankSeats, shuffled, sortCards, SUITS, SYMBOL, thinkFor, who, withDrinking, withDrinks, } from "./kit.js";
|
|
2
|
+
export const classicThirtyOne = { id: "31-classic", name: "Thirty-One (3 lives)", lives: 3, trips: true, knockerPays: true };
|
|
3
|
+
export const longThirtyOne = { ...classicThirtyOne, id: "31-long", name: "Longer (4 lives)", lives: 4 };
|
|
4
|
+
export const plainThirtyOne = { ...classicThirtyOne, id: "31-plain", name: "Suits only", trips: false, knockerPays: false };
|
|
5
|
+
export const noSuitsThirtyOne = { ...classicThirtyOne, id: "31-nosuits", name: "Every card counts (no suits)", anySuit: true };
|
|
6
|
+
const rank = (c) => c.rank;
|
|
7
|
+
const suitOf = (c) => c.suit;
|
|
8
|
+
const value = (c) => (rank(c) === 14 ? 11 : Math.min(rank(c), 10));
|
|
9
|
+
/**
|
|
10
|
+
* The hand's score: the best suit total, or 30½ for three of a kind. Only cards of one suit count
|
|
11
|
+
* together, unless the house plays `anySuit`: then every card counts.
|
|
12
|
+
*/
|
|
13
|
+
export function score31(cards, trips = true, anySuit = false) {
|
|
14
|
+
let best = anySuit ? cards.reduce((n, c) => n + value(c), 0) : 0;
|
|
15
|
+
for (const suit of SUITS)
|
|
16
|
+
best = Math.max(best, cards.filter((c) => suitOf(c) === suit).reduce((n, c) => n + value(c), 0));
|
|
17
|
+
if (trips && cards.length === 3 && cards.every((c) => rank(c) === rank(cards[0])))
|
|
18
|
+
best = Math.max(best, 30.5);
|
|
19
|
+
return best;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* A hand's score in words, saying which cards made it: "20 in ♦ (A♥ doesn't count)". The number alone
|
|
23
|
+
* leaves a player with A♥ 10♦ Q♦ wondering why it isn't 31.
|
|
24
|
+
*/
|
|
25
|
+
export function explain31(cards, trips = true, anySuit = false) {
|
|
26
|
+
const total = score31(cards, trips, anySuit);
|
|
27
|
+
if (total === 30.5)
|
|
28
|
+
return "30½ (three of a kind)";
|
|
29
|
+
if (anySuit || !cards.length)
|
|
30
|
+
return String(total);
|
|
31
|
+
const suit = SUITS.find((x) => cards.filter((c) => suitOf(c) === x).reduce((n, c) => n + value(c), 0) === total);
|
|
32
|
+
const out = cards.filter((c) => suitOf(c) !== suit);
|
|
33
|
+
if (!out.length)
|
|
34
|
+
return `${total} in ${SYMBOL[suit]}`;
|
|
35
|
+
return `${total} in ${SYMBOL[suit]} (${out.map(label).join(" and ")} ${out.length > 1 ? "don't" : "doesn't"} count)`;
|
|
36
|
+
}
|
|
37
|
+
const show = (n) => (n === 30.5 ? "30½" : String(n));
|
|
38
|
+
/** The best three of four cards: the score and the card to throw away. */
|
|
39
|
+
function bestDiscard(cards, trips, keep, anySuit = false) {
|
|
40
|
+
let best = { score: -1, card: cards[0] };
|
|
41
|
+
for (const c of cards) {
|
|
42
|
+
if (c.id === keep)
|
|
43
|
+
continue;
|
|
44
|
+
const sc = score31(cards.filter((x) => x.id !== c.id), trips, anySuit) - value(c) / 100; // on a tie, throw the lower card
|
|
45
|
+
if (sc > best.score)
|
|
46
|
+
best = { score: sc, card: c };
|
|
47
|
+
}
|
|
48
|
+
return { score: Math.round(best.score * 2) / 2, card: best.card };
|
|
49
|
+
}
|
|
50
|
+
const alive = (s) => s.lives.flatMap((l, i) => (l > 0 ? [i] : []));
|
|
51
|
+
const nextAlive = (s, from) => {
|
|
52
|
+
for (let i = 1; i <= s.seats; i++)
|
|
53
|
+
if (s.lives[(from + i) % s.seats] > 0)
|
|
54
|
+
return (from + i) % s.seats;
|
|
55
|
+
return from;
|
|
56
|
+
};
|
|
57
|
+
function deal(s) {
|
|
58
|
+
const deck = shuffled(makeDeck({ ranks: FULL }), nextRandom(s));
|
|
59
|
+
let k = 0;
|
|
60
|
+
s.hands = s.lives.map((l) => (l > 0 ? sortCards(deck.slice(k, (k += 3))) : []));
|
|
61
|
+
s.discard = [deck[k]];
|
|
62
|
+
s.stock = deck.slice(k + 1);
|
|
63
|
+
s.turn = nextAlive(s, s.dealer);
|
|
64
|
+
s.phase = "draw";
|
|
65
|
+
s.taken = null;
|
|
66
|
+
s.knocker = null;
|
|
67
|
+
s.turns = 0;
|
|
68
|
+
s.lost = Array(s.seats).fill(0);
|
|
69
|
+
s.ready = s.lives.map((l) => l <= 0);
|
|
70
|
+
s.narration = null;
|
|
71
|
+
// Dealt 31: show it at once.
|
|
72
|
+
const blitz = alive(s).find((i) => score31(s.hands[i], s.rules.trips, s.rules.anySuit) === 31);
|
|
73
|
+
if (blitz !== undefined)
|
|
74
|
+
showdown(s, blitz);
|
|
75
|
+
}
|
|
76
|
+
export function newThirtyOne(rules, seats, seed) {
|
|
77
|
+
const s = { game: "thirtyone", rules, seats, rng: seed >>> 0, hand: 0, dealer: seed % seats };
|
|
78
|
+
s.lives = Array(seats).fill(rules.lives);
|
|
79
|
+
s.outAt = Array(seats).fill(null);
|
|
80
|
+
deal(s);
|
|
81
|
+
return s;
|
|
82
|
+
}
|
|
83
|
+
/** Everyone shows. With `blitz`, that seat has 31 and everyone else loses a life. */
|
|
84
|
+
function showdown(s, blitz) {
|
|
85
|
+
const living = alive(s);
|
|
86
|
+
const scores = s.hands.map((h) => score31(h, s.rules.trips, s.rules.anySuit));
|
|
87
|
+
const lost = Array(s.seats).fill(0);
|
|
88
|
+
if (blitz !== undefined) {
|
|
89
|
+
for (const i of living)
|
|
90
|
+
if (i !== blitz)
|
|
91
|
+
lost[i] = 1;
|
|
92
|
+
s.narration = `${who(blitz)} has 31! Everyone else loses a life`;
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
const low = Math.min(...living.map((i) => scores[i]));
|
|
96
|
+
const lowest = living.filter((i) => scores[i] === low);
|
|
97
|
+
const k = s.knocker;
|
|
98
|
+
if (k !== null && lowest.includes(k) && lowest.length === 1) {
|
|
99
|
+
lost[k] = s.rules.knockerPays ? 2 : 1;
|
|
100
|
+
s.narration = `${who(k)} knocked but has the lowest hand (${show(low)})${s.rules.knockerPays ? ": two lives" : ""}`;
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
const losers = lowest.filter((i) => i !== k);
|
|
104
|
+
for (const i of losers)
|
|
105
|
+
lost[i] = 1;
|
|
106
|
+
s.narration = `${losers.map(who).join(" and ")} ${losers.length > 1 ? "tie" : "has"} the lowest hand (${show(low)}) and lose${losers.length > 1 ? "" : "s"} a life`;
|
|
107
|
+
if (k !== null && lowest.includes(k))
|
|
108
|
+
s.narration += ` (${who(k)} knocked, so a tie is safe)`;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
// Nobody left standing? Then nobody loses: deal again.
|
|
112
|
+
if (living.every((i) => s.lives[i] - lost[i] <= 0)) {
|
|
113
|
+
s.lost = Array(s.seats).fill(0);
|
|
114
|
+
s.narration = "Everyone would be out: nobody loses, deal again";
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
s.lost = lost;
|
|
118
|
+
for (const i of living) {
|
|
119
|
+
s.lives[i] = Math.max(0, s.lives[i] - lost[i]);
|
|
120
|
+
if (s.lives[i] === 0)
|
|
121
|
+
s.outAt[i] = s.hand;
|
|
122
|
+
}
|
|
123
|
+
const out = living.filter((i) => s.lives[i] === 0);
|
|
124
|
+
if (out.length)
|
|
125
|
+
s.narration += `. ${out.map(who).join(" and ")} ${out.length > 1 ? "are" : "is"} out`;
|
|
126
|
+
if (s.rules.drinking) {
|
|
127
|
+
for (const n of [1, 2])
|
|
128
|
+
s.narration = withDrinks(true, s.narration, living.filter((i) => lost[i] === n && s.lives[i] > 0), n * 2);
|
|
129
|
+
s.narration = withDrinks(true, s.narration, out, 99);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
s.ready = s.lives.map((l, i) => l <= 0 && !lost[i]);
|
|
133
|
+
s.phase = alive(s).length <= 1 ? "finished" : "reveal";
|
|
134
|
+
}
|
|
135
|
+
function refill(s) {
|
|
136
|
+
if (s.stock.length || s.discard.length <= 1)
|
|
137
|
+
return;
|
|
138
|
+
const top = s.discard.pop();
|
|
139
|
+
s.stock = shuffled(s.discard, nextRandom(s));
|
|
140
|
+
s.discard = [top];
|
|
141
|
+
}
|
|
142
|
+
function endTurn(s) {
|
|
143
|
+
s.turns += 1;
|
|
144
|
+
s.taken = null;
|
|
145
|
+
s.turn = nextAlive(s, s.turn);
|
|
146
|
+
s.phase = "draw";
|
|
147
|
+
if (s.turn === s.knocker)
|
|
148
|
+
showdown(s);
|
|
149
|
+
}
|
|
150
|
+
function apply(state, seat, move) {
|
|
151
|
+
const s = clone(state);
|
|
152
|
+
const myTurn = () => {
|
|
153
|
+
if (s.turn !== seat || (s.phase !== "draw" && s.phase !== "discard"))
|
|
154
|
+
throw new GameError("It's not your turn.");
|
|
155
|
+
};
|
|
156
|
+
switch (move.type) {
|
|
157
|
+
case "draw":
|
|
158
|
+
case "take": {
|
|
159
|
+
myTurn();
|
|
160
|
+
if (s.phase !== "draw")
|
|
161
|
+
throw new GameError("Throw a card away first.");
|
|
162
|
+
let card;
|
|
163
|
+
if (move.type === "take") {
|
|
164
|
+
card = s.discard.pop();
|
|
165
|
+
if (!card)
|
|
166
|
+
throw new GameError("There's no discard to take.");
|
|
167
|
+
s.taken = card.id;
|
|
168
|
+
s.narration = `${who(seat)} took the ${label(card)}`;
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
refill(s);
|
|
172
|
+
card = s.stock.pop();
|
|
173
|
+
if (!card)
|
|
174
|
+
throw new GameError("There's nothing left to draw.");
|
|
175
|
+
s.narration = `${who(seat)} drew a card`;
|
|
176
|
+
}
|
|
177
|
+
s.hands[seat] = sortCards([...s.hands[seat], card]);
|
|
178
|
+
s.phase = "discard";
|
|
179
|
+
return s;
|
|
180
|
+
}
|
|
181
|
+
case "knock": {
|
|
182
|
+
myTurn();
|
|
183
|
+
if (s.phase !== "draw")
|
|
184
|
+
throw new GameError("Knock instead of drawing, at the start of your turn.");
|
|
185
|
+
if (s.knocker !== null)
|
|
186
|
+
throw new GameError("Someone has already knocked.");
|
|
187
|
+
s.knocker = seat;
|
|
188
|
+
s.narration = `${who(seat)} knocked: one more turn each`;
|
|
189
|
+
endTurn(s);
|
|
190
|
+
return s;
|
|
191
|
+
}
|
|
192
|
+
case "discard": {
|
|
193
|
+
myTurn();
|
|
194
|
+
if (s.phase !== "discard")
|
|
195
|
+
throw new GameError("Draw or take a card first.");
|
|
196
|
+
const card = s.hands[seat].find((c) => c.id === move.card);
|
|
197
|
+
if (!card)
|
|
198
|
+
throw new GameError("You don't have that card.");
|
|
199
|
+
if (card.id === s.taken)
|
|
200
|
+
throw new GameError("You can't throw back the card you just took.");
|
|
201
|
+
s.hands[seat] = s.hands[seat].filter((c) => c.id !== card.id);
|
|
202
|
+
s.discard.push(card);
|
|
203
|
+
if (score31(s.hands[seat], s.rules.trips, s.rules.anySuit) === 31) {
|
|
204
|
+
showdown(s, seat);
|
|
205
|
+
return s;
|
|
206
|
+
}
|
|
207
|
+
endTurn(s);
|
|
208
|
+
return s;
|
|
209
|
+
}
|
|
210
|
+
case "next": {
|
|
211
|
+
if (s.phase !== "reveal")
|
|
212
|
+
throw new GameError("The round isn't over.");
|
|
213
|
+
if (markReady(s.ready, seat)) {
|
|
214
|
+
s.hand += 1;
|
|
215
|
+
s.dealer = nextAlive(s, s.dealer);
|
|
216
|
+
deal(s);
|
|
217
|
+
}
|
|
218
|
+
return s;
|
|
219
|
+
}
|
|
220
|
+
default:
|
|
221
|
+
throw new GameError("That's not a move in Thirty-One.");
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
const label = (c) => `${{ 11: "J", 12: "Q", 13: "K", 14: "A" }[rank(c)] ?? rank(c)}${SYMBOL[suitOf(c)]}`;
|
|
225
|
+
function view(s, seat) {
|
|
226
|
+
const over = s.phase === "finished";
|
|
227
|
+
const shown = s.phase === "reveal" || over;
|
|
228
|
+
const mine = s.turn === seat && !shown;
|
|
229
|
+
const hearts = (n) => (n > 0 ? "♥".repeat(n) : "Out");
|
|
230
|
+
const melds = shown
|
|
231
|
+
? s.hands.flatMap((h, i) => (h.length && i !== seat ? [{ owner: i, label: `${show(score31(h, s.rules.trips, s.rules.anySuit))}${s.lost[i] ? ` · −${s.lost[i] > 1 ? "2 lives" : "1 life"}` : ""}`, cards: h }] : []))
|
|
232
|
+
: [];
|
|
233
|
+
// With four cards in hand, what counts is the best three: the hand as it would be after the best throw.
|
|
234
|
+
const mineNow = s.hands[seat];
|
|
235
|
+
const kept = mineNow.length === 4 ? mineNow.filter((c) => c.id !== bestDiscard(mineNow, s.rules.trips, s.taken, s.rules.anySuit).card.id) : mineNow;
|
|
236
|
+
let choices = null;
|
|
237
|
+
if (mine && s.phase === "draw" && s.knocker === null)
|
|
238
|
+
choices = { prompt: "", options: [{ label: "Knock", move: { type: "knock" } }] };
|
|
239
|
+
if (s.phase === "reveal" && !s.ready[seat])
|
|
240
|
+
choices = { prompt: "", options: [{ label: "Next round", move: { type: "next" }, primary: true }] };
|
|
241
|
+
return {
|
|
242
|
+
game: "thirtyone",
|
|
243
|
+
seats: s.seats,
|
|
244
|
+
me: seat,
|
|
245
|
+
teams: false,
|
|
246
|
+
phase: s.phase,
|
|
247
|
+
turn: shown ? null : s.turn,
|
|
248
|
+
dealer: s.dealer,
|
|
249
|
+
hand: s.hands[seat],
|
|
250
|
+
tap: mine && s.phase === "discard" ? { type: "discard", cards: s.hands[seat].filter((c) => c.id !== s.taken).map((c) => c.id) } : null,
|
|
251
|
+
pick: null,
|
|
252
|
+
choices,
|
|
253
|
+
players: s.hands.map((h, i) => ({
|
|
254
|
+
cards: h.length,
|
|
255
|
+
line: hearts(s.lives[i]),
|
|
256
|
+
out: s.lives[i] <= 0,
|
|
257
|
+
dealer: i === s.dealer,
|
|
258
|
+
badge: s.knocker === i ? "Knocked" : undefined,
|
|
259
|
+
})),
|
|
260
|
+
center: {
|
|
261
|
+
kind: "piles",
|
|
262
|
+
stock: s.stock.length,
|
|
263
|
+
discard: s.discard.slice(-3),
|
|
264
|
+
discardCount: s.discard.length,
|
|
265
|
+
drawMove: mine && s.phase === "draw" && (s.stock.length || s.discard.length > 1) ? { type: "draw" } : null,
|
|
266
|
+
takeMove: mine && s.phase === "draw" && s.discard.length ? { type: "take" } : null,
|
|
267
|
+
},
|
|
268
|
+
melds,
|
|
269
|
+
info: [
|
|
270
|
+
...(mineNow.length ? [`${mineNow.length === 4 ? "Your best three" : "Your hand"}: ${explain31(kept, s.rules.trips, s.rules.anySuit)}`] : []),
|
|
271
|
+
...(s.knocker !== null && !shown ? [`${who(s.knocker)} knocked`] : []),
|
|
272
|
+
],
|
|
273
|
+
narration: s.narration ?? (mine ? (s.phase === "draw" ? "Draw, take the discard, or knock" : "Throw one card away") : null),
|
|
274
|
+
scores: s.lives.map((l, i) => ({ seats: [i], value: l })),
|
|
275
|
+
result: null,
|
|
276
|
+
over: over ? { winners: alive(s), title: `${who(alive(s)[0])} is the last one standing!` } : null,
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
// ---- Computer players --------------------------------------------------------------------------
|
|
280
|
+
function bot(s, seat, style) {
|
|
281
|
+
if (s.phase === "reveal")
|
|
282
|
+
return s.ready[seat] ? null : { type: "next" };
|
|
283
|
+
if (s.turn !== seat)
|
|
284
|
+
return null;
|
|
285
|
+
const hand = s.hands[seat];
|
|
286
|
+
const trips = s.rules.trips;
|
|
287
|
+
const anySuit = s.rules.anySuit;
|
|
288
|
+
const sloppy = Math.random() < (style.sloppy ?? 0) + (1 - (style.skill ?? 1)) * 0.25;
|
|
289
|
+
if (s.phase === "discard") {
|
|
290
|
+
if (sloppy) {
|
|
291
|
+
const can = hand.filter((c) => c.id !== s.taken);
|
|
292
|
+
return { type: "discard", card: can[Math.floor(Math.random() * can.length)].id };
|
|
293
|
+
}
|
|
294
|
+
return { type: "discard", card: bestDiscard(hand, trips, s.taken, anySuit).card.id };
|
|
295
|
+
}
|
|
296
|
+
if (s.phase !== "draw")
|
|
297
|
+
return null;
|
|
298
|
+
const now = score31(hand, trips, anySuit);
|
|
299
|
+
// Knock sooner as the round drags on, and later in a big game where somebody always beats you.
|
|
300
|
+
const round = s.turns / Math.max(1, alive(s).length);
|
|
301
|
+
const bar = 27 + Math.min(2, alive(s).length / 3) - round * 1.2 - (style.bold ?? 0.3) * 2;
|
|
302
|
+
if (s.knocker === null && round >= 1 && now >= bar)
|
|
303
|
+
return { type: "knock" };
|
|
304
|
+
const top = s.discard[s.discard.length - 1];
|
|
305
|
+
if (top) {
|
|
306
|
+
const withTop = bestDiscard([...hand, top], trips, top.id, anySuit).score;
|
|
307
|
+
if (withTop >= now + 4 || (withTop > now && withTop >= 25))
|
|
308
|
+
return { type: "take" };
|
|
309
|
+
}
|
|
310
|
+
if (!s.stock.length && s.discard.length <= 1)
|
|
311
|
+
return { type: "take" };
|
|
312
|
+
return { type: "draw" };
|
|
313
|
+
}
|
|
314
|
+
const thirtyOneGame = {
|
|
315
|
+
id: "thirtyone",
|
|
316
|
+
name: "Thirty-One",
|
|
317
|
+
emoji: "🎯",
|
|
318
|
+
blurb: "Three cards, one suit, as close to 31 as you dare",
|
|
319
|
+
tagline: "Draw and throw away to build the best suit. Knock when you're happy; the lowest hand loses a life.",
|
|
320
|
+
seats: { min: 2, max: 8, default: 4 },
|
|
321
|
+
teams: false,
|
|
322
|
+
presets: [classicThirtyOne, longThirtyOne, plainThirtyOne, noSuitsThirtyOne],
|
|
323
|
+
fields: [
|
|
324
|
+
{ key: "lives", label: "Lives", kind: "choice", options: [[2, "2"], [3, "3"], [4, "4"], [5, "5"]] },
|
|
325
|
+
{ key: "anySuit", label: "Every card counts", hint: "Suits don't matter: all three cards add up, whatever their suits.", kind: "toggle" },
|
|
326
|
+
{ key: "trips", label: "Three of a kind counts 30½", kind: "toggle" },
|
|
327
|
+
{ key: "knockerPays", label: "Knocker pays double", hint: "Knock and finish lowest: lose two lives.", kind: "toggle" },
|
|
328
|
+
],
|
|
329
|
+
normalize(rules) {
|
|
330
|
+
const given = (rules && typeof rules === "object" ? rules : {});
|
|
331
|
+
const base = [classicThirtyOne, longThirtyOne, plainThirtyOne, noSuitsThirtyOne].find((p) => p.id === given.id) ?? classicThirtyOne;
|
|
332
|
+
const r = { ...base, ...given };
|
|
333
|
+
return { ...r, lives: Number(r.lives), anySuit: r.anySuit === true };
|
|
334
|
+
},
|
|
335
|
+
validate(r) {
|
|
336
|
+
return r.lives >= 1 && r.lives <= 9 ? [] : ["Pick between 1 and 9 lives."];
|
|
337
|
+
},
|
|
338
|
+
describe(r) {
|
|
339
|
+
return [
|
|
340
|
+
r.anySuit
|
|
341
|
+
? "Three cards each. Your hand is worth all three cards added up, whatever their suits: aces 11, faces 10, the rest face value. 31 is perfect."
|
|
342
|
+
: "Three cards each. Only cards of one suit count together, and your hand is worth its best suit: aces 11, faces 10, the rest face value. A♥ K♥ 10♥ is a perfect 31; A♥ 10♦ Q♦ is 20, because the ace is on its own.",
|
|
343
|
+
...(r.trips ? ["Three of a kind is worth 30½."] : []),
|
|
344
|
+
"On your turn draw from the stock or take the top discard, then throw one card away (not the one you just took).",
|
|
345
|
+
`Happy with your hand? Knock instead of drawing. Everyone else gets one more turn, then all hands show and the lowest loses a life. A knocker who ties for lowest is safe${r.knockerPays ? "; a knocker who is lowest alone loses two" : ""}.`,
|
|
346
|
+
"Get 31 and show it at once: everyone else loses a life.",
|
|
347
|
+
`Everyone starts with ${r.lives} lives. Lose them all and you're out; the last one left wins.`,
|
|
348
|
+
];
|
|
349
|
+
},
|
|
350
|
+
newGame: newThirtyOne,
|
|
351
|
+
apply,
|
|
352
|
+
view,
|
|
353
|
+
bot,
|
|
354
|
+
thinkingTime: (s) => (s.phase === "reveal" ? 2400 : s.phase === "discard" ? thinkFor(4, 0.8) : thinkFor(2, 0.9)),
|
|
355
|
+
summary(s) {
|
|
356
|
+
const over = s.phase === "finished";
|
|
357
|
+
return {
|
|
358
|
+
game: "thirtyone",
|
|
359
|
+
rules: s.rules.name,
|
|
360
|
+
phase: s.phase,
|
|
361
|
+
over,
|
|
362
|
+
hand: s.hand + 1,
|
|
363
|
+
scoreLine: s.lives.join(" · ") + " lives",
|
|
364
|
+
order: over ? rankSeats(s.lives.map((l, i) => ({ seats: [i], score: l * 1000 + (s.outAt[i] ?? 999) }))) : null,
|
|
365
|
+
winners: over ? alive(s) : null,
|
|
366
|
+
teams: false,
|
|
367
|
+
seats: s.seats,
|
|
368
|
+
};
|
|
369
|
+
},
|
|
370
|
+
};
|
|
371
|
+
export const thirtyOne = withDrinking(thirtyOneGame, "Adults only. Two sips for every life lost; out and you finish your drink (or sip water).", "two sips for every life you lose; lose your last and finish your drink.");
|
|
372
|
+
//# sourceMappingURL=thirtyone.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"thirtyone.js","sourceRoot":"","sources":["../src/thirtyone.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { type BoardGame } from "./board.js";
|
|
2
|
+
import { type BaseRules } from "./table.js";
|
|
3
|
+
export interface TicTacToeRules extends BaseRules {
|
|
4
|
+
/** One board, or Ultimate's nine small ones (always 3×3 each, three in a row). */
|
|
5
|
+
board: "single" | "ultimate";
|
|
6
|
+
/** The board is size × size (one board only). */
|
|
7
|
+
size: number;
|
|
8
|
+
/** How many in a row win (one board only). More than that in a row wins too. */
|
|
9
|
+
line: number;
|
|
10
|
+
/** Who plays X in the first game. */
|
|
11
|
+
first: "random" | "seat1" | "seat2";
|
|
12
|
+
/** Games in a match: most wins takes it. */
|
|
13
|
+
games: number;
|
|
14
|
+
}
|
|
15
|
+
export declare const classicTicTacToe: TicTacToeRules;
|
|
16
|
+
export declare const ultimateTicTacToe: TicTacToeRules;
|
|
17
|
+
export declare const fourTicTacToe: TicTacToeRules;
|
|
18
|
+
export declare const gomoku: TicTacToeRules;
|
|
19
|
+
/** A cell: the seat whose mark is there, or null. */
|
|
20
|
+
type Mark = number | null;
|
|
21
|
+
export interface TicTacToeState {
|
|
22
|
+
game: "tictactoe";
|
|
23
|
+
rules: TicTacToeRules;
|
|
24
|
+
seats: number;
|
|
25
|
+
rng: number;
|
|
26
|
+
/** Which game of the match, from 1. */
|
|
27
|
+
round: number;
|
|
28
|
+
/** Who plays X (and so goes first) in this game. */
|
|
29
|
+
first: number;
|
|
30
|
+
/** Row by row. One board: size × size. Ultimate: the whole 9×9. */
|
|
31
|
+
cells: Mark[];
|
|
32
|
+
/** Ultimate: who has each small board; "draw" for a full one nobody took. */
|
|
33
|
+
blocks: (number | "draw" | null)[] | null;
|
|
34
|
+
/** Ultimate: the small board the next move must be in; null for anywhere open. */
|
|
35
|
+
forced: number | null;
|
|
36
|
+
turn: number;
|
|
37
|
+
last: number | null;
|
|
38
|
+
/** The cells of the winning line, once there is one. */
|
|
39
|
+
won: number[] | null;
|
|
40
|
+
/** Who won the game just played; null for a draw (or while playing). */
|
|
41
|
+
roundWinner: number | null;
|
|
42
|
+
wins: number[];
|
|
43
|
+
draws: number;
|
|
44
|
+
phase: "playing" | "scored" | "finished";
|
|
45
|
+
ready: boolean[];
|
|
46
|
+
narration: string | null;
|
|
47
|
+
}
|
|
48
|
+
export type TicTacToeMove = {
|
|
49
|
+
type: "mark";
|
|
50
|
+
cell: number;
|
|
51
|
+
} | {
|
|
52
|
+
type: "next";
|
|
53
|
+
};
|
|
54
|
+
/** Cells along one side of the whole grid. */
|
|
55
|
+
export declare const sideOf: (rules: TicTacToeRules) => number;
|
|
56
|
+
export declare function newTicTacToe(rules: TicTacToeRules, seats: number, seed: number): TicTacToeState;
|
|
57
|
+
/** The small board a cell of the 9×9 is in, and its place within that board (both 0–8). */
|
|
58
|
+
export declare const blockOf: (cell: number) => number;
|
|
59
|
+
export declare const spotOf: (cell: number) => number;
|
|
60
|
+
/** The 9×9 cell at a spot of a small board. */
|
|
61
|
+
export declare const cellIn: (block: number, spot: number) => number;
|
|
62
|
+
/** The cells a move can go in now. */
|
|
63
|
+
export declare function openCells(s: Pick<TicTacToeState, "rules" | "cells" | "blocks" | "forced" | "phase">): number[];
|
|
64
|
+
/** Every best move on a 3×3 board: the squares that keep the best result that can still be had. */
|
|
65
|
+
export declare function bestClassicMoves(cells: Mark[], turn: number): number[];
|
|
66
|
+
/** Tic-Tac-Toe, with resigning, draw offers and taking a move back (see offers.ts). */
|
|
67
|
+
export declare const ticTacToe: BoardGame<TicTacToeRules & import("./offers.js").OfferRules, import("./offers.js").WithOffers<TicTacToeState>, import("./offers.js").OfferMove | TicTacToeMove>;
|
|
68
|
+
export {};
|