@johnmorrisdotca/kumimoji 1.2.2 → 1.3.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.
- package/CHANGELOG.md +21 -1
- package/README.md +80 -39
- package/dist/check.d.ts +26 -1
- package/dist/check.js +26 -1
- package/dist/computer.types.d.ts +24 -2
- package/dist/computerPlay.d.ts +45 -2
- package/dist/computerPlay.js +45 -2
- package/dist/computerTurn.d.ts +42 -3
- package/dist/computerTurn.js +42 -3
- package/dist/daily.d.ts +22 -2
- package/dist/daily.js +22 -2
- package/dist/element-define.d.ts +1 -1
- package/dist/element-define.js +3 -13
- package/dist/element.d.ts +85 -4
- package/dist/element.js +176 -45
- package/dist/embed-day.d.ts +4 -0
- package/dist/embed-day.js +23 -0
- package/dist/export.d.ts +123 -6
- package/dist/export.js +91 -4
- package/dist/generate.d.ts +14 -0
- package/dist/generate.js +14 -0
- package/dist/grid.d.ts +181 -10
- package/dist/grid.js +122 -7
- package/dist/help.d.ts +36 -3
- package/dist/help.js +36 -3
- package/dist/judge.d.ts +14 -0
- package/dist/judge.js +14 -0
- package/dist/kana.d.ts +23 -1
- package/dist/kana.js +23 -1
- package/dist/kumimoji.types.d.ts +70 -5
- package/dist/party.d.ts +268 -14
- package/dist/party.js +268 -14
- package/dist/party.types.d.ts +50 -2
- package/dist/partyKept.d.ts +74 -4
- package/dist/partyKept.js +74 -4
- package/dist/partySeats.d.ts +92 -6
- package/dist/partySeats.js +72 -4
- package/dist/partyTurns.d.ts +171 -5
- package/dist/partyTurns.js +171 -5
- package/dist/placement.d.ts +50 -2
- package/dist/placement.js +30 -0
- package/dist/play.d.ts +247 -15
- package/dist/play.js +237 -15
- package/dist/random.d.ts +34 -3
- package/dist/random.js +23 -2
- package/dist/react.d.ts +42 -4
- package/dist/react.js +22 -5
- package/dist/showcase.d.ts +83 -7
- package/dist/showcase.js +49 -4
- package/dist/strings.d.ts +54 -5
- package/dist/strings.js +34 -3
- package/dist/tableView.d.ts +151 -8
- package/dist/tableView.js +129 -6
- package/dist/tileFace.d.ts +59 -5
- package/dist/tileFace.js +48 -4
- package/dist/tileFamily.d.ts +9 -0
- package/dist/tileFamily.js +9 -0
- package/dist/tileWords.d.ts +93 -6
- package/dist/tileWords.js +83 -6
- package/dist/tileWordsModule.d.ts +11 -1
- package/dist/tileWordsModule.js +11 -1
- package/dist/tiles.constants.d.ts +99 -5
- package/dist/tiles.constants.js +99 -5
- package/dist/turn.d.ts +82 -4
- package/dist/turn.js +82 -4
- package/dist/ui/board.d.ts +60 -5
- package/dist/ui/board.js +28 -2
- package/dist/ui/mount.d.ts +41 -2
- package/dist/ui/mount.js +38 -1
- package/dist/ui/style.d.ts +6 -1
- package/dist/ui/style.js +6 -0
- package/dist/version.d.ts +9 -2
- package/dist/version.js +9 -2
- package/dist/wilds.d.ts +22 -1
- package/dist/wilds.js +22 -1
- package/package.json +64 -56
package/dist/party.js
CHANGED
|
@@ -15,15 +15,48 @@ import { KUMIMOJI_PARTY, kumimojiTileCount } from "./tiles.constants.js";
|
|
|
15
15
|
* everybody — and in `partyTurns.ts`: Done, going out, the last round,
|
|
16
16
|
* resigning and who won. Pure, like every rule here: each returns a new game.
|
|
17
17
|
*/
|
|
18
|
-
/** The tiles a bag must hold for this many players: a hand each and one round of draws.
|
|
18
|
+
/** The tiles a bag must hold for this many players: a hand each and one round of draws.
|
|
19
|
+
*
|
|
20
|
+
* @param players - The requested player count or current player rows.
|
|
21
|
+
* @param hand - The hand size or tile codes, as declared by the function signature.
|
|
22
|
+
* @returns The tiles a bag must hold for this many players: a hand each and one round of draws.
|
|
23
|
+
* @example
|
|
24
|
+
* ```ts
|
|
25
|
+
* import { partyTilesNeeded } from "@johnmorrisdotca/kumimoji";
|
|
26
|
+
*
|
|
27
|
+
* console.log(partyTilesNeeded(2,3));
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
19
30
|
export function partyTilesNeeded(players, hand) {
|
|
20
31
|
return players * hand + players;
|
|
21
32
|
}
|
|
22
|
-
/** Whether a bag of this many tiles can be played by this many: one player can play any bag.
|
|
33
|
+
/** Whether a bag of this many tiles can be played by this many: one player can play any bag.
|
|
34
|
+
*
|
|
35
|
+
* @param players - The requested player count or current player rows.
|
|
36
|
+
* @param hand - The hand size or tile codes, as declared by the function signature.
|
|
37
|
+
* @param tiles - The map from row,column square names to internal tile codes.
|
|
38
|
+
* @returns Whether a bag of this many tiles can be played by this many: one player can play any bag.
|
|
39
|
+
* @example
|
|
40
|
+
* ```ts
|
|
41
|
+
* import { partyFits } from "@johnmorrisdotca/kumimoji";
|
|
42
|
+
*
|
|
43
|
+
* console.log(partyFits(2,3,12));
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
23
46
|
export function partyFits(players, hand, tiles) {
|
|
24
47
|
return players < KUMIMOJI_PARTY.least || tiles >= partyTilesNeeded(players, hand);
|
|
25
48
|
}
|
|
26
|
-
/** A players count from the address, or 1 (the solo game) for anything that is not two to eight.
|
|
49
|
+
/** A players count from the address, or 1 (the solo game) for anything that is not two to eight.
|
|
50
|
+
*
|
|
51
|
+
* @param value - The unknown setup value to interpret.
|
|
52
|
+
* @returns A players count from the address, or 1 (the solo game) for anything that is not two to eight.
|
|
53
|
+
* @example
|
|
54
|
+
* ```ts
|
|
55
|
+
* import { partyPlayersAsked } from "@johnmorrisdotca/kumimoji";
|
|
56
|
+
*
|
|
57
|
+
* console.log(partyPlayersAsked("3"));
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
27
60
|
export function partyPlayersAsked(value) {
|
|
28
61
|
const count = Number(value);
|
|
29
62
|
return Number.isInteger(count) && count >= KUMIMOJI_PARTY.least && count <= KUMIMOJI_PARTY.most ? count : 1;
|
|
@@ -35,6 +68,18 @@ const LENGTHS = ["short", "medium", "full"];
|
|
|
35
68
|
* players comes back when there are fewer again. A Full bag of one set is 144
|
|
36
69
|
* tiles, and eight Classic hands with a round of draws are 96, so there is
|
|
37
70
|
* always one.
|
|
71
|
+
*
|
|
72
|
+
* @param players - The requested player count or current player rows.
|
|
73
|
+
* @param hand - The hand size or tile codes, as declared by the function signature.
|
|
74
|
+
* @param chosen - The selected game length.
|
|
75
|
+
* @param doubleSet - Whether to use two English tile sets.
|
|
76
|
+
* @returns The game length a set-up plays at: the one chosen where the bag holds this many players, else the shortest that does, so a choice made for fewer players comes back when there are fewer again. A Full bag of one set is 144 tiles, and eight Classic hands with a round of draws are 96, so there is always one.
|
|
77
|
+
* @example
|
|
78
|
+
* ```ts
|
|
79
|
+
* import { partyLength } from "@johnmorrisdotca/kumimoji";
|
|
80
|
+
*
|
|
81
|
+
* console.log(partyLength(8,11,"short",false));
|
|
82
|
+
* ```
|
|
38
83
|
*/
|
|
39
84
|
export function partyLength(players, hand, chosen, doubleSet) {
|
|
40
85
|
// One player plays any length, and asks nothing of the size: the set-up screen asks this of every puzzle's.
|
|
@@ -49,6 +94,19 @@ export function partyLength(players, hand, chosen, doubleSet) {
|
|
|
49
94
|
* The deal: each player the next hand from the bag in turn, player one first,
|
|
50
95
|
* and every table empty. A seat is a name, or a name and whether a computer
|
|
51
96
|
* plays it; a computer is named "Computer 1", "Computer 2"… in seat order.
|
|
97
|
+
*
|
|
98
|
+
* @param settings - The native party setup settings.
|
|
99
|
+
* @param bag - The original bag in draw order.
|
|
100
|
+
* @param seats - Local player names and optional computer flags.
|
|
101
|
+
* @returns The deal: each player the next hand from the bag in turn, player one first, and every table empty. A seat is a name, or a name and whether a computer plays it; a computer is named "Computer 1", "Computer 2"… in seat order.
|
|
102
|
+
* @example
|
|
103
|
+
* ```ts
|
|
104
|
+
* import { startParty } from "@johnmorrisdotca/kumimoji";
|
|
105
|
+
*
|
|
106
|
+
* const settings = {size:3,level:"hard",seed:44,gameLength:"short",language:"english",doubleSet:false,diagonals:false,hints:false} as const;
|
|
107
|
+
* const bag = "catdogsun";
|
|
108
|
+
* console.log(startParty(settings,bag,["Seat 1","Seat 2"]).players.length);
|
|
109
|
+
* ```
|
|
52
110
|
*/
|
|
53
111
|
export function startParty(settings, bag, seats) {
|
|
54
112
|
const count = Math.min(Math.max(seats.length, KUMIMOJI_PARTY.least), KUMIMOJI_PARTY.most);
|
|
@@ -64,31 +122,106 @@ export function startParty(settings, bag, seats) {
|
|
|
64
122
|
}
|
|
65
123
|
return { settings, bag, returned: "", taken: count * hand, players, dealt: count, turn: 0, turns: 0, out: [], lastTurns: null, resigned: [], resignRun: [], ending: null, startTable: "", traded: false, passedBy: null };
|
|
66
124
|
}
|
|
67
|
-
/** The name a new computer takes: "Computer" and the lowest number no player at the table already goes by.
|
|
125
|
+
/** The name a new computer takes: "Computer" and the lowest number no player at the table already goes by.
|
|
126
|
+
*
|
|
127
|
+
* @param players - The requested player count or current player rows.
|
|
128
|
+
* @returns The name a new computer takes: "Computer" and the lowest number no player at the table already goes by.
|
|
129
|
+
* @example
|
|
130
|
+
* ```ts
|
|
131
|
+
* import { computerName, startParty } from "@johnmorrisdotca/kumimoji";
|
|
132
|
+
*
|
|
133
|
+
* const settings = {size:3,level:"hard",seed:44,gameLength:"short",language:"english",doubleSet:false,diagonals:false,hints:false} as const;
|
|
134
|
+
* const bag = "catdogsun";
|
|
135
|
+
* const game = startParty(settings,bag,["Seat 1","Seat 2"]);
|
|
136
|
+
* console.log(computerName(game.players));
|
|
137
|
+
* ```
|
|
138
|
+
*/
|
|
68
139
|
export function computerName(players) {
|
|
69
140
|
const taken = new Set(players.map((player) => player.name));
|
|
70
141
|
for (let number = 1;; number += 1)
|
|
71
142
|
if (!taken.has(`Computer ${number}`))
|
|
72
143
|
return `Computer ${number}`;
|
|
73
144
|
}
|
|
74
|
-
/** Whether a computer plays this seat.
|
|
145
|
+
/** Whether a computer plays this seat.
|
|
146
|
+
*
|
|
147
|
+
* @param game - The current immutable shared-bag party game.
|
|
148
|
+
* @param at - The word offset, seat index or date specified by this signature.
|
|
149
|
+
* @returns Whether a computer plays this seat.
|
|
150
|
+
* @example
|
|
151
|
+
* ```ts
|
|
152
|
+
* import { isComputer, startParty } from "@johnmorrisdotca/kumimoji";
|
|
153
|
+
*
|
|
154
|
+
* const settings = {size:3,level:"hard",seed:44,gameLength:"short",language:"english",doubleSet:false,diagonals:false,hints:false} as const;
|
|
155
|
+
* const bag = "catdogsun";
|
|
156
|
+
* const game = startParty(settings,bag,["Seat 1","Seat 2"]);
|
|
157
|
+
* console.log(isComputer(game,0));
|
|
158
|
+
* ```
|
|
159
|
+
*/
|
|
75
160
|
export function isComputer(game, at) {
|
|
76
161
|
return game.players[at]?.computer === true;
|
|
77
162
|
}
|
|
78
|
-
/** A table's tiles as one string in order, wherever they stand: what a turn compares to see whether anything was laid or lifted.
|
|
163
|
+
/** A table's tiles as one string in order, wherever they stand: what a turn compares to see whether anything was laid or lifted.
|
|
164
|
+
*
|
|
165
|
+
* @param tiles - The map from row,column square names to internal tile codes.
|
|
166
|
+
* @returns A table's tiles as one string in order, wherever they stand: what a turn compares to see whether anything was laid or lifted.
|
|
167
|
+
* @example
|
|
168
|
+
* ```ts
|
|
169
|
+
* import { tableTally } from "@johnmorrisdotca/kumimoji";
|
|
170
|
+
*
|
|
171
|
+
* const tiles = new Map([["0,0","c"],["0,1","a"],["0,2","t"]]);
|
|
172
|
+
* console.log(tableTally(tiles));
|
|
173
|
+
* ```
|
|
174
|
+
*/
|
|
79
175
|
export function tableTally(tiles) {
|
|
80
176
|
return [...tiles.values()].sort().join("");
|
|
81
177
|
}
|
|
82
|
-
/** A name as kept: trimmed, one line, and no longer than a line holds.
|
|
178
|
+
/** A name as kept: trimmed, one line, and no longer than a line holds.
|
|
179
|
+
*
|
|
180
|
+
* @param name - The local player name to tidy.
|
|
181
|
+
* @returns A name as kept: trimmed, one line, and no longer than a line holds.
|
|
182
|
+
* @example
|
|
183
|
+
* ```ts
|
|
184
|
+
* import { tidyName } from "@johnmorrisdotca/kumimoji";
|
|
185
|
+
*
|
|
186
|
+
* console.log(tidyName(" Seat 1 "));
|
|
187
|
+
* ```
|
|
188
|
+
*/
|
|
83
189
|
export function tidyName(name) {
|
|
84
190
|
return name.replace(/\s+/g, " ").trim().slice(0, KUMIMOJI_PARTY.nameMost);
|
|
85
191
|
}
|
|
86
|
-
/** What a player is called: their name, or "Player 2".
|
|
192
|
+
/** What a player is called: their name, or "Player 2".
|
|
193
|
+
*
|
|
194
|
+
* @param game - The current immutable shared-bag party game.
|
|
195
|
+
* @param at - The word offset, seat index or date specified by this signature.
|
|
196
|
+
* @returns What a player is called: their name, or "Player 2".
|
|
197
|
+
* @example
|
|
198
|
+
* ```ts
|
|
199
|
+
* import { nameOf, startParty } from "@johnmorrisdotca/kumimoji";
|
|
200
|
+
*
|
|
201
|
+
* const settings = {size:3,level:"hard",seed:44,gameLength:"short",language:"english",doubleSet:false,diagonals:false,hints:false} as const;
|
|
202
|
+
* const bag = "catdogsun";
|
|
203
|
+
* const game = startParty(settings,bag,["Seat 1","Seat 2"]);
|
|
204
|
+
* console.log(nameOf(game,0));
|
|
205
|
+
* ```
|
|
206
|
+
*/
|
|
87
207
|
export function nameOf(game, at) {
|
|
88
208
|
const name = game.players[at]?.name ?? "";
|
|
89
209
|
return name === "" ? `Player ${at + 1}` : name;
|
|
90
210
|
}
|
|
91
|
-
/** The player whose turn it is, as the solo game's moves take a game: the shared bag, and their own hand and table.
|
|
211
|
+
/** The player whose turn it is, as the solo game's moves take a game: the shared bag, and their own hand and table.
|
|
212
|
+
*
|
|
213
|
+
* @param game - The current immutable shared-bag party game.
|
|
214
|
+
* @returns The player whose turn it is, as the solo game's moves take a game: the shared bag, and their own hand and table.
|
|
215
|
+
* @example
|
|
216
|
+
* ```ts
|
|
217
|
+
* import { seatPlay, startParty } from "@johnmorrisdotca/kumimoji";
|
|
218
|
+
*
|
|
219
|
+
* const settings = {size:3,level:"hard",seed:44,gameLength:"short",language:"english",doubleSet:false,diagonals:false,hints:false} as const;
|
|
220
|
+
* const bag = "catdogsun";
|
|
221
|
+
* const game = startParty(settings,bag,["Seat 1","Seat 2"]);
|
|
222
|
+
* console.log(seatPlay(game));
|
|
223
|
+
* ```
|
|
224
|
+
*/
|
|
92
225
|
export function seatPlay(game) {
|
|
93
226
|
const player = game.players[game.turn];
|
|
94
227
|
return { bag: game.bag, returned: game.returned, taken: game.taken, tiles: player.tiles, hand: player.hand };
|
|
@@ -100,11 +233,37 @@ export function seatPlay(game) {
|
|
|
100
233
|
* takes three, so trading without end lets one player take the bag from the
|
|
101
234
|
* others. After a trade the player may still lay, lift and draw, and press
|
|
102
235
|
* Done; the next trade is on their next turn.
|
|
236
|
+
*
|
|
237
|
+
* @param game - The current immutable shared-bag party game.
|
|
238
|
+
* @returns ONE TRADE A TURN. John, 2026-09-29, after a player traded over and over and built up a hand: "if they swap tiles … give them a chance to lay some tiles but cannot ask for another swap until next turn." A trade gives one tile and takes three, so trading without end lets one player take the bag from the others. After a trade the player may still lay, lift and draw, and press Done; the next trade is on their next turn.
|
|
239
|
+
* @example
|
|
240
|
+
* ```ts
|
|
241
|
+
* import { mayTradeThisTurn, startParty } from "@johnmorrisdotca/kumimoji";
|
|
242
|
+
*
|
|
243
|
+
* const settings = {size:3,level:"hard",seed:44,gameLength:"short",language:"english",doubleSet:false,diagonals:false,hints:false} as const;
|
|
244
|
+
* const bag = "catdogsun";
|
|
245
|
+
* const game = startParty(settings,bag,["Seat 1","Seat 2"]);
|
|
246
|
+
* console.log(mayTradeThisTurn(game));
|
|
247
|
+
* ```
|
|
103
248
|
*/
|
|
104
249
|
export function mayTradeThisTurn(game) {
|
|
105
250
|
return game.ending === null && !game.traded && mayTrade(seatPlay(game));
|
|
106
251
|
}
|
|
107
|
-
/** A move made on `seatPlay` put back: the bag as it left it, and the hand and table to the player whose turn it is. A second trade in one turn is refused, the game given back as it was.
|
|
252
|
+
/** A move made on `seatPlay` put back: the bag as it left it, and the hand and table to the player whose turn it is. A second trade in one turn is refused, the game given back as it was.
|
|
253
|
+
*
|
|
254
|
+
* @param game - The current immutable shared-bag party game.
|
|
255
|
+
* @param play - The current immutable solo-game progress.
|
|
256
|
+
* @returns A move made on `seatPlay` put back: the bag as it left it, and the hand and table to the player whose turn it is. A second trade in one turn is refused, the game given back as it was.
|
|
257
|
+
* @example
|
|
258
|
+
* ```ts
|
|
259
|
+
* import { seatPlay, startParty, withSeatPlay } from "@johnmorrisdotca/kumimoji";
|
|
260
|
+
*
|
|
261
|
+
* const settings = {size:3,level:"hard",seed:44,gameLength:"short",language:"english",doubleSet:false,diagonals:false,hints:false} as const;
|
|
262
|
+
* const bag = "catdogsun";
|
|
263
|
+
* const game = startParty(settings,bag,["Seat 1","Seat 2"]);
|
|
264
|
+
* console.log(withSeatPlay(game,seatPlay(game)).taken);
|
|
265
|
+
* ```
|
|
266
|
+
*/
|
|
108
267
|
export function withSeatPlay(game, play) {
|
|
109
268
|
if (game.ending !== null)
|
|
110
269
|
return game;
|
|
@@ -114,15 +273,55 @@ export function withSeatPlay(game, play) {
|
|
|
114
273
|
const traded = game.traded || play.returned.length > game.returned.length;
|
|
115
274
|
return { ...game, returned: play.returned, taken: play.taken, players, traded };
|
|
116
275
|
}
|
|
117
|
-
/** Tiles still in the shared bag.
|
|
276
|
+
/** Tiles still in the shared bag.
|
|
277
|
+
*
|
|
278
|
+
* @param game - The current immutable shared-bag party game.
|
|
279
|
+
* @returns Tiles still in the shared bag.
|
|
280
|
+
* @example
|
|
281
|
+
* ```ts
|
|
282
|
+
* import { partyTilesLeft, startParty } from "@johnmorrisdotca/kumimoji";
|
|
283
|
+
*
|
|
284
|
+
* const settings = {size:3,level:"hard",seed:44,gameLength:"short",language:"english",doubleSet:false,diagonals:false,hints:false} as const;
|
|
285
|
+
* const bag = "catdogsun";
|
|
286
|
+
* const game = startParty(settings,bag,["Seat 1","Seat 2"]);
|
|
287
|
+
* console.log(partyTilesLeft(game));
|
|
288
|
+
* ```
|
|
289
|
+
*/
|
|
118
290
|
export function partyTilesLeft(game) {
|
|
119
291
|
return tilesLeft(seatPlay(game));
|
|
120
292
|
}
|
|
121
|
-
/** The players still in — not resigned — by place, in turn order. Somebody who went out is still in until the game ends.
|
|
293
|
+
/** The players still in — not resigned — by place, in turn order. Somebody who went out is still in until the game ends.
|
|
294
|
+
*
|
|
295
|
+
* @param game - The current immutable shared-bag party game.
|
|
296
|
+
* @returns The players still in — not resigned — by place, in turn order. Somebody who went out is still in until the game ends.
|
|
297
|
+
* @example
|
|
298
|
+
* ```ts
|
|
299
|
+
* import { startParty, stillIn } from "@johnmorrisdotca/kumimoji";
|
|
300
|
+
*
|
|
301
|
+
* const settings = {size:3,level:"hard",seed:44,gameLength:"short",language:"english",doubleSet:false,diagonals:false,hints:false} as const;
|
|
302
|
+
* const bag = "catdogsun";
|
|
303
|
+
* const game = startParty(settings,bag,["Seat 1","Seat 2"]);
|
|
304
|
+
* console.log(stillIn(game));
|
|
305
|
+
* ```
|
|
306
|
+
*/
|
|
122
307
|
export function stillIn(game) {
|
|
123
308
|
return game.players.flatMap((_, at) => (game.resigned.includes(at) ? [] : [at]));
|
|
124
309
|
}
|
|
125
|
-
/** The next player still in after `from`, round the table; `from` itself when nobody else is.
|
|
310
|
+
/** The next player still in after `from`, round the table; `from` itself when nobody else is.
|
|
311
|
+
*
|
|
312
|
+
* @param game - The current immutable shared-bag party game.
|
|
313
|
+
* @param from - The source square or seat index.
|
|
314
|
+
* @returns The next player still in after `from`, round the table; `from` itself when nobody else is.
|
|
315
|
+
* @example
|
|
316
|
+
* ```ts
|
|
317
|
+
* import { nextIn, startParty } from "@johnmorrisdotca/kumimoji";
|
|
318
|
+
*
|
|
319
|
+
* const settings = {size:3,level:"hard",seed:44,gameLength:"short",language:"english",doubleSet:false,diagonals:false,hints:false} as const;
|
|
320
|
+
* const bag = "catdogsun";
|
|
321
|
+
* const game = startParty(settings,bag,["Seat 1","Seat 2"]);
|
|
322
|
+
* console.log(nextIn(game,0));
|
|
323
|
+
* ```
|
|
324
|
+
*/
|
|
126
325
|
export function nextIn(game, from) {
|
|
127
326
|
const count = game.players.length;
|
|
128
327
|
for (let step = 1; step <= count; step += 1) {
|
|
@@ -136,6 +335,22 @@ export function nextIn(game, from) {
|
|
|
136
335
|
* Whether Draw may be pressed: the hand of the player whose turn it is used,
|
|
137
336
|
* their grid sound, and a tile in the bag for every player still in. Never in
|
|
138
337
|
* the last round, when the bag already holds fewer than that.
|
|
338
|
+
*
|
|
339
|
+
* @param game - The current immutable shared-bag party game.
|
|
340
|
+
* @param verdict - The native word and connectivity verdict for this grid.
|
|
341
|
+
* @returns Whether Draw may be pressed: the hand of the player whose turn it is used, their grid sound, and a tile in the bag for every player still in. Never in the last round, when the bag already holds fewer than that.
|
|
342
|
+
* @example
|
|
343
|
+
* ```ts
|
|
344
|
+
* import { loadTileWordsFromModule } from "@johnmorrisdotca/kumimoji/words";
|
|
345
|
+
* import { judgeWithWords, mayDrawAll, startParty } from "@johnmorrisdotca/kumimoji";
|
|
346
|
+
*
|
|
347
|
+
* const words = await loadTileWordsFromModule("english");
|
|
348
|
+
* const verdict = judgeWithWords(new Map([["0,0","c"],["0,1","a"],["0,2","t"]]),words);
|
|
349
|
+
* const settings = {size:3,level:"hard",seed:44,gameLength:"short",language:"english",doubleSet:false,diagonals:false,hints:false} as const;
|
|
350
|
+
* const bag = "catdogsun";
|
|
351
|
+
* const game = startParty(settings,bag,["Seat 1","Seat 2"]);
|
|
352
|
+
* console.log(mayDrawAll(game,verdict));
|
|
353
|
+
* ```
|
|
139
354
|
*/
|
|
140
355
|
export function mayDrawAll(game, verdict) {
|
|
141
356
|
return game.ending === null && game.lastTurns === null && game.players[game.turn].hand.length === 0 && verdict.sound && partyTilesLeft(game) >= stillIn(game).length;
|
|
@@ -144,6 +359,18 @@ export function mayDrawAll(game, verdict) {
|
|
|
144
359
|
* DRAW: every player still in takes one tile, in turn order from the one who
|
|
145
360
|
* pressed it — the race game's rule that when one player uses their hand,
|
|
146
361
|
* everybody draws.
|
|
362
|
+
*
|
|
363
|
+
* @param game - The current immutable shared-bag party game.
|
|
364
|
+
* @returns DRAW: every player still in takes one tile, in turn order from the one who pressed it — the race game's rule that when one player uses their hand, everybody draws.
|
|
365
|
+
* @example
|
|
366
|
+
* ```ts
|
|
367
|
+
* import { drawAll, startParty } from "@johnmorrisdotca/kumimoji";
|
|
368
|
+
*
|
|
369
|
+
* const settings = {size:3,level:"hard",seed:44,gameLength:"short",language:"english",doubleSet:false,diagonals:false,hints:false} as const;
|
|
370
|
+
* const bag = "catdogsun";
|
|
371
|
+
* const game = startParty(settings,bag,["Seat 1","Seat 2"]);
|
|
372
|
+
* console.log(drawAll(game));
|
|
373
|
+
* ```
|
|
147
374
|
*/
|
|
148
375
|
export function drawAll(game) {
|
|
149
376
|
const count = game.players.length;
|
|
@@ -161,11 +388,38 @@ export function drawAll(game) {
|
|
|
161
388
|
* screen opens on the table of whoever has just played (the first player's,
|
|
162
389
|
* before anybody has), and a swipe steps round every player in seat order,
|
|
163
390
|
* resigned ones included.
|
|
391
|
+
*
|
|
392
|
+
* @param game - The current immutable shared-bag party game.
|
|
393
|
+
* @returns WHOSE TABLE IS SHOWN. Nothing in a pass-and-play game is secret — John, 2026-09-28: "there are no secrets because they are face up" — so every table and every hand can be looked at by anybody, read-only. The pass screen opens on the table of whoever has just played (the first player's, before anybody has), and a swipe steps round every player in seat order, resigned ones included.
|
|
394
|
+
* @example
|
|
395
|
+
* ```ts
|
|
396
|
+
* import { passViewStart, startParty } from "@johnmorrisdotca/kumimoji";
|
|
397
|
+
*
|
|
398
|
+
* const settings = {size:3,level:"hard",seed:44,gameLength:"short",language:"english",doubleSet:false,diagonals:false,hints:false} as const;
|
|
399
|
+
* const bag = "catdogsun";
|
|
400
|
+
* const game = startParty(settings,bag,["Seat 1","Seat 2"]);
|
|
401
|
+
* console.log(passViewStart(game));
|
|
402
|
+
* ```
|
|
164
403
|
*/
|
|
165
404
|
export function passViewStart(game) {
|
|
166
405
|
return game.passedBy ?? game.turn;
|
|
167
406
|
}
|
|
168
|
-
/** The player a swipe or an arrow shows next: `by` seats on, round the table.
|
|
407
|
+
/** The player a swipe or an arrow shows next: `by` seats on, round the table.
|
|
408
|
+
*
|
|
409
|
+
* @param game - The current immutable shared-bag party game.
|
|
410
|
+
* @param from - The source square or seat index.
|
|
411
|
+
* @param by - The direction or distance to step between seats.
|
|
412
|
+
* @returns The player a swipe or an arrow shows next: `by` seats on, round the table.
|
|
413
|
+
* @example
|
|
414
|
+
* ```ts
|
|
415
|
+
* import { startParty, stepView } from "@johnmorrisdotca/kumimoji";
|
|
416
|
+
*
|
|
417
|
+
* const settings = {size:3,level:"hard",seed:44,gameLength:"short",language:"english",doubleSet:false,diagonals:false,hints:false} as const;
|
|
418
|
+
* const bag = "catdogsun";
|
|
419
|
+
* const game = startParty(settings,bag,["Seat 1","Seat 2"]);
|
|
420
|
+
* console.log(stepView(game,0,1));
|
|
421
|
+
* ```
|
|
422
|
+
*/
|
|
169
423
|
export function stepView(game, from, by) {
|
|
170
424
|
const count = game.players.length;
|
|
171
425
|
return (((from + by) % count) + count) % count;
|
package/dist/party.types.d.ts
CHANGED
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
import type { Tiles } from "./grid.ts";
|
|
2
2
|
import type { KumimojiLanguage, KumimojiLength, KumimojiLevel } from "./kumimoji.types.ts";
|
|
3
|
-
/** What a pass-and-play game was set up as: the address's own choices, which a kept game is matched to.
|
|
3
|
+
/** What a pass-and-play game was set up as: the address's own choices, which a kept game is matched to.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```ts
|
|
7
|
+
* import type { PartySettings } from "@johnmorrisdotca/kumimoji";
|
|
8
|
+
*
|
|
9
|
+
* const settings = {size:3,level:"hard",seed:44,gameLength:"short",language:"english",doubleSet:false,diagonals:false,hints:false} as const;
|
|
10
|
+
* const value: PartySettings = settings;
|
|
11
|
+
* console.log(value);
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
4
14
|
export type PartySettings = {
|
|
5
15
|
/** The hand each player is dealt: 7 Quick or 11 Classic (3 in the browser tests alone). */
|
|
6
16
|
size: number;
|
|
@@ -20,6 +30,15 @@ export type PartySettings = {
|
|
|
20
30
|
* their own table, and whether the seat is a computer's (`computerTurn.ts`),
|
|
21
31
|
* whose turns play themselves in the browser. A computer's name is always
|
|
22
32
|
* written out ("Computer 1"), never left for its number.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```ts
|
|
36
|
+
* import type { PartyPlayer } from "@johnmorrisdotca/kumimoji";
|
|
37
|
+
*
|
|
38
|
+
* const tiles = new Map([["0,0","c"],["0,1","a"],["0,2","t"]]);
|
|
39
|
+
* const value: PartyPlayer = {name:"Seat 1",hand:["c","a","t"],tiles:new Map()};
|
|
40
|
+
* console.log(value);
|
|
41
|
+
* ```
|
|
23
42
|
*/
|
|
24
43
|
export type PartyPlayer = {
|
|
25
44
|
name: string;
|
|
@@ -27,7 +46,16 @@ export type PartyPlayer = {
|
|
|
27
46
|
tiles: Tiles;
|
|
28
47
|
computer?: boolean;
|
|
29
48
|
};
|
|
30
|
-
/** A seat asked for before the deal or at a join: a name (empty for its number) and whether a computer plays it.
|
|
49
|
+
/** A seat asked for before the deal or at a join: a name (empty for its number) and whether a computer plays it.
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```ts
|
|
53
|
+
* import type { PartySeat } from "@johnmorrisdotca/kumimoji";
|
|
54
|
+
*
|
|
55
|
+
* const value: PartySeat = {name:"Computer",computer:true};
|
|
56
|
+
* console.log(value);
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
31
59
|
export type PartySeat = {
|
|
32
60
|
name: string;
|
|
33
61
|
computer?: boolean;
|
|
@@ -35,6 +63,18 @@ export type PartySeat = {
|
|
|
35
63
|
/**
|
|
36
64
|
* A PASS-AND-PLAY KUMIMOJI: one bag, read as a line the way the solo game
|
|
37
65
|
* reads it (`TilePlay`), and a hand and a table for each player.
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```ts
|
|
69
|
+
* import { startParty } from "@johnmorrisdotca/kumimoji";
|
|
70
|
+
* import type { PartyGame } from "@johnmorrisdotca/kumimoji";
|
|
71
|
+
*
|
|
72
|
+
* const settings = {size:3,level:"hard",seed:44,gameLength:"short",language:"english",doubleSet:false,diagonals:false,hints:false} as const;
|
|
73
|
+
* const bag = "catdogsun";
|
|
74
|
+
* const game = startParty(settings,bag,["Seat 1","Seat 2"]);
|
|
75
|
+
* const value: PartyGame = game;
|
|
76
|
+
* console.log(value);
|
|
77
|
+
* ```
|
|
38
78
|
*/
|
|
39
79
|
export type PartyGame = {
|
|
40
80
|
settings: PartySettings;
|
|
@@ -82,5 +122,13 @@ export type PartyGame = {
|
|
|
82
122
|
* had a last turn; the winners are everybody who went out. `standing`: every
|
|
83
123
|
* other player resigned and the last one in laid a tile. `tied`: nobody was
|
|
84
124
|
* left standing, and the players who resigned in that final run are tied.
|
|
125
|
+
*
|
|
126
|
+
* @example
|
|
127
|
+
* ```ts
|
|
128
|
+
* import type { PartyEnding } from "@johnmorrisdotca/kumimoji";
|
|
129
|
+
*
|
|
130
|
+
* const value: PartyEnding = "out";
|
|
131
|
+
* console.log(value);
|
|
132
|
+
* ```
|
|
85
133
|
*/
|
|
86
134
|
export type PartyEnding = "out" | "standing" | "tied";
|
package/dist/partyKept.d.ts
CHANGED
|
@@ -1,7 +1,31 @@
|
|
|
1
1
|
import type { PartyGame, PartySettings } from "./party.types.ts";
|
|
2
|
-
/** A table of players as text to keep. `decodeParty` reads it back, and given the word list's `familyKey` checks every tile held against the bag.
|
|
2
|
+
/** A table of players as text to keep. `decodeParty` reads it back, and given the word list's `familyKey` checks every tile held against the bag.
|
|
3
|
+
*
|
|
4
|
+
* @param game - The current immutable shared-bag party game.
|
|
5
|
+
* @returns A table of players as text to keep. `decodeParty` reads it back, and given the word list's `familyKey` checks every tile held against the bag.
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* import { encodeParty, startParty } from "@johnmorrisdotca/kumimoji";
|
|
9
|
+
*
|
|
10
|
+
* const settings = {size:3,level:"hard",seed:44,gameLength:"short",language:"english",doubleSet:false,diagonals:false,hints:false} as const;
|
|
11
|
+
* const bag = "catdogsun";
|
|
12
|
+
* const game = startParty(settings,bag,["Seat 1","Seat 2"]);
|
|
13
|
+
* console.log(encodeParty(game));
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
3
16
|
export declare function encodeParty(game: PartyGame): string;
|
|
4
|
-
/** A game's settings as something outside this browser sent them — a table on several devices, a kept game — checked, or null.
|
|
17
|
+
/** A game's settings as something outside this browser sent them — a table on several devices, a kept game — checked, or null.
|
|
18
|
+
*
|
|
19
|
+
* @param value - The unknown setup value to interpret.
|
|
20
|
+
* @returns A game's settings as something outside this browser sent them — a table on several devices, a kept game — checked, or null.
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* import { readSettings } from "@johnmorrisdotca/kumimoji";
|
|
24
|
+
*
|
|
25
|
+
* const settings = {size:3,level:"hard",seed:44,gameLength:"short",language:"english",doubleSet:false,diagonals:false,hints:false} as const;
|
|
26
|
+
* console.log(readSettings(settings));
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
5
29
|
export declare function readSettings(value: unknown): PartySettings | null;
|
|
6
30
|
/**
|
|
7
31
|
* A kept game read back, or null for anything that is not one. With
|
|
@@ -10,9 +34,55 @@ export declare function readSettings(value: unknown): PartySettings | null;
|
|
|
10
34
|
* it and not given back, as the solo game checks a kept run
|
|
11
35
|
* (`decodeTileProgress`). Without, its shape alone, which is enough to offer
|
|
12
36
|
* it on the set-up screen.
|
|
37
|
+
*
|
|
38
|
+
* @param code - The encoded grid or progress text.
|
|
39
|
+
* @param familyKey - The function identifying physical tile families, or null for invalid codes.
|
|
40
|
+
* @returns A kept game read back, or null for anything that is not one. With `familyKey` (the loaded word list's), it is also checked against its own bag: every tile held by anybody — hand and table — must be one taken out of it and not given back, as the solo game checks a kept run (`decodeTileProgress`). Without, its shape alone, which is enough to offer it on the set-up screen.
|
|
41
|
+
* @example
|
|
42
|
+
* ```ts
|
|
43
|
+
* import { loadTileWordsFromModule } from "@johnmorrisdotca/kumimoji/words";
|
|
44
|
+
* import { decodeParty, encodeParty, startParty } from "@johnmorrisdotca/kumimoji";
|
|
45
|
+
*
|
|
46
|
+
* const words = await loadTileWordsFromModule("english");
|
|
47
|
+
* const settings = {size:3,level:"hard",seed:44,gameLength:"short",language:"english",doubleSet:false,diagonals:false,hints:false} as const;
|
|
48
|
+
* const bag = "catdogsun";
|
|
49
|
+
* const game = startParty(settings,bag,["Seat 1","Seat 2"]);
|
|
50
|
+
* console.log(decodeParty(encodeParty(game),words.familyKey)?.players.length);
|
|
51
|
+
* ```
|
|
13
52
|
*/
|
|
14
53
|
export declare function decodeParty(code: string | null, familyKey?: (tile: string) => string | null): PartyGame | null;
|
|
15
|
-
/** Whether what everybody holds is exactly what was taken from the bag, less what was given back.
|
|
54
|
+
/** Whether what everybody holds is exactly what was taken from the bag, less what was given back.
|
|
55
|
+
*
|
|
56
|
+
* @param game - The current immutable shared-bag party game.
|
|
57
|
+
* @param familyKey - The function identifying physical tile families, or null for invalid codes.
|
|
58
|
+
* @returns Whether what everybody holds is exactly what was taken from the bag, less what was given back.
|
|
59
|
+
* @example
|
|
60
|
+
* ```ts
|
|
61
|
+
* import { loadTileWordsFromModule } from "@johnmorrisdotca/kumimoji/words";
|
|
62
|
+
* import { holdsItsBag, startParty } from "@johnmorrisdotca/kumimoji";
|
|
63
|
+
*
|
|
64
|
+
* const words = await loadTileWordsFromModule("english");
|
|
65
|
+
* const settings = {size:3,level:"hard",seed:44,gameLength:"short",language:"english",doubleSet:false,diagonals:false,hints:false} as const;
|
|
66
|
+
* const bag = "catdogsun";
|
|
67
|
+
* const game = startParty(settings,bag,["Seat 1","Seat 2"]);
|
|
68
|
+
* console.log(holdsItsBag(game,words.familyKey));
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
16
71
|
export declare function holdsItsBag(game: PartyGame, familyKey: (tile: string) => string | null): boolean;
|
|
17
|
-
/** Whether a kept game is the one an address asks for: the same settings, and dealt to as many players, whoever has joined or left since.
|
|
72
|
+
/** Whether a kept game is the one an address asks for: the same settings, and dealt to as many players, whoever has joined or left since.
|
|
73
|
+
*
|
|
74
|
+
* @param game - The current immutable shared-bag party game.
|
|
75
|
+
* @param settings - The native party setup settings.
|
|
76
|
+
* @param players - The requested player count or current player rows.
|
|
77
|
+
* @returns Whether a kept game is the one an address asks for: the same settings, and dealt to as many players, whoever has joined or left since.
|
|
78
|
+
* @example
|
|
79
|
+
* ```ts
|
|
80
|
+
* import { isPartyFor, startParty } from "@johnmorrisdotca/kumimoji";
|
|
81
|
+
*
|
|
82
|
+
* const settings = {size:3,level:"hard",seed:44,gameLength:"short",language:"english",doubleSet:false,diagonals:false,hints:false} as const;
|
|
83
|
+
* const bag = "catdogsun";
|
|
84
|
+
* const game = startParty(settings,bag,["Seat 1","Seat 2"]);
|
|
85
|
+
* console.log(isPartyFor(game,settings,2));
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
18
88
|
export declare function isPartyFor(game: PartyGame, settings: PartySettings, players: number): boolean;
|
package/dist/partyKept.js
CHANGED
|
@@ -18,7 +18,20 @@ import { KUMIMOJI_PARTY, KUMIMOJI_HANDS } from "./tiles.constants.js";
|
|
|
18
18
|
* nothing to check, and the names in it are the players' own business.
|
|
19
19
|
*/
|
|
20
20
|
const VERSION = 1;
|
|
21
|
-
/** A table of players as text to keep. `decodeParty` reads it back, and given the word list's `familyKey` checks every tile held against the bag.
|
|
21
|
+
/** A table of players as text to keep. `decodeParty` reads it back, and given the word list's `familyKey` checks every tile held against the bag.
|
|
22
|
+
*
|
|
23
|
+
* @param game - The current immutable shared-bag party game.
|
|
24
|
+
* @returns A table of players as text to keep. `decodeParty` reads it back, and given the word list's `familyKey` checks every tile held against the bag.
|
|
25
|
+
* @example
|
|
26
|
+
* ```ts
|
|
27
|
+
* import { encodeParty, startParty } from "@johnmorrisdotca/kumimoji";
|
|
28
|
+
*
|
|
29
|
+
* const settings = {size:3,level:"hard",seed:44,gameLength:"short",language:"english",doubleSet:false,diagonals:false,hints:false} as const;
|
|
30
|
+
* const bag = "catdogsun";
|
|
31
|
+
* const game = startParty(settings,bag,["Seat 1","Seat 2"]);
|
|
32
|
+
* console.log(encodeParty(game));
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
22
35
|
export function encodeParty(game) {
|
|
23
36
|
const kept = {
|
|
24
37
|
v: VERSION,
|
|
@@ -43,7 +56,18 @@ export function encodeParty(game) {
|
|
|
43
56
|
}
|
|
44
57
|
const isCount = (value, most) => Number.isInteger(value) && value >= 0 && value <= most;
|
|
45
58
|
const isTiles = (value) => typeof value === "string" && /^[a-zA-Z*-]*$/.test(value);
|
|
46
|
-
/** A game's settings as something outside this browser sent them — a table on several devices, a kept game — checked, or null.
|
|
59
|
+
/** A game's settings as something outside this browser sent them — a table on several devices, a kept game — checked, or null.
|
|
60
|
+
*
|
|
61
|
+
* @param value - The unknown setup value to interpret.
|
|
62
|
+
* @returns A game's settings as something outside this browser sent them — a table on several devices, a kept game — checked, or null.
|
|
63
|
+
* @example
|
|
64
|
+
* ```ts
|
|
65
|
+
* import { readSettings } from "@johnmorrisdotca/kumimoji";
|
|
66
|
+
*
|
|
67
|
+
* const settings = {size:3,level:"hard",seed:44,gameLength:"short",language:"english",doubleSet:false,diagonals:false,hints:false} as const;
|
|
68
|
+
* console.log(readSettings(settings));
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
47
71
|
export function readSettings(value) {
|
|
48
72
|
if (typeof value !== "object" || value === null)
|
|
49
73
|
return null;
|
|
@@ -73,6 +97,21 @@ export function readSettings(value) {
|
|
|
73
97
|
* it and not given back, as the solo game checks a kept run
|
|
74
98
|
* (`decodeTileProgress`). Without, its shape alone, which is enough to offer
|
|
75
99
|
* it on the set-up screen.
|
|
100
|
+
*
|
|
101
|
+
* @param code - The encoded grid or progress text.
|
|
102
|
+
* @param familyKey - The function identifying physical tile families, or null for invalid codes.
|
|
103
|
+
* @returns A kept game read back, or null for anything that is not one. With `familyKey` (the loaded word list's), it is also checked against its own bag: every tile held by anybody — hand and table — must be one taken out of it and not given back, as the solo game checks a kept run (`decodeTileProgress`). Without, its shape alone, which is enough to offer it on the set-up screen.
|
|
104
|
+
* @example
|
|
105
|
+
* ```ts
|
|
106
|
+
* import { loadTileWordsFromModule } from "@johnmorrisdotca/kumimoji/words";
|
|
107
|
+
* import { decodeParty, encodeParty, startParty } from "@johnmorrisdotca/kumimoji";
|
|
108
|
+
*
|
|
109
|
+
* const words = await loadTileWordsFromModule("english");
|
|
110
|
+
* const settings = {size:3,level:"hard",seed:44,gameLength:"short",language:"english",doubleSet:false,diagonals:false,hints:false} as const;
|
|
111
|
+
* const bag = "catdogsun";
|
|
112
|
+
* const game = startParty(settings,bag,["Seat 1","Seat 2"]);
|
|
113
|
+
* console.log(decodeParty(encodeParty(game),words.familyKey)?.players.length);
|
|
114
|
+
* ```
|
|
76
115
|
*/
|
|
77
116
|
export function decodeParty(code, familyKey) {
|
|
78
117
|
if (code === null)
|
|
@@ -120,7 +159,23 @@ export function decodeParty(code, familyKey) {
|
|
|
120
159
|
return null;
|
|
121
160
|
return game;
|
|
122
161
|
}
|
|
123
|
-
/** Whether what everybody holds is exactly what was taken from the bag, less what was given back.
|
|
162
|
+
/** Whether what everybody holds is exactly what was taken from the bag, less what was given back.
|
|
163
|
+
*
|
|
164
|
+
* @param game - The current immutable shared-bag party game.
|
|
165
|
+
* @param familyKey - The function identifying physical tile families, or null for invalid codes.
|
|
166
|
+
* @returns Whether what everybody holds is exactly what was taken from the bag, less what was given back.
|
|
167
|
+
* @example
|
|
168
|
+
* ```ts
|
|
169
|
+
* import { loadTileWordsFromModule } from "@johnmorrisdotca/kumimoji/words";
|
|
170
|
+
* import { holdsItsBag, startParty } from "@johnmorrisdotca/kumimoji";
|
|
171
|
+
*
|
|
172
|
+
* const words = await loadTileWordsFromModule("english");
|
|
173
|
+
* const settings = {size:3,level:"hard",seed:44,gameLength:"short",language:"english",doubleSet:false,diagonals:false,hints:false} as const;
|
|
174
|
+
* const bag = "catdogsun";
|
|
175
|
+
* const game = startParty(settings,bag,["Seat 1","Seat 2"]);
|
|
176
|
+
* console.log(holdsItsBag(game,words.familyKey));
|
|
177
|
+
* ```
|
|
178
|
+
*/
|
|
124
179
|
export function holdsItsBag(game, familyKey) {
|
|
125
180
|
const taken = [...(game.bag + game.returned).slice(0, game.taken)].map(familyKey);
|
|
126
181
|
const back = [...game.returned].map(familyKey);
|
|
@@ -135,7 +190,22 @@ export function holdsItsBag(game, familyKey) {
|
|
|
135
190
|
tally.delete(tile);
|
|
136
191
|
return sameLetters(tally, lettersOf(held));
|
|
137
192
|
}
|
|
138
|
-
/** Whether a kept game is the one an address asks for: the same settings, and dealt to as many players, whoever has joined or left since.
|
|
193
|
+
/** Whether a kept game is the one an address asks for: the same settings, and dealt to as many players, whoever has joined or left since.
|
|
194
|
+
*
|
|
195
|
+
* @param game - The current immutable shared-bag party game.
|
|
196
|
+
* @param settings - The native party setup settings.
|
|
197
|
+
* @param players - The requested player count or current player rows.
|
|
198
|
+
* @returns Whether a kept game is the one an address asks for: the same settings, and dealt to as many players, whoever has joined or left since.
|
|
199
|
+
* @example
|
|
200
|
+
* ```ts
|
|
201
|
+
* import { isPartyFor, startParty } from "@johnmorrisdotca/kumimoji";
|
|
202
|
+
*
|
|
203
|
+
* const settings = {size:3,level:"hard",seed:44,gameLength:"short",language:"english",doubleSet:false,diagonals:false,hints:false} as const;
|
|
204
|
+
* const bag = "catdogsun";
|
|
205
|
+
* const game = startParty(settings,bag,["Seat 1","Seat 2"]);
|
|
206
|
+
* console.log(isPartyFor(game,settings,2));
|
|
207
|
+
* ```
|
|
208
|
+
*/
|
|
139
209
|
export function isPartyFor(game, settings, players) {
|
|
140
210
|
const a = game.settings;
|
|
141
211
|
return (game.dealt === players &&
|