@journey-to-code/games 0.0.0-stage → 0.1.0

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.
Files changed (207) hide show
  1. package/LICENSE +21 -0
  2. package/dist/backgammon.d.ts +146 -0
  3. package/dist/backgammon.js +1221 -0
  4. package/dist/backgammon.js.map +1 -0
  5. package/dist/blackjack.d.ts +66 -0
  6. package/dist/blackjack.js +452 -0
  7. package/dist/blackjack.js.map +1 -0
  8. package/dist/bluff.d.ts +60 -0
  9. package/dist/bluff.js +239 -0
  10. package/dist/bluff.js.map +1 -0
  11. package/dist/board.d.ts +387 -0
  12. package/dist/board.js +105 -0
  13. package/dist/board.js.map +1 -0
  14. package/dist/bridge.d.ts +86 -0
  15. package/dist/bridge.js +494 -0
  16. package/dist/bridge.js.map +1 -0
  17. package/dist/canasta.d.ts +88 -0
  18. package/dist/canasta.js +646 -0
  19. package/dist/canasta.js.map +1 -0
  20. package/dist/checkers.d.ts +108 -0
  21. package/dist/checkers.js +756 -0
  22. package/dist/checkers.js.map +1 -0
  23. package/dist/chess.d.ts +162 -0
  24. package/dist/chess.js +904 -0
  25. package/dist/chess.js.map +1 -0
  26. package/dist/chesscore.d.ts +136 -0
  27. package/dist/chesscore.js +1121 -0
  28. package/dist/chesscore.js.map +1 -0
  29. package/dist/combat.d.ts +102 -0
  30. package/dist/combat.js +772 -0
  31. package/dist/combat.js.map +1 -0
  32. package/dist/contractrummy.d.ts +77 -0
  33. package/dist/contractrummy.js +430 -0
  34. package/dist/contractrummy.js.map +1 -0
  35. package/dist/crazy8.d.ts +65 -0
  36. package/dist/crazy8.js +366 -0
  37. package/dist/crazy8.js.map +1 -0
  38. package/dist/cribbage.d.ts +75 -0
  39. package/dist/cribbage.js +428 -0
  40. package/dist/cribbage.js.map +1 -0
  41. package/dist/cuckoo.d.ts +43 -0
  42. package/dist/cuckoo.js +216 -0
  43. package/dist/cuckoo.js.map +1 -0
  44. package/dist/drinkingpyramid.d.ts +54 -0
  45. package/dist/drinkingpyramid.js +213 -0
  46. package/dist/drinkingpyramid.js.map +1 -0
  47. package/dist/drinks.d.ts +25 -0
  48. package/dist/drinks.js +40 -0
  49. package/dist/drinks.js.map +1 -0
  50. package/dist/dropfour.d.ts +103 -0
  51. package/dist/dropfour.js +577 -0
  52. package/dist/dropfour.js.map +1 -0
  53. package/dist/durak.d.ts +58 -0
  54. package/dist/durak.js +332 -0
  55. package/dist/durak.js.map +1 -0
  56. package/dist/euchre.d.ts +80 -0
  57. package/dist/euchre.js +453 -0
  58. package/dist/euchre.js.map +1 -0
  59. package/dist/fivedraw.d.ts +50 -0
  60. package/dist/fivedraw.js +289 -0
  61. package/dist/fivedraw.js.map +1 -0
  62. package/dist/fivehundred.d.ts +90 -0
  63. package/dist/fivehundred.js +504 -0
  64. package/dist/fivehundred.js.map +1 -0
  65. package/dist/freecell.d.ts +50 -0
  66. package/dist/freecell.js +327 -0
  67. package/dist/freecell.js.map +1 -0
  68. package/dist/fruitsalad.d.ts +69 -0
  69. package/dist/fruitsalad.js +427 -0
  70. package/dist/fruitsalad.js.map +1 -0
  71. package/dist/gin.d.ts +72 -0
  72. package/dist/gin.js +393 -0
  73. package/dist/gin.js.map +1 -0
  74. package/dist/go.d.ts +132 -0
  75. package/dist/go.js +659 -0
  76. package/dist/go.js.map +1 -0
  77. package/dist/goboard.d.ts +218 -0
  78. package/dist/goboard.js +880 -0
  79. package/dist/goboard.js.map +1 -0
  80. package/dist/gofish.d.ts +37 -0
  81. package/dist/gofish.js +235 -0
  82. package/dist/gofish.js.map +1 -0
  83. package/dist/golf.d.ts +64 -0
  84. package/dist/golf.js +343 -0
  85. package/dist/golf.js.map +1 -0
  86. package/dist/handfoot.d.ts +86 -0
  87. package/dist/handfoot.js +515 -0
  88. package/dist/handfoot.js.map +1 -0
  89. package/dist/hearts.d.ts +65 -0
  90. package/dist/hearts.js +390 -0
  91. package/dist/hearts.js.map +1 -0
  92. package/dist/holdem.d.ts +45 -0
  93. package/dist/holdem.js +286 -0
  94. package/dist/holdem.js.map +1 -0
  95. package/dist/horserace.d.ts +49 -0
  96. package/dist/horserace.js +207 -0
  97. package/dist/horserace.js.map +1 -0
  98. package/dist/index.d.ts +65 -0
  99. package/dist/index.js +66 -0
  100. package/dist/index.js.map +1 -0
  101. package/dist/kingscorner.d.ts +59 -0
  102. package/dist/kingscorner.js +374 -0
  103. package/dist/kingscorner.js.map +1 -0
  104. package/dist/kingscup.d.ts +44 -0
  105. package/dist/kingscup.js +185 -0
  106. package/dist/kingscup.js.map +1 -0
  107. package/dist/kit.d.ts +283 -0
  108. package/dist/kit.js +73 -0
  109. package/dist/kit.js.map +1 -0
  110. package/dist/klondike.d.ts +57 -0
  111. package/dist/klondike.js +314 -0
  112. package/dist/klondike.js.map +1 -0
  113. package/dist/liarspoker.d.ts +61 -0
  114. package/dist/liarspoker.js +298 -0
  115. package/dist/liarspoker.js.map +1 -0
  116. package/dist/memory.d.ts +36 -0
  117. package/dist/memory.js +181 -0
  118. package/dist/memory.js.map +1 -0
  119. package/dist/minigolf.d.ts +104 -0
  120. package/dist/minigolf.js +724 -0
  121. package/dist/minigolf.js.map +1 -0
  122. package/dist/minigolfcourse.d.ts +127 -0
  123. package/dist/minigolfcourse.js +470 -0
  124. package/dist/minigolfcourse.js.map +1 -0
  125. package/dist/offers.d.ts +136 -0
  126. package/dist/offers.js +279 -0
  127. package/dist/offers.js.map +1 -0
  128. package/dist/ohhell.d.ts +66 -0
  129. package/dist/ohhell.js +331 -0
  130. package/dist/ohhell.js.map +1 -0
  131. package/dist/oldmaid.d.ts +40 -0
  132. package/dist/oldmaid.js +186 -0
  133. package/dist/oldmaid.js.map +1 -0
  134. package/dist/pinochle.d.ts +94 -0
  135. package/dist/pinochle.js +466 -0
  136. package/dist/pinochle.js.map +1 -0
  137. package/dist/pitch.d.ts +77 -0
  138. package/dist/pitch.js +362 -0
  139. package/dist/pitch.js.map +1 -0
  140. package/dist/poker.d.ts +79 -0
  141. package/dist/poker.js +268 -0
  142. package/dist/poker.js.map +1 -0
  143. package/dist/president.d.ts +56 -0
  144. package/dist/president.js +339 -0
  145. package/dist/president.js.map +1 -0
  146. package/dist/pyramid.d.ts +39 -0
  147. package/dist/pyramid.js +200 -0
  148. package/dist/pyramid.js.map +1 -0
  149. package/dist/registry.d.ts +17 -0
  150. package/dist/registry.js +70 -0
  151. package/dist/registry.js.map +1 -0
  152. package/dist/reversi.d.ts +69 -0
  153. package/dist/reversi.js +584 -0
  154. package/dist/reversi.js.map +1 -0
  155. package/dist/ridethebus.d.ts +48 -0
  156. package/dist/ridethebus.js +257 -0
  157. package/dist/ridethebus.js.map +1 -0
  158. package/dist/rummy500.d.ts +89 -0
  159. package/dist/rummy500.js +474 -0
  160. package/dist/rummy500.js.map +1 -0
  161. package/dist/sevens.d.ts +48 -0
  162. package/dist/sevens.js +221 -0
  163. package/dist/sevens.js.map +1 -0
  164. package/dist/slapjack.d.ts +42 -0
  165. package/dist/slapjack.js +224 -0
  166. package/dist/slapjack.js.map +1 -0
  167. package/dist/speed.d.ts +44 -0
  168. package/dist/speed.js +201 -0
  169. package/dist/speed.js.map +1 -0
  170. package/dist/spider.d.ts +51 -0
  171. package/dist/spider.js +320 -0
  172. package/dist/spider.js.map +1 -0
  173. package/dist/spite.d.ts +75 -0
  174. package/dist/spite.js +372 -0
  175. package/dist/spite.js.map +1 -0
  176. package/dist/sport.d.ts +266 -0
  177. package/dist/sport.js +48 -0
  178. package/dist/sport.js.map +1 -0
  179. package/dist/switch.d.ts +69 -0
  180. package/dist/switch.js +393 -0
  181. package/dist/switch.js.map +1 -0
  182. package/dist/table.d.ts +284 -0
  183. package/dist/table.js +67 -0
  184. package/dist/table.js.map +1 -0
  185. package/dist/talk.d.ts +17 -0
  186. package/dist/talk.js +44 -0
  187. package/dist/talk.js.map +1 -0
  188. package/dist/thirtyone.d.ts +66 -0
  189. package/dist/thirtyone.js +372 -0
  190. package/dist/thirtyone.js.map +1 -0
  191. package/dist/tictactoe.d.ts +68 -0
  192. package/dist/tictactoe.js +541 -0
  193. package/dist/tictactoe.js.map +1 -0
  194. package/dist/tricks.d.ts +21 -0
  195. package/dist/tricks.js +48 -0
  196. package/dist/tricks.js.map +1 -0
  197. package/dist/war.d.ts +44 -0
  198. package/dist/war.js +185 -0
  199. package/dist/war.js.map +1 -0
  200. package/dist/whist.d.ts +52 -0
  201. package/dist/whist.js +218 -0
  202. package/dist/whist.js.map +1 -0
  203. package/dist/yacht.d.ts +96 -0
  204. package/dist/yacht.js +653 -0
  205. package/dist/yacht.js.map +1 -0
  206. package/package.json +41 -4
  207. package/README.md +0 -3
