@johnmorrisdotca/kumimoji 1.2.1 → 1.2.2
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 +16 -0
- package/CONTRIBUTING.md +81 -44
- package/README.md +422 -312
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +4 -3
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,22 @@ All notable changes to this project are written down here. The format follows
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [1.2.2] - 2026-10-06
|
|
10
|
+
|
|
11
|
+
Nothing that was exported has changed.
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- The README takes the family's one layout, fully: a hero picture of the demo on a desk and on a phone in light and dark, a picture of each kind of table (English, kana, a run that is not a word, a hand of eleven, a wild tile), an Examples section of ten examples whose output is what they print, an Install section, and a short list of the calls to learn first. Its pictures are in `docs/images` (WebP, light and dark) and are retaken with `pnpm screenshots:readme` (it replaces `pnpm pictures` and the two JPEGs `docs/desktop.jpg` and `docs/phone.jpg`); they are not in the tarball, and `pnpm test:package` fails if one is.
|
|
16
|
+
- To keep the README under the 64,000 characters npm can show, the long tables of exports (dealing and judging, tiles and grids, playing, the table of players, looking at the table) and the table's, the element's and the React components' options moved to `docs/API.md`, and the source tree moved to `docs/ARCHITECTURE.md`, each with a summary and a link left in the README. Nothing was removed, and the tests that hold these tables to the code read the README and `docs/API.md` together.
|
|
17
|
+
- `pnpm test:readme` type-checks and runs every TypeScript and JavaScript example in the README against the built package, as a CI job of its own, and `pnpm check` holds the README to the family's lint.
|
|
18
|
+
- "The command line" says there is none, and now sits after the languages, where the other sections of the standard's order leave room for it.
|
|
19
|
+
- Repository only: the package and everything it exports are unchanged. `CONTRIBUTING.md` is the family's one text with a section of its own for Kumimoji, held to the master in johnmorrisdotca/.github by `src/family.test.js`; `ci.yml` and `pages.yml` are the family's one text (`pnpm check`, the demo, and the package on Linux, macOS and Windows), and any jobs of the package's own after them.
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
|
|
23
|
+
- The API reference page wraps a long entry path instead of running about 2 px wider than a 360 px screen. Nothing the package exports has changed.
|
|
24
|
+
|
|
9
25
|
## [1.2.1] - 2026-10-05
|
|
10
26
|
|
|
11
27
|
Nothing that was exported has changed.
|
package/CONTRIBUTING.md
CHANGED
|
@@ -1,28 +1,100 @@
|
|
|
1
|
-
# Contributing
|
|
1
|
+
# Contributing
|
|
2
2
|
|
|
3
|
-
Thank you for helping. Bug reports,
|
|
4
|
-
|
|
3
|
+
Thank you for helping. Bug reports, ideas, corrections to the Japanese and pull
|
|
4
|
+
requests are all welcome.
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
This first part is the same in every package of the family. It is the master
|
|
7
|
+
text kept in
|
|
8
|
+
[johnmorrisdotca/.github](https://github.com/johnmorrisdotca/.github/blob/main/CONTRIBUTING.md),
|
|
9
|
+
copied unchanged into `scripts/community/CONTRIBUTING.md`, and a test holds
|
|
10
|
+
this file to that copy. What is particular to the package follows it, under
|
|
11
|
+
the heading "Particular to" and the package's name.
|
|
12
|
+
|
|
13
|
+
## Before you start
|
|
14
|
+
|
|
15
|
+
Open an issue first for anything bigger than a typo, so that we can agree on the
|
|
16
|
+
shape before you spend time on it. Taking part follows the
|
|
17
|
+
[Code of Conduct](CODE_OF_CONDUCT.md); report a security concern privately, as
|
|
18
|
+
[SECURITY.md](SECURITY.md) says.
|
|
19
|
+
|
|
20
|
+
## Making a change
|
|
21
|
+
|
|
22
|
+
```sh
|
|
23
|
+
pnpm install
|
|
24
|
+
pnpm check # lint, types and tests: the same as CI
|
|
25
|
+
pnpm test:package # pack it as npm does, install it in an empty project, import every entry
|
|
26
|
+
pnpm site # build the demo into ./site, as GitHub Pages publishes it
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The package's own further commands (its browser tests, its command line, its
|
|
30
|
+
data scripts) are listed under its own heading below.
|
|
31
|
+
|
|
32
|
+
## House rules, shared by every package of the family
|
|
33
|
+
|
|
34
|
+
- **No runtime dependencies.** Development dependencies are for tests, builds and
|
|
35
|
+
documentation only.
|
|
36
|
+
- **The core is pure.** Every function in it returns new values and never
|
|
37
|
+
changes what it was given.
|
|
38
|
+
- **Test what you change.** Tests sit beside the code they test. A rule you
|
|
39
|
+
change has a test that would have caught it.
|
|
40
|
+
- **Words a person reads come in English and Japanese.** If you cannot write the
|
|
41
|
+
Japanese, say so in the pull request and someone will.
|
|
42
|
+
- **Option values and names are kebab case.**
|
|
43
|
+
- **Art and sound are CC0 or public domain only**, checked at the source and
|
|
44
|
+
credited. Data and word lists may be under another licence that lets them be
|
|
45
|
+
shipped, with its notice kept in `NOTICE.md`. No GPL or LGPL code.
|
|
46
|
+
- **Needs Node 22 or later.**
|
|
47
|
+
- **A README table, example or count that a test holds to the code** changes
|
|
48
|
+
together with the code.
|
|
49
|
+
- **The family's own files are the same in every package**: `demo/family.css`,
|
|
50
|
+
`scripts/family-template.mjs`, `scripts/family-readme.mjs`,
|
|
51
|
+
`scripts/release-notes.mjs`, the files in `scripts/community/` and
|
|
52
|
+
`family.test.js` (in `src/`, or in `test/`). Do not edit one here. To change
|
|
53
|
+
one, change it in every repository at once, bump `FAMILY_TEMPLATE_VERSION` for
|
|
54
|
+
the template, and record the new hash in `family.test.js`. What is the
|
|
55
|
+
package's own goes in its own stylesheet, `demo/<name>.css`, and its page
|
|
56
|
+
builder, `scripts/site.mjs`.
|
|
57
|
+
- **The list of the family in the README is made, not written.**
|
|
58
|
+
`pnpm family:readme` writes it between its markers from
|
|
59
|
+
`scripts/family-template.mjs`.
|
|
60
|
+
- **The workflows are the family's too.** `ci.yml` runs `pnpm check`, the demo's
|
|
61
|
+
browser tests and the packed package on Linux, macOS and Windows; `pages.yml`
|
|
62
|
+
is the same text in every package. A package adds jobs of its own after those.
|
|
63
|
+
|
|
64
|
+
## Pull requests
|
|
65
|
+
|
|
66
|
+
One change per pull request. Say what changed and how you checked it, and add a
|
|
67
|
+
line to `CHANGELOG.md` under **Unreleased**: for a change a user would notice,
|
|
68
|
+
and for one to the repository alone.
|
|
69
|
+
|
|
70
|
+
## Releasing
|
|
71
|
+
|
|
72
|
+
Maintainers bump the version in `package.json` (and in `src/version.ts`, where
|
|
73
|
+
the package has one), move *Unreleased* to the new version in `CHANGELOG.md`,
|
|
74
|
+
dated, push, wait for CI and tag `vX.Y.Z`, the same as `package.json`'s version.
|
|
75
|
+
The Release workflow (`.github/workflows/release.yml`) checks and builds the
|
|
76
|
+
package, attaches the tarball to a GitHub release and publishes it to npm by
|
|
77
|
+
trusted publishing, with provenance and no token. A version already on npm is
|
|
78
|
+
not published again.
|
|
79
|
+
|
|
80
|
+
## Particular to Kumimoji
|
|
81
|
+
|
|
82
|
+
### Reporting a bug
|
|
7
83
|
|
|
8
84
|
Open an [issue](https://github.com/johnmorrisdotca/kumimoji/issues/new?template=report-a-bug.md)
|
|
9
85
|
with what you did, what you expected and what happened. A seed deals the same
|
|
10
86
|
bag every time, so the table's *Save as JSON* file, or the seed with the
|
|
11
87
|
language, hand and level, makes almost any bug reproducible.
|
|
12
88
|
|
|
13
|
-
|
|
89
|
+
### Commands and rules
|
|
14
90
|
|
|
15
91
|
```sh
|
|
16
|
-
git clone https://github.com/johnmorrisdotca/kumimoji
|
|
17
|
-
cd kumimoji
|
|
18
|
-
pnpm install
|
|
19
92
|
pnpm check # lint, types and tests: the same as CI
|
|
20
93
|
pnpm test:table # the demo in real browsers: builds it, then taps it
|
|
21
94
|
pnpm test:package # npm pack, install the tarball, import and require every entry, read both lists
|
|
22
95
|
pnpm test:frameworks # the README's examples built in React, Vue, Svelte, Angular and a plain page
|
|
23
96
|
pnpm site # builds the demo into ./site
|
|
24
97
|
pnpm pictures # re-takes the README's two pictures from the built demo
|
|
25
|
-
pnpm dlx serve site # or any static server
|
|
26
98
|
```
|
|
27
99
|
|
|
28
100
|
- **The rules are pure.** Everything outside `src/ui` and `src/react.tsx` is
|
|
@@ -44,7 +116,6 @@ pnpm dlx serve site # or any static server
|
|
|
44
116
|
- **How the lists load is not to be changed lightly.** They are fetched by a
|
|
45
117
|
dynamic import behind `typeof window`, so that a page's server code never
|
|
46
118
|
carries them; Itsutsu relies on it.
|
|
47
|
-
- **Test what you change.** Tests sit beside their source as `*.test.ts`.
|
|
48
119
|
- **The table is tested by tapping it.** `table/*.table.mjs` are Playwright
|
|
49
120
|
tests that open the built demo in Chromium and WebKit, at a phone's width by
|
|
50
121
|
touch and at a desktop's by mouse, and do what a person does. After every
|
|
@@ -61,38 +132,4 @@ pnpm dlx serve site # or any static server
|
|
|
61
132
|
each from the packed tarball and lays a tile.
|
|
62
133
|
- **Every export gets a doc comment**, which a test holds, and the README's
|
|
63
134
|
tables (options, theming, limits) are checked against the code.
|
|
64
|
-
- **The demo wears the family's look.** `demo/family.css` is the same file in
|
|
65
|
-
every sibling package's demo, and a test fails if it differs from its
|
|
66
|
-
recorded hash. What is Kumimoji's own goes in `demo/kumimoji.css`.
|
|
67
|
-
- **No dependencies.** The package has none at run time and should stay so.
|
|
68
135
|
- **No name, art or wording of a published game.**
|
|
69
|
-
- One change per pull request, with a line in `CHANGELOG.md` under
|
|
70
|
-
*Unreleased*.
|
|
71
|
-
|
|
72
|
-
## House rules, shared by every package of the family
|
|
73
|
-
|
|
74
|
-
- Open an issue first for anything bigger than a typo, so that we can agree on the shape before you spend time on it.
|
|
75
|
-
- No runtime dependencies. Every function that plays or checks a game is pure: it returns new values and never changes what it was given.
|
|
76
|
-
- Tests sit beside the code they test. A rule you change has a test that would have caught it.
|
|
77
|
-
- Words a player reads come in English and Japanese. If you cannot write the Japanese, say so in the pull request and someone will.
|
|
78
|
-
- Option values and names are kebab case.
|
|
79
|
-
- Art and sound are CC0 or public domain only, checked at the source, and credited in the README. No GPL or LGPL code.
|
|
80
|
-
- Needs Node 22 or later. A change a user would notice gets a line in `CHANGELOG.md`.
|
|
81
|
-
- **The list of the family in the README is made, not written.** `pnpm family:readme` writes it between its
|
|
82
|
-
markers from `scripts/family-template.mjs` (the names, the Japanese names and a line on each), and
|
|
83
|
-
`scripts/family-readme.mjs` is the same file in every package. To add a package or change a line, change the
|
|
84
|
-
template in every repository, bump `FAMILY_TEMPLATE_VERSION` and record the new hash in `src/family.test.js`.
|
|
85
|
-
|
|
86
|
-
## Releasing
|
|
87
|
-
|
|
88
|
-
Maintainers bump the version in `package.json` and `src/version.ts` and move
|
|
89
|
-
*Unreleased* to the new version in `CHANGELOG.md`, dated. Pushing the tag
|
|
90
|
-
`vX.Y.Z` runs the Release workflow, which checks that the tag matches
|
|
91
|
-
`package.json`, runs the checks, builds the package, installs and uses it as
|
|
92
|
-
npm packs it, attaches the tarball to a GitHub release, and publishes it to
|
|
93
|
-
npm with provenance, through npm's trusted publishing (no token is kept). A
|
|
94
|
-
version already on npm is not published again. The workflow can also be run
|
|
95
|
-
by hand.
|
|
96
|
-
|
|
97
|
-
By contributing you agree that your code is released under the
|
|
98
|
-
[MIT licence](LICENSE), and to follow the [code of conduct](CODE_OF_CONDUCT.md).
|
package/README.md
CHANGED
|
@@ -12,12 +12,26 @@ In English and in Japanese kana. The rules as pure, seeded TypeScript, two word
|
|
|
12
12
|
<img alt="TypeScript" src="https://img.shields.io/badge/types-TypeScript-3178c6">
|
|
13
13
|
</p>
|
|
14
14
|
|
|
15
|
-
<p align="center"><a href="https://johnmorrisdotca.github.io/kumimoji/"><strong>Play a game →</strong></a> · <a href="https://johnmorrisdotca.github.io/kumimoji/api.html">API reference</a></p>
|
|
16
|
-
|
|
17
|
-
<
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
<p align="center"><a href="https://johnmorrisdotca.github.io/kumimoji/"><strong>Play a game →</strong></a> · <a href="https://johnmorrisdotca.github.io/kumimoji/api.html">API reference</a> · <a href="docs/API.md">The API in full</a></p>
|
|
16
|
+
|
|
17
|
+
<table align="center">
|
|
18
|
+
<tr>
|
|
19
|
+
<td align="center" valign="top">
|
|
20
|
+
<picture>
|
|
21
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/kumimoji/main/docs/images/hero-desk-dark.webp">
|
|
22
|
+
<img src="https://raw.githubusercontent.com/johnmorrisdotca/kumimoji/main/docs/images/hero-desk-light.webp" alt="The demo on a desk, in English: the page's header with its language chooser and cloth swatches, the choices for tiles, hand and wild tiles, and a green table with a crossword half built from the words SYNDIC, MAUP and PA crossing, one tile left in the hand and the buttons to draw, trade, sort and lift all." width="720">
|
|
23
|
+
</picture>
|
|
24
|
+
<br><em>An English game half way, on a desk: a crossword of SYNDIC and the words that cross it.</em>
|
|
25
|
+
</td>
|
|
26
|
+
<td align="center" valign="top">
|
|
27
|
+
<picture>
|
|
28
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/kumimoji/main/docs/images/hero-phone-dark.webp">
|
|
29
|
+
<img src="https://raw.githubusercontent.com/johnmorrisdotca/kumimoji/main/docs/images/hero-phone-light.webp" alt="The demo on a phone, in Japanese kana: a green table with a crossword built from kana tiles, and a hand and buttons under it." width="220">
|
|
30
|
+
</picture>
|
|
31
|
+
<br><em>A game in kana on a phone, in the device's light or dark.</em>
|
|
32
|
+
</td>
|
|
33
|
+
</tr>
|
|
34
|
+
</table>
|
|
21
35
|
|
|
22
36
|
A word game engine for the race to build a crossword. Every player lays their
|
|
23
37
|
own tiles as words that cross, draws another when the hand is used and every
|
|
@@ -69,7 +83,7 @@ isFinished(play, judgeWithWords(play.tiles, words)); // → true
|
|
|
69
83
|
|
|
70
84
|
NOW, then SNOW, then SNOWY. And a table to play on, in a page:
|
|
71
85
|
|
|
72
|
-
```js
|
|
86
|
+
```js no-run
|
|
73
87
|
import { mountKumimoji } from "@johnmorrisdotca/kumimoji/ui";
|
|
74
88
|
|
|
75
89
|
mountKumimoji(document.getElementById("table"), { language: "english", hand: 7 });
|
|
@@ -90,8 +104,108 @@ Or with nothing to install, [play a game in the demo](https://johnmorrisdotca.gi
|
|
|
90
104
|
on the や tile, and a list of 163,461 readings.
|
|
91
105
|
- **Learners and teachers** of English or Japanese spelling.
|
|
92
106
|
|
|
107
|
+
## Features
|
|
108
|
+
|
|
109
|
+
- **Dealt from a seed.** `generateKumimoji` lays a crossword first and deals
|
|
110
|
+
its tiles, so every bag can be finished.
|
|
111
|
+
- **English and Japanese.** 144 tiles in each: the English letters, or 45 base
|
|
112
|
+
kana where が plays as か, ゃ as や and を as お. 110,316 English words and
|
|
113
|
+
163,461 Japanese readings, of 2 to 15 tiles.
|
|
114
|
+
- **Wild tiles** that take any letter or kana, and are read as that in every
|
|
115
|
+
word they are part of.
|
|
116
|
+
- **Trades.** A tile you cannot use goes back into the bag for three.
|
|
117
|
+
- **Diagonals**, if chosen: every diagonal run of three or more must be a word
|
|
118
|
+
too.
|
|
119
|
+
- **Three lengths.** A short game, half the set, or all 144 tiles; and two
|
|
120
|
+
English sets at once.
|
|
121
|
+
- **The rules as plain functions.** A game in progress is a value (`TilePlay`):
|
|
122
|
+
`deal`, `placeFromHand`, `moveOnTable`, `liftToHand`, `draw` and `trade` each
|
|
123
|
+
return a new one.
|
|
124
|
+
- **A table of two to eight** sharing one bag, with a last round, resigning,
|
|
125
|
+
joining and leaving, kept as text, and a computer player for any seat.
|
|
126
|
+
- **Help**, if chosen: the words the hand's own tiles spell.
|
|
127
|
+
- **A table to play on.** `mountKumimoji` plays a whole game alone in plain
|
|
128
|
+
DOM, saves it and loads it back; `KumimojiBoard` draws a grid in React.
|
|
129
|
+
- **A tag.** `<kumimoji-table>` is the same game in one element, with no
|
|
130
|
+
framework.
|
|
131
|
+
- **One bag a day.** `kumimojiDailySeed(new Date())` is the same seed for
|
|
132
|
+
everybody, worldwide.
|
|
133
|
+
- **Played from a keyboard.** Arrow keys between squares and tiles, Enter or
|
|
134
|
+
Space to pick up and lay; see [Accessibility](#accessibility).
|
|
135
|
+
- **The table's words in English and Japanese**, and any other language by a
|
|
136
|
+
table of your own. **Themeable**: every colour is a CSS variable.
|
|
137
|
+
|
|
138
|
+
### What's in it
|
|
139
|
+
|
|
140
|
+
Each picture is the table the package draws, taken from [the demo](https://johnmorrisdotca.github.io/kumimoji/) with `pnpm screenshots:readme`, in light and dark. The game is dealt from a seed, and the words are laid by the package's own computer player, so the same pictures come again.
|
|
141
|
+
|
|
142
|
+
<table>
|
|
143
|
+
<tr>
|
|
144
|
+
<td align="center" valign="top" width="50%">
|
|
145
|
+
<picture>
|
|
146
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/kumimoji/main/docs/images/english-desk-dark.webp">
|
|
147
|
+
<img src="https://raw.githubusercontent.com/johnmorrisdotca/kumimoji/main/docs/images/english-desk-light.webp" alt="An English board on the green table: SYNDIC across with MAUP and PA crossing it, and U hanging under the N, drawn on a grid of empty squares that has no edge." width="400">
|
|
148
|
+
</picture>
|
|
149
|
+
<br><em><strong>English.</strong> 144 tiles, 110,316 words.</em>
|
|
150
|
+
</td>
|
|
151
|
+
<td align="center" valign="top" width="50%">
|
|
152
|
+
<picture>
|
|
153
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/kumimoji/main/docs/images/kana-desk-dark.webp">
|
|
154
|
+
<img src="https://raw.githubusercontent.com/johnmorrisdotca/kumimoji/main/docs/images/kana-desk-light.webp" alt="A Japanese board of kana tiles on the green table, a crossword of hiragana laid across and down on the grid of empty squares." width="400">
|
|
155
|
+
</picture>
|
|
156
|
+
<br><em><strong>Japanese kana.</strong> 45 base kana tiles, 163,461 readings.</em>
|
|
157
|
+
</td>
|
|
158
|
+
</tr>
|
|
159
|
+
<tr>
|
|
160
|
+
<td align="center" valign="top" width="50%">
|
|
161
|
+
<picture>
|
|
162
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/kumimoji/main/docs/images/not-a-word-desk-dark.webp">
|
|
163
|
+
<img src="https://raw.githubusercontent.com/johnmorrisdotca/kumimoji/main/docs/images/not-a-word-desk-light.webp" alt="A board with two tiles side by side, N and W, each ringed in red, because the two make the run NW, which is not a word." width="400">
|
|
164
|
+
</picture>
|
|
165
|
+
<br><em><strong>A run that is not a word</strong> is ringed, and named under the table.</em>
|
|
166
|
+
</td>
|
|
167
|
+
<td align="center" valign="top" width="50%">
|
|
168
|
+
<picture>
|
|
169
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/kumimoji/main/docs/images/hand-of-eleven-desk-dark.webp">
|
|
170
|
+
<img src="https://raw.githubusercontent.com/johnmorrisdotca/kumimoji/main/docs/images/hand-of-eleven-desk-light.webp" alt="A board partly built from a hand of eleven tiles, a larger crossword than a hand of seven makes, on the same green table." width="400">
|
|
171
|
+
</picture>
|
|
172
|
+
<br><em><strong>A hand of eleven.</strong> Hands are 3, 7 or 11.</em>
|
|
173
|
+
</td>
|
|
174
|
+
</tr>
|
|
175
|
+
</table>
|
|
176
|
+
|
|
177
|
+
<p align="center">
|
|
178
|
+
<picture>
|
|
179
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/kumimoji/main/docs/images/wild-tiles-desk-dark.webp">
|
|
180
|
+
<img src="https://raw.githubusercontent.com/johnmorrisdotca/kumimoji/main/docs/images/wild-tiles-desk-light.webp" alt="A hand of seven tiles, E, T, U, P, L and L in cream and one gold tile with a black star, a wild tile that is any letter or kana the player gives it." width="500">
|
|
181
|
+
</picture>
|
|
182
|
+
<br><em><strong>A wild tile</strong> is the gold star in the hand: the player gives it a letter before it is laid.</em>
|
|
183
|
+
</p>
|
|
184
|
+
|
|
93
185
|
## Use it in your project
|
|
94
186
|
|
|
187
|
+
### Install
|
|
188
|
+
|
|
189
|
+
```sh
|
|
190
|
+
npm install @johnmorrisdotca/kumimoji
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
```sh
|
|
194
|
+
pnpm add @johnmorrisdotca/kumimoji
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
```sh
|
|
198
|
+
yarn add @johnmorrisdotca/kumimoji
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
A page with no bundler loads the table as a tag from a CDN, naming the major version so that a release that changes what you use is one you choose:
|
|
202
|
+
|
|
203
|
+
```html
|
|
204
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@johnmorrisdotca/kumimoji@1/dist/element-define.js"></script>
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
On a server or in a script, `import "@johnmorrisdotca/kumimoji/words"` first, so that the word lists are read from the package's files.
|
|
208
|
+
|
|
95
209
|
Kumimoji is five things, each usable without the others: **the rules**, plain
|
|
96
210
|
functions over plain values; **the word lists**, loaded when first needed;
|
|
97
211
|
**a table** you mount into any element; **the same table as a tag**,
|
|
@@ -217,7 +331,7 @@ onBeforeUnmount(() => table?.destroy());
|
|
|
217
331
|
|
|
218
332
|
### 7. Angular
|
|
219
333
|
|
|
220
|
-
```
|
|
334
|
+
```ts no-check
|
|
221
335
|
import { Component, ElementRef, OnDestroy, afterNextRender, provideZonelessChangeDetection, signal, viewChild } from "@angular/core";
|
|
222
336
|
import { bootstrapApplication } from "@angular/platform-browser";
|
|
223
337
|
import { mountKumimoji, type KumimojiTableHandle } from "@johnmorrisdotca/kumimoji/ui";
|
|
@@ -268,156 +382,178 @@ fetches when a game is first dealt.
|
|
|
268
382
|
phone. The rules have no DOM in them and run in Node 22 and later, Deno,
|
|
269
383
|
Bun and web workers.
|
|
270
384
|
|
|
271
|
-
|
|
385
|
+
The cookbook, with the output of each example, is under [Examples](#examples).
|
|
272
386
|
|
|
273
|
-
|
|
274
|
-
every move returns the next one, and the same seed deals the same bag in every
|
|
275
|
-
browser. Word lists are loaded only when a game opens, and the table is its own
|
|
276
|
-
entry (`/ui` for plain DOM, `/element` for a tag, `/react` for React), so a page that wants only the
|
|
277
|
-
rules carries none of it. A computer player is pure too, so its turn replays
|
|
278
|
-
exactly after a reload.
|
|
387
|
+
## Examples
|
|
279
388
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
├── index.ts the main entry: the rules, the generator, the computer player and the table's pure helpers
|
|
294
|
-
├── judge.ts judging a grid against its language's word list, run by run
|
|
295
|
-
├── kana.ts Japanese tiles: the 45 base kana, and how every other kana is played as one of them
|
|
296
|
-
├── kumimoji.types.ts the game's types: how much of the set a bag holds, and the rest
|
|
297
|
-
├── party.ts pass and play: two to eight people round one device, one bag, a hand and a table each
|
|
298
|
-
├── party.types.ts what a pass-and-play game was set up as
|
|
299
|
-
├── partyKept.ts a pass-and-play game kept in the browser as one string of JSON
|
|
300
|
-
├── partySeats.ts people and computers joining and leaving a pass-and-play game between turns
|
|
301
|
-
├── partyTurns.ts how a pass-and-play turn ends, and how the game does, and who won
|
|
302
|
-
├── placement.ts where a word can cross a crossword without spoiling it
|
|
303
|
-
├── play.ts a game being played: the bag, the hand and the table, and every move on them
|
|
304
|
-
├── random.ts a seeded random, so one seed deals one game in every browser
|
|
305
|
-
├── react.tsx the "/react" entry: a grid to draw in React
|
|
306
|
-
├── showcase.ts what the rules page shows of the game, worked out from the game's own tables
|
|
307
|
-
├── strings.ts every word Kumimoji shows a person, in English and Japanese
|
|
308
|
-
├── tableView.ts how the table is looked at: which squares are shown, and how big a tile is drawn
|
|
309
|
-
├── tileFace.ts what a tile code shows, without loading a word list
|
|
310
|
-
├── tileFamily.ts which tile of the set a tile is, without loading a word list
|
|
311
|
-
├── tileWords.ts the word list, loaded once when a game opens
|
|
312
|
-
├── tileWordsModule.ts the same lists where there is no browser, imported only by a server or a test
|
|
313
|
-
├── tiles.constants.ts every number the game is played by: tile mixes, hand sizes, lengths of a game
|
|
314
|
-
├── turn.ts turning the table while every tile stays upright
|
|
315
|
-
├── ui.ts the "/ui" entry: Kumimoji played in the browser, in plain DOM
|
|
316
|
-
├── version.ts the version of this package, as package.json has it
|
|
317
|
-
├── wilds.ts a wild tile with no letter read as whatever makes the grid words
|
|
318
|
-
├── words.en.data.ts the English word list
|
|
319
|
-
├── words.ja.data.ts the Japanese word list and tile mix
|
|
320
|
-
├── words.ts the "/words" entry: the word lists, for a place with no browser, such as a server or a test
|
|
321
|
-
└── ui/ the table that draws and plays a game
|
|
322
|
-
├── board.ts how a tile on the table is drawn: sound, in a run that is not a word, or apart
|
|
323
|
-
├── mount.ts the table itself: mounting it on a page, the options it takes, and playing it from a keyboard
|
|
324
|
-
└── style.ts the table's own styles, every colour and size a CSS variable so a page can restyle it
|
|
389
|
+
Every TypeScript and JavaScript block that can run is type-checked against the built package and run by `pnpm test:readme`, so the output after `// →` is what the code prints. The word lists are read from the package's files in Node, so nothing here uses a network.
|
|
390
|
+
|
|
391
|
+
### A page with nothing else
|
|
392
|
+
|
|
393
|
+
Save this as a file and open it. The tag is the whole table: set-up, tiles, hand, clock, saving and loading.
|
|
394
|
+
|
|
395
|
+
```html
|
|
396
|
+
<!doctype html>
|
|
397
|
+
<meta charset="utf-8">
|
|
398
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
399
|
+
<title>A crossword race</title>
|
|
400
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@johnmorrisdotca/kumimoji@1/dist/element-define.js"></script>
|
|
401
|
+
<kumimoji-table language="english" hand="7" seed="daily"></kumimoji-table>
|
|
325
402
|
```
|
|
326
403
|
|
|
327
|
-
|
|
328
|
-
and checks the package as npm packs it, `demo/` is the page published on
|
|
329
|
-
GitHub Pages, and `table/` taps it in real browsers.
|
|
404
|
+
### Listen to the tag
|
|
330
405
|
|
|
331
|
-
|
|
406
|
+
The tag fires `kumimoji-change` after every change, with the game as it would be saved, and `kumimoji-finish` when the last tile is laid and every run is a word:
|
|
332
407
|
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
sense.
|
|
408
|
+
```html
|
|
409
|
+
<kumimoji-table id="game" language="japanese" hand="7" seed="2026"></kumimoji-table>
|
|
410
|
+
<p id="note"></p>
|
|
411
|
+
<script type="module">
|
|
412
|
+
import "https://cdn.jsdelivr.net/npm/@johnmorrisdotca/kumimoji@1/dist/element-define.js";
|
|
339
413
|
|
|
340
|
-
|
|
414
|
+
const game = document.getElementById("game");
|
|
415
|
+
game.addEventListener("kumimoji-change", (event) => {
|
|
416
|
+
localStorage.setItem("kumimoji", JSON.stringify(event.detail.saved));
|
|
417
|
+
});
|
|
418
|
+
game.addEventListener("kumimoji-finish", (event) => {
|
|
419
|
+
document.getElementById("note").textContent = `Done in ${Math.round(event.detail.elapsedMs / 1000)} seconds.`;
|
|
420
|
+
});
|
|
421
|
+
</script>
|
|
422
|
+
```
|
|
341
423
|
|
|
342
|
-
|
|
343
|
-
puzzles, card games and dice games played at your own pace. *Itsutsu* (五つ) is
|
|
344
|
-
Japanese for "five", after five in a row, the game the site began with. It is
|
|
345
|
-
[the Kumimoji played there](https://itsutsu.com/games/kumimoji): alone, in
|
|
346
|
-
races, round one device and across several.
|
|
424
|
+
### Deal the day's bag
|
|
347
425
|
|
|
348
|
-
|
|
426
|
+
`kumimojiDailySeed(date)` is the UTC date as a number, the same for everybody on earth, and the same number as Tane's `dailySeed`. Everybody who deals from it with the same settings gets the same bag in the same order:
|
|
349
427
|
|
|
350
|
-
|
|
351
|
-
|
|
428
|
+
```ts
|
|
429
|
+
import "@johnmorrisdotca/kumimoji/words";
|
|
430
|
+
import { generateKumimoji, kumimojiDay, kumimojiDailySeed, loadTileWords } from "@johnmorrisdotca/kumimoji";
|
|
352
431
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
432
|
+
await loadTileWords("english");
|
|
433
|
+
const now = new Date("2026-10-06T10:00:00Z");
|
|
434
|
+
kumimojiDay(now); // → "2026-10-06"
|
|
435
|
+
kumimojiDailySeed(now); // → 20261006
|
|
436
|
+
const dealt = generateKumimoji(7, "medium", kumimojiDailySeed(now));
|
|
437
|
+
dealt.givens.length; // → 40
|
|
438
|
+
dealt.givens.slice(0, 10); // → "ltlekac*rm"
|
|
439
|
+
```
|
|
356
440
|
|
|
357
|
-
|
|
441
|
+
The `*` is a wild tile, which takes any letter. The bag is one character a tile, in the order the tiles come out.
|
|
358
442
|
|
|
359
|
-
|
|
360
|
-
Kumimoji is one of twenty-four packages, each made for the same site, each at
|
|
361
|
-
[github.com/johnmorrisdotca](https://github.com/johnmorrisdotca). The code of every one is MIT.
|
|
443
|
+
### Judge a grid
|
|
362
444
|
|
|
363
|
-
|
|
364
|
-
- [Kyuubu](https://github.com/johnmorrisdotca/kyuubu) (キューブ): a turning cube for the browser, 2×2 to 7×7, with record solves to replay. [Demo](https://johnmorrisdotca.github.io/kyuubu/).
|
|
365
|
-
- [Hitotsu](https://github.com/johnmorrisdotca/hitotsu) (一つ): a colour-card shedding game for two to eight, with the house rules people play. [Demo](https://johnmorrisdotca.github.io/hitotsu/).
|
|
366
|
-
- [Toranpu](https://github.com/johnmorrisdotca/toranpu) (トランプ): a deck of playing cards, card games with computer players, and solitaires. [Demo](https://johnmorrisdotca.github.io/toranpu/).
|
|
367
|
-
- [Tane](https://github.com/johnmorrisdotca/tane) (種): seeded random numbers and daily seeds, the same in every browser and on every server. [Demo](https://johnmorrisdotca.github.io/tane/).
|
|
368
|
-
- [Narabe](https://github.com/johnmorrisdotca/narabe) (並べ): one rules engine for abstract board games, from gomoku and Reversi to Go and checkers. [Demo](https://johnmorrisdotca.github.io/narabe/).
|
|
369
|
-
- [Tenka](https://github.com/johnmorrisdotca/tenka) (天下): world conquest for two to six, on a map of the real world. [Demo](https://johnmorrisdotca.github.io/tenka/).
|
|
370
|
-
- [Kumimoji](https://github.com/johnmorrisdotca/kumimoji) (組み文字): a crossword tile race, in English and Japanese kana. [Demo](https://johnmorrisdotca.github.io/kumimoji/).
|
|
371
|
-
- [Tsunagi](https://github.com/johnmorrisdotca/tsunagi) (繋ぎ): a line-joining logic puzzle whose every level has exactly one answer. [Demo](https://johnmorrisdotca.github.io/tsunagi/).
|
|
372
|
-
- [Jarajara](https://github.com/johnmorrisdotca/jarajara) (ジャラジャラ): mahjong tiles drawn as SVG, stacked layouts, and the matching solitaire Awase. [Demo](https://johnmorrisdotca.github.io/jarajara/).
|
|
373
|
-
- [Suido](https://github.com/johnmorrisdotca/suido) (水道): a pipe puzzle: turn the pieces until the water reaches every drain. [Demo](https://johnmorrisdotca.github.io/suido/).
|
|
374
|
-
- [Domino](https://github.com/johnmorrisdotca/domino) (ドミノ): dominoes and Mexican Train. [Demo](https://johnmorrisdotca.github.io/domino/).
|
|
375
|
-
- [Kotoba](https://github.com/johnmorrisdotca/kotoba) (言葉): word lists and word-game rules in English, French, German and Japanese. [Demo](https://johnmorrisdotca.github.io/kotoba/).
|
|
376
|
-
- [Sugoroku](https://github.com/johnmorrisdotca/sugoroku) (双六): backgammon and its variants, with the doubling cube and match play. [Demo](https://johnmorrisdotca.github.io/sugoroku/).
|
|
377
|
-
- [Kazu](https://github.com/johnmorrisdotca/kazu) (数): grid number puzzles: Sudoku and its variants, Futoshiki and Skyscrapers. [Demo](https://johnmorrisdotca.github.io/kazu/).
|
|
378
|
-
- [Meikyuu](https://github.com/johnmorrisdotca/meikyuu) (迷宮): mazes on squares, hexagons, triangles and circles, made from a seed and drawn through with a finger or the mouse. [Demo](https://johnmorrisdotca.github.io/meikyuu/).
|
|
379
|
-
- [Hikidashi](https://github.com/johnmorrisdotca/hikidashi) (引き出し): a drawer of small Japanese text tools: era dates, kanji numerals, readings and sentence difficulty. [Demo](https://johnmorrisdotca.github.io/hikidashi/).
|
|
380
|
-
- [Chizu](https://github.com/johnmorrisdotca/chizu) (地図): maps of the world and of countries' regions, in English and Japanese, with a quiz and callouts. [Demo](https://johnmorrisdotca.github.io/chizu/).
|
|
381
|
-
- [Bushu](https://github.com/johnmorrisdotca/bushu) (部首): find a kanji by the parts it is made of. [Demo](https://johnmorrisdotca.github.io/bushu/).
|
|
382
|
-
- [Tobiishi](https://github.com/johnmorrisdotca/tobiishi) (飛び石): peg solitaire with nine boards and seeded solvable challenges. [Demo](https://johnmorrisdotca.github.io/tobiishi/).
|
|
383
|
-
- [Jirai](https://github.com/johnmorrisdotca/jirai) (地雷): minesweeper on shaped grids with verified no-guess boards. [Demo](https://johnmorrisdotca.github.io/jirai/).
|
|
384
|
-
- [Gunjin](https://github.com/johnmorrisdotca/gunjin) (軍人): five hidden-rank strategy games with pass-the-device play. [Demo](https://johnmorrisdotca.github.io/gunjin/).
|
|
385
|
-
- [Karakuri](https://github.com/johnmorrisdotca/karakuri) (からくり): eight hyper-casual puzzle games, some of them physics: draw a shield, pull pins, cut ropes, slide blocks, pour tubes. [Demo](https://johnmorrisdotca.github.io/karakuri/).
|
|
386
|
-
- [Houseki](https://github.com/johnmorrisdotca/houseki) (宝石): gem and stone matching puzzles: falling triplets, stone collapse, colour chains and gem swap. [Demo](https://johnmorrisdotca.github.io/houseki/).
|
|
445
|
+
`judgeWithWords(tiles, words)` says what is wrong with a grid: the tiles in runs that are not words, and the tiles standing apart from the crossword. A table draws the first as a red ring and fades the second:
|
|
387
446
|
|
|
388
|
-
|
|
389
|
-
|
|
447
|
+
```ts
|
|
448
|
+
import "@johnmorrisdotca/kumimoji/words";
|
|
449
|
+
import { decodeGrid, judgeWithWords, loadTileWords, squareAt } from "@johnmorrisdotca/kumimoji";
|
|
390
450
|
|
|
391
|
-
|
|
451
|
+
const words = await loadTileWords("english");
|
|
452
|
+
const crossword = decodeGrid("cat/2o/2w")!;
|
|
453
|
+
judgeWithWords(crossword, words).sound; // → true
|
|
454
|
+
|
|
455
|
+
const scattered = new Map(crossword);
|
|
456
|
+
scattered.set(squareAt(4, 4), "x"); // a tile that touches nothing
|
|
457
|
+
const verdict = judgeWithWords(scattered, words);
|
|
458
|
+
verdict.sound; // → false
|
|
459
|
+
[...verdict.apart]; // → ["4,4"]
|
|
460
|
+
```
|
|
392
461
|
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
462
|
+
### What the computer player would lay
|
|
463
|
+
|
|
464
|
+
`bestLaying(play, words)` finds the word the computer player lays from a hand and a table, with no randomness, so a turn replays exactly after a reload:
|
|
465
|
+
|
|
466
|
+
```ts
|
|
467
|
+
import "@johnmorrisdotca/kumimoji/words";
|
|
468
|
+
import { bestLaying, deal, generateKumimoji, loadTileWords, wordsInHand } from "@johnmorrisdotca/kumimoji";
|
|
469
|
+
|
|
470
|
+
const words = await loadTileWords("english");
|
|
471
|
+
const play = deal(generateKumimoji(7, "hard", 2026).givens, 7);
|
|
472
|
+
play.hand.join(""); // → "xbsnnny"
|
|
473
|
+
bestLaying(play, words)?.word; // → "by"
|
|
474
|
+
wordsInHand(play.hand, words); // → ["by"]
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
`wordsInHand` is the same list a player is offered as help when the game was set up with it.
|
|
478
|
+
|
|
479
|
+
### A computer's turn, step by step
|
|
480
|
+
|
|
481
|
+
`planComputerTurn(game, words)` lists a computer seat's whole turn as steps, in order, for a page to show one at a time; `afterComputerTurn` is the game after all of them:
|
|
482
|
+
|
|
483
|
+
```ts
|
|
484
|
+
import "@johnmorrisdotca/kumimoji/words";
|
|
485
|
+
import { afterComputerTurn, endTurn, generateKumimoji, handCanSpell, judgeWithWords, loadTileWords, nameOf, planComputerTurn, seatPlay, startParty } from "@johnmorrisdotca/kumimoji";
|
|
486
|
+
|
|
487
|
+
const words = await loadTileWords("english");
|
|
488
|
+
const settings = { size: 7, level: "hard", seed: 2026, gameLength: "short", language: "english", doubleSet: false, diagonals: false, hints: false } as const;
|
|
489
|
+
let game = startParty(settings, generateKumimoji(7, "hard", 2026).givens, ["Ann", { name: "Computer", computer: true }]);
|
|
490
|
+
game = endTurn(game, judgeWithWords(seatPlay(game).tiles, words), (hand) => handCanSpell(hand, words)); // Ann passes
|
|
491
|
+
nameOf(game, game.turn); // → "Computer 1"
|
|
492
|
+
|
|
493
|
+
const steps = planComputerTurn(game, words);
|
|
494
|
+
steps.map(({ said }) => (said.kind === "laid" ? `laid ${said.word}` : said.kind)); // → ["laid enamor", "traded", "laid cate", "drew", "done"]
|
|
495
|
+
nameOf(afterComputerTurn(game, words), 0); // → "Ann"
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
### Points for a finished game
|
|
499
|
+
|
|
500
|
+
A finished game scores 10 a tile, and up to as much again for speed (this one is 770 points at a minute and a half, and 500 at fifteen minutes, when no speed bonus is left). A server that has checked a grid can award the same points the table shows:
|
|
501
|
+
|
|
502
|
+
```ts
|
|
503
|
+
import "@johnmorrisdotca/kumimoji/words";
|
|
504
|
+
import { generateKumimoji, kumimojiPoints, loadTileWords } from "@johnmorrisdotca/kumimoji";
|
|
505
|
+
|
|
506
|
+
await loadTileWords("english");
|
|
507
|
+
const dealt = generateKumimoji(7, "hard", 2026);
|
|
508
|
+
kumimojiPoints(dealt.givens, 90_000); // → 770
|
|
509
|
+
kumimojiPoints(dealt.givens, 900_000); // → 500
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
### Check a race on a server
|
|
513
|
+
|
|
514
|
+
Players racing a seed are dealt the same bag, so a server that is handed only the seed and a finished grid checks the whole game in time proportional to the grid, with no search:
|
|
515
|
+
|
|
516
|
+
```ts
|
|
517
|
+
import "@johnmorrisdotca/kumimoji/words";
|
|
518
|
+
import { checkKumimoji, generateKumimoji, loadTileWords } from "@johnmorrisdotca/kumimoji";
|
|
519
|
+
|
|
520
|
+
await loadTileWords("english");
|
|
521
|
+
const dealt = generateKumimoji(3, "hard", 44);
|
|
522
|
+
checkKumimoji(3, dealt.givens, "snowy", { level: "hard" }); // → { ok: true }
|
|
523
|
+
checkKumimoji(3, dealt.givens, "snows", { level: "hard" }); // → { ok: false, reason: "the grid does not use exactly the tiles of the bag" }
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
### Mount the table with options
|
|
527
|
+
|
|
528
|
+
`mountKumimoji` plays a whole game alone in one element, and hands back the game as plain data after each change:
|
|
529
|
+
|
|
530
|
+
```ts no-run
|
|
531
|
+
import { mountKumimoji } from "@johnmorrisdotca/kumimoji/ui";
|
|
532
|
+
|
|
533
|
+
const table = mountKumimoji(document.getElementById("table")!, {
|
|
534
|
+
language: "japanese",
|
|
535
|
+
hand: 11,
|
|
536
|
+
level: "easy", // the most wild tiles
|
|
537
|
+
gameLength: "medium", // half the set
|
|
538
|
+
seed: 2026,
|
|
539
|
+
locale: "ja", // the table's own words
|
|
540
|
+
onFinish: (result) => console.log("done", result),
|
|
541
|
+
});
|
|
542
|
+
await table.newGame({ language: "english", hand: 7 }); // another game, on the same table
|
|
543
|
+
table.destroy();
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
### A look of your own
|
|
547
|
+
|
|
548
|
+
Every colour is a CSS variable on `.km-root`, so a stylesheet or the `theme` option can restyle the table:
|
|
549
|
+
|
|
550
|
+
```ts no-run
|
|
551
|
+
import { mountKumimoji } from "@johnmorrisdotca/kumimoji/ui";
|
|
552
|
+
|
|
553
|
+
mountKumimoji(document.getElementById("table")!, {
|
|
554
|
+
theme: { "--km-felt": "#23405a", "--km-tile": "#fffdf7", "--km-wild": "#d4a017", "--km-square": "40px" },
|
|
555
|
+
});
|
|
556
|
+
```
|
|
421
557
|
|
|
422
558
|
## How to play
|
|
423
559
|
|
|
@@ -611,7 +747,7 @@ The JSON, as `kumimojiToJSON` writes it:
|
|
|
611
747
|
{
|
|
612
748
|
"format": 1,
|
|
613
749
|
"game": "kumimoji",
|
|
614
|
-
"generator": "kumimoji 1.2.
|
|
750
|
+
"generator": "kumimoji 1.2.2",
|
|
615
751
|
"size": 3,
|
|
616
752
|
"level": "hard",
|
|
617
753
|
"seed": 44,
|
|
@@ -721,76 +857,22 @@ as you type. The entries:
|
|
|
721
857
|
| `@johnmorrisdotca/kumimoji/element/define` | Defines `<kumimoji-table>` on the page by being imported; exports nothing |
|
|
722
858
|
| `@johnmorrisdotca/kumimoji/react` | `KumimojiBoard` and `KumimojiTable` |
|
|
723
859
|
|
|
724
|
-
###
|
|
860
|
+
### The calls to learn first
|
|
725
861
|
|
|
726
|
-
|
|
|
862
|
+
| Call | What it does |
|
|
727
863
|
| --- | --- |
|
|
728
864
|
| `generateKumimoji(hand, level, seed, options?)` | A game dealt from a seed: the bag, and one grid that finishes it |
|
|
729
|
-
| `
|
|
730
|
-
| `
|
|
731
|
-
| `
|
|
732
|
-
| `checkKumimoji(size, givens, answer, options?)` |
|
|
733
|
-
| `
|
|
734
|
-
| `
|
|
735
|
-
| `
|
|
736
|
-
| `crossingFit`, `diagonalsRead` | Where a word may be laid crossing a tile, and the diagonal runs a new tile would make, for a generator or a computer player |
|
|
737
|
-
| `seededRandom(seed)`, `shuffled(items, random)` | The seeded random a deal is drawn from |
|
|
738
|
-
|
|
739
|
-
### Tiles and grids
|
|
740
|
-
|
|
741
|
-
| Export | What it does |
|
|
742
|
-
| --- | --- |
|
|
743
|
-
| `squareAt(row, col)`, `placeOf(square)` | A square's key, and back |
|
|
744
|
-
| `encodeGrid(tiles)`, `decodeGrid(code)`, `boundsOf(tiles)` | A grid as a string, and back; the rows and columns it stands within |
|
|
745
|
-
| `lettersOf(letters)`, `sameLetters(a, b)` | How many of each tile, and whether two tallies match |
|
|
746
|
-
| `tileFace(tile)`, `tileDescription(tile)`, `kanaTileCode(kana, wild?)` | What a tile shows; what a screen reader says; a kana's tile |
|
|
747
|
-
| `tileKana(kana)`, `BASE_KANA`, `CORNER_FORMS`, `formsOfTile(kana)` | The tile a kana is played with, the 45 tiles, and the forms each plays as |
|
|
748
|
-
| `familyKeyOf(language)` | Which tile of the set a code is, without the word list |
|
|
749
|
-
| `loadTileWords`, `tileWords`, `tileWordsReady` | The word list: fetched, handed back, asked after |
|
|
750
|
-
| `unpackTileWords`, `unpackLength`, `tileWordsFrom`, `readTileWordsWith` | How a list is read from its packed data, for the loader |
|
|
751
|
-
| `mixShown(language)`, `lengthRows(hand?)`, `LENGTHS`, `TRY_IT` | A set and the lengths of game as a page shows them |
|
|
752
|
-
|
|
753
|
-
### Playing, and a game kept
|
|
865
|
+
| `deal(bag, handSize)` and `placeFromHand`, `moveOnTable`, `liftToHand`, `draw`, `trade` | The opening hand, and each move, every one returning a new game |
|
|
866
|
+
| `judgeWithWords(tiles, words)` | What is wrong with a grid, or that it is sound |
|
|
867
|
+
| `isFinished(play, verdict)` | Whether the bag is empty, the hand used and every run a word in one piece |
|
|
868
|
+
| `checkKumimoji(size, givens, answer, options?)` | The one check a server runs on a finished grid |
|
|
869
|
+
| `loadTileWords(language)` | A word list, fetched when first needed |
|
|
870
|
+
| `mountKumimoji(element, options?)` and `<kumimoji-table>` | The table, in one call or one tag |
|
|
871
|
+
| `kumimojiToJSON`, `kumimojiFromJSON` | A game kept, and read back without trusting it |
|
|
754
872
|
|
|
755
|
-
The
|
|
873
|
+
### The long tables
|
|
756
874
|
|
|
757
|
-
|
|
758
|
-
| --- | --- |
|
|
759
|
-
| `tilesLeft(play)` | How many tiles are still in the bag |
|
|
760
|
-
| `encodeTileProgress(play)`, `readTileProgress(code)`, `decodeTileProgress(code, bag, language?)` | A game half way as one string; its shape read; and opened again on its own bag |
|
|
761
|
-
| `kumimojiToJSON(saved)`, `kumimojiFromJSON(text)`, `kumimojiExported(saved)` | A game as JSON, and back, or `null` |
|
|
762
|
-
| `kumimojiToText(saved, strings?)`, `gridToText(tiles, language?)`, `kumimojiClock(ms)` | A game, a grid and a time as text |
|
|
763
|
-
| `KUMIMOJI_EXPORT_FORMAT`, `KUMIMOJI_VERSION` | The JSON's format number, and this package's version |
|
|
764
|
-
| `KUMIMOJI_STRINGS`, `kumimojiStrings(locale, own?)`, `kumimojiSay(line, values)` | The table's words in English and Japanese |
|
|
765
|
-
|
|
766
|
-
### A table of players
|
|
767
|
-
|
|
768
|
-
| Export | What it does |
|
|
769
|
-
| --- | --- |
|
|
770
|
-
| `startParty(settings, bag, seats)` | A table dealt: two to eight seats, each a name or `{ name, computer }` |
|
|
771
|
-
| `seatPlay(game)`, `withSeatPlay(game, play)` | The player to move's hand and table as a `TilePlay`, and the game with it put back |
|
|
772
|
-
| `endTurn(game, verdict, handSpells)`, `doneRefused(…)` | End the turn; why Done is refused, if it is |
|
|
773
|
-
| `drawAll(game)`, `mayDrawAll(game, verdict)` | Everyone draws together |
|
|
774
|
-
| `resign(game)`, `mayResign(game)` | Give up the game |
|
|
775
|
-
| `joinParty(game, seat)`, `joinRefused(game)`, `leaveParty(game, at)`, `leaveRefused(game, at)` | Joining and leaving a game under way |
|
|
776
|
-
| `isOver(game)`, `winnersOf(game)`, `goesOut(game, verdict)`, `isLastTurn(game)`, `lastStanding(game)` | How the game stands and ends |
|
|
777
|
-
| `mayTradeThisTurn(game)`, `mustTradeFirst(game, handSpells)`, `laidThisTurn(game)`, `handCanSpell(hand, words)` | What this turn may and must do |
|
|
778
|
-
| `nameOf(game, at)`, `tidyName(name)`, `computerName(players)`, `isComputer(game, at)` | Names, and whether a seat is a computer's |
|
|
779
|
-
| `stillIn(game)`, `nextIn(game, from)`, `partyTilesLeft(game)`, `tilesHeldBy(game, at)`, `tableTally(tiles)` | Who is in, whose turn is next, and the tiles |
|
|
780
|
-
| `partyTilesNeeded`, `partyFits`, `partyLength`, `partyPlayersAsked` | Whether a bag is big enough for a table, for a set-up screen |
|
|
781
|
-
| `passViewStart(game)`, `stepView(game, from, by)` | Whose table a shared screen shows |
|
|
782
|
-
| `encodeParty(game)`, `decodeParty(code, familyKey?)`, `readSettings(value)`, `holdsItsBag(game, familyKey)`, `isPartyFor` | A table kept as text, read back and checked, and matched to the set-up it was dealt for |
|
|
783
|
-
| `afterComputerTurn(game, words)`, `planComputerTurn(game, words)`, `COMPUTER_STEPS_MOST` | A computer seat's turn, whole or step by step |
|
|
784
|
-
| `bestLaying(play, words, rules?)`, `tradeChoice(hand, words)`, `judgeTiles(tiles, words, rules?)` | What the computer would lay, and trade |
|
|
785
|
-
|
|
786
|
-
### Looking at the table
|
|
787
|
-
|
|
788
|
-
A table with no edges is looked at through a view, which the package keeps
|
|
789
|
-
apart from the game: `tableArea`, `fitView`, `fittedMost`, `zoomView`,
|
|
790
|
-
`panView`, `keepInReach`, `overflows`, `squareUnder`, `edgePan` and the
|
|
791
|
-
numbers in `TABLE`. A player may turn the table a quarter at a time with every
|
|
792
|
-
tile kept upright: `nextTurn`, `turnPlace`, `unturnPlace`, `turnArea`,
|
|
793
|
-
`turnView`, `typingWay` and `arrowStep`.
|
|
875
|
+
The tables of every export for dealing and judging, tiles and grids, playing and keeping a game, a table of players and looking at the table are in [docs/API.md](docs/API.md), and every export of every entry point, with its signature and doc comment, is in the [API reference](https://johnmorrisdotca.github.io/kumimoji/api.html). The types the package exports are listed there too.
|
|
794
876
|
|
|
795
877
|
The types are `TilePlay`, `Tiles`, `GridVerdict`, `GridRules`, `Run`,
|
|
796
878
|
`RunLine`, `Bounds`, `Square`, `CrossingFit`, `KumimojiDeal`,
|
|
@@ -803,65 +885,11 @@ The types are `TilePlay`, `Tiles`, `GridVerdict`, `GridRules`, `Run`,
|
|
|
803
885
|
|
|
804
886
|
### The table
|
|
805
887
|
|
|
806
|
-
`mountKumimoji(element, options?)` from `@johnmorrisdotca/kumimoji/ui` deals
|
|
807
|
-
and plays a whole game alone in the element, and returns a handle.
|
|
808
|
-
|
|
809
|
-
| Option | Default | What it does |
|
|
810
|
-
| --- | --- | --- |
|
|
811
|
-
| `language` | `"english"` | The language of the tiles: `"english"` or `"japanese"` |
|
|
812
|
-
| `hand` | `7` | The opening hand: 3, 7 or 11 tiles |
|
|
813
|
-
| `level` | `"medium"` | Wild tiles: `"easy"` the most, `"medium"` some, `"hard"` none |
|
|
814
|
-
| `gameLength` | `"short"` | `"short"`, `"medium"`, or `"full"`, all 144 tiles |
|
|
815
|
-
| `diagonals` | `false` | Every diagonal run of three or more must be a word too |
|
|
816
|
-
| `seed` | a new one each game | The seed the bag is dealt from |
|
|
817
|
-
| `onFinish` | | Called when the last tile is laid and every run is a word, with the time it took |
|
|
818
|
-
| `onChange` | | Called after every change, with the game as it would be saved |
|
|
819
|
-
| `locale` | the page's `lang` | The language of the table's words: `"en"` or `"ja"` |
|
|
820
|
-
| `strings` | | Words of your own, laid over the locale's |
|
|
821
|
-
| `theme` | | CSS variables set on the table itself |
|
|
822
|
-
| `keep` | `true` | Whether the table offers saving and loading |
|
|
823
|
-
|
|
824
|
-
| Handle | What it does |
|
|
825
|
-
| --- | --- |
|
|
826
|
-
| `play()` | The game as it stands, or `null` while it is being dealt |
|
|
827
|
-
| `saved()` | The game as it would be saved, or `null` while it is being dealt |
|
|
828
|
-
| `newGame(options?)` | A new game; any of the first six options may change |
|
|
829
|
-
| `setGame(saved)` | Put a game on the table: one read back by `kumimojiFromJSON` |
|
|
830
|
-
| `setLocale(locale, strings?)` | Change the language of the table's words |
|
|
831
|
-
| `destroy()` | Take the table off the page and stop its clock |
|
|
832
|
-
|
|
833
|
-
To play it: tap a tile in your hand and then a square to lay it; tap a tile on
|
|
834
|
-
the table and then a square to move it, or tap it again to take it back. A
|
|
835
|
-
wild is given its letter before it is laid. To draw a board yourself, the same
|
|
836
|
-
entry has `boardModel(tiles, verdict, glyphOf?)`, which works out the squares
|
|
837
|
-
to draw and how each tile stands, with `BOARD_MARGIN` and `BOARD_LEAST`, and
|
|
838
|
-
`KUMIMOJI_STYLE`, the table's stylesheet as a string.
|
|
888
|
+
`mountKumimoji(element, options?)` from `@johnmorrisdotca/kumimoji/ui` deals and plays a whole game alone in the element and returns a handle (`play()`, `saved()`, `newGame(options?)`, `setGame(saved)`, `setLocale(locale, strings?)`, `destroy()`). Its options are `language`, `hand`, `level`, `gameLength`, `diagonals`, `seed`, `onFinish`, `onChange`, `locale`, `strings`, `theme` and `keep`; each, with its default, is in [docs/API.md](docs/API.md#the-table).
|
|
839
889
|
|
|
840
890
|
### The element
|
|
841
891
|
|
|
842
|
-
`<kumimoji-table>` is `mountKumimoji` as a tag: `@johnmorrisdotca/kumimoji/element/define`
|
|
843
|
-
defines it, and `@johnmorrisdotca/kumimoji/element` holds the class alone. Each
|
|
844
|
-
attribute is read again when it changes, and a change to any but `lang` deals a
|
|
845
|
-
new game. A table the rules do not offer (a hand of 5, say) draws nothing.
|
|
846
|
-
|
|
847
|
-
| Attribute | Default | What it does |
|
|
848
|
-
| --- | --- | --- |
|
|
849
|
-
| `language` | `english` | The tiles: `english` or `japanese` kana |
|
|
850
|
-
| `hand` | `7` | The opening hand: 3, 7 or 11 |
|
|
851
|
-
| `level` | `medium` | Wild tiles: `easy` the most, `medium` some, `hard` none |
|
|
852
|
-
| `length` | `short` | `short`, `medium` or `full`, all 144 tiles |
|
|
853
|
-
| `diagonals` | off | `on` to read every diagonal run of three or more too |
|
|
854
|
-
| `seed` | a new one each game | A whole number to deal from, or `daily` for the day's seed |
|
|
855
|
-
| `lang` | the page's | The language of the table's words: `en` or `ja` |
|
|
856
|
-
| `keep` | on | `off` leaves saving and loading out |
|
|
857
|
-
|
|
858
|
-
It fires `kumimoji-change` after every change to the game, with the game as it
|
|
859
|
-
would be saved as `event.detail.saved`, and `kumimoji-finish` when the last
|
|
860
|
-
tile is laid and every run is a word, with the deal, the play and the time it
|
|
861
|
-
took as `event.detail`; both bubble. It has `saved` (the game as it would be
|
|
862
|
-
saved), `table` (the handle `mountKumimoji` returns), `newGame(options?)` and
|
|
863
|
-
`setGame(saved)`. To style it, set the table's variables on `kumimoji-table
|
|
864
|
-
.km-root`: see [Theming](#theming).
|
|
892
|
+
`<kumimoji-table>` is `mountKumimoji` as a tag: `@johnmorrisdotca/kumimoji/element/define` defines it. Its attributes are `language`, `hand`, `level`, `length`, `diagonals`, `seed` (a number, or `daily`), `lang` and `keep`; it fires `kumimoji-change` and `kumimoji-finish`, which bubble. Every attribute, event and property is in [docs/API.md](docs/API.md#the-element).
|
|
865
893
|
|
|
866
894
|
### The React components
|
|
867
895
|
|
|
@@ -900,26 +928,6 @@ export function Board() {
|
|
|
900
928
|
else for its `<div>`. Options are read when it mounts; give it a new `key` to
|
|
901
929
|
start over with different ones.
|
|
902
930
|
|
|
903
|
-
## Accessibility
|
|
904
|
-
|
|
905
|
-
- **A keyboard plays it.** Every square and every tile in the hand is a button
|
|
906
|
-
with a name. Tab lands on one square of the table and on one tile of the
|
|
907
|
-
hand, the arrow keys move between squares (and Left, Right, Home and End
|
|
908
|
-
between the hand's tiles), Enter or Space picks a tile up and lays it, and
|
|
909
|
-
Escape lets go of a tile you have picked up. The keyboard stays where it was
|
|
910
|
-
after each move, including on the buttons under the table, and the table's
|
|
911
|
-
description says so.
|
|
912
|
-
- **What is happening is said.** The line above the table, with the tiles left
|
|
913
|
-
and the time, and the line saying which runs are not words, are polite live
|
|
914
|
-
regions, and so is the note after saving or loading.
|
|
915
|
-
- **Targets are big enough.** Every button is at least 44 pixels each way,
|
|
916
|
-
which a test holds at a phone's width.
|
|
917
|
-
- **Not by colour alone.** A run that is not a word is ringed and listed in
|
|
918
|
-
words; a tile apart from the crossword is faded and said so.
|
|
919
|
-
- **Motion.** There is none to reduce: the table has no animation.
|
|
920
|
-
- **Not yet.** Letters cannot be typed to lay a tile, and a screen reader hears
|
|
921
|
-
the table as a grid of squares, not as the words they make.
|
|
922
|
-
|
|
923
931
|
## Theming
|
|
924
932
|
|
|
925
933
|
Every colour is a CSS variable on `.km-root`. Set them in your stylesheet on
|
|
@@ -945,7 +953,7 @@ on the table itself and so wins in light and dark alike.
|
|
|
945
953
|
|
|
946
954
|
A slate table with ivory tiles, a little smaller:
|
|
947
955
|
|
|
948
|
-
```js
|
|
956
|
+
```js no-run
|
|
949
957
|
import { mountKumimoji } from "@johnmorrisdotca/kumimoji/ui";
|
|
950
958
|
|
|
951
959
|
mountKumimoji(document.getElementById("table"), {
|
|
@@ -956,6 +964,47 @@ mountKumimoji(document.getElementById("table"), {
|
|
|
956
964
|
`KumimojiBoard` draws with colours of its own; style it through its `style`
|
|
957
965
|
and `className`.
|
|
958
966
|
|
|
967
|
+
## Limits
|
|
968
|
+
|
|
969
|
+
| Limit | Value | Constant |
|
|
970
|
+
| --- | --- | --- |
|
|
971
|
+
| Opening hand | 3, 7 or 11 | `KUMIMOJI_HANDS` |
|
|
972
|
+
| A word | 2 to 15 tiles | |
|
|
973
|
+
| A finished grid, either way | 60 squares | `KUMIMOJI_GRID_MOST` |
|
|
974
|
+
| Players at a table | 2 to 8 | `KUMIMOJI_PARTY` |
|
|
975
|
+
| A player's name | 20 characters | `KUMIMOJI_PARTY` |
|
|
976
|
+
| Words one hand is offered as help | 40 | `HELP_WORDS_MOST` |
|
|
977
|
+
| A seed | a whole number from 0 to 4,294,967,295 | |
|
|
978
|
+
| Two sets at once | English only | |
|
|
979
|
+
|
|
980
|
+
## Accessibility
|
|
981
|
+
|
|
982
|
+
- **A keyboard plays it.** Every square and every tile in the hand is a button
|
|
983
|
+
with a name. Tab lands on one square of the table and on one tile of the
|
|
984
|
+
hand, the arrow keys move between squares (and Left, Right, Home and End
|
|
985
|
+
between the hand's tiles), Enter or Space picks a tile up and lays it, and
|
|
986
|
+
Escape lets go of a tile you have picked up. The keyboard stays where it was
|
|
987
|
+
after each move, including on the buttons under the table, and the table's
|
|
988
|
+
description says so.
|
|
989
|
+
- **What is happening is said.** The line above the table, with the tiles left
|
|
990
|
+
and the time, and the line saying which runs are not words, are polite live
|
|
991
|
+
regions, and so is the note after saving or loading.
|
|
992
|
+
- **Targets are big enough.** Every button is at least 44 pixels each way,
|
|
993
|
+
which a test holds at a phone's width.
|
|
994
|
+
- **Not by colour alone.** A run that is not a word is ringed and listed in
|
|
995
|
+
words; a tile apart from the crossword is faded and said so.
|
|
996
|
+
- **Motion.** There is none to reduce: the table has no animation.
|
|
997
|
+
- **Not yet.** Letters cannot be typed to lay a tile, and a screen reader hears
|
|
998
|
+
the table as a grid of squares, not as the words they make.
|
|
999
|
+
|
|
1000
|
+
## Browser support
|
|
1001
|
+
|
|
1002
|
+
Any current browser: Chrome, Edge, Firefox and Safari, on a desk or a phone.
|
|
1003
|
+
It needs ES2020 and dynamic `import()`. The table is tested in Chromium and in
|
|
1004
|
+
WebKit, Safari's engine, at phone size with touch and on a desktop. The rules
|
|
1005
|
+
run in Node 22 and later, Deno, Bun and web workers, and load by `import` and
|
|
1006
|
+
by `require()`.
|
|
1007
|
+
|
|
959
1008
|
## Languages
|
|
960
1009
|
|
|
961
1010
|
Two things here have a language, and they are chosen apart. **The tiles** are
|
|
@@ -981,27 +1030,6 @@ kumimojiStrings("en", { draw: "Robar" }).draw; // → "Robar"
|
|
|
981
1030
|
A new language for the tiles is another matter: it needs a real dictionary of
|
|
982
1031
|
that language, whose licence lets its words be shipped.
|
|
983
1032
|
|
|
984
|
-
## Limits
|
|
985
|
-
|
|
986
|
-
| Limit | Value | Constant |
|
|
987
|
-
| --- | --- | --- |
|
|
988
|
-
| Opening hand | 3, 7 or 11 | `KUMIMOJI_HANDS` |
|
|
989
|
-
| A word | 2 to 15 tiles | |
|
|
990
|
-
| A finished grid, either way | 60 squares | `KUMIMOJI_GRID_MOST` |
|
|
991
|
-
| Players at a table | 2 to 8 | `KUMIMOJI_PARTY` |
|
|
992
|
-
| A player's name | 20 characters | `KUMIMOJI_PARTY` |
|
|
993
|
-
| Words one hand is offered as help | 40 | `HELP_WORDS_MOST` |
|
|
994
|
-
| A seed | a whole number from 0 to 4,294,967,295 | |
|
|
995
|
-
| Two sets at once | English only | |
|
|
996
|
-
|
|
997
|
-
## Browser support
|
|
998
|
-
|
|
999
|
-
Any current browser: Chrome, Edge, Firefox and Safari, on a desk or a phone.
|
|
1000
|
-
It needs ES2020 and dynamic `import()`. The table is tested in Chromium and in
|
|
1001
|
-
WebKit, Safari's engine, at phone size with touch and on a desktop. The rules
|
|
1002
|
-
run in Node 22 and later, Deno, Bun and web workers, and load by `import` and
|
|
1003
|
-
by `require()`.
|
|
1004
|
-
|
|
1005
1033
|
## The command line
|
|
1006
1034
|
|
|
1007
1035
|
There is none, on purpose. Checking a word or seeing a deal is a few lines of
|
|
@@ -1034,24 +1062,106 @@ runs from a static page and costs nothing to host.
|
|
|
1034
1062
|
|
|
1035
1063
|
Ideas and pull requests are welcome.
|
|
1036
1064
|
|
|
1037
|
-
##
|
|
1065
|
+
## Architecture
|
|
1066
|
+
|
|
1067
|
+
The rules are plain functions over plain data with no DOM: a game is a value,
|
|
1068
|
+
every move returns the next one, and the same seed deals the same bag in every
|
|
1069
|
+
browser. Word lists are loaded only when a game opens, and the table is its own
|
|
1070
|
+
entry (`/ui` for plain DOM, `/element` for a tag, `/react` for React), so a page that wants only the
|
|
1071
|
+
rules carries none of it. A computer player is pure too, so its turn replays
|
|
1072
|
+
exactly after a reload.
|
|
1073
|
+
|
|
1074
|
+
The file-by-file tree, with a line on each source file, is in [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md): the rules (`grid`, `judge`, `play`, `generate`, `check`), the table of players (`party*`), the computer player (`computer*`), the Japanese tiles (`kana`), the word lists (`words*`), and the three faces (`ui`, `element`, `react`). Tests sit beside the code they test (`*.test.ts`). `scripts/` builds the demo
|
|
1075
|
+
and checks the package as npm packs it, `demo/` is the page published on
|
|
1076
|
+
GitHub Pages, and `table/` taps it in real browsers.
|
|
1077
|
+
|
|
1078
|
+
## The name
|
|
1079
|
+
|
|
1080
|
+
*Kumimoji* (組み文字) is made of *kumi* (組み, from 組む, to put together or
|
|
1081
|
+
assemble) and *moji* (文字, a letter or character): letters put together,
|
|
1082
|
+
which is what a player does with the tiles. Say it in four even beats:
|
|
1083
|
+
ku-mi-mo-ji. In Japanese printing the same word names something else, several
|
|
1084
|
+
characters set together in the space of one; the game borrows only its plain
|
|
1085
|
+
sense.
|
|
1086
|
+
|
|
1087
|
+
## Where it comes from, and where it is used
|
|
1088
|
+
|
|
1089
|
+
Kumimoji was built for [Itsutsu](https://itsutsu.com), a site for board games,
|
|
1090
|
+
puzzles, card games and dice games played at your own pace. *Itsutsu* (五つ) is
|
|
1091
|
+
Japanese for "five", after five in a row, the game the site began with. It is
|
|
1092
|
+
[the Kumimoji played there](https://itsutsu.com/games/kumimoji): alone, in
|
|
1093
|
+
races, round one device and across several.
|
|
1038
1094
|
|
|
1039
|
-
|
|
1095
|
+
### Used by
|
|
1096
|
+
|
|
1097
|
+
- [Itsutsu](https://itsutsu.com), for its game of Kumimoji: its rules, its
|
|
1098
|
+
word lists and its computer player.
|
|
1099
|
+
|
|
1100
|
+
That is the whole list so far. Using Kumimoji in something? Open an
|
|
1101
|
+
[*Add my project*](https://github.com/johnmorrisdotca/kumimoji/issues/new?template=add-my-project.md)
|
|
1102
|
+
issue and we will add you.
|
|
1103
|
+
|
|
1104
|
+
### The family
|
|
1105
|
+
|
|
1106
|
+
<!-- family:start (made by scripts/family-readme.mjs from scripts/family-template.mjs; change those, not this) -->
|
|
1107
|
+
Kumimoji is one of twenty-four packages, each made for the same site, each at
|
|
1108
|
+
[github.com/johnmorrisdotca](https://github.com/johnmorrisdotca). The code of every one is MIT.
|
|
1109
|
+
|
|
1110
|
+
- [Korokoro](https://github.com/johnmorrisdotca/korokoro) (コロコロ): dice, with notation, exact odds, real sounds and the dice of many games. [Demo](https://johnmorrisdotca.github.io/korokoro/).
|
|
1111
|
+
- [Kyuubu](https://github.com/johnmorrisdotca/kyuubu) (キューブ): a turning cube for the browser, 2×2 to 7×7, with record solves to replay. [Demo](https://johnmorrisdotca.github.io/kyuubu/).
|
|
1112
|
+
- [Hitotsu](https://github.com/johnmorrisdotca/hitotsu) (一つ): a colour-card shedding game for two to eight, with the house rules people play. [Demo](https://johnmorrisdotca.github.io/hitotsu/).
|
|
1113
|
+
- [Toranpu](https://github.com/johnmorrisdotca/toranpu) (トランプ): a deck of playing cards, card games with computer players, and solitaires. [Demo](https://johnmorrisdotca.github.io/toranpu/).
|
|
1114
|
+
- [Tane](https://github.com/johnmorrisdotca/tane) (種): seeded random numbers and daily seeds, the same in every browser and on every server. [Demo](https://johnmorrisdotca.github.io/tane/).
|
|
1115
|
+
- [Narabe](https://github.com/johnmorrisdotca/narabe) (並べ): one rules engine for abstract board games, from gomoku and Reversi to Go and checkers. [Demo](https://johnmorrisdotca.github.io/narabe/).
|
|
1116
|
+
- [Tenka](https://github.com/johnmorrisdotca/tenka) (天下): world conquest for two to six, on a map of the real world. [Demo](https://johnmorrisdotca.github.io/tenka/).
|
|
1117
|
+
- [Kumimoji](https://github.com/johnmorrisdotca/kumimoji) (組み文字): a crossword tile race, in English and Japanese kana. [Demo](https://johnmorrisdotca.github.io/kumimoji/).
|
|
1118
|
+
- [Tsunagi](https://github.com/johnmorrisdotca/tsunagi) (繋ぎ): a line-joining logic puzzle whose every level has exactly one answer. [Demo](https://johnmorrisdotca.github.io/tsunagi/).
|
|
1119
|
+
- [Jarajara](https://github.com/johnmorrisdotca/jarajara) (ジャラジャラ): mahjong tiles drawn as SVG, stacked layouts, and the matching solitaire Awase. [Demo](https://johnmorrisdotca.github.io/jarajara/).
|
|
1120
|
+
- [Suido](https://github.com/johnmorrisdotca/suido) (水道): a pipe puzzle: turn the pieces until the water reaches every drain. [Demo](https://johnmorrisdotca.github.io/suido/).
|
|
1121
|
+
- [Domino](https://github.com/johnmorrisdotca/domino) (ドミノ): dominoes and Mexican Train. [Demo](https://johnmorrisdotca.github.io/domino/).
|
|
1122
|
+
- [Kotoba](https://github.com/johnmorrisdotca/kotoba) (言葉): word lists and word-game rules in English, French, German and Japanese. [Demo](https://johnmorrisdotca.github.io/kotoba/).
|
|
1123
|
+
- [Sugoroku](https://github.com/johnmorrisdotca/sugoroku) (双六): backgammon and its variants, with the doubling cube and match play. [Demo](https://johnmorrisdotca.github.io/sugoroku/).
|
|
1124
|
+
- [Kazu](https://github.com/johnmorrisdotca/kazu) (数): grid number puzzles: Sudoku and its variants, Futoshiki and Skyscrapers. [Demo](https://johnmorrisdotca.github.io/kazu/).
|
|
1125
|
+
- [Meikyuu](https://github.com/johnmorrisdotca/meikyuu) (迷宮): mazes on squares, hexagons, triangles and circles, made from a seed and drawn through with a finger or the mouse. [Demo](https://johnmorrisdotca.github.io/meikyuu/).
|
|
1126
|
+
- [Hikidashi](https://github.com/johnmorrisdotca/hikidashi) (引き出し): a drawer of small Japanese text tools: era dates, kanji numerals, readings and sentence difficulty. [Demo](https://johnmorrisdotca.github.io/hikidashi/).
|
|
1127
|
+
- [Chizu](https://github.com/johnmorrisdotca/chizu) (地図): maps of the world and of countries' regions, in English and Japanese, with a quiz and callouts. [Demo](https://johnmorrisdotca.github.io/chizu/).
|
|
1128
|
+
- [Bushu](https://github.com/johnmorrisdotca/bushu) (部首): find a kanji by the parts it is made of. [Demo](https://johnmorrisdotca.github.io/bushu/).
|
|
1129
|
+
- [Tobiishi](https://github.com/johnmorrisdotca/tobiishi) (飛び石): peg solitaire with nine boards and seeded solvable challenges. [Demo](https://johnmorrisdotca.github.io/tobiishi/).
|
|
1130
|
+
- [Jirai](https://github.com/johnmorrisdotca/jirai) (地雷): minesweeper on shaped grids with verified no-guess boards. [Demo](https://johnmorrisdotca.github.io/jirai/).
|
|
1131
|
+
- [Gunjin](https://github.com/johnmorrisdotca/gunjin) (軍人): five hidden-rank strategy games with pass-the-device play. [Demo](https://johnmorrisdotca.github.io/gunjin/).
|
|
1132
|
+
- [Karakuri](https://github.com/johnmorrisdotca/karakuri) (からくり): eight hyper-casual puzzle games, some of them physics: draw a shield, pull pins, cut ropes, slide blocks, pour tubes. [Demo](https://johnmorrisdotca.github.io/karakuri/).
|
|
1133
|
+
- [Houseki](https://github.com/johnmorrisdotca/houseki) (宝石): gem and stone matching puzzles: falling triplets, stone collapse, colour chains and gem swap. [Demo](https://johnmorrisdotca.github.io/houseki/).
|
|
1134
|
+
|
|
1135
|
+
**This package is Kumimoji.** The demos of all twenty-four share one header and footer, so each links the rest.
|
|
1136
|
+
<!-- family:end -->
|
|
1137
|
+
|
|
1138
|
+
## Development
|
|
1040
1139
|
|
|
1041
1140
|
```sh
|
|
1042
|
-
pnpm install
|
|
1043
|
-
pnpm check
|
|
1044
|
-
pnpm test:table
|
|
1045
|
-
pnpm
|
|
1046
|
-
pnpm
|
|
1141
|
+
pnpm install --frozen-lockfile
|
|
1142
|
+
pnpm check # lint, types and tests, including the checks on the README's tables and examples
|
|
1143
|
+
pnpm test:table # the demo in real browsers, by taps
|
|
1144
|
+
pnpm test:package # pack it as npm does, install it and import every entry
|
|
1145
|
+
pnpm test:frameworks # the six framework examples, built from the packed tarball and played
|
|
1146
|
+
pnpm test:readme # every TypeScript and JavaScript example in this README, type-checked and run
|
|
1147
|
+
pnpm site # build the demo into ./site
|
|
1148
|
+
pnpm screenshots:readme # retake the README's pictures into docs/images (builds the demo first)
|
|
1047
1149
|
```
|
|
1048
1150
|
|
|
1151
|
+
The pictures are taken on the maintainer's Mac and are retaken only when the look changes; they are in `docs/images` and are not in the package that npm installs.
|
|
1152
|
+
|
|
1153
|
+
## Contributing
|
|
1154
|
+
|
|
1155
|
+
See [CONTRIBUTING.md](./CONTRIBUTING.md). In short: run `pnpm check` before you push (see [Development](#development)).
|
|
1156
|
+
|
|
1049
1157
|
Please follow the [code of conduct](./CODE_OF_CONDUCT.md). A way to make a check or a deal run for long, or markup that gets out of the drawing, is for the [security policy](./SECURITY.md), not a public issue.
|
|
1050
1158
|
|
|
1051
1159
|
## Changes
|
|
1052
1160
|
|
|
1053
1161
|
See [CHANGELOG.md](./CHANGELOG.md).
|
|
1054
1162
|
|
|
1163
|
+
The latest release is 1.2.2: the README takes the family's full layout, with pictures of the table and examples that are run.
|
|
1164
|
+
|
|
1055
1165
|
## Licence
|
|
1056
1166
|
|
|
1057
1167
|
The code is [MIT](./LICENSE) © John Morris.
|
package/dist/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** The version of this package, as `package.json` has it. A test holds the two together. */
|
|
2
|
-
export declare const KUMIMOJI_VERSION = "1.2.
|
|
2
|
+
export declare const KUMIMOJI_VERSION = "1.2.2";
|
package/dist/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** The version of this package, as `package.json` has it. A test holds the two together. */
|
|
2
|
-
export const KUMIMOJI_VERSION = "1.2.
|
|
2
|
+
export const KUMIMOJI_VERSION = "1.2.2";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@johnmorrisdotca/kumimoji",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.2",
|
|
4
4
|
"description": "Crossword tile race: each player builds a crossword from a bag of letter tiles, in English or Japanese kana, alone against the clock or at a table of two to eight. Seeded deals, a computer player and a playable table. Zero dependencies.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"word-game",
|
|
@@ -143,9 +143,10 @@
|
|
|
143
143
|
"test:frameworks": "pnpm build && node scripts/check-frameworks.mjs",
|
|
144
144
|
"check": "pnpm lint && pnpm typecheck && pnpm test",
|
|
145
145
|
"site": "pnpm build && node scripts/site.mjs",
|
|
146
|
-
"pictures": "pnpm site && node scripts/readme-pictures.mjs",
|
|
147
146
|
"docs:make": "node scripts/docs.mjs",
|
|
148
|
-
"prepublishOnly": "pnpm check && pnpm build"
|
|
147
|
+
"prepublishOnly": "pnpm check && pnpm build",
|
|
148
|
+
"screenshots:readme": "pnpm site && node scripts/readme-pictures.mjs",
|
|
149
|
+
"test:readme": "pnpm build && node scripts/check-readme-examples.mjs"
|
|
149
150
|
},
|
|
150
151
|
"peerDependencies": {
|
|
151
152
|
"react": ">=18"
|