@datamoc/mw_games 0.7.6 → 0.7.8

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 (367) hide show
  1. package/CHANGELOG.md +359 -0
  2. package/README.md +7 -7
  3. package/dist/actors/Inventory.d.ts +7 -1
  4. package/dist/actors/Inventory.d.ts.map +1 -1
  5. package/dist/actors/Inventory.js.map +1 -1
  6. package/dist/actors/Shop.d.ts.map +1 -1
  7. package/dist/actors/Shop.js +4 -1
  8. package/dist/actors/Shop.js.map +1 -1
  9. package/dist/actors/craft.d.ts +35 -14
  10. package/dist/actors/craft.d.ts.map +1 -1
  11. package/dist/actors/craft.js +56 -24
  12. package/dist/actors/craft.js.map +1 -1
  13. package/dist/actors/index.d.ts +1 -1
  14. package/dist/actors/index.d.ts.map +1 -1
  15. package/dist/ai/Heuristics.d.ts +240 -0
  16. package/dist/ai/Heuristics.d.ts.map +1 -0
  17. package/dist/ai/Heuristics.js +298 -0
  18. package/dist/ai/Heuristics.js.map +1 -0
  19. package/dist/ai/index.d.ts +4 -0
  20. package/dist/ai/index.d.ts.map +1 -1
  21. package/dist/ai/index.js +2 -0
  22. package/dist/ai/index.js.map +1 -1
  23. package/dist/ai/lua.d.ts +21 -0
  24. package/dist/ai/lua.d.ts.map +1 -1
  25. package/dist/ai/lua.js +21 -0
  26. package/dist/ai/lua.js.map +1 -1
  27. package/dist/ai/score.d.ts +162 -0
  28. package/dist/ai/score.d.ts.map +1 -0
  29. package/dist/ai/score.js +147 -0
  30. package/dist/ai/score.js.map +1 -0
  31. package/dist/assets/loader.d.ts +18 -4
  32. package/dist/assets/loader.d.ts.map +1 -1
  33. package/dist/assets/loader.js +40 -11
  34. package/dist/assets/loader.js.map +1 -1
  35. package/dist/audio/Positional.d.ts +125 -0
  36. package/dist/audio/Positional.d.ts.map +1 -0
  37. package/dist/audio/Positional.js +135 -0
  38. package/dist/audio/Positional.js.map +1 -0
  39. package/dist/audio/Sound.d.ts +7 -1
  40. package/dist/audio/Sound.d.ts.map +1 -1
  41. package/dist/audio/Sound.js +8 -2
  42. package/dist/audio/Sound.js.map +1 -1
  43. package/dist/audio/index.d.ts +2 -0
  44. package/dist/audio/index.d.ts.map +1 -1
  45. package/dist/audio/index.js +1 -0
  46. package/dist/audio/index.js.map +1 -1
  47. package/dist/battle/AttackDialog.d.ts +75 -0
  48. package/dist/battle/AttackDialog.d.ts.map +1 -0
  49. package/dist/battle/AttackDialog.js +115 -0
  50. package/dist/battle/AttackDialog.js.map +1 -0
  51. package/dist/battle/AttackPreview.d.ts +70 -0
  52. package/dist/battle/AttackPreview.d.ts.map +1 -0
  53. package/dist/battle/AttackPreview.js +78 -0
  54. package/dist/battle/AttackPreview.js.map +1 -0
  55. package/dist/battle/BattleStats.d.ts +45 -0
  56. package/dist/battle/BattleStats.d.ts.map +1 -0
  57. package/dist/battle/BattleStats.js +63 -0
  58. package/dist/battle/BattleStats.js.map +1 -0
  59. package/dist/battle/UnitSelector.d.ts +72 -0
  60. package/dist/battle/UnitSelector.d.ts.map +1 -0
  61. package/dist/battle/UnitSelector.js +117 -0
  62. package/dist/battle/UnitSelector.js.map +1 -0
  63. package/dist/battle/Whiteboard.d.ts +50 -0
  64. package/dist/battle/Whiteboard.d.ts.map +1 -0
  65. package/dist/battle/Whiteboard.js +94 -0
  66. package/dist/battle/Whiteboard.js.map +1 -0
  67. package/dist/battle/index.d.ts +10 -0
  68. package/dist/battle/index.d.ts.map +1 -1
  69. package/dist/battle/index.js +5 -0
  70. package/dist/battle/index.js.map +1 -1
  71. package/dist/board/Classics.d.ts.map +1 -1
  72. package/dist/board/Classics.js +51 -39
  73. package/dist/board/Classics.js.map +1 -1
  74. package/dist/board/FogOfWar.d.ts +32 -2
  75. package/dist/board/FogOfWar.d.ts.map +1 -1
  76. package/dist/board/FogOfWar.js +70 -6
  77. package/dist/board/FogOfWar.js.map +1 -1
  78. package/dist/board/HexSkirmish.d.ts.map +1 -1
  79. package/dist/board/HexSkirmish.js +69 -20
  80. package/dist/board/HexSkirmish.js.map +1 -1
  81. package/dist/board/Tactics.d.ts +7 -0
  82. package/dist/board/Tactics.d.ts.map +1 -1
  83. package/dist/board/Tactics.js +2 -2
  84. package/dist/board/Tactics.js.map +1 -1
  85. package/dist/core/Achievements.d.ts +40 -7
  86. package/dist/core/Achievements.d.ts.map +1 -1
  87. package/dist/core/Achievements.js +53 -7
  88. package/dist/core/Achievements.js.map +1 -1
  89. package/dist/core/Hex.d.ts +26 -6
  90. package/dist/core/Hex.d.ts.map +1 -1
  91. package/dist/core/Hex.js +40 -13
  92. package/dist/core/Hex.js.map +1 -1
  93. package/dist/core/Input.d.ts +36 -0
  94. package/dist/core/Input.d.ts.map +1 -1
  95. package/dist/core/Input.js +63 -1
  96. package/dist/core/Input.js.map +1 -1
  97. package/dist/core/Random.d.ts +93 -0
  98. package/dist/core/Random.d.ts.map +1 -1
  99. package/dist/core/Random.js +177 -0
  100. package/dist/core/Random.js.map +1 -1
  101. package/dist/core/SyncGuard.d.ts +57 -0
  102. package/dist/core/SyncGuard.d.ts.map +1 -0
  103. package/dist/core/SyncGuard.js +116 -0
  104. package/dist/core/SyncGuard.js.map +1 -0
  105. package/dist/core/index.d.ts +3 -1
  106. package/dist/core/index.d.ts.map +1 -1
  107. package/dist/core/index.js +2 -1
  108. package/dist/core/index.js.map +1 -1
  109. package/dist/i18n/Po.d.ts +51 -0
  110. package/dist/i18n/Po.d.ts.map +1 -0
  111. package/dist/i18n/Po.js +176 -0
  112. package/dist/i18n/Po.js.map +1 -0
  113. package/dist/i18n/index.d.ts +2 -0
  114. package/dist/i18n/index.d.ts.map +1 -1
  115. package/dist/i18n/index.js +1 -0
  116. package/dist/i18n/index.js.map +1 -1
  117. package/dist/mw_games.global.js +104 -98
  118. package/dist/mwl/MapFile.d.ts +41 -0
  119. package/dist/mwl/MapFile.d.ts.map +1 -0
  120. package/dist/mwl/MapFile.js +43 -0
  121. package/dist/mwl/MapFile.js.map +1 -0
  122. package/dist/mwl/actors.d.ts +46 -2
  123. package/dist/mwl/actors.d.ts.map +1 -1
  124. package/dist/mwl/actors.js +46 -2
  125. package/dist/mwl/actors.js.map +1 -1
  126. package/dist/mwl/campaign.d.ts +51 -0
  127. package/dist/mwl/campaign.d.ts.map +1 -0
  128. package/dist/mwl/campaign.js +58 -0
  129. package/dist/mwl/campaign.js.map +1 -0
  130. package/dist/mwl/carryover.d.ts +86 -0
  131. package/dist/mwl/carryover.d.ts.map +1 -0
  132. package/dist/mwl/carryover.js +70 -0
  133. package/dist/mwl/carryover.js.map +1 -0
  134. package/dist/mwl/catalog.d.ts +10 -1
  135. package/dist/mwl/catalog.d.ts.map +1 -1
  136. package/dist/mwl/catalog.js +10 -1
  137. package/dist/mwl/catalog.js.map +1 -1
  138. package/dist/mwl/compiler.d.ts +70 -3
  139. package/dist/mwl/compiler.d.ts.map +1 -1
  140. package/dist/mwl/compiler.js +70 -3
  141. package/dist/mwl/compiler.js.map +1 -1
  142. package/dist/mwl/conditions.d.ts +10 -1
  143. package/dist/mwl/conditions.d.ts.map +1 -1
  144. package/dist/mwl/conditions.js +10 -1
  145. package/dist/mwl/conditions.js.map +1 -1
  146. package/dist/mwl/content.d.ts +21 -0
  147. package/dist/mwl/content.d.ts.map +1 -1
  148. package/dist/mwl/content.js +19 -0
  149. package/dist/mwl/content.js.map +1 -1
  150. package/dist/mwl/expression.d.ts +21 -0
  151. package/dist/mwl/expression.d.ts.map +1 -1
  152. package/dist/mwl/expression.js +21 -0
  153. package/dist/mwl/expression.js.map +1 -1
  154. package/dist/mwl/fengari.d.ts +12 -1
  155. package/dist/mwl/fengari.d.ts.map +1 -1
  156. package/dist/mwl/fengari.js +12 -1
  157. package/dist/mwl/fengari.js.map +1 -1
  158. package/dist/mwl/grammar.d.ts +45 -1
  159. package/dist/mwl/grammar.d.ts.map +1 -1
  160. package/dist/mwl/grammar.js +45 -1
  161. package/dist/mwl/grammar.js.map +1 -1
  162. package/dist/mwl/hooks.d.ts +51 -6
  163. package/dist/mwl/hooks.d.ts.map +1 -1
  164. package/dist/mwl/hooks.js +45 -1
  165. package/dist/mwl/hooks.js.map +1 -1
  166. package/dist/mwl/index.d.ts +9 -3
  167. package/dist/mwl/index.d.ts.map +1 -1
  168. package/dist/mwl/index.js +5 -2
  169. package/dist/mwl/index.js.map +1 -1
  170. package/dist/mwl/persistence.d.ts +32 -0
  171. package/dist/mwl/persistence.d.ts.map +1 -1
  172. package/dist/mwl/persistence.js +32 -0
  173. package/dist/mwl/persistence.js.map +1 -1
  174. package/dist/mwl/readers.d.ts +24 -2
  175. package/dist/mwl/readers.d.ts.map +1 -1
  176. package/dist/mwl/readers.js +27 -4
  177. package/dist/mwl/readers.js.map +1 -1
  178. package/dist/mwl/report.d.ts +21 -2
  179. package/dist/mwl/report.d.ts.map +1 -1
  180. package/dist/mwl/report.js +21 -2
  181. package/dist/mwl/report.js.map +1 -1
  182. package/dist/mwl/runtime.d.ts +212 -7
  183. package/dist/mwl/runtime.d.ts.map +1 -1
  184. package/dist/mwl/runtime.js +682 -90
  185. package/dist/mwl/runtime.js.map +1 -1
  186. package/dist/mwl/schema.d.ts +57 -1
  187. package/dist/mwl/schema.d.ts.map +1 -1
  188. package/dist/mwl/schema.js +181 -21
  189. package/dist/mwl/schema.js.map +1 -1
  190. package/dist/mwl/scripts.d.ts +12 -1
  191. package/dist/mwl/scripts.d.ts.map +1 -1
  192. package/dist/mwl/scripts.js +12 -1
  193. package/dist/mwl/scripts.js.map +1 -1
  194. package/dist/mwl/utils.d.ts +2 -0
  195. package/dist/mwl/utils.d.ts.map +1 -1
  196. package/dist/mwl/utils.js +4 -1
  197. package/dist/mwl/utils.js.map +1 -1
  198. package/dist/roguelike/MultiTurnBeam.d.ts +50 -12
  199. package/dist/roguelike/MultiTurnBeam.d.ts.map +1 -1
  200. package/dist/roguelike/MultiTurnBeam.js +100 -53
  201. package/dist/roguelike/MultiTurnBeam.js.map +1 -1
  202. package/dist/roguelike/Targeting.d.ts +94 -0
  203. package/dist/roguelike/Targeting.d.ts.map +1 -1
  204. package/dist/roguelike/Targeting.js +123 -0
  205. package/dist/roguelike/Targeting.js.map +1 -1
  206. package/dist/roguelike/index.d.ts +3 -1
  207. package/dist/roguelike/index.d.ts.map +1 -1
  208. package/dist/roguelike/index.js +1 -0
  209. package/dist/roguelike/index.js.map +1 -1
  210. package/dist/rpg/GameState.d.ts +2 -2
  211. package/dist/rpg/GameState.js +2 -2
  212. package/dist/simulation/CampaignSave.d.ts +68 -0
  213. package/dist/simulation/CampaignSave.d.ts.map +1 -0
  214. package/dist/simulation/CampaignSave.js +54 -0
  215. package/dist/simulation/CampaignSave.js.map +1 -0
  216. package/dist/simulation/EventPresentation.d.ts +111 -0
  217. package/dist/simulation/EventPresentation.d.ts.map +1 -0
  218. package/dist/simulation/EventPresentation.js +120 -0
  219. package/dist/simulation/EventPresentation.js.map +1 -0
  220. package/dist/simulation/index.d.ts +4 -0
  221. package/dist/simulation/index.d.ts.map +1 -1
  222. package/dist/simulation/index.js +2 -0
  223. package/dist/simulation/index.js.map +1 -1
  224. package/dist/two-d/pixi-interop.d.ts +18 -6
  225. package/dist/two-d/pixi-interop.d.ts.map +1 -1
  226. package/dist/two-d/pixi-interop.js +18 -6
  227. package/dist/two-d/pixi-interop.js.map +1 -1
  228. package/dist/two-d/render/AnimatedSprite.d.ts +74 -7
  229. package/dist/two-d/render/AnimatedSprite.d.ts.map +1 -1
  230. package/dist/two-d/render/AnimatedSprite.js +88 -26
  231. package/dist/two-d/render/AnimatedSprite.js.map +1 -1
  232. package/dist/two-d/render/Camera.d.ts +64 -4
  233. package/dist/two-d/render/Camera.d.ts.map +1 -1
  234. package/dist/two-d/render/Camera.js +132 -11
  235. package/dist/two-d/render/Camera.js.map +1 -1
  236. package/dist/two-d/render/ColorTransformBatcher.d.ts +7 -1
  237. package/dist/two-d/render/ColorTransformBatcher.d.ts.map +1 -1
  238. package/dist/two-d/render/ColorTransformBatcher.js +10 -1
  239. package/dist/two-d/render/ColorTransformBatcher.js.map +1 -1
  240. package/dist/two-d/render/Halo.d.ts +58 -0
  241. package/dist/two-d/render/Halo.d.ts.map +1 -0
  242. package/dist/two-d/render/Halo.js +48 -0
  243. package/dist/two-d/render/Halo.js.map +1 -0
  244. package/dist/two-d/render/ImageModifiers.d.ts +174 -0
  245. package/dist/two-d/render/ImageModifiers.d.ts.map +1 -1
  246. package/dist/two-d/render/ImageModifiers.js +454 -1
  247. package/dist/two-d/render/ImageModifiers.js.map +1 -1
  248. package/dist/two-d/render/LightningArc.d.ts +57 -0
  249. package/dist/two-d/render/LightningArc.d.ts.map +1 -0
  250. package/dist/two-d/render/LightningArc.js +91 -0
  251. package/dist/two-d/render/LightningArc.js.map +1 -0
  252. package/dist/two-d/render/PaletteRemap.d.ts +135 -0
  253. package/dist/two-d/render/PaletteRemap.d.ts.map +1 -0
  254. package/dist/two-d/render/PaletteRemap.js +181 -0
  255. package/dist/two-d/render/PaletteRemap.js.map +1 -0
  256. package/dist/two-d/render/Particles.d.ts +26 -0
  257. package/dist/two-d/render/Particles.d.ts.map +1 -1
  258. package/dist/two-d/render/Particles.js +23 -2
  259. package/dist/two-d/render/Particles.js.map +1 -1
  260. package/dist/two-d/render/SpriteAttachment.d.ts +55 -0
  261. package/dist/two-d/render/SpriteAttachment.d.ts.map +1 -0
  262. package/dist/two-d/render/SpriteAttachment.js +60 -0
  263. package/dist/two-d/render/SpriteAttachment.js.map +1 -0
  264. package/dist/two-d/render/TerrainGraphics.d.ts +142 -0
  265. package/dist/two-d/render/TerrainGraphics.d.ts.map +1 -0
  266. package/dist/two-d/render/TerrainGraphics.js +161 -0
  267. package/dist/two-d/render/TerrainGraphics.js.map +1 -0
  268. package/dist/two-d/render/TerrainGraphicsLayer.d.ts +55 -0
  269. package/dist/two-d/render/TerrainGraphicsLayer.d.ts.map +1 -0
  270. package/dist/two-d/render/TerrainGraphicsLayer.js +54 -0
  271. package/dist/two-d/render/TerrainGraphicsLayer.js.map +1 -0
  272. package/dist/two-d/render/TintedSprite.js +2 -2
  273. package/dist/two-d/render/TintedSprite.js.map +1 -1
  274. package/dist/two-d/render/index.d.ts +15 -3
  275. package/dist/two-d/render/index.d.ts.map +1 -1
  276. package/dist/two-d/render/index.js +7 -1
  277. package/dist/two-d/render/index.js.map +1 -1
  278. package/dist/two-d/stage/StoryScreen.d.ts +110 -0
  279. package/dist/two-d/stage/StoryScreen.d.ts.map +1 -0
  280. package/dist/two-d/stage/StoryScreen.js +178 -0
  281. package/dist/two-d/stage/StoryScreen.js.map +1 -0
  282. package/dist/two-d/stage/index.d.ts +2 -0
  283. package/dist/two-d/stage/index.d.ts.map +1 -1
  284. package/dist/two-d/stage/index.js +1 -0
  285. package/dist/two-d/stage/index.js.map +1 -1
  286. package/dist/two-d/ui/Checkbox.d.ts +44 -0
  287. package/dist/two-d/ui/Checkbox.d.ts.map +1 -0
  288. package/dist/two-d/ui/Checkbox.js +89 -0
  289. package/dist/two-d/ui/Checkbox.js.map +1 -0
  290. package/dist/two-d/ui/DataTable.d.ts +79 -0
  291. package/dist/two-d/ui/DataTable.d.ts.map +1 -0
  292. package/dist/two-d/ui/DataTable.js +164 -0
  293. package/dist/two-d/ui/DataTable.js.map +1 -0
  294. package/dist/two-d/ui/Dropdown.d.ts +72 -0
  295. package/dist/two-d/ui/Dropdown.d.ts.map +1 -0
  296. package/dist/two-d/ui/Dropdown.js +126 -0
  297. package/dist/two-d/ui/Dropdown.js.map +1 -0
  298. package/dist/two-d/ui/FloatingText.d.ts +43 -4
  299. package/dist/two-d/ui/FloatingText.d.ts.map +1 -1
  300. package/dist/two-d/ui/FloatingText.js +52 -5
  301. package/dist/two-d/ui/FloatingText.js.map +1 -1
  302. package/dist/two-d/ui/FloatingTextStack.d.ts +86 -13
  303. package/dist/two-d/ui/FloatingTextStack.d.ts.map +1 -1
  304. package/dist/two-d/ui/FloatingTextStack.js +89 -18
  305. package/dist/two-d/ui/FloatingTextStack.js.map +1 -1
  306. package/dist/two-d/ui/Layout.d.ts +105 -0
  307. package/dist/two-d/ui/Layout.d.ts.map +1 -0
  308. package/dist/two-d/ui/Layout.js +174 -0
  309. package/dist/two-d/ui/Layout.js.map +1 -0
  310. package/dist/two-d/ui/MarkupText.d.ts +53 -0
  311. package/dist/two-d/ui/MarkupText.d.ts.map +1 -0
  312. package/dist/two-d/ui/MarkupText.js +122 -0
  313. package/dist/two-d/ui/MarkupText.js.map +1 -0
  314. package/dist/two-d/ui/ScrollBox.d.ts +67 -0
  315. package/dist/two-d/ui/ScrollBox.d.ts.map +1 -0
  316. package/dist/two-d/ui/ScrollBox.js +127 -0
  317. package/dist/two-d/ui/ScrollBox.js.map +1 -0
  318. package/dist/two-d/ui/Skins.d.ts +59 -0
  319. package/dist/two-d/ui/Skins.d.ts.map +1 -0
  320. package/dist/two-d/ui/Skins.js +77 -0
  321. package/dist/two-d/ui/Skins.js.map +1 -0
  322. package/dist/two-d/ui/Slider.d.ts +91 -0
  323. package/dist/two-d/ui/Slider.d.ts.map +1 -0
  324. package/dist/two-d/ui/Slider.js +170 -0
  325. package/dist/two-d/ui/Slider.js.map +1 -0
  326. package/dist/two-d/ui/Spinner.d.ts +67 -0
  327. package/dist/two-d/ui/Spinner.d.ts.map +1 -0
  328. package/dist/two-d/ui/Spinner.js +137 -0
  329. package/dist/two-d/ui/Spinner.js.map +1 -0
  330. package/dist/two-d/ui/TabbedList.d.ts +118 -0
  331. package/dist/two-d/ui/TabbedList.d.ts.map +1 -0
  332. package/dist/two-d/ui/TabbedList.js +221 -0
  333. package/dist/two-d/ui/TabbedList.js.map +1 -0
  334. package/dist/two-d/ui/TextModel.d.ts +65 -0
  335. package/dist/two-d/ui/TextModel.d.ts.map +1 -0
  336. package/dist/two-d/ui/TextModel.js +126 -0
  337. package/dist/two-d/ui/TextModel.js.map +1 -0
  338. package/dist/two-d/ui/TreeView.d.ts +68 -0
  339. package/dist/two-d/ui/TreeView.d.ts.map +1 -0
  340. package/dist/two-d/ui/TreeView.js +133 -0
  341. package/dist/two-d/ui/TreeView.js.map +1 -0
  342. package/dist/two-d/ui/Window.d.ts +13 -0
  343. package/dist/two-d/ui/Window.d.ts.map +1 -1
  344. package/dist/two-d/ui/Window.js +23 -0
  345. package/dist/two-d/ui/Window.js.map +1 -1
  346. package/dist/two-d/ui/WindowStack.d.ts.map +1 -1
  347. package/dist/two-d/ui/WindowStack.js +2 -0
  348. package/dist/two-d/ui/WindowStack.js.map +1 -1
  349. package/dist/two-d/ui/index.d.ts +29 -3
  350. package/dist/two-d/ui/index.d.ts.map +1 -1
  351. package/dist/two-d/ui/index.js +15 -2
  352. package/dist/two-d/ui/index.js.map +1 -1
  353. package/dist/two-d/ui/markup.d.ts +181 -0
  354. package/dist/two-d/ui/markup.d.ts.map +1 -0
  355. package/dist/two-d/ui/markup.js +370 -0
  356. package/dist/two-d/ui/markup.js.map +1 -0
  357. package/dist/version.d.ts +1 -1
  358. package/dist/version.js +1 -1
  359. package/dist/world/SideTurns.d.ts +115 -0
  360. package/dist/world/SideTurns.d.ts.map +1 -0
  361. package/dist/world/SideTurns.js +138 -0
  362. package/dist/world/SideTurns.js.map +1 -0
  363. package/dist/world/index.d.ts +2 -0
  364. package/dist/world/index.d.ts.map +1 -1
  365. package/dist/world/index.js +1 -0
  366. package/dist/world/index.js.map +1 -1
  367. package/package.json +2 -1
