@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,224 @@
1
+ import { isKazuSeed, seededRandom } from "./random.js";
2
+ import { checkYajilin, isYajilinBoard, yajilinNeighbors } from "./yajilinBoard.js";
3
+ import { solveYajilin } from "./yajilinSolve.js";
4
+ const layouts = [
5
+ {
6
+ loop: [6, 7, 8, 13, 18, 17, 16, 11],
7
+ shaded: [1, 22, 5, 9, 24, 12, 20],
8
+ clues: [
9
+ [0, "left", 0],
10
+ [2, "up", 0],
11
+ [3, "up", 0],
12
+ [4, "down", 2],
13
+ [10, "up", 1],
14
+ [14, "down", 1],
15
+ [15, "left", 0],
16
+ [19, "up", 1],
17
+ [21, "down", 0],
18
+ [23, "up", 0],
19
+ ],
20
+ },
21
+ {
22
+ loop: [6, 7, 8, 13, 18, 17, 16, 11],
23
+ shaded: [0, 21, 15, 2, 14, 4, 12],
24
+ clues: [
25
+ [1, "right", 2],
26
+ [3, "left", 2],
27
+ [5, "down", 1],
28
+ [9, "right", 0],
29
+ [10, "down", 1],
30
+ [19, "up", 2],
31
+ [20, "left", 0],
32
+ [22, "up", 2],
33
+ [23, "right", 0],
34
+ [24, "down", 0],
35
+ ],
36
+ },
37
+ {
38
+ loop: [6, 7, 8, 13, 18, 17, 16, 11],
39
+ shaded: [24, 12, 22, 4, 15, 0, 2],
40
+ clues: [
41
+ [1, "right", 2],
42
+ [3, "down", 0],
43
+ [5, "down", 1],
44
+ [9, "right", 0],
45
+ [10, "left", 0],
46
+ [14, "up", 1],
47
+ [19, "left", 1],
48
+ [20, "left", 0],
49
+ [21, "down", 0],
50
+ [23, "right", 1],
51
+ ],
52
+ },
53
+ {
54
+ loop: [6, 7, 8, 13, 18, 17, 16, 11],
55
+ shaded: [12, 9, 2, 21, 0, 19, 10],
56
+ clues: [
57
+ [1, "right", 1],
58
+ [3, "up", 0],
59
+ [4, "down", 2],
60
+ [5, "up", 1],
61
+ [14, "left", 2],
62
+ [15, "right", 1],
63
+ [20, "down", 0],
64
+ [22, "up", 2],
65
+ [23, "up", 0],
66
+ [24, "up", 2],
67
+ ],
68
+ },
69
+ {
70
+ loop: [6, 7, 8, 13, 18, 17, 16, 11],
71
+ shaded: [20, 3, 22, 14, 1, 12, 24],
72
+ clues: [
73
+ [0, "left", 0],
74
+ [2, "down", 2],
75
+ [4, "up", 0],
76
+ [5, "right", 0],
77
+ [9, "down", 2],
78
+ [10, "up", 0],
79
+ [15, "right", 0],
80
+ [19, "up", 1],
81
+ [21, "right", 2],
82
+ [23, "up", 1],
83
+ ],
84
+ },
85
+ {
86
+ loop: [6, 7, 8, 13, 18, 17, 16, 11],
87
+ shaded: [14, 3, 21, 15, 24, 0, 12],
88
+ clues: [
89
+ [1, "up", 0],
90
+ [2, "right", 1],
91
+ [4, "left", 2],
92
+ [5, "right", 0],
93
+ [9, "left", 0],
94
+ [10, "down", 1],
95
+ [19, "left", 1],
96
+ [20, "right", 2],
97
+ [22, "right", 1],
98
+ [23, "left", 1],
99
+ ],
100
+ },
101
+ {
102
+ loop: [6, 7, 8, 13, 18, 17, 16, 11],
103
+ shaded: [15, 24, 9, 21, 5, 3, 1],
104
+ clues: [
105
+ [0, "left", 0],
106
+ [2, "right", 1],
107
+ [4, "right", 0],
108
+ [10, "up", 1],
109
+ [12, "down", 0],
110
+ [14, "right", 0],
111
+ [19, "left", 1],
112
+ [20, "down", 0],
113
+ [22, "up", 0],
114
+ [23, "down", 0],
115
+ ],
116
+ },
117
+ {
118
+ loop: [6, 7, 8, 13, 18, 17, 16, 11],
119
+ shaded: [4, 2, 0, 10, 23, 21, 19],
120
+ clues: [
121
+ [1, "right", 2],
122
+ [3, "left", 2],
123
+ [5, "up", 1],
124
+ [9, "down", 1],
125
+ [12, "down", 0],
126
+ [14, "up", 1],
127
+ [15, "right", 1],
128
+ [20, "right", 2],
129
+ [22, "right", 1],
130
+ [24, "up", 2],
131
+ ],
132
+ },
133
+ {
134
+ loop: [6, 7, 8, 13, 18, 23, 22, 21, 16, 11],
135
+ shaded: [10, 4, 2, 17, 0, 24],
136
+ clues: [
137
+ [1, "right", 2],
138
+ [3, "up", 0],
139
+ [5, "down", 1],
140
+ [9, "down", 1],
141
+ [12, "down", 1],
142
+ [14, "up", 1],
143
+ [15, "right", 1],
144
+ [19, "left", 1],
145
+ [20, "down", 0],
146
+ ],
147
+ },
148
+ {
149
+ loop: [6, 7, 8, 13, 18, 23, 22, 21, 16, 11],
150
+ shaded: [3, 15, 19, 17, 1, 5],
151
+ clues: [
152
+ [0, "left", 0],
153
+ [2, "right", 1],
154
+ [4, "down", 1],
155
+ [9, "down", 1],
156
+ [10, "down", 1],
157
+ [12, "right", 0],
158
+ [14, "down", 1],
159
+ [20, "left", 0],
160
+ [24, "up", 1],
161
+ ],
162
+ },
163
+ {
164
+ loop: [6, 7, 8, 13, 18, 23, 22, 21, 16, 11],
165
+ shaded: [2, 17, 4, 0, 20, 10],
166
+ clues: [
167
+ [1, "left", 1],
168
+ [3, "right", 1],
169
+ [5, "up", 1],
170
+ [9, "left", 0],
171
+ [12, "up", 1],
172
+ [14, "down", 0],
173
+ [15, "up", 2],
174
+ [19, "right", 0],
175
+ [24, "down", 0],
176
+ ],
177
+ },
178
+ ];
179
+ function transformCell(cell, turns, reflect) {
180
+ let x = cell % 5, y = Math.floor(cell / 5);
181
+ if (reflect)
182
+ x = 4 - x;
183
+ for (let turn = 0; turn < turns; turn += 1)
184
+ [x, y] = [4 - y, x];
185
+ return y * 5 + x;
186
+ }
187
+ function transformDirection(direction, turns, reflect) {
188
+ const vector = { up: [0, -1], right: [1, 0], down: [0, 1], left: [-1, 0] };
189
+ let [x, y] = vector[direction];
190
+ if (reflect)
191
+ x = -x;
192
+ for (let turn = 0; turn < turns; turn += 1)
193
+ [x, y] = [-y, x];
194
+ return (Object.entries(vector).find(([, value]) => value[0] === x && value[1] === y)?.[0] ?? "up");
195
+ }
196
+ function edgesFromLoop(board, loop) {
197
+ return loop.map((cell, index) => {
198
+ const next = loop[(index + 1) % loop.length];
199
+ return yajilinNeighbors(board, cell).find(item => item.cell === next).edge;
200
+ }).sort((a, b) => a - b);
201
+ }
202
+ /** Seeded original 5×5 families, accepted only after a completed uniqueness proof. */
203
+ export function generateYajilin(size = 5, seed = 1) {
204
+ if (size !== 5 || !isKazuSeed(seed))
205
+ throw new RangeError("Invalid Yajilin settings");
206
+ const random = seededRandom(seed), layout = layouts[Math.floor(random() * layouts.length)];
207
+ const turns = Math.floor(random() * 4), reflect = random() < 0.5;
208
+ const clues = Array(25).fill(null);
209
+ for (const [cell, direction, count] of layout.clues) {
210
+ const transformed = transformCell(cell, turns, reflect);
211
+ clues[transformed] = { direction: transformDirection(direction, turns, reflect), count };
212
+ }
213
+ const board = { width: 5, height: 5, clues };
214
+ const shaded = Array(25).fill(false);
215
+ for (const cell of layout.shaded)
216
+ shaded[transformCell(cell, turns, reflect)] = true;
217
+ const expectedEdges = edgesFromLoop(board, layout.loop.map(cell => transformCell(cell, turns, reflect)));
218
+ if (!isYajilinBoard(board) || !checkYajilin(board, shaded, expectedEdges).ok)
219
+ throw new Error("Invalid Yajilin layout");
220
+ const proof = solveYajilin(board);
221
+ if (!proof.complete || proof.count !== 1 || !proof.solution)
222
+ throw new Error("No uniquely proved Yajilin found within the generation budget; try another seed");
223
+ return { ...board, seed, solution: proof.solution };
224
+ }
@@ -0,0 +1,2 @@
1
+ import type { YajilinMount, YajilinMountOptions } from "./yajilin.types.ts";
2
+ export declare function mountYajilin(element: HTMLElement, initial: YajilinMountOptions): YajilinMount;
@@ -0,0 +1,162 @@
1
+ import { checkYajilin, yajilinNeighbors } from "./yajilinBoard.js";
2
+ import { decodeYajilin, encodeYajilin, hintYajilin, newYajilin, restartYajilin, toggleYajilinEdge, toggleYajilinShade, undoYajilin } from "./yajilinGame.js";
3
+ import { drawYajilin } from "./yajilinDraw.js";
4
+ import { YAJILIN_PLAY_STYLE } from "./yajilinStyle.js";
5
+ import { YAJILIN_STRINGS } from "./yajilinStrings.js";
6
+ export function mountYajilin(element, initial) {
7
+ const document = element.ownerDocument, style = document.createElement("style");
8
+ style.textContent = YAJILIN_PLAY_STYLE;
9
+ const root = document.createElement("section");
10
+ root.className = "kazu-yajilin";
11
+ const help = document.createElement("p"), board = document.createElement("div");
12
+ board.className = "ky-board";
13
+ const modes = document.createElement("div");
14
+ modes.className = "ky-tools ky-modes";
15
+ const tools = document.createElement("div");
16
+ tools.className = "ky-tools";
17
+ const status = document.createElement("p");
18
+ status.className = "ky-status";
19
+ status.setAttribute("aria-live", "polite");
20
+ root.append(help, modes, board, tools, status);
21
+ element.replaceChildren(style, root);
22
+ let options = { ...initial };
23
+ let game = initial.progress ? decodeYajilin(initial.progress) : null;
24
+ const sameBoard = game && game.board.width === initial.board.width && game.board.height === initial.board.height
25
+ && game.board.clues.every((clue, cell) => JSON.stringify(clue) === JSON.stringify(initial.board.clues[cell]));
26
+ if (!sameBoard)
27
+ game = newYajilin(initial.board);
28
+ let selected = 0, anchor = null, mode = "line";
29
+ let errors = [], message = "", dead = false;
30
+ const words = () => YAJILIN_STRINGS[options.language ?? "en"];
31
+ const copy = () => ({ ...game, board: { ...game.board, clues: game.board.clues.map(clue => clue ? { ...clue } : null) }, shaded: [...game.shaded], edges: [...game.edges], history: game.history.map(turn => ({ shaded: [...turn.shaded], edges: [...turn.edges] })) });
32
+ const changed = () => { options.onChange?.(copy()); if (checkYajilin(game.board, game.shaded, game.edges).ok)
33
+ options.onFinish?.(copy()); };
34
+ const toggleBetween = (first, second) => {
35
+ const edge = yajilinNeighbors(game.board, first).find(next => next.cell === second)?.edge;
36
+ if (edge === undefined)
37
+ return;
38
+ game = toggleYajilinEdge(game, edge);
39
+ anchor = second;
40
+ selected = second;
41
+ errors = [];
42
+ message = "";
43
+ render();
44
+ changed();
45
+ };
46
+ const render = () => {
47
+ if (dead)
48
+ return;
49
+ const w = words();
50
+ help.textContent = w.help;
51
+ board.innerHTML = drawYajilin(game.board, { ...options, shaded: game.shaded, edges: game.edges, selected, errors });
52
+ const controls = document.createElement("div");
53
+ controls.className = "ky-cells";
54
+ controls.style.gridTemplateColumns = `repeat(${game.board.width}, 1fr)`;
55
+ controls.style.gridTemplateRows = `repeat(${game.board.height}, 1fr)`;
56
+ game.board.clues.forEach((clue, cell) => {
57
+ const button = document.createElement("button");
58
+ button.type = "button";
59
+ button.className = "ky-cell";
60
+ button.dataset.cell = String(cell);
61
+ if (clue)
62
+ button.dataset.clue = "true";
63
+ button.textContent = clue ? `${clue.direction} ${clue.count}` : String(cell + 1);
64
+ button.setAttribute("aria-label", clue ? `${clue.direction} ${clue.count}` : `row ${Math.floor(cell / game.board.width) + 1}, column ${cell % game.board.width + 1}${game.shaded[cell] ? ", shaded" : ""}`);
65
+ button.setAttribute("aria-pressed", String(selected === cell));
66
+ button.tabIndex = selected === cell ? 0 : -1;
67
+ button.onclick = () => {
68
+ selected = cell;
69
+ if (mode === "shade") {
70
+ game = toggleYajilinShade(game, cell);
71
+ errors = [];
72
+ changed();
73
+ }
74
+ else if (anchor === null)
75
+ anchor = cell;
76
+ else if (anchor !== cell)
77
+ toggleBetween(anchor, cell);
78
+ render();
79
+ };
80
+ button.onkeydown = event => {
81
+ const x = cell % game.board.width, y = Math.floor(cell / game.board.width);
82
+ const moves = { ArrowUp: [0, -1], ArrowDown: [0, 1], ArrowLeft: [-1, 0], ArrowRight: [1, 0] };
83
+ if (event.key in moves) {
84
+ event.preventDefault();
85
+ const [dx, dy] = moves[event.key], nextX = x + dx, nextY = y + dy;
86
+ if (nextX >= 0 && nextX < game.board.width && nextY >= 0 && nextY < game.board.height) {
87
+ selected = nextY * game.board.width + nextX;
88
+ render();
89
+ board.querySelectorAll(".ky-cell")[selected]?.focus();
90
+ }
91
+ }
92
+ else if (event.key === "Enter") {
93
+ event.preventDefault();
94
+ if (mode === "shade") {
95
+ game = toggleYajilinShade(game, cell);
96
+ errors = [];
97
+ changed();
98
+ }
99
+ else if (anchor === null)
100
+ anchor = cell;
101
+ else if (anchor !== cell)
102
+ toggleBetween(anchor, cell);
103
+ render();
104
+ board.querySelectorAll(".ky-cell")[selected]?.focus();
105
+ }
106
+ else if (event.key === " ") {
107
+ event.preventDefault();
108
+ mode = "shade";
109
+ game = toggleYajilinShade(game, cell);
110
+ errors = [];
111
+ changed();
112
+ render();
113
+ board.querySelectorAll(".ky-cell")[selected]?.focus();
114
+ }
115
+ else if (event.key.toLowerCase() === "l") {
116
+ mode = "line";
117
+ render();
118
+ board.querySelectorAll(".ky-cell")[selected]?.focus();
119
+ }
120
+ else if (event.key.toLowerCase() === "s") {
121
+ mode = "shade";
122
+ render();
123
+ board.querySelectorAll(".ky-cell")[selected]?.focus();
124
+ }
125
+ };
126
+ controls.append(button);
127
+ });
128
+ board.append(controls);
129
+ modes.replaceChildren();
130
+ tools.replaceChildren();
131
+ const add = (host, label, action, pressed) => {
132
+ const button = document.createElement("button");
133
+ button.type = "button";
134
+ button.textContent = label;
135
+ if (pressed !== undefined)
136
+ button.setAttribute("aria-pressed", String(pressed));
137
+ button.onclick = action;
138
+ host.append(button);
139
+ };
140
+ add(modes, w.line, () => { mode = "line"; render(); }, mode === "line");
141
+ add(modes, w.shade, () => { mode = "shade"; render(); }, mode === "shade");
142
+ add(tools, w.undo, () => { game = undoYajilin(game); errors = []; message = ""; render(); changed(); });
143
+ add(tools, w.hint, () => {
144
+ const hint = hintYajilin(game);
145
+ if (!hint)
146
+ message = w.bad;
147
+ else {
148
+ game = hint.type === "shade" ? toggleYajilinShade(game, hint.cell) : toggleYajilinEdge(game, hint.edge);
149
+ game = { ...game, helped: true };
150
+ selected = hint.type === "shade" ? hint.cell : selected;
151
+ message = w.good;
152
+ changed();
153
+ }
154
+ render();
155
+ });
156
+ add(tools, w.check, () => { errors = checkYajilin(game.board, game.shaded, game.edges).errors; message = errors.length ? w.bad : w.good; render(); });
157
+ add(tools, w.restart, () => { game = restartYajilin(game); anchor = null; errors = []; message = ""; render(); changed(); });
158
+ status.textContent = checkYajilin(game.board, game.shaded, game.edges).ok ? (game.helped ? w.helped : w.won) : message;
159
+ };
160
+ render();
161
+ return { game: copy, progress: () => encodeYajilin(game), set: next => { options = { ...options, ...next }; render(); }, restart: () => { game = restartYajilin(game); anchor = null; render(); changed(); }, destroy: () => { dead = true; element.replaceChildren(); } };
162
+ }
@@ -0,0 +1 @@
1
+ export type { YajilinDrawOptions as YajilinDrawOptions, YajilinMount as YajilinMount, YajilinMountOptions as YajilinMountOptions } from "./yajilin.types.ts";
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,6 @@
1
+ import type { YajilinBoard, YajilinSolve } from "./yajilin.types.ts";
2
+ /** Counts public shade patterns whose remaining cells form the single required loop. */
3
+ export declare function solveYajilin(board: YajilinBoard, options?: {
4
+ limit?: number;
5
+ nodes?: number;
6
+ }): YajilinSolve;
@@ -0,0 +1,82 @@
1
+ import { YAJILIN_NODE_BUDGET } from "./yajilin.constants.js";
2
+ import { checkYajilin, isYajilinBoard, yajilinNeighbors, yajilinRay } from "./yajilinBoard.js";
3
+ /** Counts public shade patterns whose remaining cells form the single required loop. */
4
+ export function solveYajilin(board, options = {}) {
5
+ if (!isYajilinBoard(board))
6
+ throw new RangeError("Invalid Yajilin board");
7
+ const limit = options.limit ?? 2, budget = options.nodes ?? YAJILIN_NODE_BUDGET;
8
+ if (!Number.isInteger(limit) || limit < 1 || !Number.isInteger(budget) || budget < 1)
9
+ throw new RangeError("Invalid search bounds");
10
+ const total = board.width * board.height, state = Array(total).fill(-1), shadeable = [];
11
+ const rays = board.clues.flatMap((clue, cell) => clue ? [{ cell, clue, cells: yajilinRay(board, cell, clue.direction) }] : []);
12
+ board.clues.forEach((clue, cell) => { if (clue)
13
+ state[cell] = 2;
14
+ else
15
+ shadeable.push(cell); });
16
+ let count = 0, nodes = 0, complete = true, solution = null;
17
+ const candidateEdges = (shaded) => {
18
+ const edges = [];
19
+ for (let cell = 0; cell < total; cell += 1) {
20
+ if (board.clues[cell] || shaded[cell])
21
+ continue;
22
+ for (const next of yajilinNeighbors(board, cell))
23
+ if (cell < next.cell && !board.clues[next.cell] && !shaded[next.cell])
24
+ edges.push(next.edge);
25
+ }
26
+ return edges;
27
+ };
28
+ const raysPossible = () => rays.every(({ clue, cells }) => {
29
+ const shaded = cells.filter(cell => state[cell] === 1).length;
30
+ const unknown = cells.filter(cell => state[cell] === -1).length;
31
+ return shaded <= clue.count && shaded + unknown >= clue.count;
32
+ });
33
+ const visit = (depth) => {
34
+ if (++nodes > budget) {
35
+ complete = false;
36
+ return;
37
+ }
38
+ if (!raysPossible())
39
+ return;
40
+ if (depth === shadeable.length) {
41
+ const shaded = state.map(value => value === 1), edges = candidateEdges(shaded);
42
+ if (!checkYajilin(board, shaded, edges).ok)
43
+ return;
44
+ count += 1;
45
+ solution ?? (solution = { shaded, edges });
46
+ if (count >= limit)
47
+ complete = false;
48
+ return;
49
+ }
50
+ let chosen = -1, bestScore = -1;
51
+ for (const cell of shadeable) {
52
+ if (state[cell] !== -1)
53
+ continue;
54
+ let score = 0;
55
+ for (const clue of rays)
56
+ if (clue.cells.includes(cell))
57
+ score += 1;
58
+ if (score > bestScore) {
59
+ chosen = cell;
60
+ bestScore = score;
61
+ }
62
+ }
63
+ if (chosen < 0)
64
+ return;
65
+ state[chosen] = 0;
66
+ visit(depth + 1);
67
+ if (!complete) {
68
+ state[chosen] = -1;
69
+ return;
70
+ }
71
+ const x = chosen % board.width, y = Math.floor(chosen / board.width);
72
+ const touchesShade = (x > 0 && state[chosen - 1] === 1) || (x + 1 < board.width && state[chosen + 1] === 1)
73
+ || (y > 0 && state[chosen - board.width] === 1) || (y + 1 < board.height && state[chosen + board.width] === 1);
74
+ if (!touchesShade) {
75
+ state[chosen] = 1;
76
+ visit(depth + 1);
77
+ }
78
+ state[chosen] = -1;
79
+ };
80
+ visit(0);
81
+ return { count, solution, complete, nodes };
82
+ }
@@ -0,0 +1,32 @@
1
+ export declare const YAJILIN_STRINGS: {
2
+ readonly en: {
3
+ readonly title: "Yajilin";
4
+ readonly help: "Shade the number of cells each arrow points to. Shaded cells cannot touch. Every other empty cell is part of one loop.";
5
+ readonly line: "Line";
6
+ readonly shade: "Shade";
7
+ readonly undo: "Undo";
8
+ readonly hint: "Hint";
9
+ readonly check: "Check";
10
+ readonly restart: "Restart";
11
+ readonly won: "Solved!";
12
+ readonly helped: "Solved with help.";
13
+ readonly good: "Keep going; the loop is not complete yet.";
14
+ readonly bad: "Check the marked cells, arrows, and line.";
15
+ readonly cell: "cell";
16
+ };
17
+ readonly ja: {
18
+ readonly title: "やじりん";
19
+ readonly help: "矢印の先にある黒マスの数を合わせます。黒マスは辺で隣り合えません。残りの空きマスを一つの輪にします。";
20
+ readonly line: "線";
21
+ readonly shade: "黒マス";
22
+ readonly undo: "戻す";
23
+ readonly hint: "ヒント";
24
+ readonly check: "確認";
25
+ readonly restart: "やり直す";
26
+ readonly won: "完成!";
27
+ readonly helped: "ヒントを使って完成。";
28
+ readonly good: "輪はまだ完成していません。続けましょう。";
29
+ readonly bad: "印のついたマス、矢印、線を確認してください。";
30
+ readonly cell: "マス";
31
+ };
32
+ };
@@ -0,0 +1,4 @@
1
+ export const YAJILIN_STRINGS = {
2
+ en: { title: "Yajilin", help: "Shade the number of cells each arrow points to. Shaded cells cannot touch. Every other empty cell is part of one loop.", line: "Line", shade: "Shade", undo: "Undo", hint: "Hint", check: "Check", restart: "Restart", won: "Solved!", helped: "Solved with help.", good: "Keep going; the loop is not complete yet.", bad: "Check the marked cells, arrows, and line.", cell: "cell" },
3
+ ja: { title: "やじりん", help: "矢印の先にある黒マスの数を合わせます。黒マスは辺で隣り合えません。残りの空きマスを一つの輪にします。", line: "線", shade: "黒マス", undo: "戻す", hint: "ヒント", check: "確認", restart: "やり直す", won: "完成!", helped: "ヒントを使って完成。", good: "輪はまだ完成していません。続けましょう。", bad: "印のついたマス、矢印、線を確認してください。", cell: "マス" },
4
+ };
@@ -0,0 +1 @@
1
+ export declare const YAJILIN_PLAY_STYLE = "\n.kazu-yajilin { color:var(--kz-ink,#1f2320); font:16px/1.4 system-ui,sans-serif; }\n.kazu-yajilin .ky-board { position:relative; max-width:440px; margin:auto; }\n.kazu-yajilin svg { border:1px solid var(--kz-frame,#a98954); border-radius:4px; }\n.kazu-yajilin .ky-cells { position:absolute; inset:6%; display:grid; }\n.kazu-yajilin .ky-cell { border:0; background:transparent; color:transparent; cursor:pointer; }\n.kazu-yajilin .ky-cell:focus-visible { outline:3px solid var(--kz-focus,#c57d2d); outline-offset:-5px; }\n.kazu-yajilin .ky-tools { display:flex; flex-wrap:wrap; gap:.5rem; justify-content:center; margin:.8rem 0; }\n.kazu-yajilin button { font:inherit; padding:.45rem .8rem; }\n.kazu-yajilin .ky-status { min-height:1.5em; text-align:center; }\n.kazu-yajilin .ky-modes [aria-pressed=\"true\"] { outline:2px solid var(--kz-frame,#a98954); }\n";
@@ -0,0 +1,12 @@
1
+ export const YAJILIN_PLAY_STYLE = `
2
+ .kazu-yajilin { color:var(--kz-ink,#1f2320); font:16px/1.4 system-ui,sans-serif; }
3
+ .kazu-yajilin .ky-board { position:relative; max-width:440px; margin:auto; }
4
+ .kazu-yajilin svg { border:1px solid var(--kz-frame,#a98954); border-radius:4px; }
5
+ .kazu-yajilin .ky-cells { position:absolute; inset:6%; display:grid; }
6
+ .kazu-yajilin .ky-cell { border:0; background:transparent; color:transparent; cursor:pointer; }
7
+ .kazu-yajilin .ky-cell:focus-visible { outline:3px solid var(--kz-focus,#c57d2d); outline-offset:-5px; }
8
+ .kazu-yajilin .ky-tools { display:flex; flex-wrap:wrap; gap:.5rem; justify-content:center; margin:.8rem 0; }
9
+ .kazu-yajilin button { font:inherit; padding:.45rem .8rem; }
10
+ .kazu-yajilin .ky-status { min-height:1.5em; text-align:center; }
11
+ .kazu-yajilin .ky-modes [aria-pressed="true"] { outline:2px solid var(--kz-frame,#a98954); }
12
+ `;