@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,11 @@
1
+ export * from "./akari.types.js";
2
+ export * from "./akari.constants.js";
3
+ export * from "./akariBoard.js";
4
+ export * from "./akariSolve.js";
5
+ export * from "./akariGenerate.js";
6
+ export * from "./akariRate.js";
7
+ export * from "./akariGame.js";
8
+ export { drawAkari } from "./akariDraw.js";
9
+ export { mountAkari } from "./akariMount.js";
10
+ export { AKARI_PLAY_STYLE } from "./akariStyle.js";
11
+ export { AKARI_STRINGS } from "./akariStrings.js";
@@ -0,0 +1,2 @@
1
+ export { mountAkari } from "./akariMount.ts";
2
+ export type { AkariMount, AkariMountOptions, AkariDrawOptions, AkariLanguage, AkariMaterial, AkariPieces } from "./akariPlay.types.ts";
@@ -0,0 +1 @@
1
+ export { mountAkari } from "./akariMount.js";
@@ -0,0 +1,7 @@
1
+ export declare const AKARI_MOST_SIDE = 16;
2
+ export declare const AKARI_MOST_NODES = 250000;
3
+ /** How hard a puzzle is made, by what a person must do to solve it; see `rateAkari`. */
4
+ export declare const AKARI_LEVELS: readonly ["easy", "medium", "hard", "extra-hard"];
5
+ /** The sides the demo and the site offer for a square board; any side from 2 to `AKARI_MOST_SIDE` can be made. */
6
+ export declare const AKARI_SIZES: readonly [5, 7, 10, 14];
7
+ export declare const AKARI_MOST_ATTEMPTS = 60;
@@ -0,0 +1,7 @@
1
+ export const AKARI_MOST_SIDE = 16;
2
+ export const AKARI_MOST_NODES = 250000;
3
+ /** How hard a puzzle is made, by what a person must do to solve it; see `rateAkari`. */
4
+ export const AKARI_LEVELS = ["easy", "medium", "hard", "extra-hard"];
5
+ /** The sides the demo and the site offer for a square board; any side from 2 to `AKARI_MOST_SIDE` can be made. */
6
+ export const AKARI_SIZES = [5, 7, 10, 14];
7
+ export const AKARI_MOST_ATTEMPTS = 60;
@@ -0,0 +1,52 @@
1
+ /** A board is row-major. null is white, false is a plain black square, and 0–4 are numbered black squares. */
2
+ export type AkariBoard = {
3
+ width: number;
4
+ height: number;
5
+ cells: readonly (number | null | false)[];
6
+ };
7
+ export type AkariLevel = "easy" | "medium" | "hard" | "extra-hard";
8
+ export type AkariPuzzle = AkariBoard & {
9
+ seed: number;
10
+ level: AkariLevel;
11
+ solution: readonly number[];
12
+ };
13
+ /**
14
+ * How hard a board is, measured by solving it. `depth` 0 means the plain rules solve it, 1 means somebody has to
15
+ * suppose a bulb or an empty square and see it break, 2 means more than that. `probes` is how many suppositions
16
+ * the depth-1 reasoning needed. The rest describes the board.
17
+ */
18
+ export type AkariRating = {
19
+ depth: 0 | 1 | 2;
20
+ probes: number;
21
+ whites: number;
22
+ blacks: number;
23
+ clues: number;
24
+ bulbs: number;
25
+ /** Numbered squares as a share of the black squares that touch a white one. */
26
+ clueShare: number;
27
+ /** White squares as a share of the board. */
28
+ openShare: number;
29
+ };
30
+ export type AkariCheck = {
31
+ ok: boolean;
32
+ illuminated: number;
33
+ errors: readonly number[];
34
+ dark: readonly number[];
35
+ numbered: readonly number[];
36
+ conflicts: readonly number[];
37
+ };
38
+ export type AkariProgress = Omit<AkariCheck, "ok"> & {
39
+ ok: boolean;
40
+ };
41
+ export type AkariSolve = {
42
+ count: number;
43
+ solution: readonly number[] | null;
44
+ complete: boolean;
45
+ nodes: number;
46
+ };
47
+ export type AkariGame = {
48
+ board: AkariBoard;
49
+ bulbs: readonly number[];
50
+ history: readonly (readonly number[])[];
51
+ helped: boolean;
52
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,11 @@
1
+ import type { AkariBoard, AkariCheck, AkariProgress } from "./akari.types.ts";
2
+ /** Validates dimensions and the three public square kinds. */
3
+ export declare function isAkariBoard(value: unknown): value is AkariBoard;
4
+ /** Returns the orthogonally adjacent cells to a board position. */
5
+ export declare function akariNeighbours(board: AkariBoard, cell: number): number[];
6
+ /** White squares visible from a cell, including itself, stopping at black squares and edges. */
7
+ export declare function akariVisible(board: AkariBoard, cell: number): number[];
8
+ /** Checks a complete placement from the public rules, without consulting a stored answer. */
9
+ export declare function checkAkari(board: AkariBoard, bulbs: readonly number[]): AkariCheck;
10
+ /** Reports immediate contradictions while allowing required clues to remain unsatisfied during play. */
11
+ export declare function progressAkari(board: AkariBoard, bulbs: readonly number[]): AkariProgress;
@@ -0,0 +1,96 @@
1
+ import { AKARI_MOST_SIDE } from "./akari.constants.js";
2
+ /** Validates dimensions and the three public square kinds. */
3
+ export function isAkariBoard(value) {
4
+ if (!value || typeof value !== "object")
5
+ return false;
6
+ const board = value;
7
+ return Number.isInteger(board.width) && board.width >= 2 && board.width <= AKARI_MOST_SIDE
8
+ && Number.isInteger(board.height) && board.height >= 2 && board.height <= AKARI_MOST_SIDE
9
+ && Array.isArray(board.cells) && board.cells.length === board.width * board.height
10
+ && board.cells.every(cell => cell === null || cell === false
11
+ || Number.isInteger(cell) && cell >= 0 && cell <= 4)
12
+ && board.cells.some(cell => cell === null);
13
+ }
14
+ /** Returns the orthogonally adjacent cells to a board position. */
15
+ export function akariNeighbours(board, cell) {
16
+ if (!Number.isInteger(cell) || cell < 0 || cell >= board.cells.length)
17
+ return [];
18
+ const x = cell % board.width;
19
+ const y = Math.floor(cell / board.width);
20
+ const coordinates = [[x, y - 1], [x + 1, y], [x, y + 1], [x - 1, y]];
21
+ return coordinates
22
+ .filter(([cx, cy]) => cx >= 0 && cx < board.width && cy >= 0 && cy < board.height)
23
+ .map(([cx, cy]) => cy * board.width + cx);
24
+ }
25
+ /** White squares visible from a cell, including itself, stopping at black squares and edges. */
26
+ export function akariVisible(board, cell) {
27
+ if (!Number.isInteger(cell) || cell < 0 || cell >= board.cells.length || board.cells[cell] !== null)
28
+ return [];
29
+ const x = cell % board.width;
30
+ const y = Math.floor(cell / board.width);
31
+ const visible = [cell];
32
+ for (const [dx, dy] of [[1, 0], [-1, 0], [0, 1], [0, -1]]) {
33
+ let cx = x + dx;
34
+ let cy = y + dy;
35
+ while (cx >= 0 && cx < board.width && cy >= 0 && cy < board.height) {
36
+ const next = cy * board.width + cx;
37
+ if (board.cells[next] !== null)
38
+ break;
39
+ visible.push(next);
40
+ cx += dx;
41
+ cy += dy;
42
+ }
43
+ }
44
+ return visible;
45
+ }
46
+ function evaluate(board, bulbs, complete) {
47
+ if (!isAkariBoard(board))
48
+ throw new RangeError("Invalid Akari board");
49
+ const errors = [];
50
+ const conflicts = [];
51
+ const numbered = [];
52
+ const dark = [];
53
+ const unique = new Set();
54
+ bulbs.forEach((cell, index) => {
55
+ if (!Number.isInteger(cell) || cell < 0 || cell >= board.cells.length
56
+ || board.cells[cell] !== null || unique.has(cell)) {
57
+ errors.push(index);
58
+ }
59
+ else {
60
+ unique.add(cell);
61
+ }
62
+ });
63
+ const lit = new Set();
64
+ for (const bulb of unique) {
65
+ const ray = akariVisible(board, bulb);
66
+ ray.forEach(cell => lit.add(cell));
67
+ if (ray.some(cell => cell !== bulb && unique.has(cell)))
68
+ conflicts.push(bulb);
69
+ }
70
+ for (let cell = 0; cell < board.cells.length; cell += 1) {
71
+ if (board.cells[cell] === null && !lit.has(cell))
72
+ dark.push(cell);
73
+ const clue = board.cells[cell];
74
+ if (typeof clue !== "number")
75
+ continue;
76
+ const adjacent = akariNeighbours(board, cell).filter(neighbour => unique.has(neighbour)).length;
77
+ if (complete ? adjacent !== clue : adjacent > clue)
78
+ numbered.push(cell);
79
+ }
80
+ return {
81
+ ok: !errors.length && !conflicts.length && !numbered.length && (!complete || !dark.length),
82
+ illuminated: lit.size,
83
+ errors,
84
+ dark,
85
+ numbered,
86
+ conflicts,
87
+ };
88
+ }
89
+ /** Checks a complete placement from the public rules, without consulting a stored answer. */
90
+ export function checkAkari(board, bulbs) {
91
+ return evaluate(board, bulbs, true);
92
+ }
93
+ /** Reports immediate contradictions while allowing required clues to remain unsatisfied during play. */
94
+ export function progressAkari(board, bulbs) {
95
+ return evaluate(board, bulbs, false);
96
+ }
@@ -0,0 +1,4 @@
1
+ import type { AkariBoard } from "./akari.types.ts";
2
+ import type { AkariDrawOptions } from "./akariPlay.types.ts";
3
+ /** Draws the public clues and current bulbs as SVG. */
4
+ export declare function drawAkari(board: AkariBoard, options?: AkariDrawOptions): string;
@@ -0,0 +1,38 @@
1
+ import { akariVisible, isAkariBoard } from "./akariBoard.js";
2
+ import { akariWords } from "./akariStrings.js";
3
+ /** Draws the public clues and current bulbs as SVG. */
4
+ export function drawAkari(board, options = {}) {
5
+ if (!isAkariBoard(board))
6
+ throw new RangeError("Invalid Akari board");
7
+ const words = akariWords(options.language);
8
+ const size = 48;
9
+ const palettes = {
10
+ ivory: ["var(--kz-paper,#fbf8f1)", "var(--kz-ink,#1f2320)", "var(--kz-grid,#cfc6b2)", "#252923"],
11
+ wood: ["#e5cda6", "#493e2f", "#bca582", "#493e2f"],
12
+ slate: ["#262a27", "#ece8dc", "#454a44", "#111412"],
13
+ };
14
+ const [paper, ink, grid, black] = palettes[options.material ?? "ivory"];
15
+ const bulbs = new Set(options.bulbs ?? []);
16
+ const lit = new Set();
17
+ bulbs.forEach(cell => akariVisible(board, cell).forEach(illuminated => lit.add(illuminated)));
18
+ const cells = board.cells.map((clue, cell) => {
19
+ const x = cell % board.width * size;
20
+ const y = Math.floor(cell / board.width) * size;
21
+ const active = cell === options.selected;
22
+ const bad = options.errors?.includes(cell);
23
+ const bulb = bulbs.has(cell)
24
+ ? `${options.pieces === "tiles" ? `<rect x="${x + 10}" y="${y + 10}" width="28" height="28" rx="6" fill="${paper}" stroke="${grid}"/>` : ""}
25
+ <circle cx="${x + 24}" cy="${y + 24}" r="11" fill="${ink}"/>
26
+ <path d="M${x + 18} ${y + 31}h12m-10 4h8" stroke="${ink}" stroke-width="2"/>`
27
+ : "";
28
+ const body = clue === null
29
+ ? `<rect x="${x}" y="${y}" width="48" height="48" fill="${lit.has(cell) ? paper : "var(--kz-grid,#cfc6b2)"}" fill-opacity=".95"/>${bulb}`
30
+ : `<rect x="${x}" y="${y}" width="48" height="48" fill="${black}"/>${typeof clue === "number"
31
+ ? `<text x="${x + 24}" y="${y + 25}" dominant-baseline="middle" text-anchor="middle" fill="${paper}" font-size="21" font-weight="700" font-family="system-ui,sans-serif">${clue}</text>`
32
+ : ""}`;
33
+ const stroke = bad ? "var(--kz-bad,#b5452c)" : grid;
34
+ const strokeWidth = bad ? 3 : 1;
35
+ return `<g data-akari-cell="${cell}">${body}<rect x="${x}" y="${y}" width="48" height="48" fill="${active ? ink : "transparent"}" fill-opacity="${active ? ".16" : "1"}" stroke="${stroke}" stroke-width="${strokeWidth}"/></g>`;
36
+ }).join("");
37
+ return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="-2 -2 ${board.width * size + 4} ${board.height * size + 4}" role="img" aria-label="${words.title}" style="display:block;width:100%;height:auto;background:${paper}">${cells}<rect width="${board.width * size}" height="${board.height * size}" fill="none" stroke="var(--kz-frame,#a98954)" stroke-width="2"/></svg>`;
38
+ }
@@ -0,0 +1,15 @@
1
+ import type { AkariBoard, AkariGame } from "./akari.types.ts";
2
+ /** Starts a game with only its public board data. */
3
+ export declare function newAkari(board: AkariBoard): AkariGame;
4
+ /** Toggles a bulb on a white square and keeps one prior turn for undo. */
5
+ export declare function toggleAkari(game: AkariGame, cell: number): AkariGame;
6
+ /** Restores the last bulb placement. */
7
+ export declare function undoAkari(game: AkariGame): AkariGame;
8
+ /** A game is finished only when its bulbs satisfy every rule and light every white square. */
9
+ export declare function akariFinished(game: AkariGame): boolean;
10
+ /** Returns a missing bulb, or an extra bulb to remove, only after uniqueness is proved. */
11
+ export declare function hintAkari(game: AkariGame): number | null;
12
+ /** Encodes only public clues and player placements. */
13
+ export declare function encodeAkari(game: AkariGame): string;
14
+ /** Decodes a bounded save after validating the board and each placement. */
15
+ export declare function decodeAkari(code: string): AkariGame | null;
@@ -0,0 +1,71 @@
1
+ import { checkAkari, isAkariBoard } from "./akariBoard.js";
2
+ import { solveAkari } from "./akariSolve.js";
3
+ /** Starts a game with only its public board data. */
4
+ export function newAkari(board) {
5
+ if (!isAkariBoard(board))
6
+ throw new RangeError("Invalid Akari board");
7
+ return {
8
+ board: { width: board.width, height: board.height, cells: [...board.cells] },
9
+ bulbs: [],
10
+ history: [],
11
+ helped: false,
12
+ };
13
+ }
14
+ /** Toggles a bulb on a white square and keeps one prior turn for undo. */
15
+ export function toggleAkari(game, cell) {
16
+ if (!Number.isInteger(cell) || cell < 0 || cell >= game.board.cells.length || game.board.cells[cell] !== null) {
17
+ return game;
18
+ }
19
+ const bulbs = game.bulbs.includes(cell)
20
+ ? game.bulbs.filter(placed => placed !== cell)
21
+ : [...game.bulbs, cell];
22
+ return { ...game, bulbs, history: [...game.history, [...game.bulbs]] };
23
+ }
24
+ /** Restores the last bulb placement. */
25
+ export function undoAkari(game) {
26
+ const previous = game.history.at(-1);
27
+ return previous
28
+ ? { ...game, bulbs: [...previous], history: game.history.slice(0, -1) }
29
+ : game;
30
+ }
31
+ /** A game is finished only when its bulbs satisfy every rule and light every white square. */
32
+ export function akariFinished(game) {
33
+ return checkAkari(game.board, game.bulbs).ok;
34
+ }
35
+ /** Returns a missing bulb, or an extra bulb to remove, only after uniqueness is proved. */
36
+ export function hintAkari(game) {
37
+ const solved = solveAkari(game.board);
38
+ if (!solved.complete || solved.count !== 1 || !solved.solution)
39
+ return null;
40
+ return solved.solution.find(cell => !game.bulbs.includes(cell))
41
+ ?? game.bulbs.find(cell => !solved.solution.includes(cell))
42
+ ?? null;
43
+ }
44
+ /** Encodes only public clues and player placements. */
45
+ export function encodeAkari(game) {
46
+ return JSON.stringify({ version: 1, board: game.board, bulbs: game.bulbs, helped: game.helped });
47
+ }
48
+ /** Decodes a bounded save after validating the board and each placement. */
49
+ export function decodeAkari(code) {
50
+ try {
51
+ if (code.length > 40000)
52
+ return null;
53
+ const value = JSON.parse(code);
54
+ if (value.version !== 1 || !isAkariBoard(value.board) || !Array.isArray(value.bulbs)
55
+ || value.bulbs.length > value.board.cells.length || typeof value.helped !== "boolean")
56
+ return null;
57
+ if (new Set(value.bulbs).size !== value.bulbs.length)
58
+ return null;
59
+ let game = newAkari(value.board);
60
+ for (const cell of value.bulbs) {
61
+ const next = toggleAkari(game, cell);
62
+ if (next === game)
63
+ return null;
64
+ game = next;
65
+ }
66
+ return { ...game, history: [], helped: value.helped };
67
+ }
68
+ catch {
69
+ return null;
70
+ }
71
+ }
@@ -0,0 +1,10 @@
1
+ import type { AkariLevel, AkariPuzzle } from "./akari.types.ts";
2
+ /**
3
+ * Makes a seeded board and proves it has one answer. A random wall of black squares is lit by randomly placed
4
+ * bulbs, every black square that touches a white one is numbered, and then numbers are taken away for as long as
5
+ * the puzzle can still be solved the way the level asks: easy and medium by the rules alone (easy keeps most
6
+ * of its numbers), hard by supposing one square at a time, extra-hard for as long as the answer stays single,
7
+ * which leaves a board that needs more supposing than that. If no board of the level is found within the
8
+ * attempts, the next one down is tried, and the first generator, which cannot fail, is the last.
9
+ */
10
+ export declare function generateAkari(width?: number, height?: number, seed?: number, level?: AkariLevel): AkariPuzzle;
@@ -0,0 +1,101 @@
1
+ import { AKARI_LEVELS, AKARI_MOST_ATTEMPTS, AKARI_MOST_SIDE } from "./akari.constants.js";
2
+ import { akariNeighbours, akariVisible, checkAkari, isAkariBoard } from "./akariBoard.js";
3
+ import { akariModel } from "./akariLogic.js";
4
+ import { solveAkari } from "./akariSolve.js";
5
+ import { templateAkari } from "./akariTemplate.js";
6
+ import { logicCsp, openSlots } from "./csp.js";
7
+ import { isKazuSeed, seededRandom, shuffled } from "./random.js";
8
+ /**
9
+ * Makes a seeded board and proves it has one answer. A random wall of black squares is lit by randomly placed
10
+ * bulbs, every black square that touches a white one is numbered, and then numbers are taken away for as long as
11
+ * the puzzle can still be solved the way the level asks: easy and medium by the rules alone (easy keeps most
12
+ * of its numbers), hard by supposing one square at a time, extra-hard for as long as the answer stays single,
13
+ * which leaves a board that needs more supposing than that. If no board of the level is found within the
14
+ * attempts, the next one down is tried, and the first generator, which cannot fail, is the last.
15
+ */
16
+ export function generateAkari(width = 7, height = width, seed = 1, level = "medium") {
17
+ if (![width, height].every(n => Number.isInteger(n) && n >= 2 && n <= AKARI_MOST_SIDE)
18
+ || !isKazuSeed(seed) || !AKARI_LEVELS.includes(level))
19
+ throw new RangeError("Invalid Akari settings");
20
+ const random = seededRandom(seed);
21
+ for (let aim = AKARI_LEVELS.indexOf(level); aim >= 0; aim -= 1) {
22
+ const aimed = AKARI_LEVELS[aim];
23
+ // Extra-hard is the hardest of several boards that need supposing: the most suppositions wins.
24
+ const wanted = aimed === "extra-hard" ? 8 : 1;
25
+ let best = null, found = 0;
26
+ for (let attempt = 0; attempt < AKARI_MOST_ATTEMPTS && found < wanted; attempt += 1) {
27
+ const made = attemptAkari(width, height, aimed, random);
28
+ if (!made)
29
+ continue;
30
+ const proof = solveAkari(made.board, { limit: 2 });
31
+ if (!proof.complete || proof.count !== 1 || !proof.solution || !checkAkari(made.board, proof.solution).ok)
32
+ continue;
33
+ found += 1;
34
+ if (!best || made.probes > best.probes)
35
+ best = { board: made.board, probes: made.probes, solution: proof.solution };
36
+ }
37
+ if (best)
38
+ return { ...best.board, seed, level, solution: best.solution };
39
+ }
40
+ const fallback = templateAkari(width, height, seed);
41
+ return { ...fallback, level };
42
+ }
43
+ function attemptAkari(width, height, level, random) {
44
+ const size = width * height;
45
+ const density = { easy: .2, medium: .22, hard: .24, "extra-hard": .26 }[level] * (.85 + random() * .3);
46
+ const cells = Array.from({ length: size }, () => random() < density ? false : null);
47
+ if (random() < .5)
48
+ for (let y = 0; y < height; y += 1)
49
+ for (let x = 0; x < width; x += 1) {
50
+ const mirror = (height - 1 - y) * width + width - 1 - x;
51
+ if (y * width + x < mirror)
52
+ cells[mirror] = cells[y * width + x];
53
+ }
54
+ if (!cells.includes(null))
55
+ return null;
56
+ const base = { width, height, cells };
57
+ // Light every white square with randomly chosen bulbs that never see one another.
58
+ const lit = new Set(), bulbs = new Set();
59
+ for (const cell of shuffled(cells.flatMap((value, at) => value === null ? [at] : []), random)) {
60
+ if (lit.has(cell))
61
+ continue;
62
+ bulbs.add(cell);
63
+ for (const seen of akariVisible(base, cell))
64
+ lit.add(seen);
65
+ }
66
+ const numbered = cells.flatMap((value, at) => value === false && akariNeighbours(base, at).some(n => cells[n] === null) ? [at] : []);
67
+ for (const at of numbered)
68
+ cells[at] = akariNeighbours(base, at).filter(n => bulbs.has(n)).length;
69
+ if (!numbered.length)
70
+ return null;
71
+ const accepts = () => {
72
+ const { csp } = akariModel({ width, height, cells });
73
+ return logicCsp(csp, openSlots(csp), level === "easy" || level === "medium" ? 0 : 1).solved;
74
+ };
75
+ if (!accepts())
76
+ return null;
77
+ const keepAtLeast = level === "easy" ? Math.ceil(numbered.length * .7) : 0;
78
+ let left = numbered.length;
79
+ for (const at of shuffled(numbered, random)) {
80
+ if (left <= keepAtLeast)
81
+ break;
82
+ const was = cells[at];
83
+ cells[at] = false;
84
+ if (accepts())
85
+ left -= 1;
86
+ else
87
+ cells[at] = was;
88
+ }
89
+ const board = { width, height, cells };
90
+ if (!isAkariBoard(board))
91
+ return null;
92
+ const { csp } = akariModel(board);
93
+ if (level === "easy" || level === "medium")
94
+ return { board, probes: 0 };
95
+ if (logicCsp(csp, openSlots(csp), 0).solved)
96
+ return null;
97
+ const probing = logicCsp(csp, openSlots(csp), 1);
98
+ if (!probing.solved)
99
+ return level === "extra-hard" ? { board, probes: 1000 } : null;
100
+ return probing.probes >= Math.max(2, Math.round(size * .02)) ? { board, probes: probing.probes } : null;
101
+ }
@@ -0,0 +1,10 @@
1
+ import type { Csp } from "./csp.ts";
2
+ import type { AkariBoard } from "./akari.types.ts";
3
+ /** An Akari board as variables: one per white square, slot 0 for no bulb and slot 1 for a bulb. */
4
+ export type AkariModel = {
5
+ csp: Csp;
6
+ whites: readonly number[];
7
+ index: Int32Array;
8
+ };
9
+ /** Builds the pruning rules of Akari: a bulb shades its lines, a number counts its neighbours, every white square needs a lamp. */
10
+ export declare function akariModel(board: AkariBoard): AkariModel;
@@ -0,0 +1,84 @@
1
+ import { akariNeighbours, akariVisible } from "./akariBoard.js";
2
+ /** Builds the pruning rules of Akari: a bulb shades its lines, a number counts its neighbours, every white square needs a lamp. */
3
+ export function akariModel(board) {
4
+ const whites = board.cells.flatMap((value, cell) => value === null ? [cell] : []);
5
+ const index = new Int32Array(board.cells.length).fill(-1);
6
+ whites.forEach((cell, i) => { index[cell] = i; });
7
+ const sees = whites.map(cell => Int32Array.from(akariVisible(board, cell).filter(other => other !== cell).map(other => index[other])));
8
+ const clues = board.cells.flatMap((value, cell) => typeof value === "number"
9
+ ? [{ need: value, near: Int32Array.from(akariNeighbours(board, cell).filter(other => index[other] >= 0).map(other => index[other])) }]
10
+ : []);
11
+ const starts = Int32Array.from({ length: whites.length + 1 }, (_, i) => i * 2);
12
+ const propagate = (alive) => {
13
+ let changed = true;
14
+ while (changed) {
15
+ changed = false;
16
+ for (let i = 0; i < whites.length; i += 1) {
17
+ if (!alive[2 * i] && !alive[2 * i + 1])
18
+ return false;
19
+ if (alive[2 * i] || !alive[2 * i + 1])
20
+ continue;
21
+ const ray = sees[i];
22
+ for (let k = 0; k < ray.length; k += 1) {
23
+ const j = ray[k];
24
+ if (alive[2 * j + 1]) {
25
+ alive[2 * j + 1] = 0;
26
+ changed = true;
27
+ if (!alive[2 * j])
28
+ return false;
29
+ }
30
+ }
31
+ }
32
+ for (const clue of clues) {
33
+ let on = 0, maybe = 0;
34
+ for (let k = 0; k < clue.near.length; k += 1) {
35
+ const j = clue.near[k];
36
+ if (alive[2 * j + 1]) {
37
+ maybe += 1;
38
+ if (!alive[2 * j])
39
+ on += 1;
40
+ }
41
+ }
42
+ if (on > clue.need || maybe < clue.need)
43
+ return false;
44
+ if (on === clue.need && maybe > on) {
45
+ for (let k = 0; k < clue.near.length; k += 1) {
46
+ const j = clue.near[k];
47
+ if (alive[2 * j + 1] && alive[2 * j]) {
48
+ alive[2 * j + 1] = 0;
49
+ changed = true;
50
+ }
51
+ }
52
+ }
53
+ else if (maybe === clue.need && maybe > on) {
54
+ for (let k = 0; k < clue.near.length; k += 1) {
55
+ const j = clue.near[k];
56
+ if (alive[2 * j + 1] && alive[2 * j]) {
57
+ alive[2 * j] = 0;
58
+ changed = true;
59
+ }
60
+ }
61
+ }
62
+ }
63
+ for (let i = 0; i < whites.length; i += 1) {
64
+ let lamps = alive[2 * i + 1] ? 1 : 0, only = alive[2 * i + 1] ? i : -1;
65
+ const ray = sees[i];
66
+ for (let k = 0; k < ray.length && lamps < 2; k += 1) {
67
+ const j = ray[k];
68
+ if (alive[2 * j + 1]) {
69
+ lamps += 1;
70
+ only = j;
71
+ }
72
+ }
73
+ if (lamps === 0)
74
+ return false;
75
+ if (lamps === 1 && alive[2 * only]) {
76
+ alive[2 * only] = 0;
77
+ changed = true;
78
+ }
79
+ }
80
+ }
81
+ return true;
82
+ };
83
+ return { csp: { starts, propagate }, whites, index };
84
+ }
@@ -0,0 +1,3 @@
1
+ import type { AkariMount, AkariMountOptions } from "./akariPlay.types.ts";
2
+ /** Mounts the player in a host element; call destroy when the host is removed. */
3
+ export declare function mountAkari(host: HTMLElement, initial: AkariMountOptions): AkariMount;