@@ -0,0 +1,63 @@
1
+ /**
2
+ * A per-run battle statistics breakdown by category and unit type - recruits, recalls,
3
+ * advances, kills, deaths, damage dealt, damage taken - the shape Wesnoth's own
4
+ * statistics dialog shows and a bare `core.PlayerStats<T>` cannot give a game for free,
5
+ * since `T` there is an opaque summary the game must already know how to combine. Here
6
+ * the categories and the per-unit-type breakdown are the primitive: a game records one
7
+ * event at a time as it happens and reads either a category's total or its breakdown by
8
+ * unit type, then folds `toJSON()` into a `core.RunHistory` entry or a `core.PlayerStats`
9
+ * total the way any other run summary would.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * import { BattleStats } from '@datamoc/mw_games/battle';
14
+ *
15
+ * const stats = new BattleStats();
16
+ * stats.record('kills', 'orc-grunt');
17
+ * stats.record('kills', 'orc-grunt');
18
+ * stats.record('damageDealt', 'elvish-archer', 12);
19
+ *
20
+ * console.log(stats.total('kills')); // 2
21
+ * console.log(stats.breakdown('kills')); // [{ unitType: 'orc-grunt', count: 2 }]
22
+ * ```
23
+ */
24
+ export class BattleStats {
25
+ constructor() {
26
+ this.counts = new Map();
27
+ }
28
+ /** adds `amount` (default 1) to a category's count for one unit type */
29
+ record(category, unitType, amount = 1) {
30
+ const byType = this.counts.get(category) ?? new Map();
31
+ byType.set(unitType, (byType.get(unitType) ?? 0) + amount);
32
+ this.counts.set(category, byType);
33
+ }
34
+ /** one category's count for one unit type; 0 for a combination nothing has recorded yet */
35
+ forType(category, unitType) {
36
+ return this.counts.get(category)?.get(unitType) ?? 0;
37
+ }
38
+ /** a category's total across every unit type */
39
+ total(category) {
40
+ const byType = this.counts.get(category);
41
+ if (!byType)
42
+ return 0;
43
+ let sum = 0;
44
+ for (const count of byType.values())
45
+ sum += count;
46
+ return sum;
47
+ }
48
+ /** every unit type a category has recorded, with its count - the rows a stats screen breaks a category into */
49
+ breakdown(category) {
50
+ const byType = this.counts.get(category);
51
+ return byType ? [...byType.entries()].map(([unitType, count]) => ({ unitType, count })) : [];
52
+ }
53
+ toJSON() {
54
+ return { counts: [...this.counts].map(([category, byType]) => [category, [...byType]]) };
55
+ }
56
+ static fromJSON(data) {
57
+ const stats = new BattleStats();
58
+ for (const [category, entries] of data.counts)
59
+ stats.counts.set(category, new Map(entries));
60
+ return stats;
61
+ }
62
+ }
63
+ //# sourceMappingURL=BattleStats.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BattleStats.js","sourceRoot":"","sources":["../../src/battle/BattleStats.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAKH,MAAM,OAAO,WAAW;IAAxB;QACS,WAAM,GAAG,IAAI,GAAG,EAA2C,CAAC;IAsCrE,CAAC;IApCA,wEAAwE;IACxE,MAAM,CAAC,QAA4B,EAAE,QAAgB,EAAE,MAAM,GAAG,CAAC;QAChE,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,IAAI,GAAG,EAAkB,CAAC;QACtE,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC;QAC3D,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACnC,CAAC;IAED,2FAA2F;IAC3F,OAAO,CAAC,QAA4B,EAAE,QAAgB;QACrD,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACtD,CAAC;IAED,gDAAgD;IAChD,KAAK,CAAC,QAA4B;QACjC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACzC,IAAI,CAAC,MAAM;YAAE,OAAO,CAAC,CAAC;QACtB,IAAI,GAAG,GAAG,CAAC,CAAC;QACZ,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE;YAAE,GAAG,IAAI,KAAK,CAAC;QAClD,OAAO,GAAG,CAAC;IACZ,CAAC;IAED,+GAA+G;IAC/G,SAAS,CAAC,QAA4B;QACrC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACzC,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9F,CAAC;IAED,MAAM;QACL,OAAO,EAAE,MAAM,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1F,CAAC;IAED,MAAM,CAAC,QAAQ,CAAC,IAA4D;QAC3E,MAAM,KAAK,GAAG,IAAI,WAAW,EAAE,CAAC;QAChC,KAAK,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,IAAI,IAAI,CAAC,MAAM;YAAE,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;QAC5F,OAAO,KAAK,CAAC;IACd,CAAC;CACD"}
@@ -0,0 +1,72 @@
1
+ import { Signal } from '../core/Signal.ts';
2
+ export interface SelectableUnit {
3
+ id: string;
4
+ side?: string;
5
+ /** current hp, so an attack dialog can preview it; the selector itself never reads it */
6
+ hp?: number;
7
+ disabled?: boolean;
8
+ }
9
+ export interface UnitSelectorOptions {
10
+ units: readonly SelectableUnit[];
11
+ /** only units on this side may attack; every enabled unit when omitted */
12
+ side?: string;
13
+ /** further narrows who may be chosen at all (a unit that has already acted, say) */
14
+ disabled?: (unit: SelectableUnit) => boolean;
15
+ /** narrows the targets once an attacker is chosen (adjacency, range, fog) */
16
+ canTarget?: (attacker: SelectableUnit, target: SelectableUnit) => boolean;
17
+ }
18
+ export type SelectorStage = 'attacker' | 'target';
19
+ /**
20
+ * The two-step unit selector an attack starts with: pick who attacks, then pick what they attack.
21
+ *
22
+ * Renderer-free, so the choosing rules are tested without a board: `candidates` are the enabled
23
+ * units on the selecting side, `targets` are the enabled units that pass `canTarget` once an
24
+ * attacker is chosen, `move` walks the active list and `select` advances a stage. `back` undoes the
25
+ * attacker choice rather than only the target, so a player who picked the wrong attacker lands
26
+ * where they can pick again rather than being stuck one step in.
27
+ *
28
+ * @example
29
+ * ```ts
30
+ * import { UnitSelector } from '@datamoc/mw_games/battle';
31
+ *
32
+ * const selector = new UnitSelector({
33
+ * units: [{ id: 'hero', side: '1' }, { id: 'rat', side: '2' }],
34
+ * side: '1',
35
+ * });
36
+ * selector.select(); // hero attacks
37
+ * console.log(selector.targets.map((unit) => unit.id)); // ['rat']
38
+ * ```
39
+ */
40
+ export declare class UnitSelector {
41
+ readonly onChange: Signal<void>;
42
+ private readonly units;
43
+ private readonly side?;
44
+ private readonly disabledOf;
45
+ private readonly canTarget;
46
+ private stage_;
47
+ private charge;
48
+ private victim;
49
+ private highlight_;
50
+ constructor(options: UnitSelectorOptions);
51
+ get stage(): SelectorStage;
52
+ get attacker(): SelectableUnit | null;
53
+ get target(): SelectableUnit | null;
54
+ /** both steps are done, so the caller has an attack to make */
55
+ get done(): boolean;
56
+ /** the units that may be picked as the attacker */
57
+ get candidates(): readonly SelectableUnit[];
58
+ /** the units the chosen attacker may hit; empty until an attacker is chosen */
59
+ get targets(): readonly SelectableUnit[];
60
+ /** the index of the highlight within the active list */
61
+ get highlight(): number;
62
+ get highlighted(): SelectableUnit | null;
63
+ /** moves the highlight, wrapping at both ends, within whichever list is active */
64
+ move(delta: number): void;
65
+ /** takes the highlighted unit: on the attacker stage it advances to choosing a target */
66
+ select(): boolean;
67
+ /** undoes the attacker choice, so a wrong attacker can be picked again */
68
+ back(): void;
69
+ reset(): void;
70
+ private active;
71
+ }
72
+ //# sourceMappingURL=UnitSelector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UnitSelector.d.ts","sourceRoot":"","sources":["../../src/battle/UnitSelector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE3C,MAAM,WAAW,cAAc;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,yFAAyF;IACzF,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IACnC,KAAK,EAAE,SAAS,cAAc,EAAE,CAAC;IACjC,0EAA0E;IAC1E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oFAAoF;IACpF,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,OAAO,CAAC;IAC7C,6EAA6E;IAC7E,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,cAAc,EAAE,MAAM,EAAE,cAAc,KAAK,OAAO,CAAC;CAC1E;AAED,MAAM,MAAM,aAAa,GAAG,UAAU,GAAG,QAAQ,CAAC;AAElD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,YAAY;IACxB,QAAQ,CAAC,QAAQ,eAAsB;IAEvC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA4B;IAClD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAoC;IAC/D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAgE;IAE1F,OAAO,CAAC,MAAM,CAA6B;IAC3C,OAAO,CAAC,MAAM,CAA+B;IAC7C,OAAO,CAAC,MAAM,CAA+B;IAC7C,OAAO,CAAC,UAAU,CAAK;IAEvB,YAAY,OAAO,EAAE,mBAAmB,EAKvC;IAED,IAAI,KAAK,IAAI,aAAa,CAEzB;IAED,IAAI,QAAQ,IAAI,cAAc,GAAG,IAAI,CAEpC;IAED,IAAI,MAAM,IAAI,cAAc,GAAG,IAAI,CAElC;IAED,+DAA+D;IAC/D,IAAI,IAAI,IAAI,OAAO,CAElB;IAED,mDAAmD;IACnD,IAAI,UAAU,IAAI,SAAS,cAAc,EAAE,CAI1C;IAED,+EAA+E;IAC/E,IAAI,OAAO,IAAI,SAAS,cAAc,EAAE,CAUvC;IAED,wDAAwD;IACxD,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED,IAAI,WAAW,IAAI,cAAc,GAAG,IAAI,CAGvC;IAED,kFAAkF;IAClF,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAKxB;IAED,yFAAyF;IACzF,MAAM,IAAI,OAAO,CAYhB;IAED,0EAA0E;IAC1E,IAAI,IAAI,IAAI,CASX;IAED,KAAK,IAAI,IAAI,CAMZ;IAED,OAAO,CAAC,MAAM;CAGd"}
@@ -0,0 +1,117 @@
1
+ import { Signal } from '../core/Signal.js';
2
+ /**
3
+ * The two-step unit selector an attack starts with: pick who attacks, then pick what they attack.
4
+ *
5
+ * Renderer-free, so the choosing rules are tested without a board: `candidates` are the enabled
6
+ * units on the selecting side, `targets` are the enabled units that pass `canTarget` once an
7
+ * attacker is chosen, `move` walks the active list and `select` advances a stage. `back` undoes the
8
+ * attacker choice rather than only the target, so a player who picked the wrong attacker lands
9
+ * where they can pick again rather than being stuck one step in.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * import { UnitSelector } from '@datamoc/mw_games/battle';
14
+ *
15
+ * const selector = new UnitSelector({
16
+ * units: [{ id: 'hero', side: '1' }, { id: 'rat', side: '2' }],
17
+ * side: '1',
18
+ * });
19
+ * selector.select(); // hero attacks
20
+ * console.log(selector.targets.map((unit) => unit.id)); // ['rat']
21
+ * ```
22
+ */
23
+ export class UnitSelector {
24
+ constructor(options) {
25
+ this.onChange = new Signal();
26
+ this.stage_ = 'attacker';
27
+ this.charge = null;
28
+ this.victim = null;
29
+ this.highlight_ = 0;
30
+ this.units = options.units;
31
+ this.side = options.side;
32
+ this.disabledOf = options.disabled ?? ((unit) => unit.disabled ?? false);
33
+ this.canTarget = options.canTarget ?? (() => true);
34
+ }
35
+ get stage() {
36
+ return this.stage_;
37
+ }
38
+ get attacker() {
39
+ return this.charge;
40
+ }
41
+ get target() {
42
+ return this.victim;
43
+ }
44
+ /** both steps are done, so the caller has an attack to make */
45
+ get done() {
46
+ return this.charge !== null && this.victim !== null;
47
+ }
48
+ /** the units that may be picked as the attacker */
49
+ get candidates() {
50
+ return this.units.filter((unit) => (this.side === undefined || unit.side === this.side) && !this.disabledOf(unit));
51
+ }
52
+ /** the units the chosen attacker may hit; empty until an attacker is chosen */
53
+ get targets() {
54
+ const attacker = this.charge;
55
+ if (!attacker)
56
+ return [];
57
+ return this.units.filter((unit) => unit.id !== attacker.id &&
58
+ !this.disabledOf(unit) &&
59
+ !(attacker.side !== undefined && unit.side === attacker.side) &&
60
+ this.canTarget(attacker, unit));
61
+ }
62
+ /** the index of the highlight within the active list */
63
+ get highlight() {
64
+ return this.highlight_;
65
+ }
66
+ get highlighted() {
67
+ const list = this.active();
68
+ return list[this.highlight_] ?? null;
69
+ }
70
+ /** moves the highlight, wrapping at both ends, within whichever list is active */
71
+ move(delta) {
72
+ const list = this.active();
73
+ if (list.length === 0)
74
+ return;
75
+ this.highlight_ = (((this.highlight_ + delta) % list.length) + list.length) % list.length;
76
+ this.onChange.dispatch();
77
+ }
78
+ /** takes the highlighted unit: on the attacker stage it advances to choosing a target */
79
+ select() {
80
+ const chosen = this.highlighted;
81
+ if (!chosen)
82
+ return false;
83
+ if (this.stage_ === 'attacker') {
84
+ this.charge = chosen;
85
+ this.stage_ = 'target';
86
+ this.highlight_ = 0;
87
+ }
88
+ else {
89
+ this.victim = chosen;
90
+ }
91
+ this.onChange.dispatch();
92
+ return true;
93
+ }
94
+ /** undoes the attacker choice, so a wrong attacker can be picked again */
95
+ back() {
96
+ if (this.stage_ === 'attacker')
97
+ return;
98
+ const previous = this.charge;
99
+ this.charge = null;
100
+ this.victim = null;
101
+ this.stage_ = 'attacker';
102
+ const index = previous ? this.candidates.findIndex((unit) => unit.id === previous.id) : -1;
103
+ this.highlight_ = index >= 0 ? index : 0;
104
+ this.onChange.dispatch();
105
+ }
106
+ reset() {
107
+ this.charge = null;
108
+ this.victim = null;
109
+ this.stage_ = 'attacker';
110
+ this.highlight_ = 0;
111
+ this.onChange.dispatch();
112
+ }
113
+ active() {
114
+ return this.stage_ === 'attacker' ? this.candidates : this.targets;
115
+ }
116
+ }
117
+ //# sourceMappingURL=UnitSelector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UnitSelector.js","sourceRoot":"","sources":["../../src/battle/UnitSelector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ import { Signal } from '../core/Signal.ts';
2
+ export interface WhiteboardEntry {
3
+ /** the unit the plan is for; one plan per unit, the way a turn's moves are planned */
4
+ unit: string;
5
+ }
6
+ /**
7
+ * The planned-but-uncommitted orders of a turn - Wesnoth's whiteboard - with undo across them.
8
+ *
9
+ * A plan is one entry per unit, so replanning a unit replaces its earlier order in place rather
10
+ * than stacking a second one for the same unit: what is on the board is the turn as it would be
11
+ * played, not the history of how a player got there. Undo pops the last plan onto a redo stack
12
+ * (planning again clears that stack, the usual undo contract), and `commit` hands the plans to the
13
+ * caller, which is where the framework stops - actually executing them is the game's turn.
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * import { Whiteboard } from '@datamoc/mw_games/battle';
18
+ *
19
+ * const board = new Whiteboard<{ unit: string; x: number; y: number }>();
20
+ * board.plan({ unit: 'hero', x: 2, y: 3 });
21
+ * board.plan({ unit: 'archer', x: 5, y: 1 });
22
+ * board.undo();
23
+ * console.log(board.plans); // [{ unit: 'hero', x: 2, y: 3 }]
24
+ * ```
25
+ */
26
+ export declare class Whiteboard<T extends WhiteboardEntry = WhiteboardEntry> {
27
+ readonly onChange: Signal<void>;
28
+ private planned;
29
+ private undone;
30
+ get plans(): readonly T[];
31
+ get isEmpty(): boolean;
32
+ get canUndo(): boolean;
33
+ get canRedo(): boolean;
34
+ /** the plan for a unit, if it has one on the board */
35
+ plannedFor(unit: string): T | undefined;
36
+ /** adds or replaces a unit's plan; clears the redo stack, as planning after undo does */
37
+ plan(action: T): void;
38
+ /** takes the last plan off the board, returning it so a caller can put it back */
39
+ undo(): T | null;
40
+ /** puts the last undone plan back, replacing any plan the unit has picked up since */
41
+ redo(): T | null;
42
+ /** empties the board, both the plans and anything undone */
43
+ clear(): void;
44
+ /**
45
+ * Hands the plans to the caller and empties the board - the moment a turn stops being a plan.
46
+ * The orders are returned in planning order.
47
+ */
48
+ commit(): T[];
49
+ }
50
+ //# sourceMappingURL=Whiteboard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Whiteboard.d.ts","sourceRoot":"","sources":["../../src/battle/Whiteboard.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE3C,MAAM,WAAW,eAAe;IAC/B,sFAAsF;IACtF,IAAI,EAAE,MAAM,CAAC;CACb;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,UAAU,CAAC,CAAC,SAAS,eAAe,GAAG,eAAe;IAClE,QAAQ,CAAC,QAAQ,eAAsB;IAEvC,OAAO,CAAC,OAAO,CAAW;IAC1B,OAAO,CAAC,MAAM,CAAW;IAEzB,IAAI,KAAK,IAAI,SAAS,CAAC,EAAE,CAExB;IAED,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,sDAAsD;IACtD,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS,CAEtC;IAED,yFAAyF;IACzF,IAAI,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,CAMpB;IAED,kFAAkF;IAClF,IAAI,IAAI,CAAC,GAAG,IAAI,CAMf;IAED,sFAAsF;IACtF,IAAI,IAAI,CAAC,GAAG,IAAI,CAOf;IAED,4DAA4D;IAC5D,KAAK,IAAI,IAAI,CAKZ;IAED;;;OAGG;IACH,MAAM,IAAI,CAAC,EAAE,CAMZ;CACD"}
@@ -0,0 +1,94 @@
1
+ import { Signal } from '../core/Signal.js';
2
+ /**
3
+ * The planned-but-uncommitted orders of a turn - Wesnoth's whiteboard - with undo across them.
4
+ *
5
+ * A plan is one entry per unit, so replanning a unit replaces its earlier order in place rather
6
+ * than stacking a second one for the same unit: what is on the board is the turn as it would be
7
+ * played, not the history of how a player got there. Undo pops the last plan onto a redo stack
8
+ * (planning again clears that stack, the usual undo contract), and `commit` hands the plans to the
9
+ * caller, which is where the framework stops - actually executing them is the game's turn.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * import { Whiteboard } from '@datamoc/mw_games/battle';
14
+ *
15
+ * const board = new Whiteboard<{ unit: string; x: number; y: number }>();
16
+ * board.plan({ unit: 'hero', x: 2, y: 3 });
17
+ * board.plan({ unit: 'archer', x: 5, y: 1 });
18
+ * board.undo();
19
+ * console.log(board.plans); // [{ unit: 'hero', x: 2, y: 3 }]
20
+ * ```
21
+ */
22
+ export class Whiteboard {
23
+ constructor() {
24
+ this.onChange = new Signal();
25
+ this.planned = [];
26
+ this.undone = [];
27
+ }
28
+ get plans() {
29
+ return this.planned;
30
+ }
31
+ get isEmpty() {
32
+ return this.planned.length === 0;
33
+ }
34
+ get canUndo() {
35
+ return this.planned.length > 0;
36
+ }
37
+ get canRedo() {
38
+ return this.undone.length > 0;
39
+ }
40
+ /** the plan for a unit, if it has one on the board */
41
+ plannedFor(unit) {
42
+ return this.planned.find((entry) => entry.unit === unit);
43
+ }
44
+ /** adds or replaces a unit's plan; clears the redo stack, as planning after undo does */
45
+ plan(action) {
46
+ const index = this.planned.findIndex((entry) => entry.unit === action.unit);
47
+ if (index >= 0)
48
+ this.planned[index] = action;
49
+ else
50
+ this.planned.push(action);
51
+ this.undone = [];
52
+ this.onChange.dispatch();
53
+ }
54
+ /** takes the last plan off the board, returning it so a caller can put it back */
55
+ undo() {
56
+ const entry = this.planned.pop();
57
+ if (!entry)
58
+ return null;
59
+ this.undone.push(entry);
60
+ this.onChange.dispatch();
61
+ return entry;
62
+ }
63
+ /** puts the last undone plan back, replacing any plan the unit has picked up since */
64
+ redo() {
65
+ const entry = this.undone.pop();
66
+ if (!entry)
67
+ return null;
68
+ this.planned = this.planned.filter((candidate) => candidate.unit !== entry.unit);
69
+ this.planned.push(entry);
70
+ this.onChange.dispatch();
71
+ return entry;
72
+ }
73
+ /** empties the board, both the plans and anything undone */
74
+ clear() {
75
+ if (this.planned.length === 0 && this.undone.length === 0)
76
+ return;
77
+ this.planned = [];
78
+ this.undone = [];
79
+ this.onChange.dispatch();
80
+ }
81
+ /**
82
+ * Hands the plans to the caller and empties the board - the moment a turn stops being a plan.
83
+ * The orders are returned in planning order.
84
+ */
85
+ commit() {
86
+ const committed = this.planned;
87
+ this.planned = [];
88
+ this.undone = [];
89
+ if (committed.length > 0)
90
+ this.onChange.dispatch();
91
+ return committed;
92
+ }
93
+ }
94
+ //# sourceMappingURL=Whiteboard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Whiteboard.js","sourceRoot":"","sources":["../../src/battle/Whiteboard.ts"],"names":[],"mappings":"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"}
@@ -13,4 +13,14 @@ export { BattleHooks } from './Hooks.ts';
13
13
  export type { BattleHook } from './Hooks.ts';
