@johnmorrisdotca/kazu 1.1.0 → 1.2.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 (323) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +379 -7
  3. package/dist/akari-draw-entry.d.ts +2 -0
  4. package/dist/akari-draw-entry.js +1 -0
  5. package/dist/akari-entry.d.ts +12 -0
  6. package/dist/akari-entry.js +10 -0
  7. package/dist/akari-play-entry.d.ts +2 -0
  8. package/dist/akari-play-entry.js +1 -0
  9. package/dist/akari.constants.d.ts +2 -0
  10. package/dist/akari.constants.js +2 -0
  11. package/dist/akari.types.d.ts +33 -0
  12. package/dist/akari.types.js +1 -0
  13. package/dist/akariBoard.d.ts +11 -0
  14. package/dist/akariBoard.js +96 -0
  15. package/dist/akariDraw.d.ts +4 -0
  16. package/dist/akariDraw.js +38 -0
  17. package/dist/akariGame.d.ts +15 -0
  18. package/dist/akariGame.js +71 -0
  19. package/dist/akariGenerate.d.ts +7 -0
  20. package/dist/akariGenerate.js +78 -0
  21. package/dist/akariMount.d.ts +3 -0
  22. package/dist/akariMount.js +214 -0
  23. package/dist/akariPlay.types.d.ts +25 -0
  24. package/dist/akariPlay.types.js +1 -0
  25. package/dist/akariSolve.d.ts +6 -0
  26. package/dist/akariSolve.js +106 -0
  27. package/dist/akariStrings.d.ts +98 -0
  28. package/dist/akariStrings.js +53 -0
  29. package/dist/akariStyle.d.ts +1 -0
  30. package/dist/akariStyle.js +9 -0
  31. package/dist/fillomino-draw-entry.d.ts +2 -0
  32. package/dist/fillomino-draw-entry.js +1 -0
  33. package/dist/fillomino-entry.d.ts +8 -0
  34. package/dist/fillomino-entry.js +7 -0
  35. package/dist/fillomino-play-entry.d.ts +4 -0
  36. package/dist/fillomino-play-entry.js +3 -0
  37. package/dist/fillomino.constants.d.ts +5 -0
  38. package/dist/fillomino.constants.js +5 -0
  39. package/dist/fillomino.types.d.ts +30 -0
  40. package/dist/fillomino.types.js +1 -0
  41. package/dist/fillominoBoard.d.ts +6 -0
  42. package/dist/fillominoBoard.js +84 -0
  43. package/dist/fillominoDraw.d.ts +3 -0
  44. package/dist/fillominoDraw.js +31 -0
  45. package/dist/fillominoGame.d.ts +13 -0
  46. package/dist/fillominoGame.js +65 -0
  47. package/dist/fillominoGenerate.d.ts +3 -0
  48. package/dist/fillominoGenerate.js +125 -0
  49. package/dist/fillominoMount.d.ts +2 -0
  50. package/dist/fillominoMount.js +211 -0
  51. package/dist/fillominoPlay.types.d.ts +25 -0
  52. package/dist/fillominoPlay.types.js +1 -0
  53. package/dist/fillominoSolve.d.ts +6 -0
  54. package/dist/fillominoSolve.js +111 -0
  55. package/dist/fillominoStrings.d.ts +102 -0
  56. package/dist/fillominoStrings.js +13 -0
  57. package/dist/fillominoStyle.d.ts +1 -0
  58. package/dist/fillominoStyle.js +13 -0
  59. package/dist/fillominoWorker.d.ts +1 -0
  60. package/dist/fillominoWorker.js +10 -0
  61. package/dist/heyawake-draw-entry.d.ts +2 -0
  62. package/dist/heyawake-draw-entry.js +1 -0
  63. package/dist/heyawake-entry.d.ts +13 -0
  64. package/dist/heyawake-entry.js +11 -0
  65. package/dist/heyawake-play-entry.d.ts +2 -0
  66. package/dist/heyawake-play-entry.js +1 -0
  67. package/dist/heyawake.constants.d.ts +5 -0
  68. package/dist/heyawake.constants.js +5 -0
  69. package/dist/heyawake.types.d.ts +35 -0
  70. package/dist/heyawake.types.js +1 -0
  71. package/dist/heyawakeBoard.d.ts +7 -0
  72. package/dist/heyawakeBoard.js +116 -0
  73. package/dist/heyawakeDraw.d.ts +3 -0
  74. package/dist/heyawakeDraw.js +27 -0
  75. package/dist/heyawakeGame.d.ts +12 -0
  76. package/dist/heyawakeGame.js +51 -0
  77. package/dist/heyawakeGenerate.d.ts +2 -0
  78. package/dist/heyawakeGenerate.js +114 -0
  79. package/dist/heyawakeMount.d.ts +2 -0
  80. package/dist/heyawakeMount.js +106 -0
  81. package/dist/heyawakePlay.types.d.ts +24 -0
  82. package/dist/heyawakePlay.types.js +1 -0
  83. package/dist/heyawakeSolve.d.ts +5 -0
  84. package/dist/heyawakeSolve.js +52 -0
  85. package/dist/heyawakeStrings.d.ts +19 -0
  86. package/dist/heyawakeStrings.js +7 -0
  87. package/dist/heyawakeStyle.d.ts +1 -0
  88. package/dist/heyawakeStyle.js +2 -0
  89. package/dist/heyawakeWorker.d.ts +1 -0
  90. package/dist/heyawakeWorker.js +10 -0
  91. package/dist/hitori-draw-entry.d.ts +2 -0
  92. package/dist/hitori-draw-entry.js +1 -0
  93. package/dist/hitori-entry.d.ts +6 -0
  94. package/dist/hitori-entry.js +6 -0
  95. package/dist/hitori-play-entry.d.ts +4 -0
  96. package/dist/hitori-play-entry.js +3 -0
  97. package/dist/hitori.constants.d.ts +2 -0
  98. package/dist/hitori.constants.js +2 -0
  99. package/dist/hitori.types.d.ts +20 -0
  100. package/dist/hitori.types.js +1 -0
  101. package/dist/hitoriBoard.d.ts +8 -0
  102. package/dist/hitoriBoard.js +72 -0
  103. package/dist/hitoriDraw.d.ts +4 -0
  104. package/dist/hitoriDraw.js +25 -0
  105. package/dist/hitoriGame.d.ts +10 -0
  106. package/dist/hitoriGame.js +48 -0
  107. package/dist/hitoriGenerate.d.ts +3 -0
  108. package/dist/hitoriGenerate.js +163 -0
  109. package/dist/hitoriMount.d.ts +3 -0
  110. package/dist/hitoriMount.js +111 -0
  111. package/dist/hitoriPlay.types.d.ts +25 -0
  112. package/dist/hitoriPlay.types.js +1 -0
  113. package/dist/hitoriSolve.d.ts +6 -0
  114. package/dist/hitoriSolve.js +69 -0
  115. package/dist/hitoriStrings.d.ts +70 -0
  116. package/dist/hitoriStrings.js +17 -0
  117. package/dist/hitoriStyle.d.ts +1 -0
  118. package/dist/hitoriStyle.js +9 -0
  119. package/dist/index.d.ts +11 -0
  120. package/dist/index.js +11 -0
  121. package/dist/juosan-draw-entry.d.ts +2 -0
  122. package/dist/juosan-draw-entry.js +1 -0
  123. package/dist/juosan-entry.d.ts +11 -0
  124. package/dist/juosan-entry.js +10 -0
  125. package/dist/juosan-play-entry.d.ts +4 -0
  126. package/dist/juosan-play-entry.js +3 -0
  127. package/dist/juosan.constants.d.ts +4 -0
  128. package/dist/juosan.constants.js +4 -0
  129. package/dist/juosan.types.d.ts +33 -0
  130. package/dist/juosan.types.js +1 -0
  131. package/dist/juosanBoard.d.ts +7 -0
  132. package/dist/juosanBoard.js +102 -0
  133. package/dist/juosanDraw.d.ts +4 -0
  134. package/dist/juosanDraw.js +49 -0
  135. package/dist/juosanGame.d.ts +20 -0
  136. package/dist/juosanGame.js +86 -0
  137. package/dist/juosanGenerate.d.ts +3 -0
  138. package/dist/juosanGenerate.js +31 -0
  139. package/dist/juosanMount.d.ts +3 -0
  140. package/dist/juosanMount.js +206 -0
  141. package/dist/juosanPlay.types.d.ts +24 -0
  142. package/dist/juosanPlay.types.js +1 -0
  143. package/dist/juosanSolve.d.ts +3 -0
  144. package/dist/juosanSolve.js +82 -0
  145. package/dist/juosanStrings.d.ts +77 -0
  146. package/dist/juosanStrings.js +43 -0
  147. package/dist/juosanStyle.d.ts +1 -0
  148. package/dist/juosanStyle.js +1 -0
  149. package/dist/kakuro-draw-entry.d.ts +2 -0
  150. package/dist/kakuro-draw-entry.js +1 -0
  151. package/dist/kakuro-entry.d.ts +12 -0
  152. package/dist/kakuro-entry.js +10 -0
  153. package/dist/kakuro-play-entry.d.ts +4 -0
  154. package/dist/kakuro-play-entry.js +3 -0
  155. package/dist/kakuro.constants.d.ts +6 -0
  156. package/dist/kakuro.constants.js +6 -0
  157. package/dist/kakuro.types.d.ts +46 -0
  158. package/dist/kakuro.types.js +1 -0
  159. package/dist/kakuroBoard.d.ts +8 -0
  160. package/dist/kakuroBoard.js +117 -0
  161. package/dist/kakuroDraw.d.ts +10 -0
  162. package/dist/kakuroDraw.js +21 -0
  163. package/dist/kakuroGame.d.ts +12 -0
  164. package/dist/kakuroGame.js +74 -0
  165. package/dist/kakuroGenerate.d.ts +3 -0
  166. package/dist/kakuroGenerate.js +130 -0
  167. package/dist/kakuroMount.d.ts +2 -0
  168. package/dist/kakuroMount.js +109 -0
  169. package/dist/kakuroPlay.types.d.ts +20 -0
  170. package/dist/kakuroPlay.types.js +1 -0
  171. package/dist/kakuroSolve.d.ts +6 -0
  172. package/dist/kakuroSolve.js +85 -0
  173. package/dist/kakuroStrings.d.ts +82 -0
  174. package/dist/kakuroStrings.js +5 -0
  175. package/dist/kakuroStyle.d.ts +1 -0
  176. package/dist/kakuroStyle.js +1 -0
  177. package/dist/masyu-draw-entry.d.ts +2 -0
  178. package/dist/masyu-draw-entry.js +1 -0
  179. package/dist/masyu-entry.d.ts +6 -0
  180. package/dist/masyu-entry.js +6 -0
  181. package/dist/masyu-play-entry.d.ts +4 -0
  182. package/dist/masyu-play-entry.js +3 -0
  183. package/dist/masyu.constants.d.ts +2 -0
  184. package/dist/masyu.constants.js +2 -0
  185. package/dist/masyu.types.d.ts +46 -0
  186. package/dist/masyu.types.js +1 -0
  187. package/dist/masyuBoard.d.ts +10 -0
  188. package/dist/masyuBoard.js +88 -0
  189. package/dist/masyuDraw.d.ts +2 -0
  190. package/dist/masyuDraw.js +33 -0
  191. package/dist/masyuGame.d.ts +9 -0
  192. package/dist/masyuGame.js +46 -0
  193. package/dist/masyuGenerate.d.ts +3 -0
  194. package/dist/masyuGenerate.js +56 -0
  195. package/dist/masyuMount.d.ts +2 -0
  196. package/dist/masyuMount.js +118 -0
  197. package/dist/masyuPlay.types.d.ts +1 -0
  198. package/dist/masyuPlay.types.js +1 -0
  199. package/dist/masyuSolve.d.ts +6 -0
  200. package/dist/masyuSolve.js +88 -0
  201. package/dist/masyuStrings.d.ts +28 -0
  202. package/dist/masyuStrings.js +4 -0
  203. package/dist/masyuStyle.d.ts +1 -0
  204. package/dist/masyuStyle.js +11 -0
  205. package/dist/nurikabe-draw-entry.d.ts +2 -0
  206. package/dist/nurikabe-draw-entry.js +1 -0
  207. package/dist/nurikabe-entry.d.ts +6 -0
  208. package/dist/nurikabe-entry.js +6 -0
  209. package/dist/nurikabe-play-entry.d.ts +4 -0
  210. package/dist/nurikabe-play-entry.js +3 -0
  211. package/dist/nurikabe.constants.d.ts +2 -0
  212. package/dist/nurikabe.constants.js +2 -0
  213. package/dist/nurikabe.types.d.ts +20 -0
  214. package/dist/nurikabe.types.js +1 -0
  215. package/dist/nurikabeBoard.d.ts +8 -0
  216. package/dist/nurikabeBoard.js +72 -0
  217. package/dist/nurikabeDraw.d.ts +4 -0
  218. package/dist/nurikabeDraw.js +15 -0
  219. package/dist/nurikabeGame.d.ts +8 -0
  220. package/dist/nurikabeGame.js +40 -0
  221. package/dist/nurikabeGenerate.d.ts +3 -0
  222. package/dist/nurikabeGenerate.js +31 -0
  223. package/dist/nurikabeMount.d.ts +3 -0
  224. package/dist/nurikabeMount.js +99 -0
  225. package/dist/nurikabePlay.types.d.ts +25 -0
  226. package/dist/nurikabePlay.types.js +1 -0
  227. package/dist/nurikabeSolve.d.ts +6 -0
  228. package/dist/nurikabeSolve.js +75 -0
  229. package/dist/nurikabeStrings.d.ts +70 -0
  230. package/dist/nurikabeStrings.js +5 -0
  231. package/dist/nurikabeStyle.d.ts +1 -0
  232. package/dist/nurikabeStyle.js +9 -0
  233. package/dist/ripple-draw-entry.d.ts +2 -0
  234. package/dist/ripple-draw-entry.js +1 -0
  235. package/dist/ripple-entry.d.ts +12 -0
  236. package/dist/ripple-entry.js +11 -0
  237. package/dist/ripple-play-entry.d.ts +4 -0
  238. package/dist/ripple-play-entry.js +3 -0
  239. package/dist/ripple.constants.d.ts +4 -0
  240. package/dist/ripple.constants.js +4 -0
  241. package/dist/ripple.types.d.ts +34 -0
  242. package/dist/ripple.types.js +1 -0
  243. package/dist/rippleBoard.d.ts +7 -0
  244. package/dist/rippleBoard.js +99 -0
  245. package/dist/rippleDraw.d.ts +3 -0
  246. package/dist/rippleDraw.js +32 -0
  247. package/dist/rippleGame.d.ts +13 -0
  248. package/dist/rippleGame.js +85 -0
  249. package/dist/rippleGenerate.d.ts +3 -0
  250. package/dist/rippleGenerate.js +57 -0
  251. package/dist/rippleMount.d.ts +2 -0
  252. package/dist/rippleMount.js +179 -0
  253. package/dist/ripplePlay.types.d.ts +23 -0
  254. package/dist/ripplePlay.types.js +1 -0
  255. package/dist/rippleSolve.d.ts +6 -0
  256. package/dist/rippleSolve.js +83 -0
  257. package/dist/rippleStrings.d.ts +86 -0
  258. package/dist/rippleStrings.js +5 -0
  259. package/dist/rippleStyle.d.ts +1 -0
  260. package/dist/rippleStyle.js +1 -0
  261. package/dist/shikaku-entry.d.ts +1 -0
  262. package/dist/shikaku-entry.js +1 -0
  263. package/dist/shikakuPacks.d.ts +27 -0
  264. package/dist/shikakuPacks.js +26 -0
  265. package/dist/slitherlink-draw-entry.d.ts +2 -0
  266. package/dist/slitherlink-draw-entry.js +1 -0
  267. package/dist/slitherlink-entry.d.ts +11 -0
  268. package/dist/slitherlink-entry.js +9 -0
  269. package/dist/slitherlink-play-entry.d.ts +4 -0
  270. package/dist/slitherlink-play-entry.js +3 -0
  271. package/dist/slitherlink.constants.d.ts +2 -0
  272. package/dist/slitherlink.constants.js +2 -0
  273. package/dist/slitherlink.types.d.ts +34 -0
  274. package/dist/slitherlink.types.js +1 -0
  275. package/dist/slitherlinkBoard.d.ts +12 -0
  276. package/dist/slitherlinkBoard.js +132 -0
  277. package/dist/slitherlinkDraw.d.ts +4 -0
  278. package/dist/slitherlinkDraw.js +51 -0
  279. package/dist/slitherlinkGame.d.ts +8 -0
  280. package/dist/slitherlinkGame.js +63 -0
  281. package/dist/slitherlinkGenerate.d.ts +3 -0
  282. package/dist/slitherlinkGenerate.js +101 -0
  283. package/dist/slitherlinkMount.d.ts +3 -0
  284. package/dist/slitherlinkMount.js +267 -0
  285. package/dist/slitherlinkPlay.types.d.ts +23 -0
  286. package/dist/slitherlinkPlay.types.js +1 -0
  287. package/dist/slitherlinkSolve.d.ts +6 -0
  288. package/dist/slitherlinkSolve.js +127 -0
  289. package/dist/slitherlinkStrings.d.ts +86 -0
  290. package/dist/slitherlinkStrings.js +47 -0
  291. package/dist/slitherlinkStyle.d.ts +1 -0
  292. package/dist/slitherlinkStyle.js +18 -0
  293. package/dist/version.d.ts +1 -1
  294. package/dist/version.js +1 -1
  295. package/dist/yajilin-draw-entry.d.ts +2 -0
  296. package/dist/yajilin-draw-entry.js +1 -0
  297. package/dist/yajilin-entry.d.ts +6 -0
  298. package/dist/yajilin-entry.js +6 -0
  299. package/dist/yajilin-play-entry.d.ts +4 -0
  300. package/dist/yajilin-play-entry.js +3 -0
  301. package/dist/yajilin.constants.d.ts +2 -0
  302. package/dist/yajilin.constants.js +2 -0
  303. package/dist/yajilin.types.d.ts +63 -0
  304. package/dist/yajilin.types.js +1 -0
  305. package/dist/yajilinBoard.d.ts +9 -0
  306. package/dist/yajilinBoard.js +91 -0
  307. package/dist/yajilinDraw.d.ts +2 -0
  308. package/dist/yajilinDraw.js +33 -0
  309. package/dist/yajilinGame.d.ts +15 -0
  310. package/dist/yajilinGame.js +58 -0
  311. package/dist/yajilinGenerate.d.ts +3 -0
  312. package/dist/yajilinGenerate.js +224 -0
  313. package/dist/yajilinMount.d.ts +2 -0
  314. package/dist/yajilinMount.js +162 -0
  315. package/dist/yajilinPlay.types.d.ts +1 -0
  316. package/dist/yajilinPlay.types.js +1 -0
  317. package/dist/yajilinSolve.d.ts +6 -0
  318. package/dist/yajilinSolve.js +82 -0
  319. package/dist/yajilinStrings.d.ts +32 -0
  320. package/dist/yajilinStrings.js +4 -0
  321. package/dist/yajilinStyle.d.ts +1 -0
  322. package/dist/yajilinStyle.js +12 -0
  323. package/package.json +180 -3
