@johnmorrisdotca/kazu 1.1.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (372) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/README.md +424 -10
  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 +13 -0
  6. package/dist/akari-entry.js +11 -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 +7 -0
  10. package/dist/akari.constants.js +7 -0
  11. package/dist/akari.types.d.ts +52 -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 +10 -0
  20. package/dist/akariGenerate.js +101 -0
  21. package/dist/akariLogic.d.ts +10 -0
  22. package/dist/akariLogic.js +84 -0
  23. package/dist/akariMount.d.ts +3 -0
  24. package/dist/akariMount.js +214 -0
  25. package/dist/akariPlay.types.d.ts +25 -0
  26. package/dist/akariPlay.types.js +1 -0
  27. package/dist/akariRate.d.ts +6 -0
  28. package/dist/akariRate.js +34 -0
  29. package/dist/akariSolve.d.ts +6 -0
  30. package/dist/akariSolve.js +18 -0
  31. package/dist/akariStrings.d.ts +98 -0
  32. package/dist/akariStrings.js +53 -0
  33. package/dist/akariStyle.d.ts +1 -0
  34. package/dist/akariStyle.js +9 -0
  35. package/dist/akariTemplate.d.ts +7 -0
  36. package/dist/akariTemplate.js +78 -0
  37. package/dist/csp.d.ts +63 -0
  38. package/dist/csp.js +162 -0
  39. package/dist/fillomino-draw-entry.d.ts +2 -0
  40. package/dist/fillomino-draw-entry.js +1 -0
  41. package/dist/fillomino-entry.d.ts +9 -0
  42. package/dist/fillomino-entry.js +8 -0
  43. package/dist/fillomino-play-entry.d.ts +4 -0
  44. package/dist/fillomino-play-entry.js +3 -0
  45. package/dist/fillomino.constants.d.ts +9 -0
  46. package/dist/fillomino.constants.js +9 -0
  47. package/dist/fillomino.types.d.ts +47 -0
  48. package/dist/fillomino.types.js +1 -0
  49. package/dist/fillominoBoard.d.ts +6 -0
  50. package/dist/fillominoBoard.js +84 -0
  51. package/dist/fillominoBuild.d.ts +10 -0
  52. package/dist/fillominoBuild.js +78 -0
  53. package/dist/fillominoDraw.d.ts +3 -0
  54. package/dist/fillominoDraw.js +31 -0
  55. package/dist/fillominoGame.d.ts +13 -0
  56. package/dist/fillominoGame.js +65 -0
  57. package/dist/fillominoGenerate.d.ts +9 -0
  58. package/dist/fillominoGenerate.js +93 -0
  59. package/dist/fillominoLogic.d.ts +14 -0
  60. package/dist/fillominoLogic.js +177 -0
  61. package/dist/fillominoMount.d.ts +2 -0
  62. package/dist/fillominoMount.js +214 -0
  63. package/dist/fillominoPlay.types.d.ts +25 -0
  64. package/dist/fillominoPlay.types.js +1 -0
  65. package/dist/fillominoRate.d.ts +3 -0
  66. package/dist/fillominoRate.js +57 -0
  67. package/dist/fillominoSolve.d.ts +6 -0
  68. package/dist/fillominoSolve.js +38 -0
  69. package/dist/fillominoStrings.d.ts +102 -0
  70. package/dist/fillominoStrings.js +13 -0
  71. package/dist/fillominoStyle.d.ts +1 -0
  72. package/dist/fillominoStyle.js +13 -0
  73. package/dist/fillominoWorker.d.ts +1 -0
  74. package/dist/fillominoWorker.js +10 -0
  75. package/dist/heyawake-draw-entry.d.ts +2 -0
  76. package/dist/heyawake-draw-entry.js +1 -0
  77. package/dist/heyawake-entry.d.ts +13 -0
  78. package/dist/heyawake-entry.js +11 -0
  79. package/dist/heyawake-play-entry.d.ts +2 -0
  80. package/dist/heyawake-play-entry.js +1 -0
  81. package/dist/heyawake.constants.d.ts +5 -0
  82. package/dist/heyawake.constants.js +5 -0
  83. package/dist/heyawake.types.d.ts +35 -0
  84. package/dist/heyawake.types.js +1 -0
  85. package/dist/heyawakeBoard.d.ts +7 -0
  86. package/dist/heyawakeBoard.js +116 -0
  87. package/dist/heyawakeDraw.d.ts +3 -0
  88. package/dist/heyawakeDraw.js +27 -0
  89. package/dist/heyawakeGame.d.ts +12 -0
  90. package/dist/heyawakeGame.js +51 -0
  91. package/dist/heyawakeGenerate.d.ts +2 -0
  92. package/dist/heyawakeGenerate.js +114 -0
  93. package/dist/heyawakeMount.d.ts +2 -0
  94. package/dist/heyawakeMount.js +106 -0
  95. package/dist/heyawakePlay.types.d.ts +24 -0
  96. package/dist/heyawakePlay.types.js +1 -0
  97. package/dist/heyawakeSolve.d.ts +5 -0
  98. package/dist/heyawakeSolve.js +52 -0
  99. package/dist/heyawakeStrings.d.ts +19 -0
  100. package/dist/heyawakeStrings.js +7 -0
  101. package/dist/heyawakeStyle.d.ts +1 -0
  102. package/dist/heyawakeStyle.js +2 -0
  103. package/dist/heyawakeWorker.d.ts +1 -0
  104. package/dist/heyawakeWorker.js +10 -0
  105. package/dist/hitori-draw-entry.d.ts +2 -0
  106. package/dist/hitori-draw-entry.js +1 -0
  107. package/dist/hitori-entry.d.ts +7 -0
  108. package/dist/hitori-entry.js +7 -0
  109. package/dist/hitori-play-entry.d.ts +4 -0
  110. package/dist/hitori-play-entry.js +3 -0
  111. package/dist/hitori.constants.d.ts +8 -0
  112. package/dist/hitori.constants.js +8 -0
  113. package/dist/hitori.types.d.ts +37 -0
  114. package/dist/hitori.types.js +1 -0
  115. package/dist/hitoriBoard.d.ts +8 -0
  116. package/dist/hitoriBoard.js +73 -0
  117. package/dist/hitoriBuild.d.ts +12 -0
  118. package/dist/hitoriBuild.js +117 -0
  119. package/dist/hitoriDraw.d.ts +4 -0
  120. package/dist/hitoriDraw.js +25 -0
  121. package/dist/hitoriGame.d.ts +10 -0
  122. package/dist/hitoriGame.js +48 -0
  123. package/dist/hitoriGenerate.d.ts +10 -0
  124. package/dist/hitoriGenerate.js +65 -0
  125. package/dist/hitoriLogic.d.ts +12 -0
  126. package/dist/hitoriLogic.js +189 -0
  127. package/dist/hitoriMount.d.ts +3 -0
  128. package/dist/hitoriMount.js +111 -0
  129. package/dist/hitoriPlay.types.d.ts +25 -0
  130. package/dist/hitoriPlay.types.js +1 -0
  131. package/dist/hitoriRate.d.ts +3 -0
  132. package/dist/hitoriRate.js +32 -0
  133. package/dist/hitoriSolve.d.ts +9 -0
  134. package/dist/hitoriSolve.js +18 -0
  135. package/dist/hitoriStrings.d.ts +70 -0
  136. package/dist/hitoriStrings.js +17 -0
  137. package/dist/hitoriStyle.d.ts +1 -0
  138. package/dist/hitoriStyle.js +9 -0
  139. package/dist/index.d.ts +11 -0
  140. package/dist/index.js +11 -0
  141. package/dist/juosan-draw-entry.d.ts +2 -0
  142. package/dist/juosan-draw-entry.js +1 -0
  143. package/dist/juosan-entry.d.ts +11 -0
  144. package/dist/juosan-entry.js +10 -0
  145. package/dist/juosan-play-entry.d.ts +4 -0
  146. package/dist/juosan-play-entry.js +3 -0
  147. package/dist/juosan.constants.d.ts +4 -0
  148. package/dist/juosan.constants.js +4 -0
  149. package/dist/juosan.types.d.ts +33 -0
  150. package/dist/juosan.types.js +1 -0
  151. package/dist/juosanBoard.d.ts +7 -0
  152. package/dist/juosanBoard.js +102 -0
  153. package/dist/juosanDraw.d.ts +4 -0
  154. package/dist/juosanDraw.js +49 -0
  155. package/dist/juosanGame.d.ts +20 -0
  156. package/dist/juosanGame.js +86 -0
  157. package/dist/juosanGenerate.d.ts +3 -0
  158. package/dist/juosanGenerate.js +31 -0
  159. package/dist/juosanMount.d.ts +3 -0
  160. package/dist/juosanMount.js +206 -0
  161. package/dist/juosanPlay.types.d.ts +24 -0
  162. package/dist/juosanPlay.types.js +1 -0
  163. package/dist/juosanSolve.d.ts +3 -0
  164. package/dist/juosanSolve.js +82 -0
  165. package/dist/juosanStrings.d.ts +77 -0
  166. package/dist/juosanStrings.js +43 -0
  167. package/dist/juosanStyle.d.ts +1 -0
  168. package/dist/juosanStyle.js +1 -0
  169. package/dist/kakuro-draw-entry.d.ts +2 -0
  170. package/dist/kakuro-draw-entry.js +1 -0
  171. package/dist/kakuro-entry.d.ts +13 -0
  172. package/dist/kakuro-entry.js +11 -0
  173. package/dist/kakuro-play-entry.d.ts +4 -0
  174. package/dist/kakuro-play-entry.js +3 -0
  175. package/dist/kakuro.constants.d.ts +11 -0
  176. package/dist/kakuro.constants.js +11 -0
  177. package/dist/kakuro.types.d.ts +65 -0
  178. package/dist/kakuro.types.js +1 -0
  179. package/dist/kakuroBoard.d.ts +8 -0
  180. package/dist/kakuroBoard.js +117 -0
  181. package/dist/kakuroBuild.d.ts +30 -0
  182. package/dist/kakuroBuild.js +337 -0
  183. package/dist/kakuroDraw.d.ts +10 -0
  184. package/dist/kakuroDraw.js +21 -0
  185. package/dist/kakuroGame.d.ts +12 -0
  186. package/dist/kakuroGame.js +74 -0
  187. package/dist/kakuroGenerate.d.ts +10 -0
  188. package/dist/kakuroGenerate.js +62 -0
  189. package/dist/kakuroLogic.d.ts +13 -0
  190. package/dist/kakuroLogic.js +153 -0
  191. package/dist/kakuroMount.d.ts +2 -0
  192. package/dist/kakuroMount.js +109 -0
  193. package/dist/kakuroPlay.types.d.ts +20 -0
  194. package/dist/kakuroPlay.types.js +1 -0
  195. package/dist/kakuroRate.d.ts +3 -0
  196. package/dist/kakuroRate.js +40 -0
  197. package/dist/kakuroSolve.d.ts +6 -0
  198. package/dist/kakuroSolve.js +33 -0
  199. package/dist/kakuroStrings.d.ts +82 -0
  200. package/dist/kakuroStrings.js +5 -0
  201. package/dist/kakuroStyle.d.ts +1 -0
  202. package/dist/kakuroStyle.js +1 -0
  203. package/dist/kakuroTemplate.d.ts +3 -0
  204. package/dist/kakuroTemplate.js +130 -0
  205. package/dist/masyu-draw-entry.d.ts +2 -0
  206. package/dist/masyu-draw-entry.js +1 -0
  207. package/dist/masyu-entry.d.ts +6 -0
  208. package/dist/masyu-entry.js +6 -0
  209. package/dist/masyu-play-entry.d.ts +4 -0
  210. package/dist/masyu-play-entry.js +3 -0
  211. package/dist/masyu.constants.d.ts +2 -0
  212. package/dist/masyu.constants.js +2 -0
  213. package/dist/masyu.types.d.ts +46 -0
  214. package/dist/masyu.types.js +1 -0
  215. package/dist/masyuBoard.d.ts +10 -0
  216. package/dist/masyuBoard.js +88 -0
  217. package/dist/masyuDraw.d.ts +2 -0
  218. package/dist/masyuDraw.js +33 -0
  219. package/dist/masyuGame.d.ts +9 -0
  220. package/dist/masyuGame.js +46 -0
  221. package/dist/masyuGenerate.d.ts +3 -0
  222. package/dist/masyuGenerate.js +56 -0
  223. package/dist/masyuMount.d.ts +2 -0
  224. package/dist/masyuMount.js +118 -0
  225. package/dist/masyuPlay.types.d.ts +1 -0
  226. package/dist/masyuPlay.types.js +1 -0
  227. package/dist/masyuSolve.d.ts +6 -0
  228. package/dist/masyuSolve.js +88 -0
  229. package/dist/masyuStrings.d.ts +28 -0
  230. package/dist/masyuStrings.js +4 -0
  231. package/dist/masyuStyle.d.ts +1 -0
  232. package/dist/masyuStyle.js +11 -0
  233. package/dist/nurikabe-draw-entry.d.ts +2 -0
  234. package/dist/nurikabe-draw-entry.js +1 -0
  235. package/dist/nurikabe-entry.d.ts +6 -0
  236. package/dist/nurikabe-entry.js +6 -0
  237. package/dist/nurikabe-play-entry.d.ts +4 -0
  238. package/dist/nurikabe-play-entry.js +3 -0
  239. package/dist/nurikabe.constants.d.ts +2 -0
  240. package/dist/nurikabe.constants.js +2 -0
  241. package/dist/nurikabe.types.d.ts +20 -0
  242. package/dist/nurikabe.types.js +1 -0
  243. package/dist/nurikabeBoard.d.ts +8 -0
  244. package/dist/nurikabeBoard.js +72 -0
  245. package/dist/nurikabeDraw.d.ts +4 -0
  246. package/dist/nurikabeDraw.js +15 -0
  247. package/dist/nurikabeGame.d.ts +8 -0
  248. package/dist/nurikabeGame.js +40 -0
  249. package/dist/nurikabeGenerate.d.ts +3 -0
  250. package/dist/nurikabeGenerate.js +31 -0
  251. package/dist/nurikabeMount.d.ts +3 -0
  252. package/dist/nurikabeMount.js +99 -0
  253. package/dist/nurikabePlay.types.d.ts +25 -0
  254. package/dist/nurikabePlay.types.js +1 -0
  255. package/dist/nurikabeSolve.d.ts +6 -0
  256. package/dist/nurikabeSolve.js +75 -0
  257. package/dist/nurikabeStrings.d.ts +70 -0
  258. package/dist/nurikabeStrings.js +5 -0
  259. package/dist/nurikabeStyle.d.ts +1 -0
  260. package/dist/nurikabeStyle.js +9 -0
  261. package/dist/ripple-draw-entry.d.ts +2 -0
  262. package/dist/ripple-draw-entry.js +1 -0
  263. package/dist/ripple-entry.d.ts +12 -0
  264. package/dist/ripple-entry.js +11 -0
  265. package/dist/ripple-play-entry.d.ts +4 -0
  266. package/dist/ripple-play-entry.js +3 -0
  267. package/dist/ripple.constants.d.ts +4 -0
  268. package/dist/ripple.constants.js +4 -0
  269. package/dist/ripple.types.d.ts +34 -0
  270. package/dist/ripple.types.js +1 -0
  271. package/dist/rippleBoard.d.ts +7 -0
  272. package/dist/rippleBoard.js +99 -0
  273. package/dist/rippleDraw.d.ts +3 -0
  274. package/dist/rippleDraw.js +32 -0
  275. package/dist/rippleGame.d.ts +13 -0
  276. package/dist/rippleGame.js +85 -0
  277. package/dist/rippleGenerate.d.ts +3 -0
  278. package/dist/rippleGenerate.js +57 -0
  279. package/dist/rippleMount.d.ts +2 -0
  280. package/dist/rippleMount.js +179 -0
  281. package/dist/ripplePlay.types.d.ts +23 -0
  282. package/dist/ripplePlay.types.js +1 -0
  283. package/dist/rippleSolve.d.ts +6 -0
  284. package/dist/rippleSolve.js +83 -0
  285. package/dist/rippleStrings.d.ts +86 -0
  286. package/dist/rippleStrings.js +5 -0
  287. package/dist/rippleStyle.d.ts +1 -0
  288. package/dist/rippleStyle.js +1 -0
  289. package/dist/shikaku-entry.d.ts +2 -0
  290. package/dist/shikaku-entry.js +2 -0
  291. package/dist/shikaku.constants.d.ts +5 -2
  292. package/dist/shikaku.constants.js +5 -2
  293. package/dist/shikaku.types.d.ts +18 -1
  294. package/dist/shikakuBuild.d.ts +21 -0
  295. package/dist/shikakuBuild.js +135 -0
  296. package/dist/shikakuGenerate.d.ts +6 -1
  297. package/dist/shikakuGenerate.js +50 -35
  298. package/dist/shikakuLogic.d.ts +13 -0
  299. package/dist/shikakuLogic.js +84 -0
  300. package/dist/shikakuPacks.d.ts +27 -0
  301. package/dist/shikakuPacks.js +26 -0
  302. package/dist/shikakuRate.d.ts +3 -0
  303. package/dist/shikakuRate.js +27 -0
  304. package/dist/shikakuSolve.d.ts +1 -1
  305. package/dist/shikakuSolve.js +23 -44
  306. package/dist/shikakuTemplate.d.ts +3 -0
  307. package/dist/shikakuTemplate.js +43 -0
  308. package/dist/slitherlink-draw-entry.d.ts +2 -0
  309. package/dist/slitherlink-draw-entry.js +1 -0
  310. package/dist/slitherlink-entry.d.ts +12 -0
  311. package/dist/slitherlink-entry.js +10 -0
  312. package/dist/slitherlink-play-entry.d.ts +4 -0
  313. package/dist/slitherlink-play-entry.js +3 -0
  314. package/dist/slitherlink.constants.d.ts +7 -0
  315. package/dist/slitherlink.constants.js +7 -0
  316. package/dist/slitherlink.types.d.ts +52 -0
  317. package/dist/slitherlink.types.js +1 -0
  318. package/dist/slitherlinkBoard.d.ts +12 -0
  319. package/dist/slitherlinkBoard.js +132 -0
  320. package/dist/slitherlinkDraw.d.ts +4 -0
  321. package/dist/slitherlinkDraw.js +51 -0
  322. package/dist/slitherlinkGame.d.ts +8 -0
  323. package/dist/slitherlinkGame.js +63 -0
  324. package/dist/slitherlinkGenerate.d.ts +10 -0
  325. package/dist/slitherlinkGenerate.js +182 -0
  326. package/dist/slitherlinkLogic.d.ts +10 -0
  327. package/dist/slitherlinkLogic.js +267 -0
  328. package/dist/slitherlinkMount.d.ts +3 -0
  329. package/dist/slitherlinkMount.js +267 -0
  330. package/dist/slitherlinkPlay.types.d.ts +23 -0
  331. package/dist/slitherlinkPlay.types.js +1 -0
  332. package/dist/slitherlinkRate.d.ts +3 -0
  333. package/dist/slitherlinkRate.js +26 -0
  334. package/dist/slitherlinkSolve.d.ts +6 -0
  335. package/dist/slitherlinkSolve.js +19 -0
  336. package/dist/slitherlinkStrings.d.ts +86 -0
  337. package/dist/slitherlinkStrings.js +47 -0
  338. package/dist/slitherlinkStyle.d.ts +1 -0
  339. package/dist/slitherlinkStyle.js +18 -0
  340. package/dist/slitherlinkTemplate.d.ts +3 -0
  341. package/dist/slitherlinkTemplate.js +101 -0
  342. package/dist/version.d.ts +1 -1
  343. package/dist/version.js +1 -1
  344. package/dist/yajilin-draw-entry.d.ts +2 -0
  345. package/dist/yajilin-draw-entry.js +1 -0
  346. package/dist/yajilin-entry.d.ts +6 -0
  347. package/dist/yajilin-entry.js +6 -0
  348. package/dist/yajilin-play-entry.d.ts +4 -0
  349. package/dist/yajilin-play-entry.js +3 -0
  350. package/dist/yajilin.constants.d.ts +2 -0
  351. package/dist/yajilin.constants.js +2 -0
  352. package/dist/yajilin.types.d.ts +63 -0
  353. package/dist/yajilin.types.js +1 -0
  354. package/dist/yajilinBoard.d.ts +9 -0
  355. package/dist/yajilinBoard.js +91 -0
  356. package/dist/yajilinDraw.d.ts +2 -0
  357. package/dist/yajilinDraw.js +33 -0
  358. package/dist/yajilinGame.d.ts +15 -0
  359. package/dist/yajilinGame.js +58 -0
  360. package/dist/yajilinGenerate.d.ts +3 -0
  361. package/dist/yajilinGenerate.js +224 -0
  362. package/dist/yajilinMount.d.ts +2 -0
  363. package/dist/yajilinMount.js +162 -0
  364. package/dist/yajilinPlay.types.d.ts +1 -0
  365. package/dist/yajilinPlay.types.js +1 -0
  366. package/dist/yajilinSolve.d.ts +6 -0
  367. package/dist/yajilinSolve.js +82 -0
  368. package/dist/yajilinStrings.d.ts +32 -0
  369. package/dist/yajilinStrings.js +4 -0
  370. package/dist/yajilinStyle.d.ts +1 -0
  371. package/dist/yajilinStyle.js +12 -0
  372. package/package.json +180 -3