14
14
  export { Field } from './Field.ts';
15
15
  export type { FieldCondition } from './Field.ts';
16
+ export { AttackPreview } from './AttackPreview.ts';
17
+ export { AttackDialog } from './AttackDialog.ts';
18
+ export type { AttackDialogOptions, StrikeNumbers } from './AttackDialog.ts';
19
+ export type { AttackFrame, AttackPreviewOptions, PreviewCombatant } from './AttackPreview.ts';
20
+ export { UnitSelector } from './UnitSelector.ts';
21
+ export type { SelectableUnit, SelectorStage, UnitSelectorOptions } from './UnitSelector.ts';
22
+ export { Whiteboard } from './Whiteboard.ts';
23
+ export type { WhiteboardEntry } from './Whiteboard.ts';
24
+ export { BattleStats } from './BattleStats.ts';
25
+ export type { BattleStatCategory } from './BattleStats.ts';
16
26
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/battle/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,YAAY,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,YAAY,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,YAAY,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,YAAY,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,YAAY,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/battle/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,YAAY,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,YAAY,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,YAAY,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,YAAY,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,YAAY,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,YAAY,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAC5E,YAAY,EAAE,WAAW,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC9F,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAC5F,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,YAAY,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,YAAY,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC"}
@@ -7,4 +7,9 @@ export { StatStages } from './StatStages.js';
7
7
  export { chooseMove, chooseSwitch } from './BattleAI.js';