@@ -0,0 +1,136 @@
1
+ import type { BoardGame, BoardOffers, BoardView } from "./board.js";
2
+ import { type BaseRules, type TableGame } from "./table.js";
3
+ /** The house rule every game with offers shares: what a table allows besides resigning. */
4
+ export type OffersAllowed = "all" | "notakeback" | "none";
5
+ /** Added to the rules of a game with offers. Missing (rules saved before there were offers) is "all". */
6
+ export interface OfferRules {
7
+ offers?: OffersAllowed;
8
+ }
9
+ export type OfferMove = {
10
+ type: "resign";
11
+ } | {
12
+ type: "offer";
13
+ offer: "draw" | "takeback";
14
+ } | {
15
+ type: "accept";
16
+ } | {
17
+ type: "decline";
18
+ };
19
+ /** What the wrapper keeps in a game's state. */
20
+ export interface OffersState<S = unknown> {
21
+ /** Moves made on the board in this game. A take-back doesn't wind it back: it only ever counts up. */
22
+ moves: number;
23
+ /** The offer waiting for an answer, and who made it. */
24
+ open: {
25
+ kind: "draw" | "takeback";
26
+ by: number;
27
+ } | null;
28
+ /** `moves` when each seat last offered a draw; null if it never has. */
29
+ drawAt: (number | null)[];
30
+ /** `moves` when each seat last had a take-back turned down. */
31
+ backAt: (number | null)[];
32
+ /** The last thing that happened with an offer, until the board moves on past it. */
33
+ last: BoardOffers["last"];
34
+ /** The last move made was about an offer, so that is what the table's narration says. */
35
+ spoke: boolean;
36
+ /**
37
+ * The positions a take-back can return to, oldest first: the game as it stood before a seat's
38
+ * turn at the board (one entry for a whole run of jumps). Never part of any view.
39
+ */
40
+ past: {
41
+ seat: number;
42
+ state: S;
43
+ }[];
44
+ /**
45
+ * Ms that have gone by on offers since the last move on the board. An offer or its answer is a
46
+ * move as far as the room is concerned, and a room's clocks count from the last move; this is
47
+ * taken off them, so asking and answering never buys anybody time.
48
+ */
49
+ idle: number;
50
+ }
51
+ export type WithOffers<S> = S & {
52
+ offers?: OffersState<S>;
53
+ };
54
+ /** What a game says about itself to have offers. */
55
+ export interface OfferOptions<S> {
56
+ /**
57
+ * End the game being played: `winner` takes it, or nobody does (null: a draw by agreement). `s`
58
+ * is a copy to change, the way an engine's own move would end a game: score it, narrate it, go to
59
+ * the next phase. `by` is who resigned, or who offered the draw.
60
+ */
61
+ settle(s: S, result: {
62
+ winner: number | null;
63
+ by: number;
64
+ reason: "resigned" | "agreed";
65
+ }): void;
66
+ /** Is a game being played (not between games, not over)? Without it: `state.phase === "playing"`. */
67
+ live?(state: S): boolean;
68
+ /**
69
+ * Whether moves can be taken back in this game. Left out, they can't, and no earlier position is
70
+ * ever kept: say `true` only for a game where every seat sees everything and a move decides
71
+ * nothing by chance. A function can rule it out for some tables (a game against a shot clock).
72
+ */
73
+ takeBack?: boolean | ((state: S) => boolean);
74
+ /**
75
+ * How the game stands for a seat, for a computer player answering a draw offer: above zero is
76
+ * better than level, below is worse, null is "can't say". It must use only what that seat knows.
77
+ * A computer player takes a draw when it is worse, or level with the game well along (`levelAfter`),
78
+ * and plays on if it can't say.
79
+ */
80
+ standing?(state: S, seat: number): number | null;
81
+ /**
82
+ * Moves on the board before a computer player takes a draw in a level position. 20 unless given:
83
+ * every game is level at the start, and a draw two moves in is nobody's idea of a game (it would
84
+ * be a way to collect draws from the computer, too). A game short enough to be known says less.
85
+ */
86
+ levelAfter?: number;
87
+ /** Moves on the board before a seat may offer a draw again. 6 unless given. */
88
+ drawGap?: number;
89
+ /** Moves on the board before a seat that was refused may ask to take back again. 2 unless given. */
90
+ backGap?: number;
91
+ /** How many turns back a position is kept. 4 unless given: enough to take back twice running. */
92
+ history?: number;
93
+ }
94
+ export declare const noOffers: <S>() => OffersState<S>;
95
+ /** A state's offers. A game saved before there were any has none open and nothing to take back. */
96
+ export declare function offersOf<S>(state: WithOffers<S>): OffersState<S>;
97
+ /** The moves a view's offers let this seat send: what the table's menu and banner are made of. */
98
+ export declare function offerMoves(view: Pick<BoardView, "offers">): OfferMove[];
99
+ /**
100
+ * A table's rules for a match that counts (a tournament): moves can't be taken back there. A game
101
+ * without offers gets its rules back as they were.
102
+ */
103
+ export declare function matchRules<R extends object>(game: Pick<TableGame<any, any, any, any>, "fields">, rules: R): R;
104
+ /** The shape the board games' matches share: games won and drawn, and the game being played. */
105
+ interface MatchState {
106
+ rules: {
107
+ games: number;
108
+ };
109
+ round: number;
110
+ wins: number[];
111
+ draws?: number;
112
+ roundWinner: number | null;
113
+ phase: string;
114
+ narration: string | null;
115
+ }
116
+ /**
117
+ * `settle` for a game whose state keeps a match the way the board games here do (`wins`, `draws`,
118
+ * `round`, `roundWinner`, and a phase that goes to "scored" between games and "finished" at the
119
+ * end): the game being played goes to `winner`, or is drawn, and the match carries on or ends.
120
+ */
121
+ export declare function settleMatch(s: MatchState, { winner, by, reason }: {
122
+ winner: number | null;
123
+ by: number;
124
+ reason: "resigned" | "agreed";
125
+ }): void;
126
+ /**
127
+ * A board game with resigning, draw offers and (if it says so) taking moves back. The game's own
128
+ * `apply`, `view` and computer player are used as they are; see the top of this file for the rules.
129
+ */
130
+ export declare function withOffers<R extends BaseRules, S extends {
131
+ rules: R;
132
+ seats: number;
133
+ }, M extends {
134
+ type: string;
135
+ }>(game: BoardGame<R, S, M>, options: OfferOptions<S>): BoardGame<R & OfferRules, WithOffers<S>, M | OfferMove>;
136
+ export {};
package/dist/offers.js ADDED
@@ -0,0 +1,279 @@
1
+ import { clone, GameError, who } from "./table.js";
2
+ const other = (seat) => 1 - seat;
3
+ const OFFER_TYPES = new Set(["resign", "offer", "accept", "decline"]);
4
+ const ALLOWED = ["all", "notakeback", "none"];
5
+ export const noOffers = () => ({ moves: 0, open: null, drawAt: [null, null], backAt: [null, null], last: null, spoke: false, past: [], idle: 0 });
6
+ /** A state's offers. A game saved before there were any has none open and nothing to take back. */
7
+ export function offersOf(state) {
8
+ const o = state?.offers;
9
+ return o && typeof o === "object" ? { ...noOffers(), ...o } : noOffers();
10
+ }
11
+ /** The game's own state, without the wrapper's part: what the game's own engine is given. */
12
+ function inner(state) {
13
+ if (!state || typeof state !== "object" || !("offers" in state))
14
+ return state;
15
+ const { offers: _, ...rest } = state;
16
+ return rest;
17
+ }
18
+ const allowedBy = (rules) => (ALLOWED.includes(rules?.offers) ? rules.offers : "all");
19
+ /** The moves a view's offers let this seat send: what the table's menu and banner are made of. */
20
+ export function offerMoves(view) {
21
+ const o = view.offers;
22
+ if (!o)
23
+ return [];
24
+ const out = [];
25
+ for (const kind of o.can)
26
+ out.push(kind === "resign" ? { type: "resign" } : { type: "offer", offer: kind });
27
+ if (o.answer)
28
+ out.push({ type: "accept" }, { type: "decline" });
29
+ return out;
30
+ }
31
+ /**
32
+ * A table's rules for a match that counts (a tournament): moves can't be taken back there. A game
33
+ * without offers gets its rules back as they were.
34
+ */
35
+ export function matchRules(game, rules) {
36
+ if (!game.fields.some((f) => f.key === "offers"))
37
+ return rules;
38
+ return { ...rules, offers: rules.offers === "none" ? "none" : "notakeback" };
39
+ }
40
+ /**
41
+ * `settle` for a game whose state keeps a match the way the board games here do (`wins`, `draws`,
42
+ * `round`, `roundWinner`, and a phase that goes to "scored" between games and "finished" at the
43
+ * end): the game being played goes to `winner`, or is drawn, and the match carries on or ends.
44
+ */
45
+ export function settleMatch(s, { winner, by, reason }) {
46
+ const many = s.rules.games > 1;
47
+ s.roundWinner = winner;
48
+ if (winner === null) {
49
+ s.draws = (s.draws ?? 0) + 1;
50
+ s.narration = many ? `Game ${s.round} is a draw by agreement` : "A draw by agreement";
51
+ }
52
+ else {
53
+ s.wins[winner] += 1;
54
+ s.narration = reason === "resigned" ? `${who(by)} resigns: ${who(winner)} wins${many ? ` game ${s.round}` : ""}!` : `${who(winner)} wins${many ? ` game ${s.round}` : ""}!`;
55
+ }
56
+ // Finished when the games run out or one side can't be caught, as on the board.
57
+ const left = s.rules.games - s.round;
58
+ s.phase = left <= 0 || Math.abs(s.wins[0] - s.wins[1]) > left ? "finished" : "scored";
59
+ }
60
+ /** What just happened with an offer, as a line for the table; null when the game's own line says it. */
61
+ function noteOf(last) {
62
+ if (!last)
63
+ return null;
64
+ const { kind, by, outcome } = last;
65
+ if (kind === "draw")
66
+ return outcome === "offered" ? `${who(by)} offers a draw` : outcome === "declined" ? `${who(other(by))} turns down the draw` : null;
67
+ if (kind === "takeback") {
68
+ if (outcome === "offered")
69
+ return `${who(by)} asks to take a move back`;
70
+ if (outcome === "declined")
71
+ return `${who(other(by))} says no to taking the move back`;
72
+ if (outcome === "accepted")
73
+ return `${who(other(by))} lets ${who(by)} take the move back`;
74
+ }
75
+ return null;
76
+ }
77
+ /**
78
+ * A board game with resigning, draw offers and (if it says so) taking moves back. The game's own
79
+ * `apply`, `view` and computer player are used as they are; see the top of this file for the rules.
80
+ */
81
+ export function withOffers(game, options) {
82
+ if (game.seats.min !== 2 || game.seats.max !== 2 || game.teams)
83
+ throw new Error(`${game.id}: offers are for games with two sides.`);
84
+ const live = (s) => (options.live ? options.live(s) : s.phase === "playing");
85
+ const drawGap = options.drawGap ?? 6;
86
+ const backGap = options.backGap ?? 2;
87
+ const levelAfter = options.levelAfter ?? 20;
88
+ const keep = Math.max(2, options.history ?? 4);
89
+ /** Whether this table keeps positions to go back to: the game allows it, and so do the house rules. */
90
+ const keeps = (s) => allowedBy(s.rules) === "all" && (typeof options.takeBack === "function" ? options.takeBack(s) : options.takeBack === true);
91
+ const everAllowed = options.takeBack !== undefined && options.takeBack !== false;
92
+ const rngOf = (s) => s.rng;
93
+ /** Which kept position a take-back by `seat` returns to: their last turn, if it or the reply to it was the last thing played. */
94
+ function backTo(o, seat) {
95
+ for (let i = o.past.length - 1; i >= Math.max(0, o.past.length - 2); i--)
96
+ if (o.past[i].seat === seat)
97
+ return i;
98
+ return -1;
99
+ }
100
+ /** Why a seat can't do this now, in words for the player; null when it can. */
101
+ function refusal(s, o, seat, kind) {
102
+ if (seat !== 0 && seat !== 1)
103
+ return "You're not playing at this table.";
104
+ if (!live(s))
105
+ return "There's no game being played.";
106
+ if (kind === "resign")
107
+ return null;
108
+ const allowed = allowedBy(s.rules);
109
+ if (kind === "draw" && allowed === "none")
110
+ return "Draw offers are switched off at this table.";
111
+ if (kind === "takeback" && !keeps(s))
112
+ return !everAllowed ? `Moves can't be taken back in ${game.name}.` : "Taking moves back is switched off at this table.";
113
+ if (o.open)
114
+ return o.open.by === seat ? "You're waiting for an answer already." : `Answer ${who(o.open.by)}'s offer first.`;
115
+ if (kind === "draw") {
116
+ const at = o.drawAt[seat] ?? null;
117
+ const wait = at === null ? 0 : drawGap - (o.moves - at);
118
+ return wait > 0 ? `You've offered a draw: not again for ${wait} more move${wait === 1 ? "" : "s"}.` : null;
119
+ }
120
+ if (backTo(o, seat) < 0)
121
+ return "You haven't made a move that can be taken back.";
122
+ const at = o.backAt[seat] ?? null;
123
+ return at !== null && o.moves - at < backGap ? "You've just been told no: play on." : null;
124
+ }
125
+ function settled(s, winner, by, reason) {
126
+ const next = clone(s);
127
+ options.settle(next, { winner, by, reason });
128
+ if (live(next))
129
+ throw new Error(`${game.id}: settle left the game going.`);
130
+ return next;
131
+ }
132
+ function offerMove(state, seat, move, time) {
133
+ const s = inner(state);
134
+ const o = offersOf(state);
135
+ // Time spent on offers is time off the clock that was running (see `idle`).
136
+ const idle = o.idle + Math.max(0, Number(time?.elapsed) || 0);
137
+ if (move.type === "resign") {
138
+ const no = refusal(s, o, seat, "resign");
139
+ if (no)
140
+ throw new GameError(no);
141
+ return { ...settled(s, other(seat), seat, "resigned"), offers: { ...noOffers(), last: { kind: "resign", by: seat, outcome: "accepted" } } };
142
+ }
143
+ if (move.type === "offer") {
144
+ const kind = move.offer;
145
+ if (kind !== "draw" && kind !== "takeback")
146
+ throw new GameError("That's not something you can offer.");
147
+ const no = refusal(s, o, seat, kind);
148
+ if (no)
149
+ throw new GameError(no);
150
+ const drawAt = kind === "draw" ? o.drawAt.map((at, i) => (i === seat ? o.moves : at)) : o.drawAt;
151
+ return { ...s, offers: { ...o, idle, spoke: true, open: { kind, by: seat }, drawAt, last: { kind, by: seat, outcome: "offered" } } };
152
+ }
153
+ // An answer.
154
+ if (seat !== 0 && seat !== 1)
155
+ throw new GameError("You're not playing at this table.");
156
+ if (!o.open)
157
+ throw new GameError("There's nothing to answer.");
158
+ if (o.open.by === seat)
159
+ throw new GameError(`That's for ${who(other(seat))} to answer.`);
160
+ const { kind, by } = o.open;
161
+ if (move.type === "decline") {
162
+ const backAt = kind === "takeback" ? o.backAt.map((at, i) => (i === by ? o.moves : at)) : o.backAt;
163
+ return { ...s, offers: { ...o, idle, spoke: true, open: null, backAt, last: { kind, by, outcome: "declined" } } };
164
+ }
165
+ if (kind === "draw")
166
+ return { ...settled(s, null, by, "agreed"), offers: { ...noOffers(), last: { kind, by, outcome: "accepted" } } };
167
+ // Take the move back: the game is exactly as it stood before the asker's turn, and that turn
168
+ // and everything after it is forgotten. The clock starts again, as it does for any new position.
169
+ const i = backTo(o, by);
170
+ if (i < 0 || !keeps(s))
171
+ throw new GameError("That move can't be taken back any more.");
172
+ return { ...o.past[i].state, offers: { ...o, idle: 0, spoke: true, open: null, past: o.past.slice(0, i), last: { kind, by, outcome: "accepted" } } };
173
+ }
174
+ /** The wrapper's part of the state after a move on the board (or a button between games). */
175
+ function afterBoardMove(o, before, after, seat) {
176
+ if (!live(before))
177
+ return live(after) ? noOffers() : o;
178
+ // The game ended on the board: nothing is open, and nothing can be taken back.
179
+ if (!live(after))
180
+ return noOffers();
181
+ // Playing on turns down a draw offered to you, and any move makes a take-back out of date.
182
+ const lapsed = o.open && (o.open.kind === "takeback" || o.open.by !== seat);
183
+ let past = o.past;
184
+ if (!keeps(after))
185
+ past = [];
186
+ else if (rngOf(before) !== rngOf(after))
187
+ past = [];
188
+ // One entry a turn: a second hop of the same run of jumps is part of the turn already kept.
189
+ else if (past.at(-1)?.seat !== seat)
190
+ past = [...past, { seat, state: before }].slice(-keep);
191
+ return { ...o, moves: o.moves + 1, idle: 0, spoke: false, past, open: lapsed ? null : o.open, last: lapsed ? { ...o.open, outcome: "lapsed" } : o.open ? o.last : null };
192
+ }
193
+ const describeOffers = (r) => {
194
+ const allowed = allowedBy(r);
195
+ const back = everAllowed && allowed === "all";
196
+ if (allowed === "none")
197
+ return "You can resign at any time. Draw offers are switched off at this table.";
198
+ return `You can resign at any time, or offer a draw${back ? ", or ask to take your last move back" : ""}: the other player says yes or no.`;
199
+ };
200
+ const field = {
201
+ key: "offers",
202
+ label: "Offers",
203
+ hint: "What the players may ask of each other. Resigning is always allowed.",
204
+ kind: "choice",
205
+ options: everAllowed ? [["all", "Draws and taking a move back"], ["notakeback", "Draws only"], ["none", "Neither"]] : [["all", "Draw offers"], ["none", "No draw offers"]],
206
+ };
207
+ const cleanOffers = (rules) => {
208
+ const allowed = allowedBy(rules && typeof rules === "object" ? rules : undefined);
209
+ // A game that never takes moves back has two settings, not three.
210
+ return !everAllowed && allowed === "notakeback" ? "all" : allowed;
211
+ };
212
+ const inherited = game.deadline?.bind(game);
213
+ const own = game.bot.bind(game);
214
+ return {
215
+ ...game,
216
+ presets: game.presets.map((p) => ({ ...p, offers: cleanOffers(p) })),
217
+ fields: [...game.fields, field],
218
+ normalize: (rules) => ({ ...game.normalize(rules), offers: cleanOffers(rules) }),
219
+ validate: (r) => game.validate(r),
220
+ describe: (r) => [...game.describe(r), describeOffers(r)],
221
+ newGame: (rules, seats, seed) => ({ ...game.newGame(rules, seats, seed), offers: noOffers() }),
222
+ apply(state, seat, move, time) {
223
+ if (move && OFFER_TYPES.has(move.type))
224
+ return offerMove(state, seat, move, time);
225
+ const before = inner(state);
226
+ const o = offersOf(state);
227
+ // A game that keeps time (a chess clock) is told how long the move took since the last move
228
+ // on the board: the time an offer and its answer took is the mover's own.
229
+ const after = game.apply(before, seat, move, time && o.idle > 0 ? { ...time, elapsed: time.elapsed + o.idle } : time);
230
+ return { ...after, offers: afterBoardMove(o, before, after, seat) };
231
+ },
232
+ view(state, seat) {
233
+ const v = game.view(state, seat);
234
+ const s = inner(state);
235
+ const o = offersOf(state);
236
+ const can = ["resign", "draw", "takeback"].filter((kind) => refusal(s, o, seat, kind) === null);
237
+ const note = o.spoke ? noteOf(o.last) : null;
238
+ // A clock shown at a seat (`BoardSeat.clock`) has been running while an offer was talked over.
239
+ const players = o.idle > 0 ? v.players.map((p) => (p.clock?.running ? { ...p, clock: { ...p.clock, ms: Math.max(0, p.clock.ms - o.idle) } } : p)) : v.players;
240
+ return { ...v, players, narration: note ?? v.narration, offers: { can, open: o.open, answer: !!o.open && o.open.by !== seat && (seat === 0 || seat === 1), last: o.last } };
241
+ },
242
+ // A computer player answers an offer before anything else, and at once. It never makes one.
243
+ // (Anything more a caller hands a computer player, a test's own dice say, is passed along.)
244
+ bot(state, seat, style, ...rest) {
245
+ const o = offersOf(state);
246
+ if (o.open && o.open.by !== seat && (seat === 0 || seat === 1)) {
247
+ // Among friends a move can always be had back (and where it can't, it can't be asked).
248
+ if (o.open.kind === "takeback")
249
+ return { type: "accept" };
250
+ // Behind, a draw is a gift. Level, it is fair once there has been a game; before both have moved it is neither.
251
+ const standing = options.standing?.(inner(state), seat) ?? null;
252
+ const take = standing !== null && o.moves >= 2 && (standing < 0 || (standing === 0 && o.moves >= levelAfter));
253
+ return take ? { type: "accept" } : { type: "decline" };
254
+ }
255
+ return own(state, seat, style, ...rest);
256
+ },
257
+ // What the turn timer plays for a person who has run out of time: a move on the board. It never
258
+ // answers an offer for them (playing on turns a draw down, which is the answer silence gives).
259
+ play: (state, seat, style, ...rest) => (game.play ? game.play(state, seat, style, ...rest) : own(state, seat, style, ...rest)),
260
+ // Answering an offer takes no thought; the move on the board may (see TableGame.heavy).
261
+ heavy(state, seat) {
262
+ const open = offersOf(state).open;
263
+ return !(open && open.by !== seat && (seat === 0 || seat === 1)) && (game.heavy?.(state, seat) ?? false);
264
+ },
265
+ thinkingTime(state, seat) {
266
+ const open = offersOf(state).open;
267
+ return open && open.by !== seat ? 500 : game.thinkingTime(state, seat);
268
+ },
269
+ // A clock of the game's own has been running all the while an offer was being talked over.
270
+ deadline(state) {
271
+ const due = inherited?.(state) ?? null;
272
+ const idle = offersOf(state).idle;
273
+ return due && idle > 0 ? { ...due, after: Math.max(0, due.after - idle) } : due;
274
+ },
275
+ spent: (state) => offersOf(state).idle + (game.spent?.(state) ?? 0),
276
+ summary: (state) => game.summary(state),
277
+ };
278
+ }
279
+ //# sourceMappingURL=offers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"offers.js","sourceRoot":"","sources":["../src/offers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,66 @@
1
+ import type { Suit } from "@journey-to-code/rules";
2
+ import { type BaseRules, type CardGame, type KCard } from "./kit.js";
3
+ import { type Play } from "./tricks.js";
4
+ export interface OhHellRules extends BaseRules {
5
+ /** The hands, by cards dealt: up from 1 then back down, the reverse, or only down. */
6
+ order: "up-down" | "down-up" | "down";
7
+ /** The most cards in a hand (fewer when there aren't enough cards for everyone). */
8
+ maxCards: number;
9
+ /** The dealer can't bid so the bids add up to the tricks in the hand. */
10
+ hook: boolean;
11
+ /** Exact: 10 + your bid. Tricks: a point a trick, +10 for exact. Penalty: 10 + bid, or lose 5 for each trick you're off. */
12
+ scoring: "exact" | "tricks" | "penalty";
13
+ }
14
+ export declare const riverOhHell: OhHellRules;
15
+ export declare const longOhHell: OhHellRules;
16
+ export declare const quickOhHell: OhHellRules;
17
+ type Phase = "bidding" | "playing" | "scored" | "finished";
18
+ export interface OhHellState {
19
+ game: "ohhell";
20
+ rules: OhHellRules;
21
+ seats: number;
22
+ rng: number;
23
+ /** Cards dealt in each hand, in order. */
24
+ plan: number[];
25
+ hand: number;
26
+ dealer: number;
27
+ phase: Phase;
28
+ hands: KCard[][];
29
+ trumpCard: KCard | null;
30
+ bids: (number | null)[];
31
+ trick: Play[];
32
+ lastTrick: {
33
+ plays: Play[];
34
+ winner: number;
35
+ } | null;
36
+ turn: number;
37
+ tricksWon: number[];
38
+ scores: number[];
39
+ lastHand: {
40
+ bids: number[];
41
+ took: number[];
42
+ points: number[];
43
+ } | null;
44
+ ready: boolean[];
45
+ narration: string | null;
46
+ }
47
+ /** The cards dealt in each hand. Everyone gets the same; one card is left to turn up for trump when it can be. */
48
+ export declare function riverPlan(rules: OhHellRules, seats: number): number[];
49
+ export declare function newOhHell(rules: OhHellRules, seats: number, seed: number): OhHellState;
50
+ /** The bids this seat may make now: 0 to the hand size, without the dealer's forbidden one. */
51
+ export declare function allowedBids(s: OhHellState, seat: number): number[];
52
+ export declare function ohHellLegal(s: OhHellState, seat: number): KCard[];
53
+ type Move = {
54
+ type: "bid";
55
+ bid: number;
56
+ } | {
57
+ type: "play";
58
+ card: string;
59
+ } | {
60
+ type: "next";
61
+ };
62
+ export declare function handPoints(rules: OhHellRules, bid: number, took: number): number;
63
+ /** How many tricks a hand should take: high trumps, aces, guarded kings, and long trump. */
64
+ export declare function estimateTricks(hand: KCard[], trump: Suit | null, seats: number): number;
65
+ export declare const ohHell: CardGame<OhHellRules, OhHellState, Move>;
66
+ export {};