@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
package/dist/board.d.ts
ADDED
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
import type { BaseRules, BoardGameId, Choices, GameOver, RoundResult, Scores, ScoreSheet, TableGame } from "./table.js";
|
|
2
|
+
/** The colours a piece or a cell mark can take; the table decides what each looks like. */
|
|
3
|
+
export type BoardTone = "light" | "dark" | "red" | "blue" | "gold" | "green";
|
|
4
|
+
/** A piece on a cell or in a reserve. */
|
|
5
|
+
export interface BoardPiece {
|
|
6
|
+
/** Whose it is (a seat), or null for something that is nobody's: a blocked cell, a hit, a miss. */
|
|
7
|
+
owner: number | null;
|
|
8
|
+
/** What it is, in the game's own words: "x", "man", "king", "pawn", "stone", "ship", "hit". */
|
|
9
|
+
kind: string;
|
|
10
|
+
/** What is drawn: "✕", "◯", "♛", "●". */
|
|
11
|
+
glyph: string;
|
|
12
|
+
/** What a screen reader says: "X", "white queen", "red king". */
|
|
13
|
+
label: string;
|
|
14
|
+
/** Its colour, when it isn't simply its owner's (seat 0 is the first tone, seat 1 the second…). */
|
|
15
|
+
tone?: BoardTone;
|
|
16
|
+
/**
|
|
17
|
+
* The same piece keeps the same id from move to move, so the table can slide it to where it went.
|
|
18
|
+
* Games where pieces never move (Tic-Tac-Toe) don't need one.
|
|
19
|
+
*/
|
|
20
|
+
id?: string;
|
|
21
|
+
/** Drawn faintly: a piece just taken, a ship that has sunk. */
|
|
22
|
+
faded?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* A piece that covers several cells (a ship) is one of these per cell, all with the same `span`:
|
|
25
|
+
* the table joins them into one shape, and picking up any cell of it picks up the whole piece.
|
|
26
|
+
*/
|
|
27
|
+
span?: string;
|
|
28
|
+
/**
|
|
29
|
+
* A stack: this many identical pieces on the one cell (backgammon's checkers on a point, stones in
|
|
30
|
+
* a pit). Left out for a piece on its own.
|
|
31
|
+
*/
|
|
32
|
+
count?: number;
|
|
33
|
+
/**
|
|
34
|
+
* With `count`: an id for each piece in the stack, from the bottom up, so the table can follow the
|
|
35
|
+
* one that moves from stack to stack. (`id` is for a piece that is alone on its cell.)
|
|
36
|
+
*/
|
|
37
|
+
ids?: string[];
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* A grid whose cells are places on a track and not squares of a field: pieces travel along it, any
|
|
41
|
+
* number can share a place (`count` on the piece), and some cells are places beside the track. It
|
|
42
|
+
* says what the board is, never how it is drawn; `rows` and `cols` still give a plain picture of it
|
|
43
|
+
* (backgammon is two rows of twelve points with the bar between and a tray at the end), and that is
|
|
44
|
+
* all a table that knows nothing about tracks needs.
|
|
45
|
+
*/
|
|
46
|
+
export interface BoardTrack {
|
|
47
|
+
/** What the places are: "points" are backgammon's long triangles. */
|
|
48
|
+
kind: "points";
|
|
49
|
+
/**
|
|
50
|
+
* The cells of the track in the order the first seat's pieces travel them, from the farthest from
|
|
51
|
+
* home to the last. The second seat travels them the other way. A table counts the places from
|
|
52
|
+
* whichever end the viewer is heading for ("your 6 point").
|
|
53
|
+
*/
|
|
54
|
+
path: number[];
|
|
55
|
+
/** Where each seat's pieces wait once they've been knocked off the track, until they come back on: a cell per seat. */
|
|
56
|
+
bar?: number[];
|
|
57
|
+
/** Where each seat's pieces go when they have finished (borne off): a cell per seat. */
|
|
58
|
+
home?: number[];
|
|
59
|
+
}
|
|
60
|
+
/** How a cell is shaded, when it isn't plain: the two colours of a chessboard, water, a marked spot. */
|
|
61
|
+
export type CellShade = "plain" | "light" | "dark" | "water" | "spot";
|
|
62
|
+
/** Why a cell is highlighted. Several can apply to one cell. */
|
|
63
|
+
export type CellMark =
|
|
64
|
+
/** Where the last move landed. */
|
|
65
|
+
"last"
|
|
66
|
+
/** Where the last move came from. */
|
|
67
|
+
| "from"
|
|
68
|
+
/** Part of the winning line. */
|
|
69
|
+
| "win"
|
|
70
|
+
/** In danger: a king in check, a ship just hit. */
|
|
71
|
+
| "threat"
|
|
72
|
+
/** A piece that changed sides on the last move: a disc turned over in Reversi. */
|
|
73
|
+
| "flipped"
|
|
74
|
+
/** A place you could move to, in a game that points them out. Only ever sent to the seat that can. */
|
|
75
|
+
| "hint"
|
|
76
|
+
/** Has to move: a piece that must capture in checkers. */
|
|
77
|
+
| "must"
|
|
78
|
+
/** Can't be played on just now, though it is empty: the ko point in Go. */
|
|
79
|
+
| "barred"
|
|
80
|
+
/** Counted as a side's own at the end: territory in Go. The mark says whose (`owner`). */
|
|
81
|
+
| "claimed";
|
|
82
|
+
export interface BoardGrid {
|
|
83
|
+
/** Names this grid in a move when a view has more than one: "board", "mine", "theirs". */
|
|
84
|
+
id: string;
|
|
85
|
+
/** For screen readers, and shown above the grid when there are two: "Board", "Your fleet". */
|
|
86
|
+
label: string;
|
|
87
|
+
/** A private grid: whose it is. Left out for the board everyone shares. */
|
|
88
|
+
owner?: number;
|
|
89
|
+
rows: number;
|
|
90
|
+
cols: number;
|
|
91
|
+
/** Row by row from the top left, rows × cols of them; null is an empty cell. */
|
|
92
|
+
cells: (BoardPiece | null)[];
|
|
93
|
+
/** Cell colours: "checker" for a chessboard, or a shade for every cell. Plain when left out. */
|
|
94
|
+
shade?: "checker" | CellShade[];
|
|
95
|
+
/** The cells are places along a track, each holding a stack (backgammon): see `BoardTrack`. */
|
|
96
|
+
track?: BoardTrack;
|
|
97
|
+
/** Pieces sit where the lines cross instead of in the squares (Go, Gomoku). */
|
|
98
|
+
points?: boolean;
|
|
99
|
+
/** The board stands on its edge, and a piece put in a column falls to where it lands (a drop game's rack). */
|
|
100
|
+
gravity?: boolean;
|
|
101
|
+
/** Names for the columns and rows ("a"–"h", "8"–"1"), drawn round the edge and read out. */
|
|
102
|
+
coords?: {
|
|
103
|
+
cols: string[];
|
|
104
|
+
rows: string[];
|
|
105
|
+
};
|
|
106
|
+
/** What each cell is called, when a row and a column don't say it well ("centre", "top left"). */
|
|
107
|
+
names?: string[];
|
|
108
|
+
/**
|
|
109
|
+
* The grid is made of equal blocks with heavier lines between them (Ultimate Tic-Tac-Toe's nine
|
|
110
|
+
* small boards). `states` has one entry per block, row by row.
|
|
111
|
+
*/
|
|
112
|
+
blocks?: {
|
|
113
|
+
rows: number;
|
|
114
|
+
cols: number;
|
|
115
|
+
states: {
|
|
116
|
+
/** Who has taken this block, drawn over it; null for nobody (a drawn block is `closed`). */
|
|
117
|
+
owner?: number | null;
|
|
118
|
+
glyph?: string;
|
|
119
|
+
label?: string;
|
|
120
|
+
/** Where the next move has to go. */
|
|
121
|
+
active?: boolean;
|
|
122
|
+
/** Finished: nothing more can be played here. */
|
|
123
|
+
closed?: boolean;
|
|
124
|
+
}[];
|
|
125
|
+
};
|
|
126
|
+
/** `owner` is the seat a "claimed" cell belongs to. */
|
|
127
|
+
marks?: {
|
|
128
|
+
cell: number;
|
|
129
|
+
mark: CellMark;
|
|
130
|
+
owner?: number;
|
|
131
|
+
}[];
|
|
132
|
+
/**
|
|
133
|
+
* Draw the board turned half way round, so the last row is at the top and this seat's own pieces
|
|
134
|
+
* are nearest them (the second player in checkers or chess). Only the drawing turns: cells keep
|
|
135
|
+
* their numbers and their names. "rows" turns it over instead of round: the last row is at the top
|
|
136
|
+
* but left stays left, so both players of a track game run the same way across the screen and each
|
|
137
|
+
* has their home on the same hand (backgammon).
|
|
138
|
+
*/
|
|
139
|
+
flip?: boolean | "rows";
|
|
140
|
+
/**
|
|
141
|
+
* Cells you can tap now. Tapping one sends { type, cell } (plus `grid` when the view has more
|
|
142
|
+
* than one). With `by: "col"` the whole column is the target and the move is { type, col }
|
|
143
|
+
* (a drop game: any cell of the column drops a piece into it).
|
|
144
|
+
*/
|
|
145
|
+
tap?: {
|
|
146
|
+
type: string;
|
|
147
|
+
cells: number[];
|
|
148
|
+
by?: "cell" | "col";
|
|
149
|
+
} | null;
|
|
150
|
+
/**
|
|
151
|
+
* Things you can pick up now, and where each can go: `from` is a cell of this grid, or the
|
|
152
|
+
* `kind` of a piece in your reserve. Choosing one and then a destination sends { type, from, to }.
|
|
153
|
+
* `held` is a source that is already in hand (a checkers piece in the middle of a run of jumps):
|
|
154
|
+
* the table shows it picked up without being asked. `suggest` is a source the table picks up
|
|
155
|
+
* for you while you hold nothing else (the next ship to place), so one tap puts it down.
|
|
156
|
+
* With `quick`, a source that has only one place to go is played by tapping it (a table setting
|
|
157
|
+
* in backgammon); the table still shows where it went.
|
|
158
|
+
*/
|
|
159
|
+
select?: {
|
|
160
|
+
type: string;
|
|
161
|
+
sources: {
|
|
162
|
+
from: number | string;
|
|
163
|
+
to: number[];
|
|
164
|
+
}[];
|
|
165
|
+
held?: number | string;
|
|
166
|
+
suggest?: number | string;
|
|
167
|
+
/**
|
|
168
|
+
* Moves that need one more thing said (what a pawn becomes on the far row): putting `from` down
|
|
169
|
+
* on `to` asks which of `options`, in a small chooser on that cell, the first being the usual
|
|
170
|
+
* one, and sends { type, from, to, [key]: the chosen piece's kind }.
|
|
171
|
+
*/
|
|
172
|
+
choose?: {
|
|
173
|
+
from: number | string;
|
|
174
|
+
to: number;
|
|
175
|
+
key: string;
|
|
176
|
+
options: BoardPiece[];
|
|
177
|
+
}[];
|
|
178
|
+
/** Don't point out where a picked-up piece can go: the table lets it be put down anywhere and the engine says no. */
|
|
179
|
+
quiet?: boolean;
|
|
180
|
+
/** One tap moves (a table setting): a piece with one place to go is played by tapping it. */
|
|
181
|
+
quick?: boolean;
|
|
182
|
+
} | null;
|
|
183
|
+
}
|
|
184
|
+
/** Pieces off the board, per side: captured pieces, stones or discs left, ships still to place. */
|
|
185
|
+
export interface BoardReserve {
|
|
186
|
+
owner: number;
|
|
187
|
+
/** "Captured", "Left to place". */
|
|
188
|
+
label: string;
|
|
189
|
+
pieces: {
|
|
190
|
+
piece: BoardPiece;
|
|
191
|
+
count: number;
|
|
192
|
+
}[];
|
|
193
|
+
}
|
|
194
|
+
/** One die on the table. `value` is null before it has been rolled. */
|
|
195
|
+
export interface BoardDie {
|
|
196
|
+
/** The same die keeps the same id from throw to throw. */
|
|
197
|
+
id: number;
|
|
198
|
+
value: number | null;
|
|
199
|
+
/** Kept back from the next throw. */
|
|
200
|
+
held?: boolean;
|
|
201
|
+
/** Played already, or left over from the turn before: drawn dimmed. */
|
|
202
|
+
used?: boolean;
|
|
203
|
+
/** Whose die it is, when the dice on the table aren't all one player's. */
|
|
204
|
+
owner?: number | null;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* The dice a seat sees. `roll` goes up by one with every throw, so the table knows to tumble them
|
|
208
|
+
* (the dice that aren't `held` are the ones that were thrown). `tap`, when set, makes each listed
|
|
209
|
+
* die a button that sends `{ type, die: id }` (hold or release a die).
|
|
210
|
+
*/
|
|
211
|
+
export interface BoardDice {
|
|
212
|
+
dice: BoardDie[];
|
|
213
|
+
roll: number;
|
|
214
|
+
/** How many faces a die has: six when left out. */
|
|
215
|
+
sides?: number;
|
|
216
|
+
tap?: {
|
|
217
|
+
type: string;
|
|
218
|
+
dice: number[];
|
|
219
|
+
} | null;
|
|
220
|
+
/**
|
|
221
|
+
* Dice only one seat can see (everyone rolling at once, each with their own): whose they are.
|
|
222
|
+
* Left out for dice the whole table sees. Like a private grid, they are only ever sent to that
|
|
223
|
+
* seat, and someone watching is shown none.
|
|
224
|
+
*/
|
|
225
|
+
owner?: number;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* A doubling cube: what the game is being played for, and who may turn it next. The table decides
|
|
229
|
+
* where it sits (in the middle while it is nobody's, on its owner's side after).
|
|
230
|
+
*/
|
|
231
|
+
export interface BoardCube {
|
|
232
|
+
/** What the game is worth now: 1 until it has been turned, then 2, 4, 8… */
|
|
233
|
+
value: number;
|
|
234
|
+
/** Whose side it is on (only they may double next), or null while it is in the middle. */
|
|
235
|
+
owner: number | null;
|
|
236
|
+
/** A double on offer, waiting to be taken or dropped: who offered it. `value` is still the old one. */
|
|
237
|
+
offered: number | null;
|
|
238
|
+
/** Out of play for this game (the Crawford game of a match): nobody may double. */
|
|
239
|
+
dead: boolean;
|
|
240
|
+
}
|
|
241
|
+
export interface BoardSeat {
|
|
242
|
+
/** A short line under the name: "2 wins", "12 discs". */
|
|
243
|
+
line: string;
|
|
244
|
+
/** What this seat plays as, shown beside the name (an X, a black stone). */
|
|
245
|
+
piece?: BoardPiece;
|
|
246
|
+
/** Partners: 0 or 1 (seats 0 and 2 are team 0). */
|
|
247
|
+
team?: 0 | 1;
|
|
248
|
+
/** Out of the game, or sitting this round out. */
|
|
249
|
+
out?: boolean;
|
|
250
|
+
/** A small badge: "Check", "Goes first". */
|
|
251
|
+
badge?: string;
|
|
252
|
+
/**
|
|
253
|
+
* This seat's clock, in a game that has one of its own (a chess clock): the time it had left
|
|
254
|
+
* when the last move was made, and whether it is the one running down now. The table counts
|
|
255
|
+
* the running one down from the time of that move.
|
|
256
|
+
*/
|
|
257
|
+
clock?: {
|
|
258
|
+
ms: number;
|
|
259
|
+
running: boolean;
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
/** One piece going from a cell to another in a recorded move. Null for off the board: taken (`to`), or put on (`from`). */
|
|
263
|
+
export interface BoardChange {
|
|
264
|
+
/** The piece's `id`. */
|
|
265
|
+
id: string;
|
|
266
|
+
from: number | null;
|
|
267
|
+
to: number | null;
|
|
268
|
+
/** The piece as it was before the move, when it left the board or changed (a pawn that was promoted). */
|
|
269
|
+
was?: BoardPiece;
|
|
270
|
+
}
|
|
271
|
+
/** A move in the game's record, in the game's own notation, with enough to put the board back as it was before it. */
|
|
272
|
+
export interface BoardRecordMove {
|
|
273
|
+
/** "Nf3", "exd5", "O-O". */
|
|
274
|
+
label: string;
|
|
275
|
+
by: number;
|
|
276
|
+
/** The number it is written under: "1." for both White's first move and Black's. */
|
|
277
|
+
turn: number;
|
|
278
|
+
/** What moved, in the order it happened; the piece that made the move is last. */
|
|
279
|
+
changes: BoardChange[];
|
|
280
|
+
/** A cell left in danger by it: the king it checks. */
|
|
281
|
+
threat?: number;
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* The game so far, move by move, for a game that keeps a record (Chess): the table lists it, and
|
|
285
|
+
* steps back and forward through it on the first grid by undoing `changes`.
|
|
286
|
+
*/
|
|
287
|
+
export interface BoardRecord {
|
|
288
|
+
moves: BoardRecordMove[];
|
|
289
|
+
/** The whole record as text to copy: a PGN. Seats are named {0}, {1} as everywhere. */
|
|
290
|
+
export?: {
|
|
291
|
+
label: string;
|
|
292
|
+
text: string;
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
/** What a player can do besides move: give the game up, or ask the other player for something. */
|
|
296
|
+
export type OfferKind = "resign" | "draw" | "takeback";
|
|
297
|
+
/**
|
|
298
|
+
* Offers at a two-player board (see offers.ts): what is open, and what this seat may do about it.
|
|
299
|
+
* It is data, the same for every game, and the table says it in its own words. The moves are
|
|
300
|
+
* always the same four, and `offerMoves` lists the ones a view allows.
|
|
301
|
+
*/
|
|
302
|
+
export interface BoardOffers {
|
|
303
|
+
/** What this seat may send now: { type: "resign" }, or { type: "offer", offer: "draw" | "takeback" }. */
|
|
304
|
+
can: OfferKind[];
|
|
305
|
+
/** The offer waiting for an answer, and who made it. Everyone at the table sees this. */
|
|
306
|
+
open: {
|
|
307
|
+
kind: "draw" | "takeback";
|
|
308
|
+
by: number;
|
|
309
|
+
} | null;
|
|
310
|
+
/** It is this seat's to answer, with { type: "accept" } or { type: "decline" }. */
|
|
311
|
+
answer: boolean;
|
|
312
|
+
/**
|
|
313
|
+
* The last thing that happened with an offer, until play has moved on past it. "lapsed" is an
|
|
314
|
+
* offer that was played through instead of answered.
|
|
315
|
+
*/
|
|
316
|
+
last: {
|
|
317
|
+
kind: OfferKind;
|
|
318
|
+
by: number;
|
|
319
|
+
outcome: "offered" | "accepted" | "declined" | "lapsed";
|
|
320
|
+
} | null;
|
|
321
|
+
}
|
|
322
|
+
export interface BoardView {
|
|
323
|
+
game: BoardGameId;
|
|
324
|
+
seats: number;
|
|
325
|
+
me: number;
|
|
326
|
+
teams: boolean;
|
|
327
|
+
phase: string;
|
|
328
|
+
/** Whose move it is, or null when everyone may move (both placing their ships, say). */
|
|
329
|
+
turn: number | null;
|
|
330
|
+
/** The boards, the main one first. A second is drawn smaller beside or under it. None for a game of dice and a sheet. */
|
|
331
|
+
grids: BoardGrid[];
|
|
332
|
+
reserves: BoardReserve[];
|
|
333
|
+
/** The dice on the table, for a game that has them. */
|
|
334
|
+
dice?: BoardDice | null;
|
|
335
|
+
/** The doubling cube, for a game that has one in play (backgammon). */
|
|
336
|
+
cube?: BoardCube | null;
|
|
337
|
+
/** A score sheet, for a game that is scored on one (Yacht's scorecard). */
|
|
338
|
+
sheet?: ScoreSheet | null;
|
|
339
|
+
/** Buttons: "Pass", "Offer a draw", a promotion, "Next game". */
|
|
340
|
+
choices: Choices | null;
|
|
341
|
+
players: BoardSeat[];
|
|
342
|
+
/** Small facts for the table: "Four in a row wins", "Game 2 of 3". */
|
|
343
|
+
info: string[];
|
|
344
|
+
/** What just happened, in words. */
|
|
345
|
+
narration: string | null;
|
|
346
|
+
scores: Scores;
|
|
347
|
+
/** After a round of a longer match, until everyone moves on. */
|
|
348
|
+
result: RoundResult | null;
|
|
349
|
+
/** `winners` is every seat when it's a draw. */
|
|
350
|
+
over: GameOver | null;
|
|
351
|
+
/** Resigning, draw offers and taking moves back, in a game that has them. */
|
|
352
|
+
offers?: BoardOffers;
|
|
353
|
+
/** The moves so far in notation, in a game that keeps a record. */
|
|
354
|
+
record?: BoardRecord;
|
|
355
|
+
}
|
|
356
|
+
/** A board game: an engine whose seats see a `BoardView`. */
|
|
357
|
+
export interface BoardGame<R extends BaseRules = BaseRules, S = unknown, M = Record<string, unknown>> extends TableGame<R, S, M, BoardView> {
|
|
358
|
+
id: BoardGameId;
|
|
359
|
+
}
|
|
360
|
+
export declare const cellAt: (cols: number, row: number, col: number) => number;
|
|
361
|
+
export declare const rowOf: (cols: number, cell: number) => number;
|
|
362
|
+
export declare const colOf: (cols: number, cell: number) => number;
|
|
363
|
+
/** The eight directions as [row, col] steps; the first four are enough to find lines through a cell. */
|
|
364
|
+
export declare const DIRECTIONS: readonly (readonly [number, number])[];
|
|
365
|
+
/** "a", "b", … for columns and "1", "2", … for rows counted from the bottom, as on a chessboard. */
|
|
366
|
+
export declare function chessCoords(rows: number, cols: number): {
|
|
367
|
+
cols: string[];
|
|
368
|
+
rows: string[];
|
|
369
|
+
};
|
|
370
|
+
/** What a cell is called: its own name if the grid gives one, "b2" with coordinates, else "row 2, column 2". */
|
|
371
|
+
export declare function cellName(grid: Pick<BoardGrid, "cols" | "coords" | "names">, cell: number): string;
|
|
372
|
+
/**
|
|
373
|
+
* The longest unbroken line through `cell` of cells that `same` accepts, when it is at least
|
|
374
|
+
* `need` long: the cells of the line, or null. For every N-in-a-row game.
|
|
375
|
+
*/
|
|
376
|
+
export declare function lineThrough(rows: number, cols: number, cell: number, need: number, same: (cell: number) => boolean): number[] | null;
|
|
377
|
+
/**
|
|
378
|
+
* A grid's cells as they stood after the first `count` moves of the record, worked back from how
|
|
379
|
+
* they stand now by undoing the moves since. Pieces keep their ids, so a table can slide them back.
|
|
380
|
+
*/
|
|
381
|
+
export declare function cellsAfter(cells: readonly (BoardPiece | null)[], record: BoardRecord, count: number): (BoardPiece | null)[];
|
|
382
|
+
/**
|
|
383
|
+
* Everything a seat can send from a view, as moves: every tappable cell, every piece and each
|
|
384
|
+
* place it can go, every cell of the sheet it can choose, every die it can tap, every button. The table sends exactly these, and the shared tests check an
|
|
385
|
+
* engine accepts each one it offers.
|
|
386
|
+
*/
|
|
387
|
+
export declare function movesOffered(view: BoardView): Record<string, unknown>[];
|
package/dist/board.js
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
// ---- Helpers for engines ------------------------------------------------------------------------
|
|
2
|
+
export const cellAt = (cols, row, col) => row * cols + col;
|
|
3
|
+
export const rowOf = (cols, cell) => Math.floor(cell / cols);
|
|
4
|
+
export const colOf = (cols, cell) => cell % cols;
|
|
5
|
+
/** The eight directions as [row, col] steps; the first four are enough to find lines through a cell. */
|
|
6
|
+
export const DIRECTIONS = [[0, 1], [1, 0], [1, 1], [1, -1], [0, -1], [-1, 0], [-1, -1], [-1, 1]];
|
|
7
|
+
/** "a", "b", … for columns and "1", "2", … for rows counted from the bottom, as on a chessboard. */
|
|
8
|
+
export function chessCoords(rows, cols) {
|
|
9
|
+
return { cols: Array.from({ length: cols }, (_, c) => String.fromCharCode(97 + c)), rows: Array.from({ length: rows }, (_, r) => String(rows - r)) };
|
|
10
|
+
}
|
|
11
|
+
/** What a cell is called: its own name if the grid gives one, "b2" with coordinates, else "row 2, column 2". */
|
|
12
|
+
export function cellName(grid, cell) {
|
|
13
|
+
if (grid.names?.[cell])
|
|
14
|
+
return grid.names[cell];
|
|
15
|
+
const r = rowOf(grid.cols, cell);
|
|
16
|
+
const c = colOf(grid.cols, cell);
|
|
17
|
+
return grid.coords ? `${grid.coords.cols[c] ?? c + 1}${grid.coords.rows[r] ?? r + 1}` : `row ${r + 1}, column ${c + 1}`;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* The longest unbroken line through `cell` of cells that `same` accepts, when it is at least
|
|
21
|
+
* `need` long: the cells of the line, or null. For every N-in-a-row game.
|
|
22
|
+
*/
|
|
23
|
+
export function lineThrough(rows, cols, cell, need, same) {
|
|
24
|
+
const r0 = rowOf(cols, cell);
|
|
25
|
+
const c0 = colOf(cols, cell);
|
|
26
|
+
let best = null;
|
|
27
|
+
for (const [dr, dc] of DIRECTIONS.slice(0, 4)) {
|
|
28
|
+
const line = [cell];
|
|
29
|
+
for (const sign of [1, -1]) {
|
|
30
|
+
for (let r = r0 + dr * sign, c = c0 + dc * sign; r >= 0 && r < rows && c >= 0 && c < cols && same(cellAt(cols, r, c)); r += dr * sign, c += dc * sign) {
|
|
31
|
+
if (sign === 1)
|
|
32
|
+
line.push(cellAt(cols, r, c));
|
|
33
|
+
else
|
|
34
|
+
line.unshift(cellAt(cols, r, c));
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (line.length >= need && (!best || line.length > best.length))
|
|
38
|
+
best = line;
|
|
39
|
+
}
|
|
40
|
+
return best;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* A grid's cells as they stood after the first `count` moves of the record, worked back from how
|
|
44
|
+
* they stand now by undoing the moves since. Pieces keep their ids, so a table can slide them back.
|
|
45
|
+
*/
|
|
46
|
+
export function cellsAfter(cells, record, count) {
|
|
47
|
+
const out = cells.slice();
|
|
48
|
+
for (let i = record.moves.length - 1; i >= Math.max(0, count); i--) {
|
|
49
|
+
const changes = record.moves[i].changes;
|
|
50
|
+
// Everything that moved is lifted before anything is put back: in a castling move one piece
|
|
51
|
+
// may have landed where the other stood.
|
|
52
|
+
const lifted = new Map();
|
|
53
|
+
for (const c of changes) {
|
|
54
|
+
if (c.to === null || out[c.to]?.id !== c.id)
|
|
55
|
+
continue;
|
|
56
|
+
lifted.set(c.id, out[c.to]);
|
|
57
|
+
out[c.to] = null;
|
|
58
|
+
}
|
|
59
|
+
for (const c of changes) {
|
|
60
|
+
const piece = c.was ?? lifted.get(c.id);
|
|
61
|
+
if (c.from !== null && piece)
|
|
62
|
+
out[c.from] = piece;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return out;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Everything a seat can send from a view, as moves: every tappable cell, every piece and each
|
|
69
|
+
* place it can go, every cell of the sheet it can choose, every die it can tap, every button. The table sends exactly these, and the shared tests check an
|
|
70
|
+
* engine accepts each one it offers.
|
|
71
|
+
*/
|
|
72
|
+
export function movesOffered(view) {
|
|
73
|
+
const out = [];
|
|
74
|
+
const many = view.grids.length > 1;
|
|
75
|
+
for (const g of view.grids) {
|
|
76
|
+
const grid = many ? { grid: g.id } : {};
|
|
77
|
+
if (g.tap) {
|
|
78
|
+
if (g.tap.by === "col")
|
|
79
|
+
for (const col of new Set(g.tap.cells.map((c) => colOf(g.cols, c))))
|
|
80
|
+
out.push({ type: g.tap.type, col, ...grid });
|
|
81
|
+
else
|
|
82
|
+
for (const cell of g.tap.cells)
|
|
83
|
+
out.push({ type: g.tap.type, cell, ...grid });
|
|
84
|
+
}
|
|
85
|
+
for (const s of g.select?.sources ?? []) {
|
|
86
|
+
for (const to of s.to) {
|
|
87
|
+
// A move that asks a question first is one move for each answer.
|
|
88
|
+
const ask = g.select.choose?.find((c) => c.from === s.from && c.to === to);
|
|
89
|
+
if (ask)
|
|
90
|
+
for (const option of ask.options)
|
|
91
|
+
out.push({ type: g.select.type, from: s.from, to, [ask.key]: option.kind, ...grid });
|
|
92
|
+
else
|
|
93
|
+
out.push({ type: g.select.type, from: s.from, to, ...grid });
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
for (const c of view.sheet?.pick?.cells ?? [])
|
|
98
|
+
out.push({ type: view.sheet.pick.type, cell: view.sheet.columns[c.column]?.id });
|
|
99
|
+
for (const die of view.dice?.tap?.dice ?? [])
|
|
100
|
+
out.push({ type: view.dice.tap.type, die });
|
|
101
|
+
for (const o of view.choices?.options ?? [])
|
|
102
|
+
out.push(o.move);
|
|
103
|
+
return out;
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=board.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"board.js","sourceRoot":"","sources":["../src/board.ts"],"names":[],"mappings":"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"}
|
package/dist/bridge.d.ts
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { type BaseRules, type CardGame, type KCard } from "./kit.js";
|
|
2
|
+
import { type Play } from "./tricks.js";
|
|
3
|
+
export interface BridgeRules extends BaseRules {
|
|
4
|
+
/** Rounds of four deals. */
|
|
5
|
+
chukkers: number;
|
|
6
|
+
}
|
|
7
|
+
export declare const chicagoBridge: BridgeRules;
|
|
8
|
+
export declare const longBridge: BridgeRules;
|
|
9
|
+
export type Strain = "clubs" | "diamonds" | "hearts" | "spades" | "nt";
|
|
10
|
+
export interface Contract {
|
|
11
|
+
level: number;
|
|
12
|
+
strain: Strain;
|
|
13
|
+
}
|
|
14
|
+
export type Call = {
|
|
15
|
+
type: "bid";
|
|
16
|
+
level: number;
|
|
17
|
+
strain: Strain;
|
|
18
|
+
} | {
|
|
19
|
+
type: "pass";
|
|
20
|
+
} | {
|
|
21
|
+
type: "double";
|
|
22
|
+
} | {
|
|
23
|
+
type: "redouble";
|
|
24
|
+
};
|
|
25
|
+
export interface BridgeState {
|
|
26
|
+
game: "bridge";
|
|
27
|
+
rules: BridgeRules;
|
|
28
|
+
seats: 4;
|
|
29
|
+
rng: number;
|
|
30
|
+
/** Deals played so far. */
|
|
31
|
+
hand: number;
|
|
32
|
+
dealer: number;
|
|
33
|
+
phase: "bidding" | "playing" | "scored" | "finished";
|
|
34
|
+
hands: KCard[][];
|
|
35
|
+
auction: {
|
|
36
|
+
seat: number;
|
|
37
|
+
call: Call;
|
|
38
|
+
}[];
|
|
39
|
+
contract: (Contract & {
|
|
40
|
+
by: number;
|
|
41
|
+
doubled: 0 | 1 | 2;
|
|
42
|
+
}) | null;
|
|
43
|
+
declarer: number | null;
|
|
44
|
+
trick: Play[];
|
|
45
|
+
lastTrick: {
|
|
46
|
+
plays: Play[];
|
|
47
|
+
winner: number;
|
|
48
|
+
} | null;
|
|
49
|
+
turn: number;
|
|
50
|
+
tricksWon: number[];
|
|
51
|
+
scores: [number, number];
|
|
52
|
+
lastHand: {
|
|
53
|
+
contract: (Contract & {
|
|
54
|
+
doubled: 0 | 1 | 2;
|
|
55
|
+
}) | null;
|
|
56
|
+
declarer: number | null;
|
|
57
|
+
tricks: [number, number];
|
|
58
|
+
points: [number, number];
|
|
59
|
+
made: boolean;
|
|
60
|
+
} | null;
|
|
61
|
+
ready: boolean[];
|
|
62
|
+
narration: string | null;
|
|
63
|
+
}
|
|
64
|
+
export declare const strainName: (s: Strain) => string;
|
|
65
|
+
export declare const contractName: (c: Contract & {
|
|
66
|
+
doubled?: number;
|
|
67
|
+
}) => string;
|
|
68
|
+
/** Chicago vulnerability: none, dealer's side, dealer's side, both. */
|
|
69
|
+
export declare function vulnerable(s: BridgeState, team: 0 | 1): boolean;
|
|
70
|
+
export declare function newBridge(rules: BridgeRules, _seats: number, seed: number): BridgeState;
|
|
71
|
+
/** The calls this seat may make: pass, a higher bid, double their bid, redouble our doubled bid. */
|
|
72
|
+
export declare function callsFor(s: BridgeState, seat: number): Call[];
|
|
73
|
+
export declare function bridgeLegal(s: BridgeState, seat: number): KCard[];
|
|
74
|
+
type Move = Call | {
|
|
75
|
+
type: "play";
|
|
76
|
+
card: string;
|
|
77
|
+
} | {
|
|
78
|
+
type: "next";
|
|
79
|
+
};
|
|
80
|
+
/** Points for the declaring side (positive) or the defenders (negative), Chicago style. */
|
|
81
|
+
export declare function bridgeScore(c: Contract & {
|
|
82
|
+
doubled: 0 | 1 | 2;
|
|
83
|
+
}, tricks: number, vul: boolean): number;
|
|
84
|
+
export declare const hcp: (hand: KCard[]) => number;
|
|
85
|
+
export declare const bridge: CardGame<BridgeRules, BridgeState, Move>;
|
|
86
|
+
export {};
|