8
8
  export { BattleHooks } from './Hooks.js';
9
9
  export { Field } from './Field.js';
10
+ export { AttackPreview } from './AttackPreview.js';
11
+ export { AttackDialog } from './AttackDialog.js';
12
+ export { UnitSelector } from './UnitSelector.js';
13
+ export { Whiteboard } from './Whiteboard.js';
14
+ export { BattleStats } from './BattleStats.js';
10
15
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/battle/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAExC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAExC,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEhD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/battle/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAExC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAExC,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEhD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAGjD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"Classics.d.ts","sourceRoot":"","sources":["../../src/board/Classics.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Classics.d.ts","sourceRoot":"","sources":["../../src/board/Classics.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC;AAEhC,MAAM,WAAW,UAAU,CAAC,CAAC,GAAG,MAAM;IACrC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,UAAU,CAAC;IAClB,IAAI,EAAE,CAAC,CAAC;IACR,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,SAAS,CAAC,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAChC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAExB,YAAY,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,SAAS,CAAC,CAAC,GAAG,IAAI,CAAC,EAAE,EAMvE;IAED,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAGlC;IAED,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAEpC;IACD,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI,CAElC;IACD,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI,GAAG,IAAI,CAE/C;IAED,IAAI,CAAC,IAAI,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,EAAE,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,CAAC,CAMpE;CACD;AAED,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG,OAAO,CAAC;AAC3C,MAAM,WAAW,aAAa;IAC7B,IAAI,EAAE,YAAY,CAAC;IACnB,IAAI,EAAE,OAAO,CAAC;CACd;AACD,MAAM,WAAW,YAAY;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,EAAE,CAAC;CACnB;AACD,MAAM,WAAW,aAAa;IAC7B,KAAK,EAAE,KAAK,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC;IACnC,IAAI,EAAE,YAAY,CAAC;IACnB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,IAAI,aAAa,CAOhD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,aAAa,GAAG,YAAY,EAAE,CAWlE;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,YAAY,GAAG,IAAI,CA4BhF;AA4BD,MAAM,MAAM,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;AACxC,MAAM,WAAW,OAAO;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;IAC7B,IAAI,EAAE,OAAO,CAAC;IACd,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,IAAI,SAAI,GAAG,OAAO,CAG5C;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAsBjE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAI3C;AAED;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,SAAS,GAAG,UAAU,CAE/D;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAiBxE;AA0CD,MAAM,WAAW,eAAe;IAC/B,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,GAAG,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACtC,GAAG,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACtC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC;CACxB;AACD,MAAM,WAAW,cAAc;IAC9B,IAAI,EAAE,MAAM,GAAG,KAAK,CAAC;IACrB,EAAE,EAAE,MAAM,GAAG,KAAK,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;CACZ;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,IAAI,eAAe,CAWpD;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,EAAE,CAG7C;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,eAAe,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,cAAc,EAAE,CAqCjG;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,eAAe,EAAE,IAAI,EAAE,cAAc,GAAG,IAAI,CAmBtF;AAKD,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,UAAU,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAClE,MAAM,MAAM,QAAQ,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;AAC7E,MAAM,WAAW,IAAI;IACpB,IAAI,EAAE,QAAQ,CAAC;IACf,IAAI,EAAE,QAAQ,CAAC;CACf;AAED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,MAAM,SAAI,GAAG,IAAI,EAAE,CAK7C;AACD;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,CAEhD;AACD;;;;;;;;GAQG;AACH,wBAAgB,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,CAAC,EAAE,EAAE,CAG1E;AAED,MAAM,WAAW,SAAS,CAAC,CAAC,GAAG,MAAM;IACpC,KAAK,EAAE,CAAC,CAAC;IACT,IAAI,EAAE,IAAI,CAAC;CACX;AACD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,WAAW,CAAC,CAAC,GAAG,MAAM,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,SAAS,CAAC,EAAE,QAAQ,GAAG,CAAC,CAStF;AAED,MAAM,WAAW,cAAc;IAC9B,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,IAAI,EAAE,CAAC;QAAC,EAAE,EAAE,IAAI,EAAE,CAAA;KAAE,CAAC,CAAC;IAC7C,WAAW,EAAE,IAAI,EAAE,EAAE,CAAC;CACtB;AACD;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,cAAc,CAS3D;AACD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI,GAAG,IAAI,CAQhE;AACD;;;;;;;;;;;;GAYG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,SAAI,GAAG,IAAI,CAcrG;AACD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAY/F;AACD;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAE3D;AAOD;;;;;;;;;GASG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAI/D;AACD;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAIzD;AAED;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,OAAO;IACnB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,IAAI,CAAqB;IACjC,YAAY,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAIvC;IACD,MAAM,IAAI,IAAI,CAGb;IACD,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAGxB;IACD,SAAS,IAAI,IAAI,CAEhB;CACD;AAED,MAAM,MAAM,YAAY,GACrB,MAAM,GACN,MAAM,GACN,QAAQ,GACR,OAAO,GACP,OAAO,GACP,OAAO,GACP,WAAW,GACX,UAAU,GACV,WAAW,GACX,eAAe,GACf,eAAe,GACf,SAAS,GACT,QAAQ,CAAC;AACZ;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,EAAE,QAAQ,EAAE,YAAY,GAAG,MAAM,CAuBnF"}
@@ -196,7 +196,7 @@ export function playGo(state, x, y) {
196
196
  //tracked directly rather than diffed against the old board afterwards, since the played
197
197
  //stone's own cell also differs and diffing can't tell the two apart
198
198
  let soleCaptured = null;
199
- for (const neighbour of goNeighbours(state, index)) {
199
+ for (const neighbour of neighbours(state.size, index)) {
200
200
  if (board[neighbour] !== enemy || liberties(board, state.size, neighbour) !== 0)
201
201
  continue;
202
202
  const removed = group(board, state.size, neighbour);
@@ -264,7 +264,7 @@ export function goScore(state) {
264
264
  const area = group(state.board, state.size, i);
265
265
  const borders = new Set();
266
266
  for (const cell of area)
267
- for (const neighbour of goNeighbours(state, cell))
267
+ for (const neighbour of neighbours(state.size, cell))
268
268
  if (state.board[neighbour])
269
269
  borders.add(state.board[neighbour]);
270
270
  for (const cell of area)
@@ -280,41 +280,36 @@ function goIndex(state, x, y) {
280
280
  throw new Error('Go cell is outside the board');
281
281
  return y * state.size + x;
282
282
  }
283
- function goNeighbours(state, index) {
284
- const x = index % state.size;
285
- const y = Math.floor(index / state.size);
286
- return [
287
- [x - 1, y],
288
- [x + 1, y],
289
- [x, y - 1],
290
- [x, y + 1],
291
- ]
292
- .filter(([nx, ny]) => nx >= 0 && ny >= 0 && nx < state.size && ny < state.size)
293
- .map(([nx, ny]) => ny * state.size + nx);
283
+ /** the in-bounds orthogonal neighbours of a square-grid index, as indices */
284
+ function neighbours(size, index) {
285
+ const x = index % size;
286
+ const y = Math.floor(index / size);
287
+ const out = [];
288
+ if (x > 0)
289
+ out.push(index - 1);
290
+ if (x < size - 1)
291
+ out.push(index + 1);
292
+ if (y > 0)
293
+ out.push(index - size);
294
+ if (y < size - 1)
295
+ out.push(index + size);
296
+ return out;
294
297
  }
298
+ //cells connected to `start` that share its value - a group of one colour's stones, or, when
299
+ //`start` is itself empty, the empty region around it, which is what `goScore` counts as territory
295
300
  function group(board, size, start) {
296
- const stone = board[start];
297
- if (!stone)
298
- return [];
301
+ const value = board[start];
299
302
  const found = [];
300
303
  const todo = [start];
301
304
  const seen = new Set();
302
305
  while (todo.length) {
303
306
  const index = todo.pop();
304
- if (seen.has(index) || board[index] !== stone)
307
+ if (seen.has(index) || board[index] !== value)
305
308
  continue;
306
309
  seen.add(index);
307
310
  found.push(index);
308
- const x = index % size;
309
- const y = Math.floor(index / size);
310
- for (const [nx, ny] of [
311
- [x - 1, y],
312
- [x + 1, y],
313
- [x, y - 1],
314
- [x, y + 1],
315
- ])
316
- if (nx >= 0 && ny >= 0 && nx < size && ny < size)
317
- todo.push(ny * size + nx);
311
+ for (const next of neighbours(size, index))
312
+ todo.push(next);
318
313
  }
319
314
  return found;
320
315
  }
@@ -322,16 +317,9 @@ function liberties(board, size, start) {
322
317
  const cells = group(board, size, start);
323
318
  const empty = new Set();
324
319
  for (const index of cells) {
325
- const x = index % size;
326
- const y = Math.floor(index / size);
327
- for (const [nx, ny] of [
328
- [x - 1, y],
329
- [x + 1, y],
330
- [x, y - 1],
331
- [x, y + 1],
332
- ])
333
- if (nx >= 0 && ny >= 0 && nx < size && ny < size && board[ny * size + nx] === null)
334
- empty.add(ny * size + nx);
320
+ for (const next of neighbours(size, index))
321
+ if (board[next] === null)
322
+ empty.add(next);
335
323
  }
336
324
  return empty.size;
337
325
  }
@@ -381,6 +369,28 @@ export function rollBackgammonDice() {
381
369
  */
382
370
  export function backgammonMoves(state, dice) {
383
371
  const side = state.turn === 'white' ? 1 : -1;
372
+ //bearing off needs every checker in the home board (18-23 for white, 0-5 for black) and
373
+ //none on the bar; `pips` is the distance from a point to the off edge, so the checkers with
374
+ //the smallest pips are the ones closest to bearing off
375
+ const home = side === 1 ? [18, 23] : [0, 5];
376
+ const pips = (point) => (side === 1 ? 24 - point : point + 1);
377
+ let allHome = true;
378
+ let closest = Infinity;
379
+ for (let point = 0; point < 24; point++) {
380
+ if (state.points[point] * side <= 0)
381
+ continue;
382
+ if (point < home[0] || point > home[1])
383
+ allHome = false;
384
+ closest = Math.min(closest, pips(point));
385
+ }
386
+ //an exact roll bears off any checker; an over-roll only the checker nearest the off edge,
387
+ //since a checker must never skip past another one on its way off
388
+ const canBearOff = (from, die) => {
389
+ if (!allHome)
390
+ return false;
391
+ const needed = pips(from);
392
+ return die === needed || (die > needed && needed === closest);
393
+ };
384
394
  const out = [];
385
395
  for (const die of dice) {
386
396
  if (state.bar[state.turn] > 0) {
@@ -392,8 +402,10 @@ export function backgammonMoves(state, dice) {
392
402
  for (let from = 0; from < 24; from++)
393
403
  if (state.points[from] * side > 0) {
394
404
  const to = from + die * side;
395
- if (to < 0 || to >= 24)
396
- out.push({ from, to: 'off', die });
405
+ if (to < 0 || to >= 24) {
406
+ if (canBearOff(from, die))
407
+ out.push({ from, to: 'off', die });
408
+ }
397
409
  else if (canBackgammonLand(state, to, side))
398
410
  out.push({ from, to, die });
399
411
  }