@@ -0,0 +1,70 @@
1
+ import type { HitoriLanguage } from "./hitoriPlay.types.ts";
2
+ export declare const HITORI_STRINGS: {
3
+ readonly en: {
4
+ readonly title: "Hitori";
5
+ readonly help: "Tap a cell or press Space to shade it. Shaded cells cannot touch; the remaining numbers must be unique in every row and column, and the unshaded cells must stay connected. Arrow keys move.";
6
+ readonly undo: "Undo";
7
+ readonly hint: "Hint";
8
+ readonly check: "Check";
9
+ readonly restart: "Restart";
10
+ readonly won: "Solved!";
11
+ readonly helped: "Solved with help.";
12
+ readonly bad: "Some rules are broken.";
13
+ readonly good: "No rule errors yet. Keep going.";
14
+ readonly noHint: "No proved hint is available.";
15
+ readonly cell: "Row";
16
+ readonly column: "column";
17
+ readonly shaded: "shaded";
18
+ readonly white: "unshaded";
19
+ };
20
+ readonly ja: {
21
+ readonly title: "ひとりにしてくれ";
22
+ readonly help: "マスを押すかスペースキーで黒くします。黒マスは辺で隣り合えません。白マスの行と列に同じ数字がなく、白マス全体がつながるようにします。矢印キーで移動します。";
23
+ readonly undo: "戻す";
24
+ readonly hint: "ヒント";
25
+ readonly check: "確認";
26
+ readonly restart: "やり直す";
27
+ readonly won: "完成!";
28
+ readonly helped: "ヒントを使って完成。";
29
+ readonly bad: "ルールに合わないところがあります。";
30
+ readonly good: "今のところルール違反はありません。";
31
+ readonly noHint: "確かなヒントはありません。";
32
+ readonly cell: "行";
33
+ readonly column: "列";
34
+ readonly shaded: "黒";
35
+ readonly white: "白";
36
+ };
37
+ };
38
+ export declare function hitoriWords(language?: HitoriLanguage): {
39
+ readonly title: "Hitori";
40
+ readonly help: "Tap a cell or press Space to shade it. Shaded cells cannot touch; the remaining numbers must be unique in every row and column, and the unshaded cells must stay connected. Arrow keys move.";
41
+ readonly undo: "Undo";
42
+ readonly hint: "Hint";
43
+ readonly check: "Check";
44
+ readonly restart: "Restart";
45
+ readonly won: "Solved!";
46
+ readonly helped: "Solved with help.";
47
+ readonly bad: "Some rules are broken.";
48
+ readonly good: "No rule errors yet. Keep going.";
49
+ readonly noHint: "No proved hint is available.";
50
+ readonly cell: "Row";
51
+ readonly column: "column";
52
+ readonly shaded: "shaded";
53
+ readonly white: "unshaded";
54
+ } | {
55
+ readonly title: "ひとりにしてくれ";
56
+ readonly help: "マスを押すかスペースキーで黒くします。黒マスは辺で隣り合えません。白マスの行と列に同じ数字がなく、白マス全体がつながるようにします。矢印キーで移動します。";
57
+ readonly undo: "戻す";
58
+ readonly hint: "ヒント";
59
+ readonly check: "確認";
60
+ readonly restart: "やり直す";
61
+ readonly won: "完成!";
62
+ readonly helped: "ヒントを使って完成。";
63
+ readonly bad: "ルールに合わないところがあります。";
64
+ readonly good: "今のところルール違反はありません。";
65
+ readonly noHint: "確かなヒントはありません。";
66
+ readonly cell: "行";
67
+ readonly column: "列";
68
+ readonly shaded: "黒";
69
+ readonly white: "白";
70
+ };
@@ -0,0 +1,17 @@
1
+ export const HITORI_STRINGS = {
2
+ en: {
3
+ title: "Hitori",
4
+ help: "Tap a cell or press Space to shade it. Shaded cells cannot touch; the remaining numbers must be unique in every row and column, and the unshaded cells must stay connected. Arrow keys move.",
5
+ undo: "Undo", hint: "Hint", check: "Check", restart: "Restart", won: "Solved!", helped: "Solved with help.",
6
+ bad: "Some rules are broken.", good: "No rule errors yet. Keep going.", noHint: "No proved hint is available.",
7
+ cell: "Row", column: "column", shaded: "shaded", white: "unshaded",
8
+ },
9
+ ja: {
10
+ title: "ひとりにしてくれ",
11
+ help: "マスを押すかスペースキーで黒くします。黒マスは辺で隣り合えません。白マスの行と列に同じ数字がなく、白マス全体がつながるようにします。矢印キーで移動します。",
12
+ undo: "戻す", hint: "ヒント", check: "確認", restart: "やり直す", won: "完成!", helped: "ヒントを使って完成。",
13
+ bad: "ルールに合わないところがあります。", good: "今のところルール違反はありません。", noHint: "確かなヒントはありません。",
14
+ cell: "行", column: "列", shaded: "黒", white: "白",
15
+ },
16
+ };
17
+ export function hitoriWords(language = "en") { return HITORI_STRINGS[language]; }
@@ -0,0 +1 @@
1
+ export declare const HITORI_PLAY_STYLE = "\n.kh-root{color:var(--ks-ink,#1f2320);font:16px/1.5 var(--font,system-ui,sans-serif);max-width:680px;margin:auto}\n.kh-board{position:relative;width:100%;min-width:240px;touch-action:manipulation}\n.kh-cells{position:absolute;inset:0;display:grid;padding:2px}\n.kh-cell{background:transparent;border:0;min-width:0;min-height:0;padding:0;cursor:pointer;touch-action:manipulation}\n.kh-cell:focus-visible{outline:3px solid var(--accent,#b5452c);outline-offset:-4px;border-radius:4px}\n.kh-tools{display:flex;flex-wrap:wrap;gap:8px;margin:16px 0}\n.kh-tools button{font:inherit;border:1px solid var(--ks-rule,#ddd6c6);border-radius:999px;min-height:44px;padding:0 14px;background:var(--ks-surface,#fbf8f1);color:var(--ks-ink,#1f2320);cursor:pointer}\n.kh-tools button:disabled{opacity:.45;cursor:default}.kh-status{min-height:1.5em}.kh-help{font-size:14px;opacity:.8}";
@@ -0,0 +1,9 @@
1
+ export const HITORI_PLAY_STYLE = `
2
+ .kh-root{color:var(--ks-ink,#1f2320);font:16px/1.5 var(--font,system-ui,sans-serif);max-width:680px;margin:auto}
3
+ .kh-board{position:relative;width:100%;min-width:240px;touch-action:manipulation}
4
+ .kh-cells{position:absolute;inset:0;display:grid;padding:2px}
5
+ .kh-cell{background:transparent;border:0;min-width:0;min-height:0;padding:0;cursor:pointer;touch-action:manipulation}
6
+ .kh-cell:focus-visible{outline:3px solid var(--accent,#b5452c);outline-offset:-4px;border-radius:4px}
7
+ .kh-tools{display:flex;flex-wrap:wrap;gap:8px;margin:16px 0}
8
+ .kh-tools button{font:inherit;border:1px solid var(--ks-rule,#ddd6c6);border-radius:999px;min-height:44px;padding:0 14px;background:var(--ks-surface,#fbf8f1);color:var(--ks-ink,#1f2320);cursor:pointer}
9
+ .kh-tools button:disabled{opacity:.45;cursor:default}.kh-status{min-height:1.5em}.kh-help{font-size:14px;opacity:.8}`;
package/dist/index.d.ts CHANGED
@@ -35,3 +35,14 @@ export { seededRandom, shuffled, freshKazuSeed, isKazuSeed, KAZU_SEED_MOST } fro
35
35
  export type { Random } from "./random.ts";
