@johnmorrisdotca/kazu 1.0.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.
Files changed (76) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/LICENSE +21 -0
  3. package/README.md +568 -0
  4. package/dist/cells.d.ts +28 -0
  5. package/dist/cells.js +65 -0
  6. package/dist/check.d.ts +15 -0
  7. package/dist/check.js +189 -0
  8. package/dist/clock.d.ts +2 -0
  9. package/dist/clock.js +9 -0
  10. package/dist/conflicts.d.ts +14 -0
  11. package/dist/conflicts.js +79 -0
  12. package/dist/draw-entry.d.ts +14 -0
  13. package/dist/draw-entry.js +10 -0
  14. package/dist/draw.d.ts +47 -0
  15. package/dist/draw.js +219 -0
  16. package/dist/element-define.d.ts +1 -0
  17. package/dist/element-define.js +13 -0
  18. package/dist/element.d.ts +48 -0
  19. package/dist/element.js +150 -0
  20. package/dist/game.d.ts +65 -0
  21. package/dist/game.js +120 -0
  22. package/dist/generate.d.ts +11 -0
  23. package/dist/generate.js +35 -0
  24. package/dist/geometry.d.ts +33 -0
  25. package/dist/geometry.js +27 -0
  26. package/dist/givens.d.ts +30 -0
  27. package/dist/givens.js +43 -0
  28. package/dist/groupSolve.d.ts +68 -0
  29. package/dist/groupSolve.js +284 -0
  30. package/dist/hint.d.ts +39 -0
  31. package/dist/hint.js +158 -0
  32. package/dist/index.d.ts +36 -0
  33. package/dist/index.js +31 -0
  34. package/dist/jigsaw.d.ts +21 -0
  35. package/dist/jigsaw.js +144 -0
  36. package/dist/kinds.d.ts +51 -0
  37. package/dist/kinds.js +40 -0
  38. package/dist/layout.d.ts +63 -0
  39. package/dist/layout.js +128 -0
  40. package/dist/moreOrLess.d.ts +7 -0
  41. package/dist/moreOrLess.js +90 -0
  42. package/dist/moreOrLessCode.d.ts +22 -0
  43. package/dist/moreOrLessCode.js +52 -0
  44. package/dist/moreOrLessSolve.d.ts +45 -0
  45. package/dist/moreOrLessSolve.js +180 -0
  46. package/dist/mount.d.ts +117 -0
  47. package/dist/mount.js +558 -0
  48. package/dist/names.d.ts +41 -0
  49. package/dist/names.js +163 -0
  50. package/dist/numberPlace.d.ts +14 -0
  51. package/dist/numberPlace.js +123 -0
  52. package/dist/play-entry.d.ts +9 -0
  53. package/dist/play-entry.js +8 -0
  54. package/dist/playStyle.d.ts +11 -0
  55. package/dist/playStyle.js +47 -0
  56. package/dist/progress.d.ts +29 -0
  57. package/dist/progress.js +96 -0
  58. package/dist/random.d.ts +25 -0
  59. package/dist/random.js +42 -0
  60. package/dist/solve.d.ts +22 -0
  61. package/dist/solve.js +60 -0
  62. package/dist/strings.d.ts +17 -0
  63. package/dist/strings.js +143 -0
  64. package/dist/style.d.ts +13 -0
  65. package/dist/style.js +61 -0
  66. package/dist/sumCages.d.ts +60 -0
  67. package/dist/sumCages.js +190 -0
  68. package/dist/towers.d.ts +3 -0
  69. package/dist/towers.js +48 -0
  70. package/dist/towersCode.d.ts +31 -0
  71. package/dist/towersCode.js +79 -0
  72. package/dist/towersSolve.d.ts +65 -0
  73. package/dist/towersSolve.js +276 -0
  74. package/dist/version.d.ts +2 -0
  75. package/dist/version.js +2 -0
  76. package/package.json +104 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,29 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are written here. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project uses
