@johnmorrisdotca/kumimoji 1.2.2 → 1.3.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.
Files changed (83) hide show
  1. package/CHANGELOG.md +33 -1
  2. package/CONTRIBUTING.md +11 -2
  3. package/README.md +80 -39
  4. package/dist/check.d.ts +26 -1
  5. package/dist/check.js +30 -3
  6. package/dist/computer.types.d.ts +24 -2
  7. package/dist/computerPlay.d.ts +45 -2
  8. package/dist/computerPlay.js +56 -6
  9. package/dist/computerTurn.d.ts +42 -3
  10. package/dist/computerTurn.js +47 -5
  11. package/dist/daily.d.ts +22 -2
  12. package/dist/daily.js +23 -3
  13. package/dist/element-define.d.ts +1 -1
  14. package/dist/element-define.js +3 -13
  15. package/dist/element.d.ts +85 -4
  16. package/dist/element.js +359 -77
  17. package/dist/embed-day.d.ts +4 -0
  18. package/dist/embed-day.js +23 -0
  19. package/dist/export.d.ts +123 -6
  20. package/dist/export.js +109 -9
  21. package/dist/generate.d.ts +14 -0
  22. package/dist/generate.js +32 -5
  23. package/dist/grid.d.ts +181 -10
  24. package/dist/grid.js +148 -11
  25. package/dist/help.d.ts +36 -3
  26. package/dist/help.js +36 -3
  27. package/dist/index.d.ts +22 -22
  28. package/dist/index.js +22 -22
  29. package/dist/judge.d.ts +14 -0
  30. package/dist/judge.js +14 -0
  31. package/dist/kana.d.ts +23 -1
  32. package/dist/kana.js +62 -7
  33. package/dist/kumimoji.types.d.ts +70 -5
  34. package/dist/party.d.ts +268 -14
  35. package/dist/party.js +296 -19
  36. package/dist/party.types.d.ts +50 -2
  37. package/dist/partyKept.d.ts +74 -4
  38. package/dist/partyKept.js +127 -12
  39. package/dist/partySeats.d.ts +92 -6
  40. package/dist/partySeats.js +83 -8
  41. package/dist/partyTurns.d.ts +171 -5
  42. package/dist/partyTurns.js +187 -8
  43. package/dist/placement.d.ts +50 -2
  44. package/dist/placement.js +35 -2
  45. package/dist/play.d.ts +247 -15
  46. package/dist/play.js +251 -18
  47. package/dist/random.d.ts +34 -3
  48. package/dist/random.js +23 -2
  49. package/dist/react.d.ts +42 -4
  50. package/dist/react.js +54 -7
  51. package/dist/showcase.d.ts +83 -7
  52. package/dist/showcase.js +61 -7
  53. package/dist/strings.d.ts +54 -5
  54. package/dist/strings.js +34 -3
  55. package/dist/tableView.d.ts +151 -8
  56. package/dist/tableView.js +129 -6
  57. package/dist/tileFace.d.ts +59 -5
  58. package/dist/tileFace.js +48 -4
  59. package/dist/tileFamily.d.ts +9 -0
  60. package/dist/tileFamily.js +9 -0
  61. package/dist/tileWords.d.ts +93 -6
  62. package/dist/tileWords.js +94 -12
  63. package/dist/tileWordsModule.d.ts +12 -2
  64. package/dist/tileWordsModule.js +14 -2
  65. package/dist/tiles.constants.d.ts +99 -5
  66. package/dist/tiles.constants.js +171 -13
  67. package/dist/turn.d.ts +82 -4
  68. package/dist/turn.js +88 -5
  69. package/dist/ui/board.d.ts +60 -5
  70. package/dist/ui/board.js +44 -4
  71. package/dist/ui/draw.d.ts +62 -0
  72. package/dist/ui/draw.js +229 -0
  73. package/dist/ui/mount.d.ts +41 -2
  74. package/dist/ui/mount.js +190 -265
  75. package/dist/ui/style.d.ts +6 -1
  76. package/dist/ui/style.js +6 -0
  77. package/dist/ui.d.ts +3 -3
  78. package/dist/ui.js +2 -2
  79. package/dist/version.d.ts +9 -2
  80. package/dist/version.js +9 -2
  81. package/dist/wilds.d.ts +22 -1
  82. package/dist/wilds.js +25 -3
  83. package/package.json +68 -61
