@johnmorrisdotca/kumimoji 1.2.1 → 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 +37 -1
- package/CONTRIBUTING.md +81 -44
- package/README.md +478 -327
- 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 +66 -57
package/dist/element.js
CHANGED
|
@@ -9,14 +9,16 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (
|
|
|
9
9
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
10
10
|
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
11
11
|
};
|
|
12
|
-
var _KumimojiTable_instances, _KumimojiTable_table, _KumimojiTable_key, _KumimojiTable_queued, _KumimojiTable_seed, _KumimojiTable_refresh;
|
|
12
|
+
var _KumimojiTable_instances, _KumimojiTable_table, _KumimojiTable_key, _KumimojiTable_queued, _KumimojiTable_seed, _KumimojiTable_options, _KumimojiTable_revision, _KumimojiTable_widthBefore, _KumimojiTable_widthOwned, _KumimojiTable_labelBefore, _KumimojiTable_write, _KumimojiTable_frame, _KumimojiTable_refresh;
|
|
13
|
+
import { embedDay } from "./embed-day.js";
|
|
14
|
+
import { KUMIMOJI_STYLE } from "./ui/style.js";
|
|
13
15
|
import { kumimojiDailySeed } from "./daily.js";
|
|
14
16
|
import { KUMIMOJI_HANDS } from "./tiles.constants.js";
|
|
15
17
|
import { mountKumimoji } from "./ui/mount.js";
|
|
16
18
|
const ElementBase = typeof HTMLElement === "undefined" ? class {
|
|
17
19
|
} : HTMLElement;
|
|
18
20
|
const oneOf = (value, allowed) => (allowed.includes(value) ? value : undefined);
|
|
19
|
-
const isOn = (value) => value
|
|
21
|
+
const isOn = (value, fallback = false) => value === null ? fallback : !["false", "off", "no", "0"].includes(value.trim().toLowerCase());
|
|
20
22
|
const HANDS = Object.values(KUMIMOJI_HANDS);
|
|
21
23
|
/**
|
|
22
24
|
* THE `<kumimoji-table>` ELEMENT: a game of Kumimoji alone in a tag, with no
|
|
@@ -29,8 +31,7 @@ const HANDS = Object.values(KUMIMOJI_HANDS);
|
|
|
29
31
|
* <kumimoji-table language="japanese" level="easy" seed="daily"></kumimoji-table>
|
|
30
32
|
* ```
|
|
31
33
|
*
|
|
32
|
-
* Attributes
|
|
33
|
-
* deals a new game):
|
|
34
|
+
* Attributes configure the starting game; display, language and control changes preserve play:
|
|
34
35
|
* - `language`: the tiles, `english` (default) or `japanese` kana.
|
|
35
36
|
* - `hand`: the opening hand, 3, 7 (default) or 11.
|
|
36
37
|
* - `level`: how many tiles are wild, `easy` (most), `medium` (default) or `hard` (none).
|
|
@@ -42,7 +43,24 @@ const HANDS = Object.values(KUMIMOJI_HANDS);
|
|
|
42
43
|
* It fires `kumimoji-change` after every change to the game, with the game as it would
|
|
43
44
|
* be saved as `event.detail.saved`, and `kumimoji-finish` when the last tile is laid and every run
|
|
44
45
|
* is a word, with `event.detail` the deal, the play and the time it took. It has the methods
|
|
45
|
-
* `newGame()` and `setGame()`.
|
|
46
|
+
* `newGame()` and `setGame()`. Invalid input shows a status and a plain error event.
|
|
47
|
+
*/
|
|
48
|
+
/**
|
|
49
|
+
* Native table options, checked alongside builder coverage.
|
|
50
|
+
* @example
|
|
51
|
+
* ```ts
|
|
52
|
+
* import { KUMIMOJI_EMBED_OPTION_KEYS } from "@johnmorrisdotca/kumimoji/element";
|
|
53
|
+
* console.log(KUMIMOJI_EMBED_OPTION_KEYS.includes("saved"));
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
export const KUMIMOJI_EMBED_OPTION_KEYS = Object.keys({ language: true, hand: true, level: true, gameLength: true, diagonals: true, seed: true, onFinish: true, onChange: true, locale: true, strings: true, theme: true, keep: true, controls: true, saved: true, onError: true });
|
|
57
|
+
/**
|
|
58
|
+
* A reflected crossword table with the native table handle and saved-state getter.
|
|
59
|
+
* @example
|
|
60
|
+
* ```ts
|
|
61
|
+
* import { KumimojiTable } from "@johnmorrisdotca/kumimoji/element";
|
|
62
|
+
* console.log(KumimojiTable.observedAttributes.includes("daily"));
|
|
63
|
+
* ```
|
|
46
64
|
*/
|
|
47
65
|
export class KumimojiTable extends ElementBase {
|
|
48
66
|
constructor() {
|
|
@@ -52,11 +70,22 @@ export class KumimojiTable extends ElementBase {
|
|
|
52
70
|
_KumimojiTable_key.set(this, "");
|
|
53
71
|
_KumimojiTable_queued.set(this, false);
|
|
54
72
|
_KumimojiTable_seed.set(this, null);
|
|
73
|
+
_KumimojiTable_options.set(this, {});
|
|
74
|
+
_KumimojiTable_revision.set(this, 0);
|
|
75
|
+
_KumimojiTable_widthBefore.set(this, null);
|
|
76
|
+
_KumimojiTable_widthOwned.set(this, false);
|
|
77
|
+
_KumimojiTable_labelBefore.set(this, null);
|
|
55
78
|
}
|
|
79
|
+
/** Native host options. Callback/presentation changes preserve the current game. */
|
|
80
|
+
get options() { return __classPrivateFieldGet(this, _KumimojiTable_options, "f"); }
|
|
81
|
+
set options(value) { __classPrivateFieldSet(this, _KumimojiTable_options, value ?? {}, "f"); if (this.isConnected)
|
|
82
|
+
__classPrivateFieldGet(this, _KumimojiTable_instances, "m", _KumimojiTable_refresh).call(this); }
|
|
56
83
|
connectedCallback() {
|
|
57
84
|
__classPrivateFieldGet(this, _KumimojiTable_instances, "m", _KumimojiTable_refresh).call(this);
|
|
58
85
|
}
|
|
59
86
|
disconnectedCallback() {
|
|
87
|
+
var _a;
|
|
88
|
+
__classPrivateFieldSet(this, _KumimojiTable_revision, (_a = __classPrivateFieldGet(this, _KumimojiTable_revision, "f"), ++_a), "f");
|
|
60
89
|
__classPrivateFieldGet(this, _KumimojiTable_table, "f")?.destroy();
|
|
61
90
|
__classPrivateFieldSet(this, _KumimojiTable_table, null, "f");
|
|
62
91
|
__classPrivateFieldSet(this, _KumimojiTable_key, "", "f");
|
|
@@ -67,7 +96,8 @@ export class KumimojiTable extends ElementBase {
|
|
|
67
96
|
__classPrivateFieldSet(this, _KumimojiTable_queued, true, "f");
|
|
68
97
|
queueMicrotask(() => {
|
|
69
98
|
__classPrivateFieldSet(this, _KumimojiTable_queued, false, "f");
|
|
70
|
-
|
|
99
|
+
if (this.isConnected)
|
|
100
|
+
__classPrivateFieldGet(this, _KumimojiTable_instances, "m", _KumimojiTable_refresh).call(this);
|
|
71
101
|
});
|
|
72
102
|
}
|
|
73
103
|
/** The mounted table's handle (`mountKumimoji`), or null while the attributes name no table the rules offer. */
|
|
@@ -86,45 +116,146 @@ export class KumimojiTable extends ElementBase {
|
|
|
86
116
|
setGame(saved) {
|
|
87
117
|
return __classPrivateFieldGet(this, _KumimojiTable_table, "f")?.setGame(saved) ?? Promise.resolve();
|
|
88
118
|
}
|
|
119
|
+
/** The `language` attribute, reflected. */
|
|
120
|
+
get language() { return this.getAttribute("language"); }
|
|
121
|
+
set language(value) { __classPrivateFieldGet(this, _KumimojiTable_instances, "m", _KumimojiTable_write).call(this, "language", value); }
|
|
122
|
+
/** The `hand` attribute, reflected. */
|
|
123
|
+
get hand() { return this.getAttribute("hand"); }
|
|
124
|
+
set hand(value) { __classPrivateFieldGet(this, _KumimojiTable_instances, "m", _KumimojiTable_write).call(this, "hand", value); }
|
|
125
|
+
/** The `level` attribute, reflected. */
|
|
126
|
+
get level() { return this.getAttribute("level"); }
|
|
127
|
+
set level(value) { __classPrivateFieldGet(this, _KumimojiTable_instances, "m", _KumimojiTable_write).call(this, "level", value); }
|
|
128
|
+
/** The `length` attribute, reflected. */
|
|
129
|
+
get length() { return this.getAttribute("length"); }
|
|
130
|
+
set length(value) { __classPrivateFieldGet(this, _KumimojiTable_instances, "m", _KumimojiTable_write).call(this, "length", value); }
|
|
131
|
+
/** The `diagonals` attribute, reflected. */
|
|
132
|
+
get diagonals() { return this.getAttribute("diagonals"); }
|
|
133
|
+
set diagonals(value) { __classPrivateFieldGet(this, _KumimojiTable_instances, "m", _KumimojiTable_write).call(this, "diagonals", value); }
|
|
134
|
+
/** The `seed` attribute, reflected. */
|
|
135
|
+
get seed() { return this.getAttribute("seed"); }
|
|
136
|
+
set seed(value) { __classPrivateFieldGet(this, _KumimojiTable_instances, "m", _KumimojiTable_write).call(this, "seed", value); }
|
|
137
|
+
/** The `keep` attribute, reflected. */
|
|
138
|
+
get keep() { return this.getAttribute("keep"); }
|
|
139
|
+
set keep(value) { __classPrivateFieldGet(this, _KumimojiTable_instances, "m", _KumimojiTable_write).call(this, "keep", value); }
|
|
140
|
+
/** The `daily` attribute, reflected. */
|
|
141
|
+
get daily() { return this.getAttribute("daily"); }
|
|
142
|
+
set daily(value) { __classPrivateFieldGet(this, _KumimojiTable_instances, "m", _KumimojiTable_write).call(this, "daily", value); }
|
|
143
|
+
/** The `controls` attribute, reflected. */
|
|
144
|
+
get controls() { return this.getAttribute("controls"); }
|
|
145
|
+
set controls(value) { __classPrivateFieldGet(this, _KumimojiTable_instances, "m", _KumimojiTable_write).call(this, "controls", value); }
|
|
146
|
+
/** The `theme` attribute, reflected. */
|
|
147
|
+
get theme() { return this.getAttribute("theme"); }
|
|
148
|
+
set theme(value) { __classPrivateFieldGet(this, _KumimojiTable_instances, "m", _KumimojiTable_write).call(this, "theme", value); }
|
|
149
|
+
/** The `size` attribute, reflected. */
|
|
150
|
+
get size() { return this.getAttribute("size"); }
|
|
151
|
+
set size(value) { __classPrivateFieldGet(this, _KumimojiTable_instances, "m", _KumimojiTable_write).call(this, "size", value); }
|
|
152
|
+
/** The `width` attribute, reflected. */
|
|
153
|
+
get width() { return this.getAttribute("width"); }
|
|
154
|
+
set width(value) { __classPrivateFieldGet(this, _KumimojiTable_instances, "m", _KumimojiTable_write).call(this, "width", value); }
|
|
155
|
+
/** The `label` attribute, reflected. */
|
|
156
|
+
get label() { return this.getAttribute("label"); }
|
|
157
|
+
set label(value) { __classPrivateFieldGet(this, _KumimojiTable_instances, "m", _KumimojiTable_write).call(this, "label", value); }
|
|
89
158
|
}
|
|
90
|
-
_KumimojiTable_table = new WeakMap(), _KumimojiTable_key = new WeakMap(), _KumimojiTable_queued = new WeakMap(), _KumimojiTable_seed = new WeakMap(), _KumimojiTable_instances = new WeakSet(),
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
const
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
159
|
+
_KumimojiTable_table = new WeakMap(), _KumimojiTable_key = new WeakMap(), _KumimojiTable_queued = new WeakMap(), _KumimojiTable_seed = new WeakMap(), _KumimojiTable_options = new WeakMap(), _KumimojiTable_revision = new WeakMap(), _KumimojiTable_widthBefore = new WeakMap(), _KumimojiTable_widthOwned = new WeakMap(), _KumimojiTable_labelBefore = new WeakMap(), _KumimojiTable_instances = new WeakSet(), _KumimojiTable_write = function _KumimojiTable_write(name, value) { if (value === null || value === undefined)
|
|
160
|
+
this.removeAttribute(name);
|
|
161
|
+
else
|
|
162
|
+
this.setAttribute(name, String(value)); }, _KumimojiTable_frame = function _KumimojiTable_frame() {
|
|
163
|
+
this.style.display = "block";
|
|
164
|
+
this.style.maxWidth = "100%";
|
|
165
|
+
const width = Number(this.getAttribute("width")), size = this.getAttribute("size");
|
|
166
|
+
const pixels = this.hasAttribute("width") && width > 0 && Number.isFinite(width) ? Math.min(width, 2000) : size === "small" ? 320 : size === "medium" ? 480 : size === "large" ? 640 : null;
|
|
167
|
+
if (pixels !== null) {
|
|
168
|
+
if (!__classPrivateFieldGet(this, _KumimojiTable_widthOwned, "f"))
|
|
169
|
+
__classPrivateFieldSet(this, _KumimojiTable_widthBefore, this.style.width, "f");
|
|
170
|
+
__classPrivateFieldSet(this, _KumimojiTable_widthOwned, true, "f");
|
|
171
|
+
this.style.width = `${pixels}px`;
|
|
172
|
+
}
|
|
173
|
+
else if (__classPrivateFieldGet(this, _KumimojiTable_widthOwned, "f")) {
|
|
174
|
+
this.style.width = __classPrivateFieldGet(this, _KumimojiTable_widthBefore, "f") ?? "";
|
|
175
|
+
__classPrivateFieldSet(this, _KumimojiTable_widthOwned, false, "f");
|
|
176
|
+
}
|
|
177
|
+
const theme = this.getAttribute("theme");
|
|
178
|
+
this.style.colorScheme = theme === "light" || theme === "dark" ? theme : "light dark";
|
|
179
|
+
this.setAttribute("data-kumimoji-embed", "");
|
|
180
|
+
const root = this.getRootNode(), target = typeof ShadowRoot !== "undefined" && root instanceof ShadowRoot ? root : this.ownerDocument.head;
|
|
181
|
+
if (target.querySelector("style[data-kumimoji-embed-style]") === null) {
|
|
182
|
+
const style = this.ownerDocument.createElement("style");
|
|
183
|
+
style.setAttribute("data-kumimoji-embed-style", "");
|
|
184
|
+
const light = KUMIMOJI_STYLE.match(/\.km-root \{([^}]+)\}/)?.[1] ?? "";
|
|
185
|
+
const dark = KUMIMOJI_STYLE.match(/@media \(prefers-color-scheme: dark\) \{\s*\.km-root \{([^}]+)\}/)?.[1] ?? "";
|
|
186
|
+
style.textContent = `[data-kumimoji-embed][theme="light"] .km-root{${light}}[data-kumimoji-embed][theme="dark"] .km-root{${dark}}[data-kumimoji-embed]>.km-root{background:var(--km-panel);padding:12px;border-radius:12px}[data-kumimoji-embed] .km-controls[hidden]{display:none}`;
|
|
187
|
+
target.append(style);
|
|
188
|
+
}
|
|
189
|
+
if (this.hasAttribute("label")) {
|
|
190
|
+
__classPrivateFieldSet(this, _KumimojiTable_labelBefore, __classPrivateFieldGet(this, _KumimojiTable_labelBefore, "f") ?? { role: this.getAttribute("role"), label: this.getAttribute("aria-label") }, "f");
|
|
191
|
+
this.setAttribute("role", "group");
|
|
192
|
+
this.setAttribute("aria-label", this.getAttribute("label"));
|
|
193
|
+
}
|
|
194
|
+
else if (__classPrivateFieldGet(this, _KumimojiTable_labelBefore, "f") !== null) {
|
|
195
|
+
for (const [name, value] of [["role", __classPrivateFieldGet(this, _KumimojiTable_labelBefore, "f").role], ["aria-label", __classPrivateFieldGet(this, _KumimojiTable_labelBefore, "f").label]]) {
|
|
196
|
+
if (value === null)
|
|
197
|
+
this.removeAttribute(name);
|
|
198
|
+
else
|
|
199
|
+
this.setAttribute(name, value);
|
|
200
|
+
}
|
|
201
|
+
__classPrivateFieldSet(this, _KumimojiTable_labelBefore, null, "f");
|
|
202
|
+
}
|
|
203
|
+
}, _KumimojiTable_refresh = function _KumimojiTable_refresh() {
|
|
204
|
+
var _a;
|
|
205
|
+
__classPrivateFieldGet(this, _KumimojiTable_instances, "m", _KumimojiTable_frame).call(this);
|
|
206
|
+
try {
|
|
207
|
+
const language = oneOf(this.getAttribute("language"), ["english", "japanese"]) ?? __classPrivateFieldGet(this, _KumimojiTable_options, "f").language;
|
|
208
|
+
const hand = this.hasAttribute("hand") ? Number(this.getAttribute("hand")) : __classPrivateFieldGet(this, _KumimojiTable_options, "f").hand;
|
|
209
|
+
const level = oneOf(this.getAttribute("level"), ["easy", "medium", "hard"]) ?? __classPrivateFieldGet(this, _KumimojiTable_options, "f").level;
|
|
210
|
+
const gameLength = oneOf(this.getAttribute("length"), ["short", "medium", "full"]) ?? __classPrivateFieldGet(this, _KumimojiTable_options, "f").gameLength;
|
|
211
|
+
const diagonals = isOn(this.getAttribute("diagonals"), __classPrivateFieldGet(this, _KumimojiTable_options, "f").diagonals ?? false);
|
|
212
|
+
const seedAttribute = this.getAttribute("seed"), asked = Number(seedAttribute);
|
|
213
|
+
const day = embedDay(this.hasAttribute("daily") ? this.getAttribute("daily") : seedAttribute === "daily" ? "today" : null);
|
|
214
|
+
const seed = day !== null ? kumimojiDailySeed(new Date(`${day}T00:00:00Z`)) : seedAttribute !== null && Number.isInteger(asked) && asked >= 0 && asked <= 0xffffffff ? asked : __classPrivateFieldGet(this, _KumimojiTable_options, "f").seed ?? (__classPrivateFieldSet(this, _KumimojiTable_seed, __classPrivateFieldGet(this, _KumimojiTable_seed, "f") ?? Math.floor(Math.random() * 2 ** 31), "f"));
|
|
215
|
+
const lang = this.getAttribute("lang"), locale = lang === "en" || lang === "ja" ? lang : __classPrivateFieldGet(this, _KumimojiTable_options, "f").locale ?? (this.ownerDocument.documentElement.lang.toLowerCase().startsWith("ja") ? "ja" : "en");
|
|
216
|
+
const keep = isOn(this.getAttribute("keep"), __classPrivateFieldGet(this, _KumimojiTable_options, "f").keep ?? true), controls = isOn(this.getAttribute("controls"), __classPrivateFieldGet(this, _KumimojiTable_options, "f").controls ?? true);
|
|
217
|
+
const key = JSON.stringify([language, hand, level, gameLength, diagonals, seed, day, __classPrivateFieldGet(this, _KumimojiTable_options, "f").saved]);
|
|
218
|
+
if (key === __classPrivateFieldGet(this, _KumimojiTable_key, "f") && __classPrivateFieldGet(this, _KumimojiTable_table, "f") !== null) {
|
|
219
|
+
__classPrivateFieldGet(this, _KumimojiTable_table, "f").set({ locale, strings: __classPrivateFieldGet(this, _KumimojiTable_options, "f").strings, theme: __classPrivateFieldGet(this, _KumimojiTable_options, "f").theme ?? {}, keep, controls });
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
if (hand !== undefined && !HANDS.includes(hand))
|
|
223
|
+
throw new RangeError("Choose a hand of 3, 7 or 11 tiles.");
|
|
224
|
+
__classPrivateFieldGet(this, _KumimojiTable_table, "f")?.destroy();
|
|
225
|
+
__classPrivateFieldSet(this, _KumimojiTable_table, null, "f");
|
|
226
|
+
__classPrivateFieldSet(this, _KumimojiTable_key, "", "f");
|
|
227
|
+
this.replaceChildren();
|
|
228
|
+
const revision = __classPrivateFieldSet(this, _KumimojiTable_revision, (_a = __classPrivateFieldGet(this, _KumimojiTable_revision, "f"), ++_a), "f");
|
|
229
|
+
const table = mountKumimoji(this, { ...__classPrivateFieldGet(this, _KumimojiTable_options, "f"), language, hand, level, gameLength, diagonals, seed, locale, keep, controls, onChange: saved => { this.dispatchEvent(new CustomEvent("kumimoji-change", { detail: JSON.parse(JSON.stringify({ saved })), bubbles: true, composed: true })); __classPrivateFieldGet(this, _KumimojiTable_options, "f").onChange?.(saved); }, onFinish: result => { this.dispatchEvent(new CustomEvent("kumimoji-finish", { detail: JSON.parse(JSON.stringify(result)), bubbles: true, composed: true })); __classPrivateFieldGet(this, _KumimojiTable_options, "f").onFinish?.(result); }, onError: error => { this.dispatchEvent(new CustomEvent("kumimoji-error", { detail: { message: error.message }, bubbles: true, composed: true })); __classPrivateFieldGet(this, _KumimojiTable_options, "f").onError?.(error); } });
|
|
230
|
+
__classPrivateFieldSet(this, _KumimojiTable_table, table, "f");
|
|
231
|
+
__classPrivateFieldSet(this, _KumimojiTable_key, key, "f");
|
|
232
|
+
void table.ready.then(() => { if (this.isConnected && revision === __classPrivateFieldGet(this, _KumimojiTable_revision, "f") && table.saved() !== null)
|
|
233
|
+
this.dispatchEvent(new CustomEvent("kumimoji-load", { bubbles: true, composed: true, detail: { seed: table.saved().deal.seed, day } })); }).catch(() => { });
|
|
234
|
+
}
|
|
235
|
+
catch (error) {
|
|
236
|
+
__classPrivateFieldGet(this, _KumimojiTable_table, "f")?.destroy();
|
|
237
|
+
__classPrivateFieldSet(this, _KumimojiTable_table, null, "f");
|
|
238
|
+
__classPrivateFieldSet(this, _KumimojiTable_key, "", "f");
|
|
239
|
+
const message = error instanceof Error ? error.message : String(error), status = this.ownerDocument.createElement("p");
|
|
240
|
+
status.setAttribute("role", "status");
|
|
241
|
+
status.textContent = message;
|
|
242
|
+
this.replaceChildren(status);
|
|
243
|
+
this.dispatchEvent(new CustomEvent("kumimoji-error", { detail: { message }, bubbles: true, composed: true }));
|
|
111
244
|
}
|
|
112
|
-
__classPrivateFieldGet(this, _KumimojiTable_table, "f")?.destroy();
|
|
113
|
-
__classPrivateFieldSet(this, _KumimojiTable_table, null, "f");
|
|
114
|
-
__classPrivateFieldSet(this, _KumimojiTable_key, key, "f");
|
|
115
|
-
if (hand !== undefined && !HANDS.includes(hand))
|
|
116
|
-
return;
|
|
117
|
-
__classPrivateFieldSet(this, _KumimojiTable_table, mountKumimoji(this, {
|
|
118
|
-
language,
|
|
119
|
-
hand,
|
|
120
|
-
level,
|
|
121
|
-
gameLength,
|
|
122
|
-
diagonals,
|
|
123
|
-
seed,
|
|
124
|
-
locale,
|
|
125
|
-
keep,
|
|
126
|
-
onChange: (saved) => this.dispatchEvent(new CustomEvent("kumimoji-change", { detail: { saved }, bubbles: true })),
|
|
127
|
-
onFinish: (result) => this.dispatchEvent(new CustomEvent("kumimoji-finish", { detail: result, bubbles: true })),
|
|
128
|
-
}), "f");
|
|
129
245
|
};
|
|
130
|
-
KumimojiTable.observedAttributes = ["language", "hand", "level", "length", "diagonals", "seed", "lang", "keep"];
|
|
246
|
+
KumimojiTable.observedAttributes = ["language", "hand", "level", "length", "diagonals", "seed", "lang", "keep", "daily", "controls", "theme", "size", "width", "label"];
|
|
247
|
+
/**
|
|
248
|
+
* Defines the table or a subclass under a custom tag. Server-safe and idempotent.
|
|
249
|
+
* @param tagName - The tag name; kumimoji-table by default.
|
|
250
|
+
* @param registry - The page registry, or undefined on a server.
|
|
251
|
+
* @returns Nothing; existing definitions are left alone.
|
|
252
|
+
* @example
|
|
253
|
+
* ```ts
|
|
254
|
+
* import { defineTable } from "@johnmorrisdotca/kumimoji/element";
|
|
255
|
+
* defineTable();
|
|
256
|
+
* console.log(typeof defineTable);
|
|
257
|
+
* ```
|
|
258
|
+
*/
|
|
259
|
+
export function defineTable(tagName = "kumimoji-table", registry = typeof customElements === "undefined" ? undefined : customElements) { if (registry !== undefined && registry.get(tagName) === undefined)
|
|
260
|
+
registry.define(tagName, tagName === "kumimoji-table" ? KumimojiTable : class extends KumimojiTable {
|
|
261
|
+
}); }
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** Shared UTC day parsing for the family's daily embeds. No storage, service or rollover timer. */
|
|
2
|
+
export declare function embedDay(value: string | null | undefined, now?: Date): string | null;
|
|
3
|
+
/** The same day and namespace give the same nonzero 32-bit seed on every machine. */
|
|
4
|
+
export declare function dailySeed(day: string, namespace: string): number;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** Shared UTC day parsing for the family's daily embeds. No storage, service or rollover timer. */
|
|
2
|
+
export function embedDay(value, now = new Date()) {
|
|
3
|
+
if (value === null || value === undefined || ["off", "false", "no", "0"].includes(value.trim().toLowerCase()))
|
|
4
|
+
return null;
|
|
5
|
+
const asked = value.trim().toLowerCase();
|
|
6
|
+
const day = ["", "today", "on", "true", "1"].includes(asked) ? Number.isNaN(now.getTime()) ? "" : now.toISOString().slice(0, 10) : value.trim();
|
|
7
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(day))
|
|
8
|
+
throw new RangeError("Use a real UTC date written YYYY-MM-DD.");
|
|
9
|
+
const time = Date.parse(`${day}T00:00:00Z`);
|
|
10
|
+
if (!Number.isFinite(time) || new Date(time).toISOString().slice(0, 10) !== day)
|
|
11
|
+
throw new RangeError("Use a real UTC date written YYYY-MM-DD.");
|
|
12
|
+
return day;
|
|
13
|
+
}
|
|
14
|
+
/** The same day and namespace give the same nonzero 32-bit seed on every machine. */
|
|
15
|
+
export function dailySeed(day, namespace) {
|
|
16
|
+
const parsed = embedDay(day);
|
|
17
|
+
if (parsed === null)
|
|
18
|
+
throw new RangeError("A daily seed needs a UTC date.");
|
|
19
|
+
let hash = 2166136261;
|
|
20
|
+
for (const letter of `${parsed}/${namespace}`)
|
|
21
|
+
hash = Math.imul(hash ^ letter.charCodeAt(0), 16777619) >>> 0;
|
|
22
|
+
return hash || 1;
|
|
23
|
+
}
|
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
|
@@ -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;
|
|
@@ -102,7 +153,17 @@ export async function kumimojiFromJSON(text) {
|
|
|
102
153
|
const play = decodeTileProgress(progress, deal.givens, language);
|
|
103
154
|
return play === null ? null : { deal, play, elapsedMs: spent };
|
|
104
155
|
}
|
|
105
|
-
/** A time as minutes and seconds: `1:05`.
|
|
156
|
+
/** A time as minutes and seconds: `1:05`.
|
|
157
|
+
*
|
|
158
|
+
* @param ms - The duration in milliseconds.
|
|
159
|
+
* @returns A time as minutes and seconds: `1:05`.
|
|
160
|
+
* @example
|
|
161
|
+
* ```ts
|
|
162
|
+
* import { kumimojiClock } from "@johnmorrisdotca/kumimoji";
|
|
163
|
+
*
|
|
164
|
+
* console.log(kumimojiClock(65000));
|
|
165
|
+
* ```
|
|
166
|
+
*/
|
|
106
167
|
export function kumimojiClock(ms) {
|
|
107
168
|
const seconds = Math.max(0, Math.floor(ms / 1000));
|
|
108
169
|
return `${Math.floor(seconds / 60)}:${String(seconds % 60).padStart(2, "0")}`;
|
|
@@ -112,6 +173,17 @@ export function kumimojiClock(ms) {
|
|
|
112
173
|
* capitals with a space between squares and a dot for an empty one, kana side
|
|
113
174
|
* by side with a full-width dot for an empty one, so that either lines up in a
|
|
114
175
|
* fixed-width face, every row as wide as the crossword. A wild that has been given nothing is `*`. No tiles is "".
|
|
176
|
+
*
|
|
177
|
+
* @param tiles - The map from row,column square names to internal tile codes.
|
|
178
|
+
* @param language - The English or Japanese tile language.
|
|
179
|
+
* @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 "".
|
|
180
|
+
* @example
|
|
181
|
+
* ```ts
|
|
182
|
+
* import { gridToText } from "@johnmorrisdotca/kumimoji";
|
|
183
|
+
*
|
|
184
|
+
* const tiles = new Map([["0,0","c"],["0,1","a"],["0,2","t"]]);
|
|
185
|
+
* console.log(gridToText(tiles));
|
|
186
|
+
* ```
|
|
115
187
|
*/
|
|
116
188
|
export function gridToText(tiles, language = "english") {
|
|
117
189
|
const bounds = boundsOf(tiles);
|
|
@@ -140,6 +212,21 @@ export function gridToText(tiles, language = "english") {
|
|
|
140
212
|
* English unless given another table of strings (`KUMIMOJI_STRINGS.ja`). The
|
|
141
213
|
* word list of the game's language must have been loaded, as for any judging.
|
|
142
214
|
* Lines end with a line feed.
|
|
215
|
+
*
|
|
216
|
+
* @param saved - The original deal, current progress and elapsed time.
|
|
217
|
+
* @param strings - The localized words for readable export.
|
|
218
|
+
* @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.
|
|
219
|
+
* @example
|
|
220
|
+
* ```ts
|
|
221
|
+
* import { deal, generateKumimoji, kumimojiToText } from "@johnmorrisdotca/kumimoji";
|
|
222
|
+
* import { loadTileWordsFromModule } from "@johnmorrisdotca/kumimoji/words";
|
|
223
|
+
*
|
|
224
|
+
* await loadTileWordsFromModule("english");
|
|
225
|
+
* const play = deal("catdog",3);
|
|
226
|
+
* const dealt = generateKumimoji(3,"hard",44);
|
|
227
|
+
* const saved = {deal:dealt,play:deal(dealt.givens,dealt.size),elapsedMs:0};
|
|
228
|
+
* console.log(kumimojiToText(saved));
|
|
229
|
+
* ```
|
|
143
230
|
*/
|
|
144
231
|
export function kumimojiToText(saved, strings = KUMIMOJI_STRINGS.en) {
|
|
145
232
|
const { deal, play } = saved;
|
package/dist/generate.d.ts
CHANGED
|
@@ -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;
|