5
+ [Semantic Versioning](https://semver.org/).
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [1.0.0] - 2026-10-01
10
+
11
+ The Numbers family of grid puzzles, taken out of itsutsu.com so that the site can import them as it
12
+ imports its other family packages. Every puzzle the site made before the move is made again here, givens and
13
+ solution, byte for byte: `src/site.fixture.json` holds 3,600 of them (every puzzle, size and level, sixty
14
+ seeds each) and six tests make each again.
15
+
16
+ - **Six puzzles**, by key: `number-place` (Sudoku, 4×4 to a 16×16 Giant), `jigsaw`, `diagonal`, `sum-cages` (Killer
17
+ Sudoku), `more-or-less` (Futoshiki) and `towers` (Skyscrapers), each at `easy`, `medium` and `hard`.
18
+ - **`@johnmorrisdotca/kazu`**: `generateKazu`, `solveKazu`, `countKazuSolutions`, `kazuGuessDepth`, `checkKazu` (the
19
+ O(cells) check, with the site's own reasons), `hintKazu` (the next cell and why), `conflictsOf`, `readGivens`, the
20
+ string codes of givens, runs, pencil marks and step logs (the site's own spellings, which decode unchanged), and a
21
+ game in play as pure functions.
22
+ - **`@johnmorrisdotca/kazu/draw`**: a puzzle as SVG text with entries, pencil marks, the chosen cell and its lines,
23
+ conflicts, diagonals, dashed cages with their sums, more-than marks and the tower clues round the edge, in light and
24
+ dark, with generic colours as custom properties.
25
+ - **`@johnmorrisdotca/kazu/play`**: `mountKazu` plays a puzzle in any element by touch, mouse and keyboard, with a
26
+ number pad, pencil marks, Undo, Hint, Check, a clock and events; English and Japanese.
27
+ - **`<kazu-board>`** (`/element`, `/element/define`): the same in a tag.
28
+ - A demo with a chooser, a Help switch, the cloth patches, and browser tests (`pnpm test:demo`) at a phone's width
29
+ and a desk's, in Chromium and WebKit.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 John Morris
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,568 @@
1
+ <h1 align="center">Kazu <sub>数</sub></h1>
2
+
3
+ <p align="center"><strong>Grid number puzzles for JavaScript and TypeScript.</strong><br>
4
+ Sudoku (4×4 to a 16×16 Giant), Jigsaw, Diagonal and Killer Sudoku, Futoshiki and Skyscrapers. A seeded generator whose every puzzle has exactly one answer, at three levels; a solver that counts answers; a check that reads a finished grid in O(cells); a hint that says which cell to fill next and why; puzzles and runs as short codes; the grid drawn as SVG; and played by touch, mouse and keyboard in any page, with pencil marks, undo and a clock, as one call or one tag. No dependencies.</p>
5
+
6
+ <p align="center">
7
+ <a href="https://github.com/johnmorrisdotca/kazu/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/johnmorrisdotca/kazu/actions/workflows/ci.yml/badge.svg"></a>
8
+ <a href="https://www.npmjs.com/package/@johnmorrisdotca/kazu"><img alt="npm" src="https://img.shields.io/npm/v/@johnmorrisdotca/kazu?color=2f5d4a"></a>
9
+ <a href="./LICENSE"><img alt="MIT licence" src="https://img.shields.io/badge/licence-MIT-2f5d4a"></a>
10
+ <img alt="No dependencies" src="https://img.shields.io/badge/dependencies-0-2f5d4a">
11
+ </p>
12
+
13
+ <p align="center"><a href="https://johnmorrisdotca.github.io/kazu/"><strong>Play a puzzle →</strong></a> · <a href="https://johnmorrisdotca.github.io/kazu/api.html">API reference</a></p>
14
+
15
+ <p align="center">
16
+ <img src="docs/desktop.jpg" alt="A 9×9 Killer Sudoku part filled in, under the demo's header with its language chooser, the API reference link, five cloth patches and the Help switch: the choices of puzzle, size and level, then the board on green felt with dashed cages and their sums, the chosen cell and its row, column and box washed in colour, the number pad and the Undo, Pencil, Hint and Check buttons" width="620">
17
+ <img src="docs/phone.jpg" alt="A 6×6 Skyscrapers puzzle part filled in, on a phone in dark mode and in Japanese: the clues round the edge, the number pad, the buttons and the first of the settings under it" width="200">
18
+ </p>
19
+
20
+ Kazu is the family of grid puzzles Sudoku belongs to: fill every cell with a number, so that no number repeats where the rules say it must not. It is
21
+ played at [itsutsu.com](https://itsutsu.com), which this package was taken out of, and in
22
+ [the demo](https://johnmorrisdotca.github.io/kazu/), with nothing to install.
23
+
24
+ ## In 30 seconds
25
+
26
+ ```sh
27
+ npm install @johnmorrisdotca/kazu
28
+ ```
29
+
30
+ ```ts
31
+ import { checkKazu, countKazuSolutions, generateKazu, hintKazu } from "@johnmorrisdotca/kazu";
32
+
33
+ const puzzle = generateKazu("sum-cages", 9, "medium", 42); // a Killer Sudoku: the same one in every browser, for ever
34
+ countKazuSolutions("sum-cages", 9, puzzle.givens); // 1: exactly one answer
35
+ checkKazu("sum-cages", 9, puzzle.givens, puzzle.solution); // { ok: true }, read in O(cells)
36
+
37
+ const sudoku = generateKazu("number-place", 9, "easy", 7);
38
+ hintKazu("number-place", 9, sudoku.givens, new Array(81).fill(0));
39
+ // { cell: 2, value: 8, why: "only-number", replaces: false }: which cell, what goes in it, and why
40
+ ```
41
+
42
+ And in a page, a puzzle to play, by touch, mouse and keyboard, with nothing else to set up:
43
+
44
+ ```html
45
+ <script type="module" src="https://cdn.jsdelivr.net/npm/@johnmorrisdotca/kazu@1/dist/element-define.js"></script>
46
+ <kazu-board kind="number-place" size="9" level="medium" seed="7"></kazu-board>
47
+ ```
48
+
49
+ ## Who it is for
50
+
51
+ - **Puzzle sites and apps** that want these six puzzles with the rules already right: puzzles everybody
52
+ plays alike from a seed, a check a server can trust in O(cells), a hint that is a reason and not just
53
+ an answer, and runs kept as short strings.
54
+ - **Anyone making number puzzles of their own**, who wants a solver that counts answers, generators whose
55
+ every puzzle has exactly one, and the layout of groups (rows, columns, boxes, regions, diagonals, cages)
56
+ one solver reads for four of the six.
57
+ - **Pages that just want the grid**: it draws itself as SVG text, and plays itself in an element or one
58
+ function call, with a number pad, pencil marks, Undo, Hint, Check and a clock, and its words in English and
59
+ Japanese.
60
+
61
+ ## Features
62
+
63
+ - **Six puzzles, three levels.** Sudoku (4×4, 6×6, 9×9 and a 16×16 Giant), Jigsaw, Diagonal and Killer Sudoku, Futoshiki and Skyscrapers, each at `easy`, `medium` and `hard`, named by kebab-case keys.
64
+ - **Exactly one answer.** A generator makes puzzles from a seed, and a solver that counts answers confirms there is one. The same kind, size, level and seed make the same puzzle in every browser and every Node, for ever.
65
+ - **A check a server can trust.** `checkKazu` reads a finished grid in O(cells), with no search, and says the first thing wrong in words.
66
+ - **A hint that is a reason.** Which cell to fill next, with the rule that says so (a cell with one number left, a number with one place left), never built on a wrong entry.
67
+ - **Puzzles and runs as short strings**, so a game half done, its pencil marks and its steps can be kept in a database column.
68
+ - **Drawn as SVG text**, in an entry of its own: a server that only checks answers never loads the drawing.
69
+ - **Played in any page** by touch, mouse and keyboard, with pencil marks, Undo, Hint, Check and a clock, as one function call (`mountKazu`) or one tag (`<kazu-board>`).
70
+ - **English and Japanese**, in the board's words, the puzzles' names and rules, and the demo.
71
+ - **No dependencies**, no network requests, no sound, no animation, and nothing stored outside the page it is in.
72
+
73
+ ## Use it in your project
74
+
75
+ Kazu is three things, each usable without the others: **the puzzles** (making, solving, checking and hinting, as plain functions over strings), **the drawing** (SVG text), and **the page** (a mounted board or a tag). The table under [The element](#the-element) says which entry holds which. The examples are one puzzle each time, written in `number-place` at 9×9.
76
+
77
+ ### 1. The API alone, on a server
78
+
79
+ ```ts
80
+ import { checkKazu, generateKazu } from "@johnmorrisdotca/kazu";
81
+
82
+ const { givens } = generateKazu("number-place", 9, "medium", 42); // send `givens` to the browser; keep `42` and the answer
83
+ checkKazu("number-place", 9, givens, answerFromThePlayer); // { ok: true } or { ok: false, reason }, in O(cells)
84
+ ```
85
+
86
+ Importing the main entry on a server is safe: it touches no page.
87
+
88
+ ### 2. One tag, no bundler
89
+
90
+ ```html
91
+ <script type="module" src="https://cdn.jsdelivr.net/npm/@johnmorrisdotca/kazu@1/dist/element-define.js"></script>
92
+ <kazu-board kind="number-place" size="9" level="medium" seed="42"></kazu-board>
93
+ <script>
94
+ document.querySelector("kazu-board").addEventListener("kazu-solve", (event) => console.log(event.detail.elapsedMs));
95
+ </script>
96
+ ```
97
+
98
+ ### 3. A bundler, and a framework
99
+
100
+ `import "@johnmorrisdotca/kazu/element/define"` once, in code that runs in the browser, and `<kazu-board>` is a tag like any other. The tag draws itself in the page's own DOM, so the page's CSS reaches it. Its attributes are read again when they change, and it speaks through DOM events (`kazu-change`, `kazu-hint`, `kazu-check`, `kazu-solve`) that carry a `detail`.
101
+
102
+ ```jsx
103
+ // React 19
104
+ import { useEffect, useRef } from "react";
105
+ import "@johnmorrisdotca/kazu/element/define";
106
+
107
+ export function Puzzle({ seed, onSolved }) {
108
+ const board = useRef(null);
109
+ useEffect(() => {
110
+ const listen = (event) => onSolved(event.detail.elapsedMs);
111
+ board.current?.addEventListener("kazu-solve", listen);
112
+ return () => board.current?.removeEventListener("kazu-solve", listen);
113
+ }, [onSolved]);
114
+ return <kazu-board ref={board} kind="number-place" size="9" level="medium" seed={String(seed)} />;
115
+ }
116
+ ```
117
+
118
+ ```vue
119
+ <!-- Vue 3: tell the compiler the tag is not a Vue component -->
120
+ <script setup>
121
+ import "@johnmorrisdotca/kazu/element/define";
122
+ defineProps({ seed: Number });
123
+ </script>
124
+ <template>
125
+ <kazu-board kind="number-place" size="9" level="medium" :seed="seed" @kazu-solve="(event) => console.log(event.detail.elapsedMs)" />
126
+ </template>
127
+ <!-- in vite.config: vue({ template: { compilerOptions: { isCustomElement: (tag) => tag.startsWith("kazu-") } } }) -->
128
+ ```
129
+
130
+ ```svelte
131
+ <!-- Svelte 5 -->
132
+ <script>
133
+ import "@johnmorrisdotca/kazu/element/define";
134
+ let { seed } = $props();
135
+ let board;
136
+ $effect(() => {
137
+ const listen = (event) => console.log(event.detail.elapsedMs);
138
+ board.addEventListener("kazu-solve", listen);
139
+ return () => board.removeEventListener("kazu-solve", listen);
140
+ });
141
+ </script>
142
+ <kazu-board bind:this={board} kind="number-place" size="9" level="medium" seed={seed}></kazu-board>
143
+ ```
144
+
145
+ ```ts
146
+ // Angular: a standalone component with CUSTOM_ELEMENTS_SCHEMA
147
+ import { Component, CUSTOM_ELEMENTS_SCHEMA } from "@angular/core";
148
+ import "@johnmorrisdotca/kazu/element/define";
149
+
150
+ @Component({
151
+ selector: "app-puzzle",
152
+ standalone: true,
153
+ schemas: [CUSTOM_ELEMENTS_SCHEMA],
154
+ template: `<kazu-board kind="number-place" size="9" level="medium" seed="42" (kazu-solve)="solved($event)"></kazu-board>`,
155
+ })
156
+ export class Puzzle {
157
+ solved(event: Event) { console.log((event as CustomEvent).detail.elapsedMs); }
158
+ }
159
+ ```
160
+
161
+ In Next.js or any server-rendering framework, import the define entry from a client component, so the tag is defined in the browser. Or skip the tag and call `mountKazu(element, options)` from `@johnmorrisdotca/kazu/play` in an effect: the handle it returns has `destroy()`.
162
+
163
+ These recipes are written to the tag's documented attributes and events; they are not built from the packed tarball by this repository's tests, which play the tag in a bare page in Chromium and WebKit.
164
+
165
+ ### What a developer gets
166
+
167
+ - **Typed results**, with a doc comment on every export. Every function is pure and returns new values.
168
+ - **No dependencies.** ES modules, an entry per concern, and `sideEffects` set so that only the define entry has an effect.
169
+ - **Where it runs.** See [Browser support](#browser-support).
170
+
171
+ ## The puzzles
172
+
173
+ A puzzle is a grid of `size × size` cells, a few printed numbers and whatever else the kind prints, and
174
+ exactly one answer. Every kind is named by a kebab-case key.
175
+
176
+ | Key | Called | In Japanese | Sizes | What it prints | What is new |
177
+ | --- | --- | --- | --- | --- | --- |
178
+ | `number-place` | Sudoku | ナンプレ | 4×4, 6×6, 9×9, 16×16 | numbers | every row, column and box holds each number once; the 16×16 Giant uses 1 to 9 and then A to G |
179
+ | `jigsaw` | Jigsaw Sudoku | 変形ナンプレ | 5×5, 6×6, 7×7, 9×9 | numbers, and the regions | the boxes are irregular regions, each joined and none a row or a column |
180
+ | `diagonal` | Diagonal Sudoku | 対角ナンプレ | 6×6, 9×9 | numbers | the two long diagonals hold each number once too |
181
+ | `sum-cages` | Killer Sudoku | サムナンプレ | 6×6, 9×9 | cages and their sums | next to no numbers: dashed cages each add to a sum, and repeat nothing |
182
+ | `more-or-less` | Futoshiki | 不等式 | 4×4, 5×5, 6×6, 7×7 | numbers, and more-than marks | rows and columns, and every mark between two cells must be true |
183
+ | `towers` | Skyscrapers | 摩天楼 | 4×4, 5×5, 6×6, 7×7 | numbers, and clues round the edge | a clue is how many towers show from there; a taller one hides those behind it |
184
+
185
+ Each is made at three levels, `easy`, `medium` and `hard`: what the solver needed, not how many numbers
186
+ are printed. Easy yields to singles alone (a cell with one number left, a number with one place left in a
187
+ group); medium needs one guess; hard whatever it takes. Sum Cages' levels are the size of its cages, and
188
+ fewer of them.
189
+
190
+ *Sudoku* 数独 is Nikoli's mark in Japan, so its Japanese name here is ナンプレ (Number Place, the puzzle's
191
+ own original name and the word Japanese publishers use); the English names are the ones players search
192
+ for. `KAZU_NAMES` has each puzzle's names, its rules in English and Japanese, and where it comes from.
193
+
194
+ ## Making, solving and checking
195
+
196
+ ```ts
197
+ import { checkKazu, generateKazu, solveKazu, countKazuSolutions, kazuGuessDepth, readGivens } from "@johnmorrisdotca/kazu";
198
+
199
+ const { kind, size, level, seed, givens, solution } = generateKazu("towers", 6, "hard", 1234);
200
+ solveKazu("towers", 6, givens) === solution; // the one answer, worked out from the givens alone
201
+ countKazuSolutions("towers", 6, givens); // 1 (up to a limit, two by default); null for givens that are not a puzzle
202
+ kazuGuessDepth("towers", 6, givens); // how many guesses a person needs: 0 easy, 1 medium, more hard
203
+ readGivens("towers", 6, givens); // { cells, clues, … }: what the puzzle was printed with
204
+ ```
205
+
206
+ The same kind, size, level and seed make the same puzzle in every browser and every Node, for ever
207
+ (`seededRandom` is mulberry32). That is the promise itsutsu.com's kept runs and solves are built on, and
208
+ it is held by a test: `src/site.fixture.json` is 3,600 puzzles the site made before the move, every kind at
209
+ every size and level from sixty seeds, and each is made again here, givens and solution, byte for byte.
210
+ Changing how any puzzle is made is a new major version, never a fix.
211
+
212
+ `checkKazu(kind, size, givens, answer)` reads a finished grid in O(cells), with no search: right in every group,
213
+ every given where it was, every cage, mark and clue true. `{ ok: false, reason }` says the first thing
214
+ wrong (`"row 3 repeats a number"`, `"cage 4 does not add to 17"`, `"the top clue 3 sees 2"`), in the words the site
215
+ has always used. It restates the rules rather than reading the solver's mind, so a server can trust it.
216
+ A solver and a generator never run on a server unless you ask them to.
217
+
218
+ A run is kept as short strings the site's own stored runs decode as they are: `encodeRun(entries)` and
219
+ `decodeRun(code, size)` (one character a cell, `.` for empty, A to G past nine), `encodeSteps` and
220
+ `decodeSteps` for a step log, `kazuHash(givens)` for a fingerprint of a puzzle, and `encodeNotes` and
221
+ `decodeNotes` for Kazu's own pencil marks.
222
+
223
+ ### A hint
224
+
225
+ ```ts
226
+ import { hintKazu } from "@johnmorrisdotca/kazu";
227
+
228
+ hintKazu("number-place", 9, givens, entries);
229
+ // for example { cell: 25, value: 7, why: "only-place", group: { type: "row", index: 2 }, replaces: false }
230
+ ```
231
+
232
+ It reasons from what is right on the grid so far (a wrong entry is treated as empty, so it never builds on a
233
+ mistake), one step at a time, as a person does: a cell only one number fits (`only-number`, and `by` says
234
+ whether a cage's sum, a Futoshiki mark or a Skyscrapers clue did part of the ruling out), or a number with
235
+ only one place left in a row, column, box, region or diagonal (`only-place`). When nothing follows by a single
236
+ step, which a hard puzzle asks for, it says so (`answer`). `mountKazu` puts the reason into words.
237
+
238
+ ## Drawing a puzzle
239
+
240
+ ```ts
241
+ import { drawKazu, KAZU_STYLE } from "@johnmorrisdotca/kazu/draw";
242
+
243
+ const svg = drawKazu("sum-cages", 9, givens, { entries, notes, selected: 40, peers: true, conflicts: [3, 4], language: "ja" });
244
+ ```
245
+
246
+ `drawKazu` returns SVG text: put it in a page, a file or an image, with nothing to load. It draws the grid with
247
+ its printed numbers and whatever has been written, pencil marks in a small grid in the cell, the heavier rules
248
+ round boxes or a Jigsaw's regions, the shaded diagonals, a cage's dashed outline with its sum in the corner,
249
+ the more-than marks as chevrons between cells, and the clues of a Towers puzzle round the edge. Null for givens
250
+ that are not a puzzle.
251
+
252
+ | Option | What it does |
253
+ | --- | --- |
254
+ | `entries` | what the player has written, row-major, 0 for empty |
255
+ | `notes` | pencil marks, a bit mask a cell: bit `v` is the note `v` |
256
+ | `selected`, `peers` | the chosen cell, and with `peers` its row, column and group and every cell holding its number washed |
257
+ | `conflicts` | cells that break a rule, in red with their numbers (`conflictsOf` finds them from the rules alone) |
258
+ | `wrong`, `hint` | the cells Check flagged, and the cell a hint pointed at |
259
+ | `done` | a faint wash of green, and `data-solved="true"` |
260
+ | `interactive` | a transparent square over every cell with its `data-cell`, for a page to press on (`mountKazu` does) |
261
+ | `language`, `label` | what a screen reader hears, and a description instead of "Sudoku puzzle, 9 by 9" |
262
+ | `style`, `frame` | `style: true` puts `KAZU_STYLE` inside, so the drawing stands alone as an image; `frame` draws a wooden frame round the paper |
263
+
264
+ Generic colours, no branding: every colour is a custom property on `.kazu` (`--kz-paper`, `--kz-ink`,
265
+ `--kz-given`, `--kz-entry`, `--kz-note`, `--kz-grid`, `--kz-box`, `--kz-frame`, `--kz-cage`, `--kz-clue`,
266
+ `--kz-diagonal`, `--kz-peer`, `--kz-same`, `--kz-select`, `--kz-hint`, `--kz-conflict`, `--kz-wrong`,
267
+ `--kz-good`), so a page sets only what it wants different, and the paper follows the page's light or dark. The parts carry classes
268
+ and data attributes to style or find them: `kz-given`, `kz-entry`, `kz-note`, `kz-cage-sum`, `kz-clue`, `kz-mark`,
269
+ `kz-conflict`, `kz-hit` (`data-cell`). It is one steady square whatever is drawn, so nothing moves as numbers
270
+ are written, and nothing in it can be selected, dragged or double-tapped into a selection.
271
+ `kazuGeometry(kind, size)` says where every cell is in the drawing and which cell a point is over, so a page of
272
+ your own can play it.
273
+
274
+ ## Playing it in a page
275
+
276
+ ```ts
277
+ import { mountKazu } from "@johnmorrisdotca/kazu/play";
278
+
279
+ const board = mountKazu(document.getElementById("here")!, {
280
+ kind: "towers", size: 6, givens, solution, level: "hard", seed: 1234,
281
+ hints: "show", check: "count",
282
+ onChange: ({ run, notes, elapsedMs }) => keep(run, notes, elapsedMs), // to carry on a puzzle half done
283
+ onSolve: ({ answer, elapsedMs, helped }) => send(answer, elapsedMs, helped), // `answer` is what checkKazu takes
284
+ });
285
+ board?.undo(); board?.hint(); board?.load({ kind: "diagonal", size: 9, givens: other });
286
+ ```
287
+
288
+ Tap a cell and tap a number on the pad (or type it); tap the chosen cell again to step its number on, 1, 2, 3
289
+ … and round to empty. Turn **Pencil** on and the pad writes small notes instead, and a number written takes itself
290
+ out of the notes of the cells it shares a group with. **Undo** takes the last change back, **Hint** says which
291
+ cell to fill next and why, **Check** says how many cells are wrong, never which. A clock starts on the first entry
292
+ and stops when the last cell is right, and waits while the page is hidden.
293
+
294
+ The keys: the arrows move, a number (1 to 9, and A to G on the 16×16) fills the chosen cell, Shift with a
295
+ number writes it as a pencil mark, Backspace empties the cell, N turns Pencil on or off, Ctrl or Cmd with Z
296
+ undoes, Escape lets the cell go. The board's box keeps one steady square, and the lines of words under it keep
297
+ the room their longest wording takes, so nothing moves as numbers are written or messages come and go. Nothing
298
+ the player touches can be selected. Its words are English and Japanese and follow the page's `lang`.
299
+
300
+ | Option | What it does |
301
+ | --- | --- |
302
+ | `kind`, `size`, `givens`, `solution` | the puzzle; `solution` is worked out when Hint or Check needs it if you leave it out |
303
+ | `level`, `seed` | carried in the events, to say which puzzle it was |
304
+ | `run`, `notes`, `elapsed` | a run kept half done (`decodeRun`'s code), its pencil marks, and the milliseconds already on the clock |
305
+ | `hints` | `place` (default) writes the number it found, `show` only points at the cell and says why, `off` takes the button away |
306
+ | `check` | `count` (default) says how many are wrong, `show` marks them too, `off` takes the button away |
307
+ | `conflicts`, `peers`, `tidy`, `tapToStep` | each on by default: cells that break a rule in red, the chosen cell's lines washed, a written number rubbed out of the notes beside it, a tap on the chosen cell stepping it on |
308
+ | `clock`, `controls` | the clock (default on); the number pad and buttons (default on) |
309
+ | `language` | `en` or `ja`; left out, the host's `lang` or the page's, and it follows the page's |
310
+ | `onChange`, `onHint`, `onCheck`, `onSolve` | callbacks, and the same four as DOM events on the host: `kazu-change`, `kazu-hint`, `kazu-check`, `kazu-solve`. Each `detail` has `run`, `notes`, `answer`, `progress`, `elapsedMs`, `hints`, `checks`, `helped` and `solved` |
311
+
312
+ Everything a button does is also a method on the handle (`undo`, `hint`, `check`, `restart`, `pencil`, `select`,
313
+ `enter`, `load`, `set`, `destroy`). The rules it plays by are `game.ts`'s, which are pure and need no page
314
+ (`newKazuGame`, `enterNumber`, `toggleNote`, `undoKazu`, `isSolved`), so a server can replay a game.
315
+
316
+ ### The element
317
+
318
+ ```html
319
+ <script type="module" src="https://cdn.jsdelivr.net/npm/@johnmorrisdotca/kazu@1/dist/element-define.js"></script>
320
+ <kazu-board kind="sum-cages" size="9" level="medium" seed="42"></kazu-board>
321
+ <kazu-board kind="towers" size="5" givens="…" solution="…" hints="show" lang="ja"></kazu-board>
322
+ ```
323
+
324
+ Or `import "@johnmorrisdotca/kazu/element/define"` in a bundle. Attributes, each read again when it changes:
325
+ `kind` (the key of one of the six), `size`, `level` (`easy`, `medium` or `hard`) and `seed` (a new one if left out): the
326
+ puzzle is made in the page; or `size` with `givens` and `solution`, a puzzle of your own; `run`, `notes` and
327
+ `elapsed`, to carry on a puzzle half done; `hints` (`place`, `show`, `off`); `check` (`count`, `show`, `off`);
328
+ `conflicts`, `peers`, `tidy`, `tap-to-step`, `clock` and `controls`, each on unless set to `off`; and `lang`. It
329
+ fires the four events above and has the methods `undo()`, `hint()`, `check()`, `restart()`, `pencil()` and
330
+ `select()`. Importing either entry on a server is safe.
331
+
332
+ | Import | What it holds |
333
+ | --- | --- |
334
+ | `@johnmorrisdotca/kazu` | the generator, the solver, the check, the hint, the codes, and the game in play as pure functions: everything but the drawing and the page |
335
+ | `@johnmorrisdotca/kazu/draw` | `drawKazu` and the rest of the drawing as SVG text, its style, where everything sits in it, the words and the names; no page needed |
336
+ | `@johnmorrisdotca/kazu/play` | `mountKazu`: a puzzle played in any element by touch, mouse and keyboard, with its pad, buttons, clock, words and events |
337
+ | `@johnmorrisdotca/kazu/element` | the `KazuBoard` class behind `<kazu-board>`, to extend or to define under another name |
338
+ | `@johnmorrisdotca/kazu/element/define` | defines `<kazu-board>` on the page, for its effect |
339
+
340
+ ## API
341
+
342
+ The [API reference](https://johnmorrisdotca.github.io/kazu/api.html) lists every export of every entry point with its signature and its doc comment. It is made from the source by `pnpm site`, so it cannot fall behind the code.
343
+
344
+ | Export | What it does |
345
+ | --- | --- |
346
+ | `generateKazu(kind, size, level, seed)` | a puzzle: `{ kind, size, level, seed, givens, solution }`; throws a RangeError for what it does not make |
347
+ | `generateNumberPlace`, `generateJigsaw`, `generateDiagonal`, `generateSumCages`, `generateMoreOrLess`, `generateTowers` | each puzzle's own generator |
348
+ | `solveKazu`, `countKazuSolutions`, `kazuGuessDepth` | the one answer, how many answers (up to a limit and a budget; null when it cannot say), and how many guesses a person needs |
349
+ | `checkKazu(kind, size, givens, answer)`, `isKazuGivens` | whether a finished grid is right, in O(cells), and whether givens are a well-formed puzzle |
350
+ | `hintKazu(kind, size, givens, entries)` | the next cell a person could fill in, and why |
351
+ | `conflictsOf(givens, values)` | the cells that break a rule right now, from the rules alone |
352
+ | `readGivens(kind, size, code)` | what a puzzle was printed with: cells, regions, cages, marks or clues; null for a code that is not a puzzle |
353
+ | `encodeCells`, `decodeCells`, `symbolOf`, `valueOfSymbol`, `stepEntry`, `kazuHash` | a grid as a string, one character a cell |
354
+ | `encodeJigsaw`, `encodeKiller`, `encodeMoreOrLess`, `encodeTowers` and their `decode…` | each kind's givens code |
355
+ | `encodeRun`, `decodeRun`, `encodeNotes`, `decodeNotes`, `encodeSteps`, `decodeSteps` | a puzzle half done, its pencil marks and its steps |
356
+ | `newKazuGame`, `enterNumber`, `toggleNote`, `clearCell`, `undoKazu`, `restartKazu`, `isSolved`, `kazuProgress`, `answerOf`, `valuesOf`, `numberCounts`, `gameConflicts` | a game in play as pure functions; each returns a new game |
357
+ | `boxedLayout`, `regionsAreSound`, `cageOutline`, `lineFrom`, `towersSeen`, `cluesOf` | the groups a puzzle is made of, a cage's outline, and what a clue sees |
358
+ | `seededRandom(seed)`, `freshKazuSeed`, `isKazuSeed` | the mulberry32 stream every puzzle is made from, and seeds |
359
+ | `KAZU_KINDS`, `KAZU_LEVELS`, `KAZU_SPECS`, `KAZU_KIND_OF_SITE_KIND` | the six keys, the three levels, what each offers, and the names itsutsu.com's code used |
360
+ | `KAZU_NAMES`, `KAZU_SIZE_NAMES`, `KAZU_STRINGS`, `kazuSay` | names, rules and words in English and Japanese |
361
+
362
+ Every function is pure: it returns new values and never changes what it was given.
363
+
364
+ ## Theming
365
+
366
+ Nothing here is branded. The drawing and the playable board are coloured by custom properties, and a page sets only the ones it wants different. The paper follows the device's light or dark setting; `data-theme="light"` or `"dark"` on `<html>` forces one.
367
+
368
+ **The drawing** (`drawKazu`), custom properties on `.kazu`:
369
+
370
+ | Property | What it colours | Light | Dark |
371
+ | --- | --- | --- | --- |
372
+ | `--kz-paper` | the grid's paper | `#fbf8f1` | `#262a27` |
373
+ | `--kz-ink` | a mark's outline (Futoshiki's chevrons) | `#1f2320` | `#ece8dc` |
374
+ | `--kz-given` | a printed number | `#1f2320` | `#ece8dc` |
375
+ | `--kz-entry` | a number the player wrote | `#1d5fa8` | `#8fc1ff` |
376
+ | `--kz-note` | a pencil mark | `#5b6b7d` | `#9fb0c2` |
377
+ | `--kz-grid` | the thin lines between cells | `#cfc6b2` | `#454a44` |
378
+ | `--kz-box` | the heavy lines round boxes and regions | `#3a3d38` | `#c9c5b8` |
379
+ | `--kz-frame` | the frame, when `frame` is on | `#a98954` | `#6b5632` |
380
+ | `--kz-cage` | a Killer Sudoku cage and its sum | `#6a5a8e` | `#b8a5e6` |
381
+ | `--kz-clue` | a Skyscrapers clue | `#7a4b14` | `#e8c48f` |
382
+ | `--kz-diagonal` | the two diagonals of Diagonal Sudoku | `#e9dfc6` | `#34382f` |
383
+ | `--kz-peer` | the chosen cell's row, column and group | `#efe8d8` | `#2f332f` |
384
+ | `--kz-same` | every cell holding the chosen number | `#dcd0f2` | `#433a5c` |
385
+ | `--kz-select` | the chosen cell | `#ffe08a` | `#6b5a1f` |
386
+ | `--kz-hint` | the cell a hint pointed at | `#b9e3c4` | `#25503a` |
387
+ | `--kz-conflict` | a cell that breaks a rule | `#f4b8ad` | `#6e2f26` |
388
+ | `--kz-wrong` | a cell Check flagged | `#f4b8ad` | `#6e2f26` |
389
+ | `--kz-bad` | the number in a cell that breaks a rule | `#b5452c` | `#ff8a6b` |
390
+ | `--kz-good` | a solved puzzle's wash | `#2f7a4f` | `#6fcf97` |
391
+ | `--kz-font` | the numbers' type | the system's own | the same |
392
+
393
+ **The playable board** (`mountKazu` and `<kazu-board>`) wears the drawing's properties, and six of its own on `.kazu-play`:
394
+
395
+ | Property | What it colours | Light | Dark |
396
+ | --- | --- | --- | --- |
397
+ | `--kzp-ink` | text, the number pad's numbers, and a pressed button | `#1f2320` | `#ece8dc` |
398
+ | `--kzp-muted` | the progress count, the erase key and the words under the board | `#6b6f68` | `#a09d93` |
399
+ | `--kzp-rule` | borders | `#ddd6c6` | `#3a3d38` |
400
+ | `--kzp-surface` | the number pad and the buttons | `#fbf8f1` | `#1d201e` |
401
+ | `--kzp-accent` | the focus ring, and a warning in the words under the board | `#b5452c` | `#ff8a6b` |
402
+ | `--kzp-good` | the words and the clock once the puzzle is solved | `#2f7a4f` | `#6fcf97` |
403
+
404
+ ```css
405
+ kazu-board, .kazu, .kazu-play { --kz-select: #ffd23f; --kz-entry: #0b5cad; --kzp-accent: #8a1c1c; }
406
+ ```
407
+
408
+ The demo's own page is the worked example: its green felt and its cloth patches are the family's stylesheet, [`demo/family.css`](./demo/family.css), which is the same file byte for byte in every sibling's demo, and a test holds it to its hash. The parts of the drawing carry classes (`kz-given`, `kz-entry`, `kz-note`, `kz-cage-sum`, `kz-clue`, `kz-mark`, `kz-conflict`, `kz-hit`) for anything a property cannot reach.
409
+
410
+ ## Limits
411
+
412
+ All of these are held by tests, and the ones with a name are exported.
413
+
414
+ | Limit | Value | Where |
415
+ | --- | --- | --- |
416
+ | Puzzles | the six keys of `KAZU_KINDS` | the table under [The puzzles](#the-puzzles) |
417
+ | Levels | `easy`, `medium`, `hard` | `KAZU_LEVELS` |
418
+ | Sizes | each puzzle's own, 4×4 to 16×16 | `KAZU_SPECS[kind].sizes` |
419
+ | A seed | a whole number from 1 to 2,147,483,647 | `KAZU_SEED_MOST`, `isKazuSeed` |
420
+ | Symbols in a grid | `1` to `9`, then `A` to `G` for the 16×16 | `symbolOf`, `valueOfSymbol` |
421
+ | The longest givens code | Sudoku 256 characters, Jigsaw 162, Diagonal 81, Killer Sudoku 286, Futoshiki 133, Skyscrapers 77 | `KAZU_SPECS[kind].mostCells`, for a route that must refuse anything larger |
422
+ | Answers counted | two, so that "many" costs no more than "two" | the `limit` argument of `countKazuSolutions` |
423
+ | The solver's work | 2,000,000 steps, then it says it cannot say (`null`) | the `budget` argument of `solveKazu` |
424
+ | A step log | the newest 400 steps | `KAZU_STEPS_KEPT` |
425
+
426
+ A generator never runs on a server unless you ask it to. The check never searches: it is linear in the size of the grid.
427
+
428
+ ## Browser support
429
+
430
+ Any browser with ES2020 modules, custom elements and CSS `aspect-ratio`: Chrome and Edge 88, Safari 15, Firefox 89, all from 2021 on. The element draws in the page's own DOM, with no shadow DOM and no CSS the page cannot reach. The demo is played in a real Chromium at a phone's width (with touch) and a desk's, and in WebKit, Safari's engine, at a phone's width; Firefox is not in that run. The package itself (everything but the drawing and the page) needs no DOM: it runs in Node 22 or later (CI tests 22 and 24). Deno and Bun are not tested.
431
+
432
+ ## Languages
433
+
434
+ English and Japanese, chosen by the `language` option, the host's `lang` or the page's, and followed when the page's `lang` changes. The demo has a chooser of its own and takes the browser's language on a first visit. The board's words (`KAZU_STRINGS`), each puzzle's names and rules (`KAZU_NAMES`) and the sizes' names are in both. **Japanese: included; not yet reviewed by a native reader. Corrections welcome.** Every string of the board is listed beside its English in [docs/strings-ja.md](./docs/strings-ja.md), and there is an [issue template](https://github.com/johnmorrisdotca/kazu/issues/new?template=fix-a-translation.md) for fixing one. Any other language is a table of your own, passed beside these two.
435
+
436
+ ## Roadmap
437
+
438
+ Not here yet, and each welcome as an [issue](https://github.com/johnmorrisdotca/kazu/issues):
439
+
440
+ - A daily puzzle: a puzzle of the day for each kind and level, from the date, the way [Tane](https://github.com/johnmorrisdotca/tane) makes daily seeds.
441
+ - A command line: make a puzzle, solve a code, check an answer, and print the grid as text.
442
+
443
+ Left out on purpose: a puzzle with more than one answer, and any account, ranking or storage. A page keeps its own runs: `onChange` hands them over.
444
+
445
+ ## Architecture
446
+
447
+ The generators, the solvers, the check, the hint and the game are plain functions over short codes, with no
448
+ DOM. The drawing is SVG text in an entry of its own, so a server that only checks an answer never loads it, and
449
+ the page's part (the mount and the element) is another.
450
+
451
+ ```text
452
+ src/
453
+ ├── index.ts the main entry: everything but the drawing and the page
454
+ ├── kinds.ts the six puzzles' keys, sizes and levels, and the shape of a puzzle
455
+ ├── random.ts the seeded random numbers every puzzle is made from
456
+ ├── cells.ts a grid of numbers as a string, 1 to 9 and A to G
457
+ ├── layout.ts the groups that must each hold every number once: rows, columns, boxes, regions, diagonals, cages
458
+ ├── groupSolve.ts the solver for puzzles made of groups: counting, singles, depth
459
+ ├── numberPlace.ts Sudoku and Diagonal Sudoku: the generator and how givens are carved
460
+ ├── jigsaw.ts Jigsaw Sudoku: irregular regions, their code and the generator
461
+ ├── sumCages.ts Killer Sudoku: cages grown by joining, their code and outline
462
+ ├── moreOrLess.ts Futoshiki: the Latin square, the marks and the generator
463
+ ├── moreOrLessCode.ts Futoshiki's givens as a string
464
+ ├── moreOrLessSolve.ts Futoshiki's solver
465
+ ├── towers.ts Skyscrapers: the generator
466
+ ├── towersCode.ts Skyscrapers' givens as a string, and what a clue sees
467
+ ├── towersSolve.ts Skyscrapers' solver
468
+ ├── generate.ts generateKazu: the one door to every generator
469
+ ├── solve.ts solving, counting and measuring any puzzle from its givens
470
+ ├── givens.ts what a puzzle was printed with, read from its code
471
+ ├── check.ts whether a finished grid is right, in O(cells)
472
+ ├── conflicts.ts the cells that break a rule right now
473
+ ├── hint.ts the next cell a person could fill in, and why
474
+ ├── progress.ts runs, pencil marks and step logs as strings
475
+ ├── game.ts a game in play as pure functions: entries, notes, Undo
476
+ ├── clock.ts a time as a clock shows it
477
+ ├── names.ts each puzzle's names, rules and origin, in English and Japanese
478
+ ├── strings.ts the words a board says, in English and Japanese
479
+ ├── geometry.ts where every cell is in the drawing, and which cell a point is over
480
+ ├── style.ts the drawing's style: its colours as custom properties
481
+ ├── draw.ts a puzzle as SVG text
482
+ ├── draw-entry.ts the "/draw" entry
483
+ ├── playStyle.ts the style of a playable board: its box, pad, buttons and words
484
+ ├── mount.ts mountKazu: draws a puzzle into an element and plays it
485
+ ├── play-entry.ts the "/play" entry
486
+ ├── element.ts the "/element" entry: the <kazu-board> class
487
+ ├── element-define.ts the "/element/define" entry: defines the tag on the page
488
+ └── version.ts the package's version
489
+ ```
490
+
491
+ Tests sit beside the code they test (`*.test.ts`). `src/site.fixture.json` is what itsutsu.com made before the move,
492
+ and six `site.<puzzle>.test.ts` files make it all again. `scripts/` builds the demo and its API reference page, takes the
493
+ README's pictures and checks the package as npm packs it; `demo/` is the playable page, and `e2e/` its browser tests.
494
+
495
+ ## The name
496
+
497
+ *Kazu* (数) is Japanese for "number": the everyday word for a number or an amount, read かず, as in 数を数える
498
+ (*kazu o kazoeru*), to count numbers; its other reading, すう (*sū*), is the one used in mathematics, and 数える
499
+ (*kazoeru*), to count, is the verb that goes with it. It is said in two beats, *ka-zu*. In every puzzle here a
500
+ number is what you write in each cell. ([Wiktionary: 数](https://en.wiktionary.org/wiki/数), which gives かず as
501
+ "number; amount" and かぞえる as "to count".)
502
+
503
+ ## Where it comes from, and where it is used
504
+
505
+ Kazu was built for [Itsutsu](https://itsutsu.com), a site for board games, puzzles, card games and dice games
506
+ played at your own pace. *Itsutsu* (五つ) is Japanese for "five", after five in a row, the game the site began
507
+ with. The site's Numbers family of six puzzles was made there, one by one, each from its own solver and generator
508
+ and each checked on a server in O(cells); once they all stood alone it seemed worth sharing them.
509
+
510
+ ### Used by
511
+
512
+ - [Itsutsu](https://itsutsu.com), for its Numbers puzzles: Sudoku, Jigsaw Sudoku, Diagonal Sudoku, Killer Sudoku, Futoshiki and Skyscrapers.
513
+
514
+ Using Kazu in something? Open an *Add my project* issue and we will add you.
515
+
516
+ ### The family
517
+
518
+ <!-- family:start (made by scripts/family-readme.mjs from scripts/family-template.mjs; change those, not this) -->
519
+ Kazu is one of nineteen packages, each made for the same site, each at
520
+ [github.com/johnmorrisdotca](https://github.com/johnmorrisdotca). The code of every one is MIT.
521
+
522
+ - [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/).
523
+ - [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/).
524
+ - [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/).
525
+ - [Toranpu](https://github.com/johnmorrisdotca/toranpu) (トランプ): a deck of playing cards, card games with computer players, and solitaires. [Demo](https://johnmorrisdotca.github.io/toranpu/).
526
+ - [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/).
527
+ - [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/).
528
+ - [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/).
529
+ - [Kumimoji](https://github.com/johnmorrisdotca/kumimoji) (組み文字): a crossword tile race, in English and Japanese kana. [Demo](https://johnmorrisdotca.github.io/kumimoji/).
530
+ - [Tsunagi](https://github.com/johnmorrisdotca/tsunagi) (繋ぎ): a line-joining logic puzzle whose every level has exactly one answer. [Demo](https://johnmorrisdotca.github.io/tsunagi/).
531
+ - [Jarajara](https://github.com/johnmorrisdotca/jarajara) (ジャラジャラ): mahjong tiles drawn as SVG, stacked layouts, and the matching solitaire Awase. [Demo](https://johnmorrisdotca.github.io/jarajara/).
532
+ - [Suido](https://github.com/johnmorrisdotca/suido) (水道): a pipe puzzle: turn the pieces until the water reaches every drain. [Demo](https://johnmorrisdotca.github.io/suido/).
533
+ - [Domino](https://github.com/johnmorrisdotca/domino) (ドミノ): dominoes and Mexican Train. [Demo](https://johnmorrisdotca.github.io/domino/).
534
+ - [Kotoba](https://github.com/johnmorrisdotca/kotoba) (言葉): word lists and word-game rules in English, French, German and Japanese. [Demo](https://johnmorrisdotca.github.io/kotoba/).
535
+ - [Sugoroku](https://github.com/johnmorrisdotca/sugoroku) (双六): backgammon and its variants, with the doubling cube and match play. [Demo](https://johnmorrisdotca.github.io/sugoroku/).
536
+ - [Kazu](https://github.com/johnmorrisdotca/kazu) (数): grid number puzzles: Sudoku and its variants, Futoshiki and Skyscrapers. [Demo](https://johnmorrisdotca.github.io/kazu/).
537
+ - [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/).
538
+ - [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/).
539
+ - [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/).
540
+ - [Bushu](https://github.com/johnmorrisdotca/bushu) (部首): find a kanji by the parts it is made of. [Demo](https://johnmorrisdotca.github.io/bushu/).
541
+
542
+ **This package is Kazu.** The demos of all nineteen share one header and footer, so each links the rest.
543
+ <!-- family:end -->
544
+
545
+ ## Development
546
+
547
+ ```sh
548
+ pnpm install
549
+ pnpm check # lint, types and every test, every puzzle the site made made again
550
+ pnpm test:package # pack, install and import it as somebody who installed it would
551
+ pnpm test:demo # build the demo and play it in a real browser, at a phone's width and a desk's
552
+ pnpm site # build the demo into site/, as the Pages workflow publishes it
553
+ pnpm pictures # take the README's two pictures from the built demo
554
+ ```
555
+
556
+ ## Contributing
557
+
558
+ See [CONTRIBUTING.md](./CONTRIBUTING.md). The commands are under [Development](#development).
559
+
560
+ Please follow the [code of conduct](./CODE_OF_CONDUCT.md). A way to make the check or the solver run for long, or markup that gets out of the drawing, is for the [security policy](./SECURITY.md), not a public issue.
561
+
562
+ ## Changes
563
+
564
+ See [CHANGELOG.md](./CHANGELOG.md).
565
+
566
+ ## Licence
567
+
568
+ MIT, © John Morris. The puzzles are made in code and the drawing is SVG; there is no sound and no data file but the record of what the site made.