package/dist/export.d.ts CHANGED
@@ -14,9 +14,31 @@ import { type KumimojiStrings } from "./strings.ts";
14
14
  * the game only if every tile in the hand and on the table is one that came
15
15
  * out of that bag and was not given back.
16
16
  */
17
- /** The shape of the JSON this package writes. It goes up only when a reader of the old shape would be wrong about the new one. */
17
+ /** The shape of the JSON this package writes. It goes up only when a reader of the old shape would be wrong about the new one.
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * import { KUMIMOJI_EXPORT_FORMAT } from "@johnmorrisdotca/kumimoji";
22
+ * console.log(KUMIMOJI_EXPORT_FORMAT);
23
+ * ```
24
+ */
18
25
  export declare const KUMIMOJI_EXPORT_FORMAT = 1;
19
- /** A game alone as it is kept: the deal, where the player has got to, and the time spent so far. */
26
+ /** A game alone as it is kept: the deal, where the player has got to, and the time spent so far.
27
+ *
28
+ * @example
29
+ * ```ts
30
+ * import { deal, generateKumimoji } from "@johnmorrisdotca/kumimoji";
31
+ * import type { KumimojiSaved } from "@johnmorrisdotca/kumimoji";
32
+ * import { loadTileWordsFromModule } from "@johnmorrisdotca/kumimoji/words";
33
+ *
34
+ * await loadTileWordsFromModule("english");
35
+ * const play = deal("catdog",3);
36
+ * const dealt = generateKumimoji(3,"hard",44);
37
+ * const saved = {deal:dealt,play:deal(dealt.givens,dealt.size),elapsedMs:0};
38
+ * const value: KumimojiSaved = saved;
39
+ * console.log(value);
40
+ * ```
41
+ */
20
42
  export type KumimojiSaved = {
21
43
  /** The game as dealt: `generateKumimoji`'s. */
22
44
  deal: KumimojiDeal;
@@ -25,7 +47,22 @@ export type KumimojiSaved = {
25
47
  /** Milliseconds spent on it so far. */
26
48
  elapsedMs: number;
27
49
  };
28
- /** A whole JSON export of one game: what `kumimojiToJSON` writes and `kumimojiFromJSON` reads. */
50
+ /** A whole JSON export of one game: what `kumimojiToJSON` writes and `kumimojiFromJSON` reads.
51
+ *
52
+ * @example
53
+ * ```ts
54
+ * import { deal, generateKumimoji, kumimojiExported } from "@johnmorrisdotca/kumimoji";
55
+ * import type { KumimojiExported } from "@johnmorrisdotca/kumimoji";
56
+ * import { loadTileWordsFromModule } from "@johnmorrisdotca/kumimoji/words";
57
+ *
58
+ * await loadTileWordsFromModule("english");
59
+ * const play = deal("catdog",3);
60
+ * const dealt = generateKumimoji(3,"hard",44);
61
+ * const saved = {deal:dealt,play:deal(dealt.givens,dealt.size),elapsedMs:0};
62
+ * const value: KumimojiExported = kumimojiExported(saved);
63
+ * console.log(value);
64
+ * ```
65
+ */
29
66
  export type KumimojiExported = {
30
67
  /** The shape's number: `KUMIMOJI_EXPORT_FORMAT`. */
31
68
  format: typeof KUMIMOJI_EXPORT_FORMAT;
@@ -52,9 +89,39 @@ export type KumimojiExported = {
52
89
  /** Milliseconds spent so far. */
53
90
  elapsedMs: number;
54
91
  };
55
- /** A game as the JSON export's object. */
92
+ /** A game as the JSON export's object.
93
+ *
94
+ * @param saved - The original deal, current progress and elapsed time.
95
+ * @returns A game as the JSON export's object.
96
+ * @example
97
+ * ```ts
98
+ * import { deal, generateKumimoji, kumimojiExported } from "@johnmorrisdotca/kumimoji";
99
+ * import { loadTileWordsFromModule } from "@johnmorrisdotca/kumimoji/words";
100
+ *
101
+ * await loadTileWordsFromModule("english");
102
+ * const play = deal("catdog",3);
103
+ * const dealt = generateKumimoji(3,"hard",44);
104
+ * const saved = {deal:dealt,play:deal(dealt.givens,dealt.size),elapsedMs:0};
105
+ * console.log(kumimojiExported(saved).format);
106
+ * ```
107
+ */
56
108
  export declare function kumimojiExported(saved: KumimojiSaved): KumimojiExported;
57
- /** A game as JSON, two spaces deep, with the format's number first. `kumimojiFromJSON` reads it back. */
109
+ /** A game as JSON, two spaces deep, with the format's number first. `kumimojiFromJSON` reads it back.
110
+ *
111
+ * @param saved - The original deal, current progress and elapsed time.
112
+ * @returns A game as JSON, two spaces deep, with the format's number first. `kumimojiFromJSON` reads it back.
113
+ * @example
114
+ * ```ts
115
+ * import { deal, generateKumimoji, kumimojiToJSON } from "@johnmorrisdotca/kumimoji";
116
+ * import { loadTileWordsFromModule } from "@johnmorrisdotca/kumimoji/words";
117
+ *
118
+ * await loadTileWordsFromModule("english");
119
+ * const play = deal("catdog",3);
120
+ * const dealt = generateKumimoji(3,"hard",44);
121
+ * const saved = {deal:dealt,play:deal(dealt.givens,dealt.size),elapsedMs:0};
122
+ * console.log(kumimojiToJSON(saved));
123
+ * ```
124
+ */
58
125
  export declare function kumimojiToJSON(saved: KumimojiSaved): string;
59
126
  /**
60
127
  * A game from JSON that `kumimojiToJSON` wrote. Nothing in it is trusted: the
@@ -66,15 +133,50 @@ export declare function kumimojiToJSON(saved: KumimojiSaved): string;
66
133
  * The word list of the game's language is loaded first, since dealing needs
67
134
  * it; where there is no browser, import `@johnmorrisdotca/kumimoji/words`
68
135
  * once, or the promise is rejected as `loadTileWords` rejects it.
136
+ *
137
+ * @param text - The saved JSON text to validate.
138
+ * @returns A game from JSON that `kumimojiToJSON` wrote. Nothing in it is trusted: the bag is dealt again from the seed, and the game opens only if every tile held is one that came out of that bag. Resolves to null when the text is not JSON, is of a later format than this version reads, is another game's, or holds a hand or a grid that this bag never dealt.
139
+ * @example
140
+ * ```ts
141
+ * import { deal, generateKumimoji, kumimojiFromJSON, kumimojiToJSON } from "@johnmorrisdotca/kumimoji";
142
+ * import { loadTileWordsFromModule } from "@johnmorrisdotca/kumimoji/words";
143
+ *
144
+ * await loadTileWordsFromModule("english");
145
+ * const play = deal("catdog",3);
146
+ * const dealt = generateKumimoji(3,"hard",44);
147
+ * const saved = {deal:dealt,play:deal(dealt.givens,dealt.size),elapsedMs:0};
148
+ * console.log((await kumimojiFromJSON(kumimojiToJSON(saved)))?.deal.seed);
149
+ * ```
69
150
  */
70
151
  export declare function kumimojiFromJSON(text: string): Promise<KumimojiSaved | null>;
71
- /** A time as minutes and seconds: `1:05`. */
152
+ /** A time as minutes and seconds: `1:05`.
153
+ *
154
+ * @param ms - The duration in milliseconds.
155
+ * @returns A time as minutes and seconds: `1:05`.
156
+ * @example
157
+ * ```ts
158
+ * import { kumimojiClock } from "@johnmorrisdotca/kumimoji";
159
+ *
160
+ * console.log(kumimojiClock(65000));
161
+ * ```
162
+ */
72
163
  export declare function kumimojiClock(ms: number): string;
73
164
  /**
74
165
  * A grid as lines of text, the way it lies on the table: English letters in
75
166
  * capitals with a space between squares and a dot for an empty one, kana side
76
167
  * by side with a full-width dot for an empty one, so that either lines up in a
77
168
  * fixed-width face, every row as wide as the crossword. A wild that has been given nothing is `*`. No tiles is "".
169
+ *
170
+ * @param tiles - The map from row,column square names to internal tile codes.
171
+ * @param language - The English or Japanese tile language.
172
+ * @returns A grid as lines of text, the way it lies on the table: English letters in capitals with a space between squares and a dot for an empty one, kana side by side with a full-width dot for an empty one, so that either lines up in a fixed-width face, every row as wide as the crossword. A wild that has been given nothing is `*`. No tiles is "".
173
+ * @example
174
+ * ```ts
175
+ * import { gridToText } from "@johnmorrisdotca/kumimoji";
176
+ *
177
+ * const tiles = new Map([["0,0","c"],["0,1","a"],["0,2","t"]]);
178
+ * console.log(gridToText(tiles));
179
+ * ```
78
180
  */
79
181
  export declare function gridToText(tiles: Tiles, language?: KumimojiLanguage): string;
80
182
  /**
@@ -83,5 +185,20 @@ export declare function gridToText(tiles: Tiles, language?: KumimojiLanguage): s
83
185
  * English unless given another table of strings (`KUMIMOJI_STRINGS.ja`). The
84
186
  * word list of the game's language must have been loaded, as for any judging.
85
187
  * Lines end with a line feed.
188
+ *
189
+ * @param saved - The original deal, current progress and elapsed time.
190
+ * @param strings - The localized words for readable export.
191
+ * @returns A game as plain text, for a chat or a note: how it was set up, the crossword as it lies, the hand, how many tiles are left, and the time. In English unless given another table of strings (`KUMIMOJI_STRINGS.ja`). The word list of the game's language must have been loaded, as for any judging. Lines end with a line feed.
192
+ * @example
193
+ * ```ts
194
+ * import { deal, generateKumimoji, kumimojiToText } from "@johnmorrisdotca/kumimoji";
195
+ * import { loadTileWordsFromModule } from "@johnmorrisdotca/kumimoji/words";
196
+ *
197
+ * await loadTileWordsFromModule("english");
198
+ * const play = deal("catdog",3);
199
+ * const dealt = generateKumimoji(3,"hard",44);
200
+ * const saved = {deal:dealt,play:deal(dealt.givens,dealt.size),elapsedMs:0};
201
+ * console.log(kumimojiToText(saved));
202
+ * ```
86
203
  */
87
204
  export declare function kumimojiToText(saved: KumimojiSaved, strings?: KumimojiStrings): string;
package/dist/export.js CHANGED
@@ -1,5 +1,5 @@
1
- import { boundsOf, squareAt } from "./grid.js";
2
1
  import { generateKumimoji } from "./generate.js";
2
+ import { boundsOf, squareAt } from "./grid.js";
3
3
  import { judgeWithWords } from "./judge.js";
4
4
  import { decodeTileProgress, encodeTileProgress, isFinished, tilesLeft } from "./play.js";
5
5
  import { KUMIMOJI_STRINGS, kumimojiSay } from "./strings.js";
@@ -19,9 +19,31 @@ import { KUMIMOJI_VERSION } from "./version.js";
19
19
  * the game only if every tile in the hand and on the table is one that came
20
20
  * out of that bag and was not given back.
21
21
  */
22
- /** The shape of the JSON this package writes. It goes up only when a reader of the old shape would be wrong about the new one. */
22
+ /** The shape of the JSON this package writes. It goes up only when a reader of the old shape would be wrong about the new one.
23
+ *
24
+ * @example
25
+ * ```ts
26
+ * import { KUMIMOJI_EXPORT_FORMAT } from "@johnmorrisdotca/kumimoji";
27
+ * console.log(KUMIMOJI_EXPORT_FORMAT);
28
+ * ```
29
+ */
23
30
  export const KUMIMOJI_EXPORT_FORMAT = 1;
24
- /** A game as the JSON export's object. */
31
+ /** A game as the JSON export's object.
32
+ *
33
+ * @param saved - The original deal, current progress and elapsed time.
34
+ * @returns A game as the JSON export's object.
35
+ * @example
36
+ * ```ts
37
+ * import { deal, generateKumimoji, kumimojiExported } from "@johnmorrisdotca/kumimoji";
38
+ * import { loadTileWordsFromModule } from "@johnmorrisdotca/kumimoji/words";
39
+ *
40
+ * await loadTileWordsFromModule("english");
41
+ * const play = deal("catdog",3);
42
+ * const dealt = generateKumimoji(3,"hard",44);
43
+ * const saved = {deal:dealt,play:deal(dealt.givens,dealt.size),elapsedMs:0};
44
+ * console.log(kumimojiExported(saved).format);
45
+ * ```
46
+ */
25
47
  export function kumimojiExported(saved) {
26
48
  const { deal, play } = saved;
27
49
  return {
@@ -39,7 +61,22 @@ export function kumimojiExported(saved) {
39
61
  elapsedMs: Math.max(0, Math.round(saved.elapsedMs)),
40
62
  };
41
63
  }
42
- /** A game as JSON, two spaces deep, with the format's number first. `kumimojiFromJSON` reads it back. */
64
+ /** A game as JSON, two spaces deep, with the format's number first. `kumimojiFromJSON` reads it back.
65
+ *
66
+ * @param saved - The original deal, current progress and elapsed time.
67
+ * @returns A game as JSON, two spaces deep, with the format's number first. `kumimojiFromJSON` reads it back.
68
+ * @example
69
+ * ```ts
70
+ * import { deal, generateKumimoji, kumimojiToJSON } from "@johnmorrisdotca/kumimoji";
71
+ * import { loadTileWordsFromModule } from "@johnmorrisdotca/kumimoji/words";
72
+ *
73
+ * await loadTileWordsFromModule("english");
74
+ * const play = deal("catdog",3);
75
+ * const dealt = generateKumimoji(3,"hard",44);
76
+ * const saved = {deal:dealt,play:deal(dealt.givens,dealt.size),elapsedMs:0};
77
+ * console.log(kumimojiToJSON(saved));
78
+ * ```
79
+ */
43
80
  export function kumimojiToJSON(saved) {
44
81
  return `${JSON.stringify(kumimojiExported(saved), null, 2)}\n`;
45
82
  }
@@ -57,6 +94,20 @@ const PROGRESS_MOST = 4000;
57
94
  * The word list of the game's language is loaded first, since dealing needs
58
95
  * it; where there is no browser, import `@johnmorrisdotca/kumimoji/words`
59
96
  * once, or the promise is rejected as `loadTileWords` rejects it.
97
+ *
98
+ * @param text - The saved JSON text to validate.
99
+ * @returns A game from JSON that `kumimojiToJSON` wrote. Nothing in it is trusted: the bag is dealt again from the seed, and the game opens only if every tile held is one that came out of that bag. Resolves to null when the text is not JSON, is of a later format than this version reads, is another game's, or holds a hand or a grid that this bag never dealt.
100
+ * @example
101
+ * ```ts
102
+ * import { deal, generateKumimoji, kumimojiFromJSON, kumimojiToJSON } from "@johnmorrisdotca/kumimoji";
103
+ * import { loadTileWordsFromModule } from "@johnmorrisdotca/kumimoji/words";
104
+ *
105
+ * await loadTileWordsFromModule("english");
106
+ * const play = deal("catdog",3);
107
+ * const dealt = generateKumimoji(3,"hard",44);
108
+ * const saved = {deal:dealt,play:deal(dealt.givens,dealt.size),elapsedMs:0};
109
+ * console.log((await kumimojiFromJSON(kumimojiToJSON(saved)))?.deal.seed);
110
+ * ```
60
111
  */
61
112
  export async function kumimojiFromJSON(text) {
62
113
  let data;
@@ -94,7 +145,12 @@ export async function kumimojiFromJSON(text) {
94
145
  await loadTileWords(language);
95
146
  let deal;
96
147
  try {
97
- deal = generateKumimoji(size, level, seed, { language, gameLength: gameLength, doubleSet, diagonals });
148
+ deal = generateKumimoji(size, level, seed, {
149
+ language,
150
+ gameLength: gameLength,
151
+ doubleSet,
152
+ diagonals,
153
+ });
98
154
  }
99
155
  catch {
100
156
  return null;
@@ -102,7 +158,17 @@ export async function kumimojiFromJSON(text) {
102
158
  const play = decodeTileProgress(progress, deal.givens, language);
103
159
  return play === null ? null : { deal, play, elapsedMs: spent };
104
160
  }
105
- /** A time as minutes and seconds: `1:05`. */
161
+ /** A time as minutes and seconds: `1:05`.
162
+ *
163
+ * @param ms - The duration in milliseconds.
164
+ * @returns A time as minutes and seconds: `1:05`.
165
+ * @example
166
+ * ```ts
167
+ * import { kumimojiClock } from "@johnmorrisdotca/kumimoji";
168
+ *
169
+ * console.log(kumimojiClock(65000));
170
+ * ```
171
+ */
106
172
  export function kumimojiClock(ms) {
107
173
  const seconds = Math.max(0, Math.floor(ms / 1000));
108
174
  return `${Math.floor(seconds / 60)}:${String(seconds % 60).padStart(2, "0")}`;
@@ -112,6 +178,17 @@ export function kumimojiClock(ms) {
112
178
  * capitals with a space between squares and a dot for an empty one, kana side
113
179
  * by side with a full-width dot for an empty one, so that either lines up in a
114
180
  * fixed-width face, every row as wide as the crossword. A wild that has been given nothing is `*`. No tiles is "".
181
+ *
182
+ * @param tiles - The map from row,column square names to internal tile codes.
183
+ * @param language - The English or Japanese tile language.
184
+ * @returns A grid as lines of text, the way it lies on the table: English letters in capitals with a space between squares and a dot for an empty one, kana side by side with a full-width dot for an empty one, so that either lines up in a fixed-width face, every row as wide as the crossword. A wild that has been given nothing is `*`. No tiles is "".
185
+ * @example
186
+ * ```ts
187
+ * import { gridToText } from "@johnmorrisdotca/kumimoji";
188
+ *
189
+ * const tiles = new Map([["0,0","c"],["0,1","a"],["0,2","t"]]);
190
+ * console.log(gridToText(tiles));
191
+ * ```
115
192
  */
116
193
  export function gridToText(tiles, language = "english") {
117
194
  const bounds = boundsOf(tiles);
@@ -140,17 +217,40 @@ export function gridToText(tiles, language = "english") {
140
217
  * English unless given another table of strings (`KUMIMOJI_STRINGS.ja`). The
141
218
  * word list of the game's language must have been loaded, as for any judging.
142
219
  * Lines end with a line feed.
220
+ *
221
+ * @param saved - The original deal, current progress and elapsed time.
222
+ * @param strings - The localized words for readable export.
223
+ * @returns A game as plain text, for a chat or a note: how it was set up, the crossword as it lies, the hand, how many tiles are left, and the time. In English unless given another table of strings (`KUMIMOJI_STRINGS.ja`). The word list of the game's language must have been loaded, as for any judging. Lines end with a line feed.
224
+ * @example
225
+ * ```ts
226
+ * import { deal, generateKumimoji, kumimojiToText } from "@johnmorrisdotca/kumimoji";
227
+ * import { loadTileWordsFromModule } from "@johnmorrisdotca/kumimoji/words";
228
+ *
229
+ * await loadTileWordsFromModule("english");
230
+ * const play = deal("catdog",3);
231
+ * const dealt = generateKumimoji(3,"hard",44);
232
+ * const saved = {deal:dealt,play:deal(dealt.givens,dealt.size),elapsedMs:0};
233
+ * console.log(kumimojiToText(saved));
234
+ * ```
143
235
  */
144
236
  export function kumimojiToText(saved, strings = KUMIMOJI_STRINGS.en) {
145
237
  const { deal, play } = saved;
146
238
  const words = tileWords(deal.language);
147
- const face = (tile) => (tileFace(tile).blank ? "*" : deal.language === "japanese" ? words.glyphOf(tile) : words.glyphOf(tile).toUpperCase());
148
- const lines = [kumimojiSay(strings.textTitle, { language: deal.language === "japanese" ? strings.japanese : strings.english, hand: deal.size, seed: deal.seed })];
239
+ const face = (tile) => tileFace(tile).blank ? "*" : deal.language === "japanese" ? words.glyphOf(tile) : words.glyphOf(tile).toUpperCase();
240
+ const lines = [
241
+ kumimojiSay(strings.textTitle, {
242
+ language: deal.language === "japanese" ? strings.japanese : strings.english,
243
+ hand: deal.size,
244
+ seed: deal.seed,
245
+ }),
246
+ ];
149
247
  lines.push(play.tiles.size === 0 ? strings.textEmpty : gridToText(play.tiles, deal.language));
150
248
  if (isFinished(play, judgeWithWords(play.tiles, words, { diagonals: deal.diagonals === true })))
151
249
  lines.push(strings.textFinished);
152
250
  else {
153
- lines.push(play.hand.length === 0 ? strings.textHandEmpty : kumimojiSay(strings.textHand, { tiles: play.hand.map(face).join(" ") }));
251
+ lines.push(play.hand.length === 0
252
+ ? strings.textHandEmpty
253
+ : kumimojiSay(strings.textHand, { tiles: play.hand.map(face).join(" ") }));
154
254
  lines.push(kumimojiSay(strings.textLeft, { n: tilesLeft(play) }));
155
255
  }
156
256
  lines.push(kumimojiSay(strings.textTime, { time: kumimojiClock(saved.elapsedMs) }));
@@ -25,5 +25,19 @@ import type { KumimojiDeal, KumimojiLevel, KumimojiOptions } from "./kumimoji.ty
25
25
  *
26
26
  * Deterministic in the seed, like every generator here: two browsers in a
27
27
  * race, or one tomorrow, deal the same bag in the same order.
28
+ *
29
+ * @param size - The supported initial hand size.
30
+ * @param level - The difficulty that determines the wildcard allowance.
31
+ * @param seed - The numeric seed for deterministic deals or random draws.
32
+ * @param options - Native game, component or presentation options.
33
+ * @returns MAKING A KUMIMOJI, in the browser, from a seed: the bag the game is played from, in the order its tiles come out.
34
+ * @example
35
+ * ```ts
36
+ * import { generateKumimoji } from "@johnmorrisdotca/kumimoji";
37
+ * import { loadTileWordsFromModule } from "@johnmorrisdotca/kumimoji/words";
38
+ *
39
+ * await loadTileWordsFromModule("english");
40
+ * console.log(generateKumimoji(3,"hard",44).givens);
41
+ * ```
28
42
  */
29
43
  export declare function generateKumimoji(size: number, level: KumimojiLevel, seed: number, options?: KumimojiOptions): KumimojiDeal;
package/dist/generate.js CHANGED
@@ -1,6 +1,6 @@
1
- import { seededRandom, shuffled } from "./random.js";
2
1
  import { encodeGrid, squareAt } from "./grid.js";
3
2
  import { crossingFit } from "./placement.js";
3
+ import { seededRandom, shuffled } from "./random.js";
4
4
  import { kumimojiTileCount, kumimojiWildCount, TILE_MIX_TOTAL } from "./tiles.constants.js";
5
5
  import { tileWords } from "./tileWords.js";
6
6
  /**
@@ -29,6 +29,20 @@ import { tileWords } from "./tileWords.js";
29
29
  *
30
30
  * Deterministic in the seed, like every generator here: two browsers in a
31
31
  * race, or one tomorrow, deal the same bag in the same order.
32
+ *
33
+ * @param size - The supported initial hand size.
34
+ * @param level - The difficulty that determines the wildcard allowance.
35
+ * @param seed - The numeric seed for deterministic deals or random draws.
36
+ * @param options - Native game, component or presentation options.
37
+ * @returns MAKING A KUMIMOJI, in the browser, from a seed: the bag the game is played from, in the order its tiles come out.
38
+ * @example
39
+ * ```ts
40
+ * import { generateKumimoji } from "@johnmorrisdotca/kumimoji";
41
+ * import { loadTileWordsFromModule } from "@johnmorrisdotca/kumimoji/words";
42
+ *
43
+ * await loadTileWordsFromModule("english");
44
+ * console.log(generateKumimoji(3,"hard",44).givens);
45
+ * ```
32
46
  */
33
47
  export function generateKumimoji(size, level, seed, options = {}) {
34
48
  const gameLength = options.gameLength ?? "short";
@@ -44,10 +58,12 @@ export function generateKumimoji(size, level, seed, options = {}) {
44
58
  const side = layingSideFor(tiles);
45
59
  let bestProgress = 0;
46
60
  for (let attempt = 0; attempt < 50; attempt += 1) {
47
- const squares = layCrossword(tiles, random, words, side, multiplier, words.mix, (laid) => { bestProgress = Math.max(bestProgress, laid); }, diagonals);
61
+ const squares = layCrossword(tiles, random, words, side, multiplier, words.mix, (laid) => {
62
+ bestProgress = Math.max(bestProgress, laid);
63
+ }, diagonals);
48
64
  if (squares === null)
49
65
  continue;
50
- const positions = shuffled(squares.flatMap((tile, at) => tile === "" ? [] : [at]), random);
66
+ const positions = shuffled(squares.flatMap((tile, at) => (tile === "" ? [] : [at])), random);
51
67
  const wildAt = new Set(positions.slice(0, wilds));
52
68
  const bag = squares.flatMap((tile, at) => {
53
69
  if (tile === "")
@@ -60,7 +76,18 @@ export function generateKumimoji(size, level, seed, options = {}) {
60
76
  squares[at] = assigned;
61
77
  return ["*"];
62
78
  });
63
- return { kind: "kumimoji", size, level, seed, givens: shuffled(bag, random).join(""), solution: encodeGrid(tilesOf(squares, side)), gameLength, doubleSet, language, ...(diagonals ? { diagonals } : {}) };
79
+ return {
80
+ kind: "kumimoji",
81
+ size,
82
+ level,
83
+ seed,
84
+ givens: shuffled(bag, random).join(""),
85
+ solution: encodeGrid(tilesOf(squares, side)),
86
+ gameLength,
87
+ doubleSet,
88
+ language,
89
+ ...(diagonals ? { diagonals } : {}),
90
+ };
64
91
  }
65
92
  throw new Error(`Could not lay a Kumimoji of ${tiles} tiles from seed ${seed}; furthest attempt laid ${bestProgress}.`);
66
93
  }
@@ -88,7 +115,7 @@ const LONGEST_LAID = 7;
88
115
  const ANCHORS_TRIED = 8;
89
116
  const WORDS_READ = 60;
90
117
  const FINISH_BRANCHES = 40;
91
- const FINISH_NODES = 2000;
118
+ const FINISH_NODES = 2_000;
92
119
  /**
93
120
  * With Diagonals the last tiles are placed from every tile but a sample of
94
121
  * words, and a try that cannot finish is given up sooner: a crossword read