36
36
  export { VERSION } from "./version.ts";
37
37
  export * from "./shikaku-entry.ts";
38
+ export * from "./hitori-entry.ts";
39
+ export * from "./nurikabe-entry.ts";
40
+ export * from "./akari-entry.ts";
41
+ export * from "./juosan-entry.ts";
42
+ export * from "./slitherlink-entry.ts";
43
+ export * from "./ripple-entry.ts";
44
+ export * from "./kakuro-entry.ts";
45
+ export * from "./fillomino-entry.ts";
46
+ export * from "./heyawake-entry.ts";
47
+ export * from "./masyu-entry.ts";
48
+ export * from "./yajilin-entry.ts";
package/dist/index.js CHANGED
@@ -30,3 +30,14 @@ export { boxedLayout, boxOf, KAZU_BOXES, neighbours, regionsAreSound } from "./l
30
30
  export { seededRandom, shuffled, freshKazuSeed, isKazuSeed, KAZU_SEED_MOST } from "./random.js";
31
31
  export { VERSION } from "./version.js";
32
32
  export * from "./shikaku-entry.js";
33
+ export * from "./hitori-entry.js";
34
+ export * from "./nurikabe-entry.js";
35
+ export * from "./akari-entry.js";
36
+ export * from "./juosan-entry.js";
37
+ export * from "./slitherlink-entry.js";
38
+ export * from "./ripple-entry.js";
39
+ export * from "./kakuro-entry.js";
40
+ export * from "./fillomino-entry.js";
41
+ export * from "./heyawake-entry.js";
42
+ export * from "./masyu-entry.js";
43
+ export * from "./yajilin-entry.js";
@@ -0,0 +1,2 @@
1
+ export { drawJuosan } from "./juosanDraw.ts";
2
+ export type { JuosanDrawOptions } from "./juosanPlay.types.ts";
@@ -0,0 +1 @@
1
+ export { drawJuosan } from "./juosanDraw.js";
@@ -0,0 +1,11 @@
1
+ export * from "./juosan.types.ts";
2
+ export * from "./juosan.constants.ts";
3
+ export * from "./juosanBoard.ts";
4
+ export * from "./juosanSolve.ts";
5
+ export * from "./juosanGenerate.ts";
6
+ export * from "./juosanGame.ts";
7
+ export { drawJuosan } from "./juosanDraw.ts";
8
+ export { mountJuosan } from "./juosanMount.ts";
9
+ export { JUOSAN_PLAY_STYLE } from "./juosanStyle.ts";
10
+ export { JUOSAN_STRINGS } from "./juosanStrings.ts";
11
+ export type * from "./juosanPlay.types.ts";
@@ -0,0 +1,10 @@
1
+ export * from "./juosan.types.js";
2
+ export * from "./juosan.constants.js";
3
+ export * from "./juosanBoard.js";
4
+ export * from "./juosanSolve.js";
5
+ export * from "./juosanGenerate.js";
6
+ export * from "./juosanGame.js";
7
+ export { drawJuosan } from "./juosanDraw.js";
8
+ export { mountJuosan } from "./juosanMount.js";
9
+ export { JUOSAN_PLAY_STYLE } from "./juosanStyle.js";
10
+ export { JUOSAN_STRINGS } from "./juosanStrings.js";
@@ -0,0 +1,4 @@
1
+ export { mountJuosan } from "./juosanMount.ts";
2
+ export { JUOSAN_PLAY_STYLE } from "./juosanStyle.ts";
3
+ export { JUOSAN_STRINGS } from "./juosanStrings.ts";
4
+ export type * from "./juosanPlay.types.ts";
@@ -0,0 +1,3 @@
1
+ export { mountJuosan } from "./juosanMount.js";
2
+ export { JUOSAN_PLAY_STYLE } from "./juosanStyle.js";
3
+ export { JUOSAN_STRINGS } from "./juosanStrings.js";
@@ -0,0 +1,4 @@
1
+ export declare const JUOSAN_MOST_SIDE = 16;
2
+ export declare const JUOSAN_MOST_NODES = 250000;
3
+ export declare const JUOSAN_MOST_ATTEMPTS = 500;
4
+ export declare const JUOSAN_LEVELS: readonly ["easy", "medium", "hard"];
@@ -0,0 +1,4 @@
1
+ export const JUOSAN_MOST_SIDE = 16;
2
+ export const JUOSAN_MOST_NODES = 250000;
3
+ export const JUOSAN_MOST_ATTEMPTS = 500;
4
+ export const JUOSAN_LEVELS = ["easy", "medium", "hard"];
@@ -0,0 +1,33 @@
1
+ /** A territory is a list of zero-based cell indexes and an absolute orientation difference. */
2
+ export type JuosanTerritory = {
3
+ cells: readonly number[];
4
+ difference: number | null;
5
+ };
6
+ export type JuosanBoard = {
7
+ width: number;
8
+ height: number;
9
+ territories: readonly JuosanTerritory[];
10
+ };
11
+ export type JuosanMark = 0 | 1 | 2;
12
+ export type JuosanLevel = "easy" | "medium" | "hard";
13
+ export type JuosanPuzzle = JuosanBoard & {
14
+ seed: number;
15
+ level: JuosanLevel;
16
+ solution: readonly JuosanMark[];
17
+ };
18
+ export type JuosanCheck = {
19
+ ok: boolean;
20
+ errors: readonly number[];
21
+ };
22
+ export type JuosanSolve = {
23
+ count: number;
24
+ solution: readonly JuosanMark[] | null;
25
+ complete: boolean;
26
+ nodes: number;
27
+ };
28
+ export type JuosanGame = {
29
+ board: JuosanBoard;
30
+ marks: readonly JuosanMark[];
31
+ history: readonly (readonly JuosanMark[])[];
32
+ helped: boolean;
33
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,7 @@
1
+ import type { JuosanBoard, JuosanCheck, JuosanMark } from "./juosan.types.ts";
2
+ /** Whether territories partition a bounded board and each territory is connected. */
3
+ export declare function isJuosanBoard(value: unknown): value is JuosanBoard;
4
+ /** Returns the index of the territory containing a cell, or -1 when absent. */
5
+ export declare function juosanTerritoryAt(board: JuosanBoard, cell: number): number;
6
+ /** Checks public rules directly, independently of the solver and stored answer. */
7
+ export declare function checkJuosan(board: JuosanBoard, marks: readonly JuosanMark[]): JuosanCheck;
@@ -0,0 +1,102 @@
1
+ import { JUOSAN_MOST_SIDE } from "./juosan.constants.js";
2
+ /** Whether territories partition a bounded board and each territory is connected. */
3
+ export function isJuosanBoard(value) {
4
+ if (!value || typeof value !== "object")
5
+ return false;
6
+ const board = value;
7
+ if (!Number.isInteger(board.width) ||
8
+ board.width < 2 ||
9
+ board.width > JUOSAN_MOST_SIDE ||
10
+ !Number.isInteger(board.height) ||
11
+ board.height < 2 ||
12
+ board.height > JUOSAN_MOST_SIDE ||
13
+ !Array.isArray(board.territories)) {
14
+ return false;
15
+ }
16
+ const cellCount = board.width * board.height;
17
+ const occupied = new Set();
18
+ for (const territory of board.territories) {
19
+ if (!territory ||
20
+ !Array.isArray(territory.cells) ||
21
+ territory.cells.length === 0 ||
22
+ !(territory.difference === null ||
23
+ (Number.isInteger(territory.difference) &&
24
+ territory.difference >= 0 &&
25
+ territory.difference <= territory.cells.length))) {
26
+ return false;
27
+ }
28
+ for (const cell of territory.cells) {
29
+ if (!Number.isInteger(cell) ||
30
+ cell < 0 ||
31
+ cell >= cellCount ||
32
+ occupied.has(cell)) {
33
+ return false;
34
+ }
35
+ occupied.add(cell);
36
+ }
37
+ const members = new Set(territory.cells);
38
+ const reached = new Set([territory.cells[0]]);
39
+ const queue = [territory.cells[0]];
40
+ while (queue.length > 0) {
41
+ const cell = queue.pop();
42
+ const x = cell % board.width;
43
+ const y = Math.floor(cell / board.width);
44
+ const neighbors = [
45
+ x > 0 ? cell - 1 : -1,
46
+ x + 1 < board.width ? cell + 1 : -1,
47
+ y > 0 ? cell - board.width : -1,
48
+ y + 1 < board.height ? cell + board.width : -1,
49
+ ];
50
+ for (const neighbor of neighbors) {
51
+ if (members.has(neighbor) && !reached.has(neighbor)) {
52
+ reached.add(neighbor);
53
+ queue.push(neighbor);
54
+ }
55
+ }
56
+ }
57
+ if (reached.size !== members.size)
58
+ return false;
59
+ }
60
+ return occupied.size === cellCount;
61
+ }
62
+ /** Returns the index of the territory containing a cell, or -1 when absent. */
63
+ export function juosanTerritoryAt(board, cell) {
64
+ return board.territories.findIndex(territory => territory.cells.includes(cell));
65
+ }
66
+ /** Checks public rules directly, independently of the solver and stored answer. */
67
+ export function checkJuosan(board, marks) {
68
+ if (!isJuosanBoard(board))
69
+ throw new RangeError("Invalid Juosan board");
70
+ if (!Array.isArray(marks) ||
71
+ marks.length !== board.width * board.height ||
72
+ marks.some(mark => mark !== 1 && mark !== 2)) {
73
+ return { ok: false, errors: [-1] };
74
+ }
75
+ const errors = [];
76
+ board.territories.forEach((territory, index) => {
77
+ if (territory.difference === null)
78
+ return;
79
+ const horizontal = territory.cells.filter(cell => marks[cell] === 1).length;
80
+ const vertical = territory.cells.length - horizontal;
81
+ if (Math.abs(horizontal - vertical) !== territory.difference)
82
+ errors.push(index);
83
+ });
84
+ for (let y = 0; y < board.height; y += 1) {
85
+ for (let x = 0; x < board.width; x += 1) {
86
+ const cell = y * board.width + x;
87
+ if (x + 2 < board.width &&
88
+ marks[cell] === 2 &&
89
+ marks[cell + 1] === 2 &&
90
+ marks[cell + 2] === 2) {
91
+ errors.push(-2);
92
+ }
93
+ if (y + 2 < board.height &&
94
+ marks[cell] === 1 &&
95
+ marks[cell + board.width] === 1 &&
96
+ marks[cell + 2 * board.width] === 1) {
97
+ errors.push(-3);
98
+ }
99
+ }
100
+ }
101
+ return { ok: errors.length === 0, errors: [...new Set(errors)] };
102
+ }
@@ -0,0 +1,4 @@
1
+ import type { JuosanBoard } from "./juosan.types.ts";
2
+ import type { JuosanDrawOptions } from "./juosanPlay.types.ts";
3
+ /** Draws a public Juosan board as an SVG string. */
4
+ export declare function drawJuosan(board: JuosanBoard, options?: JuosanDrawOptions): string;
@@ -0,0 +1,49 @@
1
+ import { isJuosanBoard } from "./juosanBoard.js";
2
+ import { juosanWords } from "./juosanStrings.js";
3
+ /** Draws a public Juosan board as an SVG string. */
4
+ export function drawJuosan(board, options = {}) {
5
+ if (!isJuosanBoard(board))
6
+ throw new RangeError("Invalid Juosan board");
7
+ const cellSize = 48;
8
+ const words = juosanWords(options.language);
9
+ const palettes = {
10
+ ivory: ["var(--kz-paper,#fbf8f1)", "var(--kz-ink,#1f2320)", "var(--kz-grid,#cfc6b2)"],
11
+ wood: ["#e5cda6", "#493e2f", "#bca582"],
12
+ slate: ["#262a27", "#ece8dc", "#454a44"],
13
+ };
14
+ const [paper, ink, grid] = palettes[options.material ?? "ivory"];
15
+ const territoryByCell = Array(board.width * board.height).fill(-1);
16
+ board.territories.forEach((territory, index) => {
17
+ territory.cells.forEach(cell => {
18
+ territoryByCell[cell] = index;
19
+ });
20
+ });
21
+ const cells = territoryByCell.map((territoryIndex, cell) => {
22
+ const x = (cell % board.width) * cellSize;
23
+ const y = Math.floor(cell / board.width) * cellSize;
24
+ const territory = board.territories[territoryIndex];
25
+ const mark = options.marks?.[cell] ?? 0;
26
+ const selected = options.selected === cell;
27
+ const tile = options.pieces === "tiles"
28
+ ? `<rect x="${x + 10}" y="${y + 10}" width="28" height="28" rx="6" fill="${paper}" stroke="${grid}"/>`
29
+ : "";
30
+ const glyph = mark === 1 ? "—" : mark === 2 ? "|" : "";
31
+ const clue = territory.cells[0] === cell && territory.difference !== null
32
+ ? `<text x="${x + 5}" y="${y + 13}" fill="${ink}" font-size="10" font-weight="700" font-family="system-ui,sans-serif">${territory.difference}</text>`
33
+ : "";
34
+ const right = cell % board.width + 1 < board.width
35
+ ? territoryByCell[cell + 1]
36
+ : -1;
37
+ const below = cell + board.width < territoryByCell.length
38
+ ? territoryByCell[cell + board.width]
39
+ : -1;
40
+ const rightEdge = right !== territoryIndex
41
+ ? `<path d="M${x + cellSize} ${y}v${cellSize}" stroke="${ink}" stroke-width="3"/>`
42
+ : "";
43
+ const bottomEdge = below !== territoryIndex
44
+ ? `<path d="M${x} ${y + cellSize}h${cellSize}" stroke="${ink}" stroke-width="3"/>`
45
+ : "";
46
+ return `<g data-juosan-cell="${cell}"><rect x="${x}" y="${y}" width="${cellSize}" height="${cellSize}" fill="${selected ? ink : "transparent"}" fill-opacity="${selected ? ".12" : "1"}" stroke="${grid}" stroke-width="1"/>${tile}${clue}<text x="${x + 24}" y="${y + 27}" dominant-baseline="middle" text-anchor="middle" fill="${ink}" font-size="29" font-weight="700" font-family="system-ui,sans-serif">${glyph}</text>${rightEdge}${bottomEdge}</g>`;
47
+ }).join("");
48
+ return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="-2 -2 ${board.width * cellSize + 4} ${board.height * cellSize + 4}" role="img" aria-label="${words.title}" style="display:block;width:100%;height:auto;background:${paper}">${cells}<rect width="${board.width * cellSize}" height="${board.height * cellSize}" fill="none" stroke="var(--kz-frame,#a98954)" stroke-width="2"/></svg>`;
49
+ }
@@ -0,0 +1,20 @@
1
+ import type { JuosanBoard, JuosanGame, JuosanMark } from "./juosan.types.ts";
2
+ /** Starts a game with a copy of its public board and no generated answer. */
3
+ export declare function newJuosan(board: JuosanBoard): JuosanGame;
4
+ /** Writes a mark and records the previous state; invalid or unchanged moves are ignored. */
5
+ export declare function setJuosanMark(game: JuosanGame, cell: number, mark: JuosanMark): JuosanGame;
6
+ /** Restores the preceding mark state, if one exists. */
7
+ export declare function undoJuosan(game: JuosanGame): JuosanGame;
8
+ /** Clears the board while retaining whether the player used a hint. */
9
+ export declare function restartJuosan(game: JuosanGame): JuosanGame;
10
+ /** Whether every cell is filled and the independent checker accepts the board. */
11
+ export declare function juosanFinished(game: JuosanGame): boolean;
12
+ /** Returns one next mark only when the public clues prove a unique answer. */
13
+ export declare function hintJuosan(game: JuosanGame): {
14
+ cell: number;
15
+ mark: JuosanMark;
16
+ } | null;
17
+ /** Serializes public clues, placements, and assisted status. */
18
+ export declare function encodeJuosan(game: JuosanGame): string;
19
+ /** Reads a bounded public save; malformed or incompatible data returns null. */
20
+ export declare function decodeJuosan(code: string): JuosanGame | null;
@@ -0,0 +1,86 @@
1
+ import { checkJuosan, isJuosanBoard } from "./juosanBoard.js";
2
+ import { solveJuosan } from "./juosanSolve.js";
3
+ /** Starts a game with a copy of its public board and no generated answer. */
4
+ export function newJuosan(board) {
5
+ if (!isJuosanBoard(board))
6
+ throw new RangeError("Invalid Juosan board");
7
+ return {
8
+ board: {
9
+ width: board.width,
10
+ height: board.height,
11
+ territories: board.territories.map(territory => ({
12
+ cells: [...territory.cells],
13
+ difference: territory.difference,
14
+ })),
15
+ },
16
+ marks: Array(board.width * board.height).fill(0),
17
+ history: [],
18
+ helped: false,
19
+ };
20
+ }
21
+ /** Writes a mark and records the previous state; invalid or unchanged moves are ignored. */
22
+ export function setJuosanMark(game, cell, mark) {
23
+ if (!Number.isInteger(cell) ||
24
+ cell < 0 ||
25
+ cell >= game.marks.length ||
26
+ (mark !== 1 && mark !== 2) ||
27
+ game.marks[cell] === mark) {
28
+ return game;
29
+ }
30
+ const marks = [...game.marks];
31
+ marks[cell] = mark;
32
+ return { ...game, marks, history: [...game.history, [...game.marks]] };
33
+ }
34
+ /** Restores the preceding mark state, if one exists. */
35
+ export function undoJuosan(game) {
36
+ const previous = game.history.at(-1);
37
+ return previous
38
+ ? { ...game, marks: [...previous], history: game.history.slice(0, -1) }
39
+ : game;
40
+ }
41
+ /** Clears the board while retaining whether the player used a hint. */
42
+ export function restartJuosan(game) {
43
+ return { ...newJuosan(game.board), helped: game.helped };
44
+ }
45
+ /** Whether every cell is filled and the independent checker accepts the board. */
46
+ export function juosanFinished(game) {
47
+ return (game.marks.every(mark => mark !== 0) &&
48
+ checkJuosan(game.board, game.marks).ok);
49
+ }
50
+ /** Returns one next mark only when the public clues prove a unique answer. */
51
+ export function hintJuosan(game) {
52
+ const counted = solveJuosan(game.board, 2);
53
+ if (!counted.complete || counted.count !== 1 || !counted.solution)
54
+ return null;
55
+ const cell = game.marks.findIndex((mark, index) => mark !== counted.solution[index]);
56
+ return cell < 0 ? null : { cell, mark: counted.solution[cell] };
57
+ }
58
+ /** Serializes public clues, placements, and assisted status. */
59
+ export function encodeJuosan(game) {
60
+ return JSON.stringify({
61
+ version: 1,
62
+ board: game.board,
63
+ marks: game.marks,
64
+ helped: game.helped,
65
+ });
66
+ }
67
+ /** Reads a bounded public save; malformed or incompatible data returns null. */
68
+ export function decodeJuosan(code) {
69
+ try {
70
+ if (code.length > 40000)
71
+ return null;
72
+ const value = JSON.parse(code);
73
+ if (value.version !== 1 ||
74
+ !isJuosanBoard(value.board) ||
75
+ !Array.isArray(value.marks) ||
76
+ value.marks.length !== value.board.width * value.board.height ||
77
+ value.marks.some((mark) => mark !== 0 && mark !== 1 && mark !== 2) ||
78
+ typeof value.helped !== "boolean") {
79
+ return null;
80
+ }
81
+ return { ...newJuosan(value.board), marks: [...value.marks], helped: value.helped };
82
+ }
83
+ catch {
84
+ return null;
85
+ }
86
+ }
@@ -0,0 +1,3 @@
1
+ import type { JuosanLevel, JuosanPuzzle } from "./juosan.types.ts";
2
+ /** Makes an original small training puzzle and returns it only after uniqueness is proved. */
3
+ export declare function generateJuosan(width?: number, height?: number, level?: JuosanLevel, seed?: number): JuosanPuzzle;
@@ -0,0 +1,31 @@
1
+ import { JUOSAN_LEVELS, JUOSAN_MOST_NODES } from "./juosan.constants.js";
2
+ import { isJuosanBoard } from "./juosanBoard.js";
3
+ import { solveJuosan } from "./juosanSolve.js";
4
+ import { isKazuSeed } from "./random.js";
5
+ /** Makes an original small training puzzle and returns it only after uniqueness is proved. */
6
+ export function generateJuosan(width = 3, height = 2, level = "medium", seed = 1) {
7
+ const supported = (width === 3 && height === 2) || (width === 2 && height === 3);
8
+ if (!isKazuSeed(seed) || !JUOSAN_LEVELS.includes(level) || !supported) {
9
+ throw new RangeError("Juosan generation currently supports 3 × 2 and 2 × 3 boards");
10
+ }
11
+ const mark = width > height ? 1 : 2;
12
+ const territories = makeTrainingTerritories(width, height, seed);
13
+ const board = { width, height, territories };
14
+ if (!isJuosanBoard(board))
15
+ throw new RangeError("Invalid Juosan board");
16
+ const counted = solveJuosan(board, 2, JUOSAN_MOST_NODES);
17
+ if (!counted.complete ||
18
+ counted.count !== 1 ||
19
+ !counted.solution ||
20
+ counted.solution.some(value => value !== mark)) {
21
+ throw new Error("The generated Juosan did not pass its uniqueness proof");
22
+ }
23
+ return { ...board, seed, level, solution: counted.solution };
24
+ }
25
+ function makeTrainingTerritories(width, height, seed) {
26
+ const split = seed % 2 === 0;
27
+ const cells = width > height
28
+ ? (split ? [[0, 1, 2], [3, 4, 5]] : [[0, 1, 2, 3, 4, 5]])
29
+ : (split ? [[0, 2, 4], [1, 3, 5]] : [[0, 1, 2, 3, 4, 5]]);
30
+ return cells.map(group => ({ cells: group, difference: group.length }));
31
+ }
@@ -0,0 +1,3 @@
1
+ import type { JuosanMount, JuosanMountOptions } from "./juosanPlay.types.ts";
2
+ /** Mounts a touch, mouse, and keyboard player into an existing page element. */
3
+ export declare function mountJuosan(host: HTMLElement, initial: JuosanMountOptions): JuosanMount;