@@ -0,0 +1,102 @@
1
+ import type { FillominoLanguage } from "./fillominoPlay.types.ts";
2
+ export declare const FILLOMINO_STRINGS: {
3
+ readonly en: {
4
+ readonly title: "Fillomino";
5
+ readonly help: "Fill every cell with a number. Connected regions of equal numbers must have exactly that many cells. Regions of the same size cannot touch. Arrow keys move; type a number to fill a cell. Clear removes your entry.";
6
+ readonly undo: "Undo";
7
+ readonly hint: "Hint";
8
+ readonly check: "Check";
9
+ readonly restart: "Restart";
10
+ readonly selectNumber: "Number";
11
+ readonly fill: "Enter";
12
+ readonly clear: "Clear";
13
+ readonly selected: "Selected";
14
+ readonly row: "Row";
15
+ readonly column: "column";
16
+ readonly empty: "empty";
17
+ readonly clue: "given";
18
+ readonly filled: "filled";
19
+ readonly checked: "The filled regions follow the rules so far.";
20
+ readonly wrong: "Some regions are too large or a clue was changed.";
21
+ readonly remaining: "Keep filling the empty cells.";
22
+ readonly solved: "Every region has the right size. Solved!";
23
+ readonly helped: "Solved with a hint.";
24
+ readonly hintWhy: "This cell follows from the only complete solution.";
25
+ readonly noHint: "No proved hint is available from the current entries.";
26
+ readonly restored: "Progress restored.";
27
+ };
28
+ readonly ja: {
29
+ readonly title: "フィロミノ";
30
+ readonly help: "すべてのマスに数字を入れます。同じ数字が上下左右につながった領域のマス数は、その数字と同じです。同じ大きさの領域は辺で接しません。矢印キーで移動し、数字を入力します。消去で入力を消します。";
31
+ readonly undo: "戻す";
32
+ readonly hint: "ヒント";
33
+ readonly check: "確かめる";
34
+ readonly restart: "やり直す";
35
+ readonly selectNumber: "数字";
36
+ readonly fill: "入力";
37
+ readonly clear: "消去";
38
+ readonly selected: "選択中";
39
+ readonly row: "行";
40
+ readonly column: "列";
41
+ readonly empty: "空き";
42
+ readonly clue: "ヒント";
43
+ readonly filled: "入力済み";
44
+ readonly checked: "ここまでの領域はルールに合っています。";
45
+ readonly wrong: "大きすぎる領域か、変更されたヒントがあります。";
46
+ readonly remaining: "空きマスを埋めましょう。";
47
+ readonly solved: "すべての領域の大きさが合いました。完成!";
48
+ readonly helped: "ヒントを使って完成!";
49
+ readonly hintWhy: "唯一の完成形から、このマスが決まります。";
50
+ readonly noHint: "現在の入力から確かなヒントを出せません。";
51
+ readonly restored: "続きから再開しました。";
52
+ };
53
+ };
54
+ export declare function fillominoWords(language?: FillominoLanguage): {
55
+ readonly title: "Fillomino";
56
+ readonly help: "Fill every cell with a number. Connected regions of equal numbers must have exactly that many cells. Regions of the same size cannot touch. Arrow keys move; type a number to fill a cell. Clear removes your entry.";
57
+ readonly undo: "Undo";
58
+ readonly hint: "Hint";
59
+ readonly check: "Check";
60
+ readonly restart: "Restart";
61
+ readonly selectNumber: "Number";
62
+ readonly fill: "Enter";
63
+ readonly clear: "Clear";
64
+ readonly selected: "Selected";
65
+ readonly row: "Row";
66
+ readonly column: "column";
67
+ readonly empty: "empty";
68
+ readonly clue: "given";
69
+ readonly filled: "filled";
70
+ readonly checked: "The filled regions follow the rules so far.";
71
+ readonly wrong: "Some regions are too large or a clue was changed.";
72
+ readonly remaining: "Keep filling the empty cells.";
73
+ readonly solved: "Every region has the right size. Solved!";
74
+ readonly helped: "Solved with a hint.";
75
+ readonly hintWhy: "This cell follows from the only complete solution.";
76
+ readonly noHint: "No proved hint is available from the current entries.";
77
+ readonly restored: "Progress restored.";
78
+ } | {
79
+ readonly title: "フィロミノ";
80
+ readonly help: "すべてのマスに数字を入れます。同じ数字が上下左右につながった領域のマス数は、その数字と同じです。同じ大きさの領域は辺で接しません。矢印キーで移動し、数字を入力します。消去で入力を消します。";
81
+ readonly undo: "戻す";
82
+ readonly hint: "ヒント";
83
+ readonly check: "確かめる";
84
+ readonly restart: "やり直す";
85
+ readonly selectNumber: "数字";
86
+ readonly fill: "入力";
87
+ readonly clear: "消去";
88
+ readonly selected: "選択中";
89
+ readonly row: "行";
90
+ readonly column: "列";
91
+ readonly empty: "空き";
92
+ readonly clue: "ヒント";
93
+ readonly filled: "入力済み";
94
+ readonly checked: "ここまでの領域はルールに合っています。";
95
+ readonly wrong: "大きすぎる領域か、変更されたヒントがあります。";
96
+ readonly remaining: "空きマスを埋めましょう。";
97
+ readonly solved: "すべての領域の大きさが合いました。完成!";
98
+ readonly helped: "ヒントを使って完成!";
99
+ readonly hintWhy: "唯一の完成形から、このマスが決まります。";
100
+ readonly noHint: "現在の入力から確かなヒントを出せません。";
101
+ readonly restored: "続きから再開しました。";
102
+ };
@@ -0,0 +1,13 @@
1
+ export const FILLOMINO_STRINGS = {
2
+ en: {
3
+ title: "Fillomino", help: "Fill every cell with a number. Connected regions of equal numbers must have exactly that many cells. Regions of the same size cannot touch. Arrow keys move; type a number to fill a cell. Clear removes your entry.",
4
+ undo: "Undo", hint: "Hint", check: "Check", restart: "Restart", selectNumber: "Number", fill: "Enter", clear: "Clear", selected: "Selected", row: "Row", column: "column", empty: "empty", clue: "given", filled: "filled", checked: "The filled regions follow the rules so far.", wrong: "Some regions are too large or a clue was changed.", remaining: "Keep filling the empty cells.", solved: "Every region has the right size. Solved!", helped: "Solved with a hint.", hintWhy: "This cell follows from the only complete solution.", noHint: "No proved hint is available from the current entries.", restored: "Progress restored.",
5
+ },
6
+ ja: {
7
+ title: "フィロミノ", help: "すべてのマスに数字を入れます。同じ数字が上下左右につながった領域のマス数は、その数字と同じです。同じ大きさの領域は辺で接しません。矢印キーで移動し、数字を入力します。消去で入力を消します。",
8
+ undo: "戻す", hint: "ヒント", check: "確かめる", restart: "やり直す", selectNumber: "数字", fill: "入力", clear: "消去", selected: "選択中", row: "行", column: "列", empty: "空き", clue: "ヒント", filled: "入力済み", checked: "ここまでの領域はルールに合っています。", wrong: "大きすぎる領域か、変更されたヒントがあります。", remaining: "空きマスを埋めましょう。", solved: "すべての領域の大きさが合いました。完成!", helped: "ヒントを使って完成!", hintWhy: "唯一の完成形から、このマスが決まります。", noHint: "現在の入力から確かなヒントを出せません。", restored: "続きから再開しました。",
9
+ },
10
+ };
11
+ export function fillominoWords(language = "en") {
12
+ return FILLOMINO_STRINGS[language];
13
+ }
@@ -0,0 +1 @@
1
+ export declare const FILLOMINO_PLAY_STYLE = "\n.fillomino-play{font:1rem/1.45 system-ui,sans-serif;color:var(--kz-ink,#202521);max-width:58rem;margin:auto}\n.fillomino-status{min-height:1.5em;text-align:center;font-weight:600}\n.fillomino-board{width:min(100%,42rem);margin:1rem auto}\n.fillomino-drawing{position:relative}\n.fillomino-cells{position:absolute;inset:0;display:grid;grid-template-columns:repeat(var(--fillomino-width),1fr);grid-template-rows:repeat(var(--fillomino-height),1fr)}\n.fillomino-cell{min-width:0;min-height:0;border:0;background:transparent;color:transparent;cursor:pointer}\n.fillomino-cell:focus-visible{outline:3px solid #b5963d;outline-offset:-3px}\n.fillomino-controls{display:flex;flex-wrap:wrap;align-items:center;justify-content:center;gap:.5rem;margin:1rem auto}\n.fillomino-controls button,.fillomino-controls select{font:inherit;min-height:2.75rem;padding:.45rem .8rem;border:1px solid var(--kz-grid,#cfc6b2);border-radius:.55rem;background:var(--kz-paper,#fbf8f1);color:inherit}\n.fillomino-number-label{display:flex;align-items:center;gap:.45rem}\n@media(max-width:700px){.fillomino-controls{gap:.35rem}.fillomino-controls button{flex:1 1 28%}}\n";
@@ -0,0 +1,13 @@
1
+ export const FILLOMINO_PLAY_STYLE = `
2
+ .fillomino-play{font:1rem/1.45 system-ui,sans-serif;color:var(--kz-ink,#202521);max-width:58rem;margin:auto}
3
+ .fillomino-status{min-height:1.5em;text-align:center;font-weight:600}
4
+ .fillomino-board{width:min(100%,42rem);margin:1rem auto}
5
+ .fillomino-drawing{position:relative}
6
+ .fillomino-cells{position:absolute;inset:0;display:grid;grid-template-columns:repeat(var(--fillomino-width),1fr);grid-template-rows:repeat(var(--fillomino-height),1fr)}
7
+ .fillomino-cell{min-width:0;min-height:0;border:0;background:transparent;color:transparent;cursor:pointer}
8
+ .fillomino-cell:focus-visible{outline:3px solid #b5963d;outline-offset:-3px}
9
+ .fillomino-controls{display:flex;flex-wrap:wrap;align-items:center;justify-content:center;gap:.5rem;margin:1rem auto}
10
+ .fillomino-controls button,.fillomino-controls select{font:inherit;min-height:2.75rem;padding:.45rem .8rem;border:1px solid var(--kz-grid,#cfc6b2);border-radius:.55rem;background:var(--kz-paper,#fbf8f1);color:inherit}
11
+ .fillomino-number-label{display:flex;align-items:center;gap:.45rem}
12
+ @media(max-width:700px){.fillomino-controls{gap:.35rem}.fillomino-controls button{flex:1 1 28%}}
13
+ `;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,10 @@
1
+ import { generateFillomino } from "./fillominoGenerate.js";
2
+ self.onmessage = (event) => {
3
+ try {
4
+ const { width, height, level, seed } = event.data;
5
+ self.postMessage({ puzzle: generateFillomino(width, height, level, seed) });
6
+ }
7
+ catch (error) {
8
+ self.postMessage({ error: error instanceof Error ? error.message : String(error) });
9
+ }
10
+ };
@@ -0,0 +1,2 @@
1
+ export { drawHeyawake } from "./heyawakeDraw.ts";
2
+ export type { HeyawakeDrawOptions } from "./heyawakePlay.types.ts";
@@ -0,0 +1 @@
1
+ export { drawHeyawake } from "./heyawakeDraw.js";
@@ -0,0 +1,13 @@
1
+ /** Heyawake has its own room model alongside Kazu's number puzzles. */
2
+ export * from "./heyawake.types.ts";
3
+ export * from "./heyawake.constants.ts";
4
+ export * from "./heyawakeBoard.ts";
5
+ export * from "./heyawakeSolve.ts";
6
+ export * from "./heyawakeGenerate.ts";
7
+ export * from "./heyawakeGame.ts";
8
+ export { drawHeyawake } from "./heyawakeDraw.ts";
9
+ export type { HeyawakeDrawOptions } from "./heyawakePlay.types.ts";
10
+ export { mountHeyawake } from "./heyawakeMount.ts";
11
+ export { HEYAWAKE_PLAY_STYLE } from "./heyawakeStyle.ts";
12
+ export { heyawakeWords } from "./heyawakeStrings.ts";
13
+ export type * from "./heyawakePlay.types.ts";
@@ -0,0 +1,11 @@
1
+ /** Heyawake has its own room model alongside Kazu's number puzzles. */
2
+ export * from "./heyawake.types.js";
3
+ export * from "./heyawake.constants.js";
4
+ export * from "./heyawakeBoard.js";
5
+ export * from "./heyawakeSolve.js";
6
+ export * from "./heyawakeGenerate.js";
7
+ export * from "./heyawakeGame.js";
8
+ export { drawHeyawake } from "./heyawakeDraw.js";
9
+ export { mountHeyawake } from "./heyawakeMount.js";
10
+ export { HEYAWAKE_PLAY_STYLE } from "./heyawakeStyle.js";
11
+ export { heyawakeWords } from "./heyawakeStrings.js";
@@ -0,0 +1,2 @@
1
+ export { mountHeyawake } from "./heyawakeMount.ts";
2
+ export type { HeyawakeMount, HeyawakeMountOptions, HeyawakeAppearance } from "./heyawakePlay.types.ts";
@@ -0,0 +1 @@
1
+ export { mountHeyawake } from "./heyawakeMount.js";
@@ -0,0 +1,5 @@
1
+ export declare const HEYAWAKE_MOST_SIDE = 12;
2
+ export declare const HEYAWAKE_GENERATOR_MOST_CELLS = 25;
3
+ export declare const HEYAWAKE_MOST_NODES = 250000;
4
+ export declare const HEYAWAKE_MOST_ATTEMPTS = 500;
5
+ export declare const HEYAWAKE_LEVELS: readonly ["easy", "medium", "hard"];
@@ -0,0 +1,5 @@
1
+ export const HEYAWAKE_MOST_SIDE = 12;
2
+ export const HEYAWAKE_GENERATOR_MOST_CELLS = 25;
3
+ export const HEYAWAKE_MOST_NODES = 250000;
4
+ export const HEYAWAKE_MOST_ATTEMPTS = 500;
5
+ export const HEYAWAKE_LEVELS = ["easy", "medium", "hard"];
@@ -0,0 +1,35 @@
1
+ export type HeyawakeRoom = {
2
+ x: number;
3
+ y: number;
4
+ width: number;
5
+ height: number;
6
+ blacks: number | null;
7
+ };
8
+ export type HeyawakeBoard = {
9
+ width: number;
10
+ height: number;
11
+ rooms: readonly HeyawakeRoom[];
12
+ };
13
+ export type HeyawakeLevel = "easy" | "medium" | "hard";
14
+ export type HeyawakePuzzle = HeyawakeBoard & {
15
+ seed: number;
16
+ level: HeyawakeLevel;
17
+ solution: readonly boolean[];
18
+ };
19
+ export type HeyawakeCheck = {
20
+ ok: boolean;
21
+ complete: boolean;
22
+ errors: readonly number[];
23
+ };
24
+ export type HeyawakeSolve = {
25
+ count: number;
26
+ solution: readonly boolean[] | null;
27
+ complete: boolean;
28
+ nodes: number;
29
+ };
30
+ export type HeyawakeGame = {
31
+ board: HeyawakeBoard;
32
+ entries: readonly (boolean | null)[];
33
+ history: readonly (readonly (boolean | null)[])[];
34
+ helped: boolean;
35
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,7 @@
1
+ import type { HeyawakeBoard, HeyawakeCheck, HeyawakeRoom } from "./heyawake.types.ts";
2
+ export declare function heyawakeCells(board: HeyawakeBoard, room: HeyawakeRoom): number[] | null;
3
+ export declare function isHeyawakeBoard(value: unknown): value is HeyawakeBoard;
4
+ export declare function heyawakeNeighbours(board: HeyawakeBoard, cell: number): number[];
5
+ export declare function roomForCell(board: HeyawakeBoard): number[];
6
+ export declare function checkHeyawake(board: HeyawakeBoard, entries: readonly (boolean | null)[]): HeyawakeCheck;
7
+ export declare function checkRoomSpans(board: HeyawakeBoard, entries: readonly (boolean | null)[], roomIds?: number[], errors?: Set<number>): void;
@@ -0,0 +1,116 @@
1
+ import { HEYAWAKE_MOST_SIDE } from "./heyawake.constants.js";
2
+ export function heyawakeCells(board, room) {
3
+ if (!room || ![room.x, room.y, room.width, room.height].every(Number.isInteger)
4
+ || room.x < 0 || room.y < 0 || room.width < 1 || room.height < 1
5
+ || room.x + room.width > board.width || room.y + room.height > board.height)
6
+ return null;
7
+ return Array.from({ length: room.width * room.height }, (_, index) => (room.y + Math.floor(index / room.width)) * board.width + room.x + index % room.width);
8
+ }
9
+ export function isHeyawakeBoard(value) {
10
+ if (!value || typeof value !== "object")
11
+ return false;
12
+ const board = value;
13
+ if (!Number.isInteger(board.width) || board.width < 2 || board.width > HEYAWAKE_MOST_SIDE
14
+ || !Number.isInteger(board.height) || board.height < 2 || board.height > HEYAWAKE_MOST_SIDE
15
+ || !Array.isArray(board.rooms) || board.rooms.length === 0)
16
+ return false;
17
+ const occupied = new Set();
18
+ for (const room of board.rooms) {
19
+ if (!room || typeof room !== "object"
20
+ || ![room.x, room.y, room.width, room.height].every(Number.isInteger)
21
+ || !(room.blacks === null || Number.isInteger(room.blacks) && room.blacks >= 0 && room.blacks <= room.width * room.height))
22
+ return false;
23
+ const cells = heyawakeCells(board, room);
24
+ if (!cells || cells.some(cell => occupied.has(cell)))
25
+ return false;
26
+ cells.forEach(cell => occupied.add(cell));
27
+ }
28
+ return occupied.size === board.width * board.height;
29
+ }
30
+ export function heyawakeNeighbours(board, cell) {
31
+ const x = cell % board.width, y = Math.floor(cell / board.width);
32
+ return [[x - 1, y], [x + 1, y], [x, y - 1], [x, y + 1]]
33
+ .filter(([nx, ny]) => nx >= 0 && nx < board.width && ny >= 0 && ny < board.height)
34
+ .map(([nx, ny]) => ny * board.width + nx);
35
+ }
36
+ export function roomForCell(board) {
37
+ const lookup = Array(board.width * board.height).fill(-1);
38
+ board.rooms.forEach((room, index) => heyawakeCells(board, room)?.forEach(cell => { lookup[cell] = index; }));
39
+ return lookup;
40
+ }
41
+ export function checkHeyawake(board, entries) {
42
+ if (!isHeyawakeBoard(board))
43
+ throw new RangeError("Invalid Heyawake board");
44
+ if (!Array.isArray(entries) || entries.length !== board.width * board.height
45
+ || entries.some(value => value !== true && value !== false && value !== null))
46
+ throw new RangeError("Invalid Heyawake entries");
47
+ const errors = new Set(), complete = entries.every(value => value !== null), ids = roomForCell(board);
48
+ for (let cell = 0; cell < entries.length; cell += 1) {
49
+ if (entries[cell] !== true)
50
+ continue;
51
+ if (heyawakeNeighbours(board, cell).some(next => entries[next] === true)) {
52
+ errors.add(cell);
53
+ heyawakeNeighbours(board, cell).filter(next => entries[next] === true).forEach(next => errors.add(next));
54
+ }
55
+ }
56
+ for (let index = 0; index < board.rooms.length; index += 1) {
57
+ const room = board.rooms[index];
58
+ const cells = heyawakeCells(board, room);
59
+ const marked = cells.filter(cell => entries[cell] === true).length;
60
+ if (room.blacks !== null && (marked > room.blacks || complete && marked !== room.blacks))
61
+ cells.forEach(cell => errors.add(cell));
62
+ }
63
+ if (complete) {
64
+ const white = entries.flatMap((value, cell) => value === false ? [cell] : []);
65
+ const reached = new Set();
66
+ if (white.length) {
67
+ const pending = [white[0]];
68
+ reached.add(white[0]);
69
+ while (pending.length)
70
+ for (const next of heyawakeNeighbours(board, pending.pop())) {
71
+ if (entries[next] === false && !reached.has(next)) {
72
+ reached.add(next);
73
+ pending.push(next);
74
+ }
75
+ }
76
+ }
77
+ if (reached.size !== white.length)
78
+ white.filter(cell => !reached.has(cell)).forEach(cell => errors.add(cell));
79
+ checkRoomSpans(board, entries, ids, errors);
80
+ }
81
+ return { ok: errors.size === 0 && complete, complete, errors: [...errors].sort((a, b) => a - b) };
82
+ }
83
+ export function checkRoomSpans(board, entries, roomIds = roomForCell(board), errors = new Set()) {
84
+ for (let y = 0; y < board.height; y += 1) {
85
+ let rooms = new Set(), cells = [];
86
+ for (let x = 0; x <= board.width; x += 1) {
87
+ const cell = y * board.width + x;
88
+ if (x < board.width && entries[cell] === false) {
89
+ cells.push(cell);
90
+ rooms.add(roomIds[cell]);
91
+ }
92
+ else {
93
+ if (rooms.size > 2)
94
+ cells.forEach(value => errors.add(value));
95
+ rooms = new Set();
96
+ cells = [];
97
+ }
98
+ }
99
+ }
100
+ for (let x = 0; x < board.width; x += 1) {
101
+ let rooms = new Set(), cells = [];
102
+ for (let y = 0; y <= board.height; y += 1) {
103
+ const cell = y * board.width + x;
104
+ if (y < board.height && entries[cell] === false) {
105
+ cells.push(cell);
106
+ rooms.add(roomIds[cell]);
107
+ }
108
+ else {
109
+ if (rooms.size > 2)
110
+ cells.forEach(value => errors.add(value));
111
+ rooms = new Set();
112
+ cells = [];
113
+ }
114
+ }
115
+ }
116
+ }
@@ -0,0 +1,3 @@
1
+ import type { HeyawakeBoard } from "./heyawake.types.ts";
2
+ import type { HeyawakeDrawOptions } from "./heyawakePlay.types.ts";
3
+ export declare function drawHeyawake(board: HeyawakeBoard, options?: HeyawakeDrawOptions): string;
@@ -0,0 +1,27 @@
1
+ import { heyawakeCells, isHeyawakeBoard } from "./heyawakeBoard.js";
2
+ import { heyawakeWords } from "./heyawakeStrings.js";
3
+ export function drawHeyawake(board, options = {}) {
4
+ if (!isHeyawakeBoard(board))
5
+ throw new RangeError("Invalid Heyawake board");
6
+ const words = heyawakeWords(options.language), size = 48;
7
+ const palettes = { ivory: ["var(--kz-paper,#fbf8f1)", "var(--kz-ink,#1f2320)", "var(--kz-grid,#cfc6b2)"], wood: ["#e5cda6", "#493e2f", "#bca582"], slate: ["#262a27", "#ece8dc", "#454a44"] };
8
+ const [paper, ink, grid] = palettes[options.material ?? "ivory"];
9
+ const roomAt = Array(board.width * board.height).fill(-1);
10
+ board.rooms.forEach((room, index) => heyawakeCells(board, room).forEach(cell => { roomAt[cell] = index; }));
11
+ const cells = Array.from({ length: board.width * board.height }, (_, cell) => {
12
+ const x = cell % board.width * size, y = Math.floor(cell / board.width) * size;
13
+ const entry = options.entries?.[cell], room = board.rooms[roomAt[cell]];
14
+ const selected = cell === options.selected, error = options.errors?.includes(cell);
15
+ const color = error ? "var(--kz-bad,#b5452c)" : ink;
16
+ const top = Math.floor(cell / board.width) === room.y ? 3 : 1;
17
+ const left = cell % board.width === room.x ? 3 : 1;
18
+ const right = cell % board.width === room.x + room.width - 1 ? 3 : 1;
19
+ const bottom = Math.floor(cell / board.width) === room.y + room.height - 1 ? 3 : 1;
20
+ const clue = cell === room.y * board.width + room.x && room.blacks !== null
21
+ ? `<text x="${x + 5}" y="${y + 13}" fill="${ink}" font-size="11" font-weight="700">${room.blacks}</text>` : "";
22
+ const mark = entry === true ? `<rect x="${x + 1}" y="${y + 1}" width="46" height="46" fill="${color}"/>` : entry === false ? `<circle cx="${x + 24}" cy="${y + 24}" r="5" fill="${color}"/>` : "";
23
+ return `<g data-heyawake-cell="${cell}"><rect x="${x}" y="${y}" width="48" height="48" fill="${selected ? ink : paper}" fill-opacity="${selected ? ".12" : "1"}" stroke="${grid}" stroke-width="${Math.min(top, right, bottom, left)}"/>${clue}${mark}</g>`;
24
+ }).join("");
25
+ const roomLines = board.rooms.map(room => `<rect x="${room.x * size + 1.5}" y="${room.y * size + 1.5}" width="${room.width * size - 3}" height="${room.height * size - 3}" fill="none" stroke="${ink}" stroke-width="3" pointer-events="none"/>`).join("");
26
+ return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${board.width * size} ${board.height * size}" role="img" aria-label="${words.title}" style="display:block;width:100%;height:auto;background:${paper}">${cells}${roomLines}</svg>`;
27
+ }
@@ -0,0 +1,12 @@
1
+ import type { HeyawakeBoard, HeyawakeGame } from "./heyawake.types.ts";
2
+ export declare function newHeyawake(board: HeyawakeBoard): HeyawakeGame;
3
+ export declare function setHeyawakeCell(game: HeyawakeGame, cell: number, value: boolean | null): HeyawakeGame;
4
+ export declare function undoHeyawake(game: HeyawakeGame): HeyawakeGame;
5
+ export declare function restartHeyawake(game: HeyawakeGame): HeyawakeGame;
6
+ export declare function hintHeyawake(game: HeyawakeGame): {
7
+ cell: number;
8
+ value: boolean;
9
+ } | null;
10
+ export declare function heyawakeFinished(game: HeyawakeGame): boolean;
11
+ export declare function encodeHeyawake(game: HeyawakeGame): string;
12
+ export declare function decodeHeyawake(code: string): HeyawakeGame | null;
@@ -0,0 +1,51 @@
1
+ import { checkHeyawake, isHeyawakeBoard } from "./heyawakeBoard.js";
2
+ import { solveHeyawake } from "./heyawakeSolve.js";
3
+ export function newHeyawake(board) {
4
+ if (!isHeyawakeBoard(board))
5
+ throw new RangeError("Invalid Heyawake board");
6
+ return { board: publicBoard(board), entries: Array(board.width * board.height).fill(null), history: [], helped: false };
7
+ }
8
+ export function setHeyawakeCell(game, cell, value) {
9
+ if (value !== null && typeof value !== "boolean" || !Number.isInteger(cell) || cell < 0 || cell >= game.entries.length || game.entries[cell] === value)
10
+ return game;
11
+ const entries = [...game.entries];
12
+ entries[cell] = value;
13
+ return { ...game, entries, history: [...game.history, game.entries] };
14
+ }
15
+ export function undoHeyawake(game) {
16
+ const previous = game.history.at(-1);
17
+ return previous ? { ...game, entries: previous, history: game.history.slice(0, -1) } : game;
18
+ }
19
+ export function restartHeyawake(game) {
20
+ return { ...game, entries: Array(game.entries.length).fill(null), history: [], helped: false };
21
+ }
22
+ export function hintHeyawake(game) {
23
+ const result = solveHeyawake(game.board, game.entries);
24
+ if (!result.complete || result.count !== 1 || !result.solution)
25
+ return null;
26
+ const cell = game.entries.findIndex(value => value === null);
27
+ return cell < 0 ? null : { cell, value: result.solution[cell] };
28
+ }
29
+ export function heyawakeFinished(game) {
30
+ return checkHeyawake(game.board, game.entries).ok;
31
+ }
32
+ export function encodeHeyawake(game) {
33
+ return JSON.stringify({ version: 1, board: publicBoard(game.board), entries: game.entries.map(value => value === null ? "?" : value ? "#" : ".").join(""), helped: game.helped });
34
+ }
35
+ export function decodeHeyawake(code) {
36
+ try {
37
+ const data = JSON.parse(code);
38
+ if (data.version !== 1 || !isHeyawakeBoard(data.board) || typeof data.helped !== "boolean" || typeof data.entries !== "string")
39
+ return null;
40
+ const entries = [...data.entries].map((value) => value === "?" ? null : value === "#" ? true : value === "." ? false : undefined);
41
+ if (entries.length !== data.board.width * data.board.height || entries.some((value) => value === undefined))
42
+ return null;
43
+ return { board: publicBoard(data.board), entries: entries, history: [], helped: data.helped };
44
+ }
45
+ catch {
46
+ return null;
47
+ }
48
+ }
49
+ function publicBoard(board) {
50
+ return { width: board.width, height: board.height, rooms: board.rooms.map(room => ({ x: room.x, y: room.y, width: room.width, height: room.height, blacks: room.blacks })) };
51
+ }
@@ -0,0 +1,2 @@
1
+ import type { HeyawakeLevel, HeyawakePuzzle } from "./heyawake.types.ts";
2
+ export declare function generateHeyawake(width?: number, height?: number, level?: HeyawakeLevel, seed?: number): HeyawakePuzzle;
@@ -0,0 +1,114 @@
1
+ import { HEYAWAKE_GENERATOR_MOST_CELLS, HEYAWAKE_LEVELS, HEYAWAKE_MOST_ATTEMPTS } from "./heyawake.constants.js";
2
+ import { checkHeyawake, heyawakeNeighbours, roomForCell } from "./heyawakeBoard.js";
3
+ import { solveHeyawake } from "./heyawakeSolve.js";
4
+ import { isKazuSeed, seededRandom, shuffled } from "./random.js";
5
+ export function generateHeyawake(width = 4, height = width, level = "easy", seed = 1) {
6
+ if (![width, height].every(value => Number.isInteger(value) && value >= 4 && value <= 8) || width * height > HEYAWAKE_GENERATOR_MOST_CELLS
7
+ || !HEYAWAKE_LEVELS.includes(level) || !isKazuSeed(seed))
8
+ throw new RangeError("Heyawake generation supports 4–8 cells per side and a valid level and seed");
9
+ const random = seededRandom(seed);
10
+ for (let attempt = 0; attempt < HEYAWAKE_MOST_ATTEMPTS; attempt += 1) {
11
+ const roomLimit = Math.min(10, 5 + Math.floor(attempt / 50));
12
+ const rooms = partitionRooms(width, height, random, roomLimit);
13
+ const open = { width, height, rooms: rooms.map(room => ({ ...room, blacks: null })) };
14
+ const solution = randomSolution(open, random);
15
+ if (!solution)
16
+ continue;
17
+ const order = shuffled(rooms.map((_, index) => index), random);
18
+ const clueCount = Math.max(2, Math.ceil(rooms.length * ({ easy: 0.95, medium: 0.75, hard: 0.55 }[level])));
19
+ const revealed = new Set(order.slice(0, clueCount));
20
+ const hidden = order.slice(clueCount);
21
+ for (let extra = 0; extra <= hidden.length; extra += 1) {
22
+ const clues = rooms.map((room, index) => ({ ...room, blacks: revealed.has(index) ? countBlacks(room, width, solution) : null }));
23
+ const board = { width, height, rooms: clues };
24
+ const proof = solveHeyawake(board);
25
+ if (proof.complete && proof.count === 1 && proof.solution && checkHeyawake(board, proof.solution).ok) {
26
+ return { ...board, seed, level, solution: proof.solution };
27
+ }
28
+ if (extra < hidden.length)
29
+ revealed.add(hidden[extra]);
30
+ }
31
+ }
32
+ throw new Error("No unique Heyawake found within the generation budget; try another seed or smaller board");
33
+ }
34
+ function partitionRooms(width, height, random, maximumRooms) {
35
+ const pending = [{ x: 0, y: 0, width, height }];
36
+ const rooms = [];
37
+ while (pending.length) {
38
+ const area = pending.pop();
39
+ if (rooms.length + pending.length >= maximumRooms || area.width * area.height <= 3) {
40
+ rooms.push({ ...area, blacks: null });
41
+ continue;
42
+ }
43
+ const canVertical = area.width >= 4, canHorizontal = area.height >= 4;
44
+ if (!canVertical && !canHorizontal) {
45
+ rooms.push({ ...area, blacks: null });
46
+ continue;
47
+ }
48
+ const vertical = canVertical && (!canHorizontal || random() < 0.5);
49
+ if (vertical) {
50
+ const cut = 1 + Math.floor(random() * (area.width - 1));
51
+ pending.push({ x: area.x + cut, y: area.y, width: area.width - cut, height: area.height });
52
+ pending.push({ x: area.x, y: area.y, width: cut, height: area.height });
53
+ }
54
+ else {
55
+ const cut = 1 + Math.floor(random() * (area.height - 1));
56
+ pending.push({ x: area.x, y: area.y + cut, width: area.width, height: area.height - cut });
57
+ pending.push({ x: area.x, y: area.y, width: area.width, height: cut });
58
+ }
59
+ }
60
+ return rooms;
61
+ }
62
+ function randomSolution(board, random) {
63
+ const entries = Array(board.width * board.height).fill(null);
64
+ const roomIds = roomForCell(board);
65
+ let nodes = 0;
66
+ const visit = (cell) => {
67
+ if (++nodes > 12000)
68
+ return false;
69
+ if (cell === entries.length) {
70
+ const blackCount = entries.filter(value => value === true).length;
71
+ return blackCount >= 2 && checkHeyawake(board, entries).ok;
72
+ }
73
+ const choices = random() < 0.31 ? [true, false] : [false, true];
74
+ for (const black of choices) {
75
+ if (black && heyawakeNeighbours(board, cell).some(next => entries[next] === true))
76
+ continue;
77
+ entries[cell] = black;
78
+ if (partialRoomSpanIsLegal(board, entries, roomIds) && visit(cell + 1))
79
+ return true;
80
+ entries[cell] = null;
81
+ }
82
+ return false;
83
+ };
84
+ return visit(0) ? entries.map(value => value === true) : null;
85
+ }
86
+ function partialRoomSpanIsLegal(board, entries, roomIds) {
87
+ const exceeds = (cells) => {
88
+ let rooms = new Set();
89
+ for (const cell of cells) {
90
+ if (entries[cell] === false)
91
+ rooms.add(roomIds[cell]);
92
+ else
93
+ rooms = new Set();
94
+ if (rooms.size > 2)
95
+ return true;
96
+ }
97
+ return false;
98
+ };
99
+ for (let y = 0; y < board.height; y += 1)
100
+ if (exceeds(Array.from({ length: board.width }, (_, x) => y * board.width + x)))
101
+ return false;
102
+ for (let x = 0; x < board.width; x += 1)
103
+ if (exceeds(Array.from({ length: board.height }, (_, y) => y * board.width + x)))
104
+ return false;
105
+ return true;
106
+ }
107
+ function countBlacks(room, width, solution) {
108
+ let count = 0;
109
+ for (let y = room.y; y < room.y + room.height; y += 1)
110
+ for (let x = room.x; x < room.x + room.width; x += 1)
111
+ if (solution[y * width + x])
112
+ count += 1;
113
+ return count;
114
+ }
@@ -0,0 +1,2 @@
1
+ import type { HeyawakeMount, HeyawakeMountOptions } from "./heyawakePlay.types.ts";
2
+ export declare function mountHeyawake(host: HTMLElement, initial: HeyawakeMountOptions): HeyawakeMount;