c64-kb 0.17.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 (970) hide show
  1. package/CHANGELOG.md +2082 -0
  2. package/LICENSE +29 -0
  3. package/README.md +559 -0
  4. package/VERSION +25 -0
  5. package/dist/cli/setup.js +66 -0
  6. package/dist/cli/setup.js.map +1 -0
  7. package/dist/cli-memorize-audit.js +97 -0
  8. package/dist/cli-memorize-audit.js.map +1 -0
  9. package/dist/cli.js +335 -0
  10. package/dist/cli.js.map +1 -0
  11. package/dist/config.js +83 -0
  12. package/dist/config.js.map +1 -0
  13. package/dist/context.js +53 -0
  14. package/dist/context.js.map +1 -0
  15. package/dist/domain/budget-notes.js +104 -0
  16. package/dist/domain/budget-notes.js.map +1 -0
  17. package/dist/domain/budget.js +417 -0
  18. package/dist/domain/budget.js.map +1 -0
  19. package/dist/domain/game-design.js +77 -0
  20. package/dist/domain/game-design.js.map +1 -0
  21. package/dist/domain/timing.js +39 -0
  22. package/dist/domain/timing.js.map +1 -0
  23. package/dist/graph/apply.js +132 -0
  24. package/dist/graph/apply.js.map +1 -0
  25. package/dist/graph/claims.js +231 -0
  26. package/dist/graph/claims.js.map +1 -0
  27. package/dist/graph/extract/archetype.js +118 -0
  28. package/dist/graph/extract/archetype.js.map +1 -0
  29. package/dist/graph/extract/common.js +69 -0
  30. package/dist/graph/extract/common.js.map +1 -0
  31. package/dist/graph/extract/failure.js +37 -0
  32. package/dist/graph/extract/failure.js.map +1 -0
  33. package/dist/graph/extract/game-design.js +189 -0
  34. package/dist/graph/extract/game-design.js.map +1 -0
  35. package/dist/graph/extract/hardware.js +124 -0
  36. package/dist/graph/extract/hardware.js.map +1 -0
  37. package/dist/graph/extract/pitfall.js +62 -0
  38. package/dist/graph/extract/pitfall.js.map +1 -0
  39. package/dist/graph/extract/raster-band.js +56 -0
  40. package/dist/graph/extract/raster-band.js.map +1 -0
  41. package/dist/graph/extract/recipe.js +71 -0
  42. package/dist/graph/extract/recipe.js.map +1 -0
  43. package/dist/graph/extract/technique-entities.js +180 -0
  44. package/dist/graph/extract/technique-entities.js.map +1 -0
  45. package/dist/graph/extract/technique.js +179 -0
  46. package/dist/graph/extract/technique.js.map +1 -0
  47. package/dist/graph/extract/toolchain.js +67 -0
  48. package/dist/graph/extract/toolchain.js.map +1 -0
  49. package/dist/graph/extract/types.js +3 -0
  50. package/dist/graph/extract/types.js.map +1 -0
  51. package/dist/graph/extract/vocabulary.js +65 -0
  52. package/dist/graph/extract/vocabulary.js.map +1 -0
  53. package/dist/graph/extract.js +43 -0
  54. package/dist/graph/extract.js.map +1 -0
  55. package/dist/graph/kernal-clobbers.js +64 -0
  56. package/dist/graph/kernal-clobbers.js.map +1 -0
  57. package/dist/graph/machine-variants.js +208 -0
  58. package/dist/graph/machine-variants.js.map +1 -0
  59. package/dist/ingest/files.js +99 -0
  60. package/dist/ingest/files.js.map +1 -0
  61. package/dist/ingest/passes.js +104 -0
  62. package/dist/ingest/passes.js.map +1 -0
  63. package/dist/ingest/points.js +50 -0
  64. package/dist/ingest/points.js.map +1 -0
  65. package/dist/ingest/report.js +140 -0
  66. package/dist/ingest/report.js.map +1 -0
  67. package/dist/ingest/tally.js +81 -0
  68. package/dist/ingest/tally.js.map +1 -0
  69. package/dist/ingest/verified-on.js +43 -0
  70. package/dist/ingest/verified-on.js.map +1 -0
  71. package/dist/ingest.js +135 -0
  72. package/dist/ingest.js.map +1 -0
  73. package/dist/schemas/cost-basis.js +5 -0
  74. package/dist/schemas/cost-basis.js.map +1 -0
  75. package/dist/schemas/machine-variant.js +25 -0
  76. package/dist/schemas/machine-variant.js.map +1 -0
  77. package/dist/schemas/plan-budget.js +121 -0
  78. package/dist/schemas/plan-budget.js.map +1 -0
  79. package/dist/schemas/tool-outputs.js +526 -0
  80. package/dist/schemas/tool-outputs.js.map +1 -0
  81. package/dist/server/define-tool.js +52 -0
  82. package/dist/server/define-tool.js.map +1 -0
  83. package/dist/server/defined-only.js +9 -0
  84. package/dist/server/defined-only.js.map +1 -0
  85. package/dist/server/tools-briefings.js +70 -0
  86. package/dist/server/tools-briefings.js.map +1 -0
  87. package/dist/server/tools-lookup.js +180 -0
  88. package/dist/server/tools-lookup.js.map +1 -0
  89. package/dist/server/tools-maintenance.js +116 -0
  90. package/dist/server/tools-maintenance.js.map +1 -0
  91. package/dist/server/tools-pitfalls.js +89 -0
  92. package/dist/server/tools-pitfalls.js.map +1 -0
  93. package/dist/server/tools-recipes.js +296 -0
  94. package/dist/server/tools-recipes.js.map +1 -0
  95. package/dist/server/tools-runtime.js +48 -0
  96. package/dist/server/tools-runtime.js.map +1 -0
  97. package/dist/server/tools.js +43 -0
  98. package/dist/server/tools.js.map +1 -0
  99. package/dist/server.js +95 -0
  100. package/dist/server.js.map +1 -0
  101. package/dist/services/analytics/schema.js +78 -0
  102. package/dist/services/analytics/schema.js.map +1 -0
  103. package/dist/services/analytics/statements.js +99 -0
  104. package/dist/services/analytics/statements.js.map +1 -0
  105. package/dist/services/analytics.js +195 -0
  106. package/dist/services/analytics.js.map +1 -0
  107. package/dist/services/bm25.js +158 -0
  108. package/dist/services/bm25.js.map +1 -0
  109. package/dist/services/chunker.js +81 -0
  110. package/dist/services/chunker.js.map +1 -0
  111. package/dist/services/embeddings.js +58 -0
  112. package/dist/services/embeddings.js.map +1 -0
  113. package/dist/services/falkor/base.js +85 -0
  114. package/dist/services/falkor/base.js.map +1 -0
  115. package/dist/services/falkor/links.js +361 -0
  116. package/dist/services/falkor/links.js.map +1 -0
  117. package/dist/services/falkor/nodes.js +183 -0
  118. package/dist/services/falkor/nodes.js.map +1 -0
  119. package/dist/services/falkor/params.js +45 -0
  120. package/dist/services/falkor/params.js.map +1 -0
  121. package/dist/services/falkor/schema.js +77 -0
  122. package/dist/services/falkor/schema.js.map +1 -0
  123. package/dist/services/falkor.js +100 -0
  124. package/dist/services/falkor.js.map +1 -0
  125. package/dist/services/qdrant.js +238 -0
  126. package/dist/services/qdrant.js.map +1 -0
  127. package/dist/services/versions.js +73 -0
  128. package/dist/services/versions.js.map +1 -0
  129. package/dist/services/vice-bin.js +51 -0
  130. package/dist/services/vice-bin.js.map +1 -0
  131. package/dist/tools/briefings/archetype.js +174 -0
  132. package/dist/tools/briefings/archetype.js.map +1 -0
  133. package/dist/tools/briefings/budget.js +177 -0
  134. package/dist/tools/briefings/budget.js.map +1 -0
  135. package/dist/tools/briefings/build-order.js +135 -0
  136. package/dist/tools/briefings/build-order.js.map +1 -0
  137. package/dist/tools/briefings/build.js +185 -0
  138. package/dist/tools/briefings/build.js.map +1 -0
  139. package/dist/tools/briefings/discovery.js +290 -0
  140. package/dist/tools/briefings/discovery.js.map +1 -0
  141. package/dist/tools/briefings/plan-pitfalls.js +69 -0
  142. package/dist/tools/briefings/plan-pitfalls.js.map +1 -0
  143. package/dist/tools/briefings/render.js +151 -0
  144. package/dist/tools/briefings/render.js.map +1 -0
  145. package/dist/tools/briefings/rows.js +41 -0
  146. package/dist/tools/briefings/rows.js.map +1 -0
  147. package/dist/tools/briefings/toolchain.js +63 -0
  148. package/dist/tools/briefings/toolchain.js.map +1 -0
  149. package/dist/tools/briefings/why-proposed.js +69 -0
  150. package/dist/tools/briefings/why-proposed.js.map +1 -0
  151. package/dist/tools/briefings.js +44 -0
  152. package/dist/tools/briefings.js.map +1 -0
  153. package/dist/tools/feedback.js +97 -0
  154. package/dist/tools/feedback.js.map +1 -0
  155. package/dist/tools/hydrate.js +75 -0
  156. package/dist/tools/hydrate.js.map +1 -0
  157. package/dist/tools/intelligence.js +67 -0
  158. package/dist/tools/intelligence.js.map +1 -0
  159. package/dist/tools/lint/asm-decimal.js +86 -0
  160. package/dist/tools/lint/asm-decimal.js.map +1 -0
  161. package/dist/tools/lint/asm-rules.js +221 -0
  162. package/dist/tools/lint/asm-rules.js.map +1 -0
  163. package/dist/tools/lint/asm-shared.js +3 -0
  164. package/dist/tools/lint/asm-shared.js.map +1 -0
  165. package/dist/tools/lint/c-rules.js +215 -0
  166. package/dist/tools/lint/c-rules.js.map +1 -0
  167. package/dist/tools/lint/text.js +122 -0
  168. package/dist/tools/lint/text.js.map +1 -0
  169. package/dist/tools/lint/types.js +40 -0
  170. package/dist/tools/lint/types.js.map +1 -0
  171. package/dist/tools/lint.js +76 -0
  172. package/dist/tools/lint.js.map +1 -0
  173. package/dist/tools/memorization-mcp.js +111 -0
  174. package/dist/tools/memorization-mcp.js.map +1 -0
  175. package/dist/tools/pitfalls/bm25.js +53 -0
  176. package/dist/tools/pitfalls/bm25.js.map +1 -0
  177. package/dist/tools/pitfalls/format.js +58 -0
  178. package/dist/tools/pitfalls/format.js.map +1 -0
  179. package/dist/tools/pitfalls/graph.js +124 -0
  180. package/dist/tools/pitfalls/graph.js.map +1 -0
  181. package/dist/tools/pitfalls.js +134 -0
  182. package/dist/tools/pitfalls.js.map +1 -0
  183. package/dist/tools/prompts.js +81 -0
  184. package/dist/tools/prompts.js.map +1 -0
  185. package/dist/tools/query/compatibility/closure.js +62 -0
  186. package/dist/tools/query/compatibility/closure.js.map +1 -0
  187. package/dist/tools/query/compatibility/facts.js +28 -0
  188. package/dist/tools/query/compatibility/facts.js.map +1 -0
  189. package/dist/tools/query/compatibility/fetch.js +164 -0
  190. package/dist/tools/query/compatibility/fetch.js.map +1 -0
  191. package/dist/tools/query/compatibility/hard-rules.js +159 -0
  192. package/dist/tools/query/compatibility/hard-rules.js.map +1 -0
  193. package/dist/tools/query/compatibility/index.js +27 -0
  194. package/dist/tools/query/compatibility/index.js.map +1 -0
  195. package/dist/tools/query/compatibility/kernal-zp-rule.js +90 -0
  196. package/dist/tools/query/compatibility/kernal-zp-rule.js.map +1 -0
  197. package/dist/tools/query/compatibility/render.js +106 -0
  198. package/dist/tools/query/compatibility/render.js.map +1 -0
  199. package/dist/tools/query/compatibility/rules.js +337 -0
  200. package/dist/tools/query/compatibility/rules.js.map +1 -0
  201. package/dist/tools/query/compatibility/unit-rules.js +253 -0
  202. package/dist/tools/query/compatibility/unit-rules.js.map +1 -0
  203. package/dist/tools/query/game-design.js +83 -0
  204. package/dist/tools/query/game-design.js.map +1 -0
  205. package/dist/tools/query/lookups.js +220 -0
  206. package/dist/tools/query/lookups.js.map +1 -0
  207. package/dist/tools/query/plan-budget.js +266 -0
  208. package/dist/tools/query/plan-budget.js.map +1 -0
  209. package/dist/tools/query/recipes.js +214 -0
  210. package/dist/tools/query/recipes.js.map +1 -0
  211. package/dist/tools/query/retrieval.js +128 -0
  212. package/dist/tools/query/retrieval.js.map +1 -0
  213. package/dist/tools/query/shared.js +121 -0
  214. package/dist/tools/query/shared.js.map +1 -0
  215. package/dist/tools/query/techniques.js +331 -0
  216. package/dist/tools/query/techniques.js.map +1 -0
  217. package/dist/tools/query/timing.js +106 -0
  218. package/dist/tools/query/timing.js.map +1 -0
  219. package/dist/tools/query/types.js +11 -0
  220. package/dist/tools/query/types.js.map +1 -0
  221. package/dist/tools/query.js +21 -0
  222. package/dist/tools/query.js.map +1 -0
  223. package/dist/tools/resources.js +186 -0
  224. package/dist/tools/resources.js.map +1 -0
  225. package/dist/tools/run-game.js +249 -0
  226. package/dist/tools/run-game.js.map +1 -0
  227. package/dist/tools/selfimprovement.js +367 -0
  228. package/dist/tools/selfimprovement.js.map +1 -0
  229. package/docker-compose.yml +35 -0
  230. package/docs/ARCHITECTURE.md +164 -0
  231. package/docs/CONVENTIONS-archetypes.md +158 -0
  232. package/docs/CONVENTIONS-failures.md +46 -0
  233. package/docs/CONVENTIONS-game-designs.md +75 -0
  234. package/docs/CONVENTIONS-hardware-reference.md +184 -0
  235. package/docs/CONVENTIONS-pitfalls.md +91 -0
  236. package/docs/CONVENTIONS-recipes.md +106 -0
  237. package/docs/CONVENTIONS-techniques.md +309 -0
  238. package/docs/CONVENTIONS-toolchain-reference.md +89 -0
  239. package/docs/ONTOLOGY.md +655 -0
  240. package/docs/art/art-production-reference.md +157 -0
  241. package/docs/art/asset-pipelines.md +586 -0
  242. package/docs/c64-failure-patterns.md +693 -0
  243. package/docs/demo-design/demo-composition.md +349 -0
  244. package/docs/demo-design/demo-design-philosophy.md +320 -0
  245. package/docs/demo-design/intro-cracktro-patterns.md +435 -0
  246. package/docs/figures/ctm-spd-embed-probe.png +0 -0
  247. package/docs/figures/dot-flag-mid-5000000.png +0 -0
  248. package/docs/figures/dot-flag-no-erase-12000000.png +0 -0
  249. package/docs/figures/edges.json +1 -0
  250. package/docs/figures/fig6-architecture.png +0 -0
  251. package/docs/figures/fig7-ontology.png +0 -0
  252. package/docs/figures/screen-dissolve-mid-frame25.png +0 -0
  253. package/docs/figures/screen-dissolve-wipe-frame25.png +0 -0
  254. package/docs/figures/spindle-two-parts-part1.png +0 -0
  255. package/docs/figures/spindle-two-parts-part2.png +0 -0
  256. package/docs/figures/starters/action-puzzle.png +0 -0
  257. package/docs/figures/starters/adventure.png +0 -0
  258. package/docs/figures/starters/beat-em-up.png +0 -0
  259. package/docs/figures/starters/demo.png +0 -0
  260. package/docs/figures/starters/platformer.png +0 -0
  261. package/docs/figures/starters/shmup-vertical.png +0 -0
  262. package/docs/figures/tape-kernal-master-ntsc.png +0 -0
  263. package/docs/figures/tape-kernal-master-pal.png +0 -0
  264. package/docs/figures/tape-turbo-loader-ntsc.png +0 -0
  265. package/docs/figures/tape-turbo-loader-pal.png +0 -0
  266. package/docs/figures/tape-turbo-master-ntsc.png +0 -0
  267. package/docs/figures/tape-turbo-master-pal.png +0 -0
  268. package/docs/figures/tech-tech-pad2-12000000.png +0 -0
  269. package/docs/figures/tech-tech-pad4-12000000.png +0 -0
  270. package/docs/figures/tech-tech-seven-12000000.png +0 -0
  271. package/docs/figures/twister-mid-5000000.png +0 -0
  272. package/docs/figures/twister-straight-12000000.png +0 -0
  273. package/docs/figures/vector-balls-nosort-ntsc.png +0 -0
  274. package/docs/figures/vector-balls-nosort.png +0 -0
  275. package/docs/formats/c64-file-formats.md +1212 -0
  276. package/docs/formats/iec-disk-reference.md +754 -0
  277. package/docs/game-design/c64-game-archetypes.md +273 -0
  278. package/docs/game-design/designs/falling-blocks.md +54 -0
  279. package/docs/game-design/designs/platformer-scaffold.md +48 -0
  280. package/docs/game-design/designs/simple-shmup.md +27 -0
  281. package/docs/game-design/enemy-behaviour-and-difficulty.md +349 -0
  282. package/docs/game-design/game-design-patterns.md +1189 -0
  283. package/docs/game-design/game-structure.md +354 -0
  284. package/docs/game-design/production-planning.md +349 -0
  285. package/docs/game-design/reference-game-sources.md +90 -0
  286. package/docs/hardware/6502-illegal-opcodes.md +1353 -0
  287. package/docs/hardware/6510-cpu-reference.md +2112 -0
  288. package/docs/hardware/c64-memory-map.md +3184 -0
  289. package/docs/hardware/c64-registers-reference.md +996 -0
  290. package/docs/hardware/cia-reference.md +1281 -0
  291. package/docs/hardware/kernal-routines-reference.md +1836 -0
  292. package/docs/hardware/pal-ntsc-reference.md +813 -0
  293. package/docs/hardware/sid-reference.md +1137 -0
  294. package/docs/hardware/vic-ii-reference.md +1714 -0
  295. package/docs/music/music-production-reference.md +403 -0
  296. package/docs/pitfalls/banking.md +1067 -0
  297. package/docs/pitfalls/cia.md +1147 -0
  298. package/docs/pitfalls/cpu.md +874 -0
  299. package/docs/pitfalls/input.md +282 -0
  300. package/docs/pitfalls/kernal-and-io.md +1615 -0
  301. package/docs/pitfalls/loader.md +1191 -0
  302. package/docs/pitfalls/logic.md +94 -0
  303. package/docs/pitfalls/maths.md +187 -0
  304. package/docs/pitfalls/raster-and-badline.md +721 -0
  305. package/docs/pitfalls/region-timing.md +660 -0
  306. package/docs/pitfalls/scroll.md +207 -0
  307. package/docs/pitfalls/sid.md +738 -0
  308. package/docs/pitfalls/sprite.md +979 -0
  309. package/docs/pitfalls/text-mode-render.md +1172 -0
  310. package/docs/recipes/cc65/cartridge-8k.md +398 -0
  311. package/docs/recipes/cc65/hello-world-conio.md +76 -0
  312. package/docs/recipes/cc65/memory-layout.md +312 -0
  313. package/docs/recipes/cc65/screenshots/README.md +14 -0
  314. package/docs/recipes/cc65/screenshots/cartridge-8k-ntsc.png +0 -0
  315. package/docs/recipes/cc65/screenshots/cartridge-8k.png +0 -0
  316. package/docs/recipes/cc65/screenshots/hello-world-conio.png +0 -0
  317. package/docs/recipes/cc65/screenshots/memory-layout-ntsc.png +0 -0
  318. package/docs/recipes/cc65/screenshots/memory-layout.png +0 -0
  319. package/docs/recipes/kickassembler/basic-float-calls.md +578 -0
  320. package/docs/recipes/kickassembler/basic-wedge.md +398 -0
  321. package/docs/recipes/kickassembler/big-font-scroller.md +620 -0
  322. package/docs/recipes/kickassembler/charset-copy-rom-to-ram.md +623 -0
  323. package/docs/recipes/kickassembler/cia-revision-detect.md +366 -0
  324. package/docs/recipes/kickassembler/colour-cycling.md +343 -0
  325. package/docs/recipes/kickassembler/colour-fade.md +303 -0
  326. package/docs/recipes/kickassembler/compare-16bit-signed.md +1007 -0
  327. package/docs/recipes/kickassembler/cracktro-template.md +526 -0
  328. package/docs/recipes/kickassembler/crt-banked.md +276 -0
  329. package/docs/recipes/kickassembler/dos-error-codes.md +466 -0
  330. package/docs/recipes/kickassembler/dot-flag.md +576 -0
  331. package/docs/recipes/kickassembler/drive-job-queue.md +667 -0
  332. package/docs/recipes/kickassembler/drive-via-probe.md +690 -0
  333. package/docs/recipes/kickassembler/dycp-scroller.md +568 -0
  334. package/docs/recipes/kickassembler/dypp-sprite-scroller.md +681 -0
  335. package/docs/recipes/kickassembler/dysp.md +670 -0
  336. package/docs/recipes/kickassembler/easyflash-save.md +800 -0
  337. package/docs/recipes/kickassembler/eight-way-scroll.md +1484 -0
  338. package/docs/recipes/kickassembler/file-io-roundtrip.md +546 -0
  339. package/docs/recipes/kickassembler/fire-effect.md +420 -0
  340. package/docs/recipes/kickassembler/fld.md +414 -0
  341. package/docs/recipes/kickassembler/fli-image.md +336 -0
  342. package/docs/recipes/kickassembler/four-player-read.md +672 -0
  343. package/docs/recipes/kickassembler/headless-verify.md +228 -0
  344. package/docs/recipes/kickassembler/hello-world.md +98 -0
  345. package/docs/recipes/kickassembler/high-score-insert.md +660 -0
  346. package/docs/recipes/kickassembler/hires-plot-line.md +723 -0
  347. package/docs/recipes/kickassembler/irq-chain.md +316 -0
  348. package/docs/recipes/kickassembler/irq-owns-port.md +668 -0
  349. package/docs/recipes/kickassembler/isometric-room.md +1145 -0
  350. package/docs/recipes/kickassembler/light-pen-read.md +926 -0
  351. package/docs/recipes/kickassembler/logic-rate-decoupling.md +670 -0
  352. package/docs/recipes/kickassembler/mci-interlace.md +543 -0
  353. package/docs/recipes/kickassembler/memory-layout.md +277 -0
  354. package/docs/recipes/kickassembler/mouse-1351-read.md +801 -0
  355. package/docs/recipes/kickassembler/nmi-timer-tick.md +562 -0
  356. package/docs/recipes/kickassembler/own-keyscan.md +881 -0
  357. package/docs/recipes/kickassembler/paddle-read.md +751 -0
  358. package/docs/recipes/kickassembler/palette-cells.md +219 -0
  359. package/docs/recipes/kickassembler/pseudo-3d-road.md +930 -0
  360. package/docs/recipes/kickassembler/pwm-digi.md +463 -0
  361. package/docs/recipes/kickassembler/raster-bars.md +264 -0
  362. package/docs/recipes/kickassembler/reu-dma.md +1019 -0
  363. package/docs/recipes/kickassembler/runtime-relocation.md +743 -0
  364. package/docs/recipes/kickassembler/screen-dissolve.md +545 -0
  365. package/docs/recipes/kickassembler/screen-wipe.md +408 -0
  366. package/docs/recipes/kickassembler/screenshots/README.md +72 -0
  367. package/docs/recipes/kickassembler/screenshots/basic-float-calls-ntsc.png +0 -0
  368. package/docs/recipes/kickassembler/screenshots/basic-float-calls.png +0 -0
  369. package/docs/recipes/kickassembler/screenshots/basic-wedge-ntsc.png +0 -0
  370. package/docs/recipes/kickassembler/screenshots/basic-wedge.png +0 -0
  371. package/docs/recipes/kickassembler/screenshots/big-font-scroller-ntsc.png +0 -0
  372. package/docs/recipes/kickassembler/screenshots/big-font-scroller.png +0 -0
  373. package/docs/recipes/kickassembler/screenshots/charset-copy-rom-to-ram-ntsc.png +0 -0
  374. package/docs/recipes/kickassembler/screenshots/charset-copy-rom-to-ram.png +0 -0
  375. package/docs/recipes/kickassembler/screenshots/cia-revision-detect-ntsc.png +0 -0
  376. package/docs/recipes/kickassembler/screenshots/cia-revision-detect.png +0 -0
  377. package/docs/recipes/kickassembler/screenshots/colour-cycling-ntsc.png +0 -0
  378. package/docs/recipes/kickassembler/screenshots/colour-cycling.png +0 -0
  379. package/docs/recipes/kickassembler/screenshots/colour-fade-ntsc.png +0 -0
  380. package/docs/recipes/kickassembler/screenshots/colour-fade.png +0 -0
  381. package/docs/recipes/kickassembler/screenshots/compare-16bit-signed-ntsc.png +0 -0
  382. package/docs/recipes/kickassembler/screenshots/compare-16bit-signed.png +0 -0
  383. package/docs/recipes/kickassembler/screenshots/cracktro-template.png +0 -0
  384. package/docs/recipes/kickassembler/screenshots/crt-banked-ntsc.png +0 -0
  385. package/docs/recipes/kickassembler/screenshots/crt-banked.png +0 -0
  386. package/docs/recipes/kickassembler/screenshots/dos-error-codes-ntsc.png +0 -0
  387. package/docs/recipes/kickassembler/screenshots/dos-error-codes.png +0 -0
  388. package/docs/recipes/kickassembler/screenshots/dot-flag-ntsc.png +0 -0
  389. package/docs/recipes/kickassembler/screenshots/dot-flag.png +0 -0
  390. package/docs/recipes/kickassembler/screenshots/drive-job-queue-ntsc.png +0 -0
  391. package/docs/recipes/kickassembler/screenshots/drive-job-queue.png +0 -0
  392. package/docs/recipes/kickassembler/screenshots/drive-via-probe-ntsc.png +0 -0
  393. package/docs/recipes/kickassembler/screenshots/drive-via-probe.png +0 -0
  394. package/docs/recipes/kickassembler/screenshots/dycp-scroller-ntsc.png +0 -0
  395. package/docs/recipes/kickassembler/screenshots/dycp-scroller.png +0 -0
  396. package/docs/recipes/kickassembler/screenshots/dypp-sprite-scroller-ntsc.png +0 -0
  397. package/docs/recipes/kickassembler/screenshots/dypp-sprite-scroller.png +0 -0
  398. package/docs/recipes/kickassembler/screenshots/dysp-ntsc.png +0 -0
  399. package/docs/recipes/kickassembler/screenshots/dysp.png +0 -0
  400. package/docs/recipes/kickassembler/screenshots/easyflash-save-ntsc-run2.png +0 -0
  401. package/docs/recipes/kickassembler/screenshots/easyflash-save-ntsc.png +0 -0
  402. package/docs/recipes/kickassembler/screenshots/easyflash-save-run2.png +0 -0
  403. package/docs/recipes/kickassembler/screenshots/easyflash-save.png +0 -0
  404. package/docs/recipes/kickassembler/screenshots/eight-way-scroll-ntsc.png +0 -0
  405. package/docs/recipes/kickassembler/screenshots/eight-way-scroll.png +0 -0
  406. package/docs/recipes/kickassembler/screenshots/file-io-roundtrip-ntsc.png +0 -0
  407. package/docs/recipes/kickassembler/screenshots/file-io-roundtrip.png +0 -0
  408. package/docs/recipes/kickassembler/screenshots/fire-effect-ntsc.png +0 -0
  409. package/docs/recipes/kickassembler/screenshots/fire-effect.png +0 -0
  410. package/docs/recipes/kickassembler/screenshots/fld-ntsc.png +0 -0
  411. package/docs/recipes/kickassembler/screenshots/fld.png +0 -0
  412. package/docs/recipes/kickassembler/screenshots/fli-image.png +0 -0
  413. package/docs/recipes/kickassembler/screenshots/four-player-read-ntsc.png +0 -0
  414. package/docs/recipes/kickassembler/screenshots/four-player-read.png +0 -0
  415. package/docs/recipes/kickassembler/screenshots/headless-verify-ntsc.png +0 -0
  416. package/docs/recipes/kickassembler/screenshots/headless-verify.png +0 -0
  417. package/docs/recipes/kickassembler/screenshots/hello-world.png +0 -0
  418. package/docs/recipes/kickassembler/screenshots/high-score-insert-ntsc.png +0 -0
  419. package/docs/recipes/kickassembler/screenshots/high-score-insert.png +0 -0
  420. package/docs/recipes/kickassembler/screenshots/hires-plot-line-ntsc.png +0 -0
  421. package/docs/recipes/kickassembler/screenshots/hires-plot-line.png +0 -0
  422. package/docs/recipes/kickassembler/screenshots/irq-chain-ntsc.png +0 -0
  423. package/docs/recipes/kickassembler/screenshots/irq-chain.png +0 -0
  424. package/docs/recipes/kickassembler/screenshots/irq-owns-port-ntsc.png +0 -0
  425. package/docs/recipes/kickassembler/screenshots/irq-owns-port.png +0 -0
  426. package/docs/recipes/kickassembler/screenshots/isometric-room-ntsc.png +0 -0
  427. package/docs/recipes/kickassembler/screenshots/isometric-room.png +0 -0
  428. package/docs/recipes/kickassembler/screenshots/light-pen-read-ntsc.png +0 -0
  429. package/docs/recipes/kickassembler/screenshots/light-pen-read.png +0 -0
  430. package/docs/recipes/kickassembler/screenshots/logic-rate-decoupling-ntsc.png +0 -0
  431. package/docs/recipes/kickassembler/screenshots/logic-rate-decoupling.png +0 -0
  432. package/docs/recipes/kickassembler/screenshots/mci-interlace-average.png +0 -0
  433. package/docs/recipes/kickassembler/screenshots/mci-interlace-frame-b.png +0 -0
  434. package/docs/recipes/kickassembler/screenshots/mci-interlace-ntsc.png +0 -0
  435. package/docs/recipes/kickassembler/screenshots/mci-interlace.png +0 -0
  436. package/docs/recipes/kickassembler/screenshots/memory-layout-ntsc.png +0 -0
  437. package/docs/recipes/kickassembler/screenshots/memory-layout.png +0 -0
  438. package/docs/recipes/kickassembler/screenshots/mouse-1351-read-ntsc.png +0 -0
  439. package/docs/recipes/kickassembler/screenshots/mouse-1351-read.png +0 -0
  440. package/docs/recipes/kickassembler/screenshots/nmi-timer-tick-ntsc.png +0 -0
  441. package/docs/recipes/kickassembler/screenshots/nmi-timer-tick.png +0 -0
  442. package/docs/recipes/kickassembler/screenshots/own-keyscan-ntsc.png +0 -0
  443. package/docs/recipes/kickassembler/screenshots/own-keyscan.png +0 -0
  444. package/docs/recipes/kickassembler/screenshots/paddle-read-ntsc.png +0 -0
  445. package/docs/recipes/kickassembler/screenshots/paddle-read.png +0 -0
  446. package/docs/recipes/kickassembler/screenshots/palette-cells-ntsc.png +0 -0
  447. package/docs/recipes/kickassembler/screenshots/palette-cells.png +0 -0
  448. package/docs/recipes/kickassembler/screenshots/pseudo-3d-road-ntsc.png +0 -0
  449. package/docs/recipes/kickassembler/screenshots/pseudo-3d-road.png +0 -0
  450. package/docs/recipes/kickassembler/screenshots/pwm-digi-ntsc.png +0 -0
  451. package/docs/recipes/kickassembler/screenshots/pwm-digi.png +0 -0
  452. package/docs/recipes/kickassembler/screenshots/raster-bars.png +0 -0
  453. package/docs/recipes/kickassembler/screenshots/reu-dma-ntsc.png +0 -0
  454. package/docs/recipes/kickassembler/screenshots/reu-dma.png +0 -0
  455. package/docs/recipes/kickassembler/screenshots/runtime-relocation-ntsc.png +0 -0
  456. package/docs/recipes/kickassembler/screenshots/runtime-relocation.png +0 -0
  457. package/docs/recipes/kickassembler/screenshots/screen-dissolve-ntsc.png +0 -0
  458. package/docs/recipes/kickassembler/screenshots/screen-dissolve.png +0 -0
  459. package/docs/recipes/kickassembler/screenshots/screen-wipe-ntsc.png +0 -0
  460. package/docs/recipes/kickassembler/screenshots/screen-wipe.png +0 -0
  461. package/docs/recipes/kickassembler/screenshots/scroll-panel-split-ntsc.png +0 -0
  462. package/docs/recipes/kickassembler/screenshots/scroll-panel-split.png +0 -0
  463. package/docs/recipes/kickassembler/screenshots/sfx-in-player-ntsc.png +0 -0
  464. package/docs/recipes/kickassembler/screenshots/sfx-in-player.png +0 -0
  465. package/docs/recipes/kickassembler/screenshots/shadebobs-ntsc.png +0 -0
  466. package/docs/recipes/kickassembler/screenshots/shadebobs.png +0 -0
  467. package/docs/recipes/kickassembler/screenshots/sideborder-open.png +0 -0
  468. package/docs/recipes/kickassembler/screenshots/sine-scroller.png +0 -0
  469. package/docs/recipes/kickassembler/screenshots/sine-table-runtime-ntsc.png +0 -0
  470. package/docs/recipes/kickassembler/screenshots/sine-table-runtime.png +0 -0
  471. package/docs/recipes/kickassembler/screenshots/software-sprite-preshifted-ntsc.png +0 -0
  472. package/docs/recipes/kickassembler/screenshots/software-sprite-preshifted.png +0 -0
  473. package/docs/recipes/kickassembler/screenshots/speedcode-generator-ntsc.png +0 -0
  474. package/docs/recipes/kickassembler/screenshots/speedcode-generator.png +0 -0
  475. package/docs/recipes/kickassembler/screenshots/sprite-border-scroller-ntsc.png +0 -0
  476. package/docs/recipes/kickassembler/screenshots/sprite-border-scroller.png +0 -0
  477. package/docs/recipes/kickassembler/screenshots/sprite-cache-flip-ntsc.png +0 -0
  478. package/docs/recipes/kickassembler/screenshots/sprite-cache-flip.png +0 -0
  479. package/docs/recipes/kickassembler/screenshots/sprite-multiplex-24.png +0 -0
  480. package/docs/recipes/kickassembler/screenshots/sprite-multiplex-game-ntsc.png +0 -0
  481. package/docs/recipes/kickassembler/screenshots/sprite-multiplex-game.png +0 -0
  482. package/docs/recipes/kickassembler/screenshots/sprite-priority-classes-ntsc.png +0 -0
  483. package/docs/recipes/kickassembler/screenshots/sprite-priority-classes.png +0 -0
  484. package/docs/recipes/kickassembler/screenshots/sprite-sine-chain-ntsc.png +0 -0
  485. package/docs/recipes/kickassembler/screenshots/sprite-sine-chain.png +0 -0
  486. package/docs/recipes/kickassembler/screenshots/sprite-stretcher-ntsc.png +0 -0
  487. package/docs/recipes/kickassembler/screenshots/sprite-stretcher.png +0 -0
  488. package/docs/recipes/kickassembler/screenshots/sprites-only-screen-ntsc.png +0 -0
  489. package/docs/recipes/kickassembler/screenshots/sprites-only-screen.png +0 -0
  490. package/docs/recipes/kickassembler/screenshots/sqrt-atan2-ntsc.png +0 -0
  491. package/docs/recipes/kickassembler/screenshots/sqrt-atan2.png +0 -0
  492. package/docs/recipes/kickassembler/screenshots/stable-raster-irq-control.png +0 -0
  493. package/docs/recipes/kickassembler/screenshots/stable-raster-irq.png +0 -0
  494. package/docs/recipes/kickassembler/screenshots/tech-tech-ntsc.png +0 -0
  495. package/docs/recipes/kickassembler/screenshots/tech-tech.png +0 -0
  496. package/docs/recipes/kickassembler/screenshots/tod-alarm-ntsc.png +0 -0
  497. package/docs/recipes/kickassembler/screenshots/tod-alarm.png +0 -0
  498. package/docs/recipes/kickassembler/screenshots/topbottom-border-open.png +0 -0
  499. package/docs/recipes/kickassembler/screenshots/twister-ntsc.png +0 -0
  500. package/docs/recipes/kickassembler/screenshots/twister.png +0 -0
  501. package/docs/recipes/kickassembler/screenshots/unit-test-driver-ntsc.png +0 -0
  502. package/docs/recipes/kickassembler/screenshots/unit-test-driver.png +0 -0
  503. package/docs/recipes/kickassembler/screenshots/vector-balls-ntsc.png +0 -0
  504. package/docs/recipes/kickassembler/screenshots/vector-balls.png +0 -0
  505. package/docs/recipes/kickassembler/screenshots/wireframe-ships-ntsc.png +0 -0
  506. package/docs/recipes/kickassembler/screenshots/wireframe-ships.png +0 -0
  507. package/docs/recipes/kickassembler/scroll-panel-split.md +381 -0
  508. package/docs/recipes/kickassembler/sfx-in-player.md +907 -0
  509. package/docs/recipes/kickassembler/shadebobs.md +522 -0
  510. package/docs/recipes/kickassembler/sideborder-open.md +338 -0
  511. package/docs/recipes/kickassembler/sine-scroller.md +321 -0
  512. package/docs/recipes/kickassembler/sine-table-runtime.md +815 -0
  513. package/docs/recipes/kickassembler/software-sprite-preshifted.md +725 -0
  514. package/docs/recipes/kickassembler/speedcode-generator.md +606 -0
  515. package/docs/recipes/kickassembler/sprite-border-scroller.md +696 -0
  516. package/docs/recipes/kickassembler/sprite-cache-flip.md +1071 -0
  517. package/docs/recipes/kickassembler/sprite-multiplex-24.md +326 -0
  518. package/docs/recipes/kickassembler/sprite-multiplex-game.md +986 -0
  519. package/docs/recipes/kickassembler/sprite-priority-classes.md +463 -0
  520. package/docs/recipes/kickassembler/sprite-sine-chain.md +338 -0
  521. package/docs/recipes/kickassembler/sprite-stretcher.md +501 -0
  522. package/docs/recipes/kickassembler/sprites-only-screen.md +550 -0
  523. package/docs/recipes/kickassembler/sqrt-atan2.md +1014 -0
  524. package/docs/recipes/kickassembler/stable-raster-irq.md +360 -0
  525. package/docs/recipes/kickassembler/tape-turbo-loader.md +875 -0
  526. package/docs/recipes/kickassembler/tech-tech.md +679 -0
  527. package/docs/recipes/kickassembler/tod-alarm.md +754 -0
  528. package/docs/recipes/kickassembler/topbottom-border-open.md +407 -0
  529. package/docs/recipes/kickassembler/twister.md +518 -0
  530. package/docs/recipes/kickassembler/unit-test-driver.md +314 -0
  531. package/docs/recipes/kickassembler/vector-balls.md +545 -0
  532. package/docs/recipes/kickassembler/wireframe-ships.md +2324 -0
  533. package/docs/recipes/oscar64/actor-activation-window.md +807 -0
  534. package/docs/recipes/oscar64/adventure-engine.md +1094 -0
  535. package/docs/recipes/oscar64/attract-replay.md +465 -0
  536. package/docs/recipes/oscar64/beat-em-up-lanes.md +563 -0
  537. package/docs/recipes/oscar64/bfs-distance-map.md +723 -0
  538. package/docs/recipes/oscar64/bitmap-koala-viewer.md +355 -0
  539. package/docs/recipes/oscar64/car-contact.md +950 -0
  540. package/docs/recipes/oscar64/cave-scan.md +609 -0
  541. package/docs/recipes/oscar64/char-bullets.md +477 -0
  542. package/docs/recipes/oscar64/charset-animation.md +383 -0
  543. package/docs/recipes/oscar64/charset-parallax.md +401 -0
  544. package/docs/recipes/oscar64/destructible-terrain.md +1099 -0
  545. package/docs/recipes/oscar64/difficulty-tables.md +654 -0
  546. package/docs/recipes/oscar64/dig-and-guards.md +975 -0
  547. package/docs/recipes/oscar64/directory-reader.md +535 -0
  548. package/docs/recipes/oscar64/divide-check.md +581 -0
  549. package/docs/recipes/oscar64/double-buffer-nomirror.md +205 -0
  550. package/docs/recipes/oscar64/double-buffer.md +255 -0
  551. package/docs/recipes/oscar64/falling-blocks.md +874 -0
  552. package/docs/recipes/oscar64/fixed-point-jump-velocity.md +289 -0
  553. package/docs/recipes/oscar64/fixed-point-jump.md +210 -0
  554. package/docs/recipes/oscar64/flip-screen-rooms.md +793 -0
  555. package/docs/recipes/oscar64/frame-sync-loop-overrun.md +214 -0
  556. package/docs/recipes/oscar64/frame-sync-loop.md +254 -0
  557. package/docs/recipes/oscar64/game-tree-search.md +743 -0
  558. package/docs/recipes/oscar64/ghost-targeting.md +867 -0
  559. package/docs/recipes/oscar64/headless-verify.md +345 -0
  560. package/docs/recipes/oscar64/hello-world.md +83 -0
  561. package/docs/recipes/oscar64/high-score-persist.md +772 -0
  562. package/docs/recipes/oscar64/iffl-kernal-skip.md +421 -0
  563. package/docs/recipes/oscar64/joystick-input.md +358 -0
  564. package/docs/recipes/oscar64/lane-pursuit.md +1028 -0
  565. package/docs/recipes/oscar64/level-rle-decoder.md +620 -0
  566. package/docs/recipes/oscar64/lfsr-random-seed2.md +338 -0
  567. package/docs/recipes/oscar64/lfsr-random.md +403 -0
  568. package/docs/recipes/oscar64/load-asset-runtime.md +492 -0
  569. package/docs/recipes/oscar64/memory-layout.md +232 -0
  570. package/docs/recipes/oscar64/mixed-fighters.md +781 -0
  571. package/docs/recipes/oscar64/multi-sprite-object.md +533 -0
  572. package/docs/recipes/oscar64/nav-area-pathfinding.md +881 -0
  573. package/docs/recipes/oscar64/object-pool.md +572 -0
  574. package/docs/recipes/oscar64/pal-ntsc-detect.md +257 -0
  575. package/docs/recipes/oscar64/password-state.md +532 -0
  576. package/docs/recipes/oscar64/per-frame-hitbox.md +651 -0
  577. package/docs/recipes/oscar64/petscii-screen-codes.md +428 -0
  578. package/docs/recipes/oscar64/platformer-scaffold.md +1467 -0
  579. package/docs/recipes/oscar64/print-number.md +367 -0
  580. package/docs/recipes/oscar64/raster-bars.md +239 -0
  581. package/docs/recipes/oscar64/raster-profile-bars.md +404 -0
  582. package/docs/recipes/oscar64/rel-side-sectors.md +391 -0
  583. package/docs/recipes/oscar64/relative-file-records.md +378 -0
  584. package/docs/recipes/oscar64/save-load-seq-file.md +365 -0
  585. package/docs/recipes/oscar64/screenshots/README.md +99 -0
  586. package/docs/recipes/oscar64/screenshots/actor-activation-window-ntsc.png +0 -0
  587. package/docs/recipes/oscar64/screenshots/actor-activation-window.png +0 -0
  588. package/docs/recipes/oscar64/screenshots/adventure-engine-ntsc.png +0 -0
  589. package/docs/recipes/oscar64/screenshots/adventure-engine.png +0 -0
  590. package/docs/recipes/oscar64/screenshots/attract-replay-ntsc.png +0 -0
  591. package/docs/recipes/oscar64/screenshots/attract-replay.png +0 -0
  592. package/docs/recipes/oscar64/screenshots/beat-em-up-lanes-ntsc.png +0 -0
  593. package/docs/recipes/oscar64/screenshots/beat-em-up-lanes.png +0 -0
  594. package/docs/recipes/oscar64/screenshots/bfs-distance-map-ntsc.png +0 -0
  595. package/docs/recipes/oscar64/screenshots/bfs-distance-map.png +0 -0
  596. package/docs/recipes/oscar64/screenshots/bitmap-koala-viewer.png +0 -0
  597. package/docs/recipes/oscar64/screenshots/car-contact-ntsc.png +0 -0
  598. package/docs/recipes/oscar64/screenshots/car-contact.png +0 -0
  599. package/docs/recipes/oscar64/screenshots/cave-scan-ntsc.png +0 -0
  600. package/docs/recipes/oscar64/screenshots/cave-scan.png +0 -0
  601. package/docs/recipes/oscar64/screenshots/char-bullets-ntsc.png +0 -0
  602. package/docs/recipes/oscar64/screenshots/char-bullets.png +0 -0
  603. package/docs/recipes/oscar64/screenshots/charset-animation-ntsc.png +0 -0
  604. package/docs/recipes/oscar64/screenshots/charset-animation.png +0 -0
  605. package/docs/recipes/oscar64/screenshots/charset-parallax-ntsc.png +0 -0
  606. package/docs/recipes/oscar64/screenshots/charset-parallax.png +0 -0
  607. package/docs/recipes/oscar64/screenshots/destructible-terrain-ntsc.png +0 -0
  608. package/docs/recipes/oscar64/screenshots/destructible-terrain.png +0 -0
  609. package/docs/recipes/oscar64/screenshots/difficulty-tables-ntsc.png +0 -0
  610. package/docs/recipes/oscar64/screenshots/difficulty-tables.png +0 -0
  611. package/docs/recipes/oscar64/screenshots/dig-and-guards-ntsc.png +0 -0
  612. package/docs/recipes/oscar64/screenshots/dig-and-guards.png +0 -0
  613. package/docs/recipes/oscar64/screenshots/directory-reader-ntsc.png +0 -0
  614. package/docs/recipes/oscar64/screenshots/directory-reader.png +0 -0
  615. package/docs/recipes/oscar64/screenshots/divide-check-ntsc.png +0 -0
  616. package/docs/recipes/oscar64/screenshots/divide-check.png +0 -0
  617. package/docs/recipes/oscar64/screenshots/double-buffer-nomirror.png +0 -0
  618. package/docs/recipes/oscar64/screenshots/double-buffer-ntsc.png +0 -0
  619. package/docs/recipes/oscar64/screenshots/double-buffer.png +0 -0
  620. package/docs/recipes/oscar64/screenshots/falling-blocks-ntsc.png +0 -0
  621. package/docs/recipes/oscar64/screenshots/falling-blocks.png +0 -0
  622. package/docs/recipes/oscar64/screenshots/fixed-point-jump-ntsc.png +0 -0
  623. package/docs/recipes/oscar64/screenshots/fixed-point-jump-velocity-ntsc.png +0 -0
  624. package/docs/recipes/oscar64/screenshots/fixed-point-jump-velocity.png +0 -0
  625. package/docs/recipes/oscar64/screenshots/fixed-point-jump.png +0 -0
  626. package/docs/recipes/oscar64/screenshots/flip-screen-rooms-ntsc.png +0 -0
  627. package/docs/recipes/oscar64/screenshots/flip-screen-rooms.png +0 -0
  628. package/docs/recipes/oscar64/screenshots/frame-sync-loop-ntsc.png +0 -0
  629. package/docs/recipes/oscar64/screenshots/frame-sync-loop-overrun.png +0 -0
  630. package/docs/recipes/oscar64/screenshots/frame-sync-loop.png +0 -0
  631. package/docs/recipes/oscar64/screenshots/game-tree-search-ntsc.png +0 -0
  632. package/docs/recipes/oscar64/screenshots/game-tree-search.png +0 -0
  633. package/docs/recipes/oscar64/screenshots/ghost-targeting-ntsc.png +0 -0
  634. package/docs/recipes/oscar64/screenshots/ghost-targeting.png +0 -0
  635. package/docs/recipes/oscar64/screenshots/headless-verify-ntsc.png +0 -0
  636. package/docs/recipes/oscar64/screenshots/headless-verify.png +0 -0
  637. package/docs/recipes/oscar64/screenshots/hello-world.png +0 -0
  638. package/docs/recipes/oscar64/screenshots/high-score-persist-ntsc.png +0 -0
  639. package/docs/recipes/oscar64/screenshots/high-score-persist.png +0 -0
  640. package/docs/recipes/oscar64/screenshots/iffl-kernal-skip-ntsc.png +0 -0
  641. package/docs/recipes/oscar64/screenshots/iffl-kernal-skip.png +0 -0
  642. package/docs/recipes/oscar64/screenshots/joystick-input-ntsc.png +0 -0
  643. package/docs/recipes/oscar64/screenshots/joystick-input.png +0 -0
  644. package/docs/recipes/oscar64/screenshots/lane-pursuit-ntsc.png +0 -0
  645. package/docs/recipes/oscar64/screenshots/lane-pursuit.png +0 -0
  646. package/docs/recipes/oscar64/screenshots/level-rle-decoder-ntsc.png +0 -0
  647. package/docs/recipes/oscar64/screenshots/level-rle-decoder.png +0 -0
  648. package/docs/recipes/oscar64/screenshots/lfsr-random-ntsc.png +0 -0
  649. package/docs/recipes/oscar64/screenshots/lfsr-random-seed2.png +0 -0
  650. package/docs/recipes/oscar64/screenshots/lfsr-random.png +0 -0
  651. package/docs/recipes/oscar64/screenshots/load-asset-runtime-ntsc.png +0 -0
  652. package/docs/recipes/oscar64/screenshots/load-asset-runtime.png +0 -0
  653. package/docs/recipes/oscar64/screenshots/memory-layout-ntsc.png +0 -0
  654. package/docs/recipes/oscar64/screenshots/memory-layout.png +0 -0
  655. package/docs/recipes/oscar64/screenshots/mixed-fighters-ntsc.png +0 -0
  656. package/docs/recipes/oscar64/screenshots/mixed-fighters.png +0 -0
  657. package/docs/recipes/oscar64/screenshots/multi-sprite-object-ntsc.png +0 -0
  658. package/docs/recipes/oscar64/screenshots/multi-sprite-object.png +0 -0
  659. package/docs/recipes/oscar64/screenshots/nav-area-pathfinding-ntsc.png +0 -0
  660. package/docs/recipes/oscar64/screenshots/nav-area-pathfinding.png +0 -0
  661. package/docs/recipes/oscar64/screenshots/object-pool-ntsc.png +0 -0
  662. package/docs/recipes/oscar64/screenshots/object-pool.png +0 -0
  663. package/docs/recipes/oscar64/screenshots/pal-ntsc-detect-ntsc.png +0 -0
  664. package/docs/recipes/oscar64/screenshots/pal-ntsc-detect-oldntsc.png +0 -0
  665. package/docs/recipes/oscar64/screenshots/pal-ntsc-detect-pal.png +0 -0
  666. package/docs/recipes/oscar64/screenshots/password-state-ntsc.png +0 -0
  667. package/docs/recipes/oscar64/screenshots/password-state.png +0 -0
  668. package/docs/recipes/oscar64/screenshots/per-frame-hitbox-ntsc.png +0 -0
  669. package/docs/recipes/oscar64/screenshots/per-frame-hitbox.png +0 -0
  670. package/docs/recipes/oscar64/screenshots/petscii-screen-codes-ntsc.png +0 -0
  671. package/docs/recipes/oscar64/screenshots/petscii-screen-codes.png +0 -0
  672. package/docs/recipes/oscar64/screenshots/platformer-scaffold-d64-ntsc.png +0 -0
  673. package/docs/recipes/oscar64/screenshots/platformer-scaffold-d64.png +0 -0
  674. package/docs/recipes/oscar64/screenshots/platformer-scaffold-ntsc.png +0 -0
  675. package/docs/recipes/oscar64/screenshots/platformer-scaffold.png +0 -0
  676. package/docs/recipes/oscar64/screenshots/print-number-ntsc.png +0 -0
  677. package/docs/recipes/oscar64/screenshots/print-number.png +0 -0
  678. package/docs/recipes/oscar64/screenshots/raster-bars.png +0 -0
  679. package/docs/recipes/oscar64/screenshots/raster-profile-bars-ntsc.png +0 -0
  680. package/docs/recipes/oscar64/screenshots/raster-profile-bars.png +0 -0
  681. package/docs/recipes/oscar64/screenshots/rel-side-sectors-ntsc.png +0 -0
  682. package/docs/recipes/oscar64/screenshots/rel-side-sectors.png +0 -0
  683. package/docs/recipes/oscar64/screenshots/relative-file-records-ntsc.png +0 -0
  684. package/docs/recipes/oscar64/screenshots/relative-file-records.png +0 -0
  685. package/docs/recipes/oscar64/screenshots/save-load-seq-file-ntsc.png +0 -0
  686. package/docs/recipes/oscar64/screenshots/save-load-seq-file.png +0 -0
  687. package/docs/recipes/oscar64/screenshots/seeded-level-fill-ntsc.png +0 -0
  688. package/docs/recipes/oscar64/screenshots/seeded-level-fill.png +0 -0
  689. package/docs/recipes/oscar64/screenshots/sfx-engine-ntsc.png +0 -0
  690. package/docs/recipes/oscar64/screenshots/sfx-engine.png +0 -0
  691. package/docs/recipes/oscar64/screenshots/sid-music-player.png +0 -0
  692. package/docs/recipes/oscar64/screenshots/simple-shmup.png +0 -0
  693. package/docs/recipes/oscar64/screenshots/slope-collision-ntsc.png +0 -0
  694. package/docs/recipes/oscar64/screenshots/slope-collision.png +0 -0
  695. package/docs/recipes/oscar64/screenshots/soft-scroll-h.png +0 -0
  696. package/docs/recipes/oscar64/screenshots/sprite-animation-table-ntsc.png +0 -0
  697. package/docs/recipes/oscar64/screenshots/sprite-animation-table.png +0 -0
  698. package/docs/recipes/oscar64/screenshots/sprite-multiplex-8.png +0 -0
  699. package/docs/recipes/oscar64/screenshots/stable-raster-irq.png +0 -0
  700. package/docs/recipes/oscar64/screenshots/text-input-ntsc.png +0 -0
  701. package/docs/recipes/oscar64/screenshots/text-input.png +0 -0
  702. package/docs/recipes/oscar64/screenshots/text-overlay-playfield-gameover.png +0 -0
  703. package/docs/recipes/oscar64/screenshots/text-overlay-playfield-notrail-control.png +0 -0
  704. package/docs/recipes/oscar64/screenshots/text-overlay-playfield-ntsc.png +0 -0
  705. package/docs/recipes/oscar64/screenshots/text-overlay-playfield-ungated-control.png +0 -0
  706. package/docs/recipes/oscar64/screenshots/text-overlay-playfield.png +0 -0
  707. package/docs/recipes/oscar64/screenshots/text-window-menu-ntsc.png +0 -0
  708. package/docs/recipes/oscar64/screenshots/text-window-menu.png +0 -0
  709. package/docs/recipes/oscar64/screenshots/tile-grid-collision-ntsc.png +0 -0
  710. package/docs/recipes/oscar64/screenshots/tile-grid-collision.png +0 -0
  711. package/docs/recipes/oscar64/screenshots/tile-map-render-ntsc.png +0 -0
  712. package/docs/recipes/oscar64/screenshots/tile-map-render.png +0 -0
  713. package/docs/recipes/oscar64/screenshots/two-player-ntsc.png +0 -0
  714. package/docs/recipes/oscar64/screenshots/two-player.png +0 -0
  715. package/docs/recipes/oscar64/screenshots/two-word-parser-ntsc.png +0 -0
  716. package/docs/recipes/oscar64/screenshots/two-word-parser.png +0 -0
  717. package/docs/recipes/oscar64/screenshots/vehicle-control-ntsc.png +0 -0
  718. package/docs/recipes/oscar64/screenshots/vehicle-control.png +0 -0
  719. package/docs/recipes/oscar64/screenshots/wave-director-ntsc.png +0 -0
  720. package/docs/recipes/oscar64/screenshots/wave-director.png +0 -0
  721. package/docs/recipes/oscar64/seeded-level-fill.md +364 -0
  722. package/docs/recipes/oscar64/sfx-engine.md +514 -0
  723. package/docs/recipes/oscar64/sid-music-player.md +441 -0
  724. package/docs/recipes/oscar64/simple-shmup.md +1000 -0
  725. package/docs/recipes/oscar64/slope-collision.md +610 -0
  726. package/docs/recipes/oscar64/soft-scroll-h.md +261 -0
  727. package/docs/recipes/oscar64/sprite-animation-table.md +671 -0
  728. package/docs/recipes/oscar64/sprite-multiplex-8.md +314 -0
  729. package/docs/recipes/oscar64/stable-raster-irq.md +236 -0
  730. package/docs/recipes/oscar64/text-input.md +274 -0
  731. package/docs/recipes/oscar64/text-overlay-playfield.md +617 -0
  732. package/docs/recipes/oscar64/text-window-menu.md +551 -0
  733. package/docs/recipes/oscar64/tile-grid-collision.md +563 -0
  734. package/docs/recipes/oscar64/tile-map-render.md +395 -0
  735. package/docs/recipes/oscar64/two-player.md +528 -0
  736. package/docs/recipes/oscar64/two-word-parser.md +510 -0
  737. package/docs/recipes/oscar64/vehicle-control.md +771 -0
  738. package/docs/recipes/oscar64/wave-director.md +787 -0
  739. package/docs/recipes/runs.json +1606 -0
  740. package/docs/runtime/sim6502-reference.md +466 -0
  741. package/docs/runtime/vice-mcp-reference.md +351 -0
  742. package/docs/runtime/vice-reference.md +1393 -0
  743. package/docs/techniques/bitmap-modes.md +685 -0
  744. package/docs/techniques/cpu-cycle-tricks.md +1570 -0
  745. package/docs/techniques/effects-vector-3d.md +1431 -0
  746. package/docs/techniques/file-io.md +1427 -0
  747. package/docs/techniques/input.md +1072 -0
  748. package/docs/techniques/loaders-packers.md +768 -0
  749. package/docs/techniques/logic.md +3091 -0
  750. package/docs/techniques/maths.md +1524 -0
  751. package/docs/techniques/memory-banking.md +1686 -0
  752. package/docs/techniques/music-sid.md +1144 -0
  753. package/docs/techniques/raster.md +1543 -0
  754. package/docs/techniques/scroll.md +1292 -0
  755. package/docs/techniques/sprite.md +2566 -0
  756. package/docs/techniques/text-mode-render.md +717 -0
  757. package/docs/techniques/text.md +1095 -0
  758. package/docs/techniques/transitions.md +405 -0
  759. package/docs/toolchains/cartconv-reference.md +262 -0
  760. package/docs/toolchains/cc1541-reference.md +316 -0
  761. package/docs/toolchains/cc65-reference.md +667 -0
  762. package/docs/toolchains/error-sources/cc65/README.md +1 -0
  763. package/docs/toolchains/error-sources/cc65/missing-setcpu.s +4 -0
  764. package/docs/toolchains/error-sources/cc65/range-error.s +4 -0
  765. package/docs/toolchains/error-sources/cc65/segment-overflow.c +6 -0
  766. package/docs/toolchains/error-sources/cc65/unresolved-external.c +6 -0
  767. package/docs/toolchains/error-sources/kickassembler/README.md +1 -0
  768. package/docs/toolchains/error-sources/kickassembler/branch-out-of-range.asm +4 -0
  769. package/docs/toolchains/error-sources/kickassembler/failed-assert.asm +3 -0
  770. package/docs/toolchains/error-sources/kickassembler/flat-lib.asm +4 -0
  771. package/docs/toolchains/error-sources/kickassembler/import-source-no-namespace.asm +5 -0
  772. package/docs/toolchains/error-sources/kickassembler/macro-without-parentheses.asm +6 -0
  773. package/docs/toolchains/error-sources/kickassembler/memory-block-overlap.asm +4 -0
  774. package/docs/toolchains/error-sources/kickassembler/symbol-clash-lib.asm +5 -0
  775. package/docs/toolchains/error-sources/kickassembler/symbol-clash-main.asm +6 -0
  776. package/docs/toolchains/error-sources/kickassembler/unknown-symbol.asm +4 -0
  777. package/docs/toolchains/error-sources/oscar64/README.md +1 -0
  778. package/docs/toolchains/error-sources/oscar64/asm-addressing-mode.c +7 -0
  779. package/docs/toolchains/error-sources/oscar64/region-overflow.c +6 -0
  780. package/docs/toolchains/error-sources/oscar64/undefined-extern-var.c +5 -0
  781. package/docs/toolchains/error-sources/oscar64/undefined-extern.c +6 -0
  782. package/docs/toolchains/error-sources/oscar64/unknown-vic-field.c +6 -0
  783. package/docs/toolchains/error-sources/oscar64/void-main.c +3 -0
  784. package/docs/toolchains/kickassembler-reference.md +1020 -0
  785. package/docs/toolchains/memory-layout-planning.md +362 -0
  786. package/docs/toolchains/oscar64-headers-reference.md +583 -0
  787. package/docs/toolchains/oscar64-reference.md +892 -0
  788. package/docs/toolchains/petcat-reference.md +290 -0
  789. package/docs/toolchains/png2prg.md +188 -0
  790. package/docs/toolchains/release-disk.md +314 -0
  791. package/docs/toolchains/sidreloc.md +236 -0
  792. package/docs/toolchains/spindle-reference.md +487 -0
  793. package/docs/toolchains/tape-mastering.md +592 -0
  794. package/docs/toolchains/unit-testing-6502.md +281 -0
  795. package/docs/workflow/agent-harness.md +478 -0
  796. package/package.json +105 -0
  797. package/templates/_harness/CLAUDE.md.template +91 -0
  798. package/templates/_harness/PLAN.md.template +72 -0
  799. package/templates/_harness/check.py +442 -0
  800. package/templates/_harness/claude/settings.json +17 -0
  801. package/templates/_harness/gen-asm-header.py +96 -0
  802. package/templates/_harness/harness.mk +273 -0
  803. package/templates/_harness/hooks/plan-gate.py +185 -0
  804. package/templates/_harness/meter/frame_meter.asm +311 -0
  805. package/templates/_harness/meter/frame_meter.c +155 -0
  806. package/templates/_harness/meter/frame_meter.h +80 -0
  807. package/templates/_harness/zp-used.py +104 -0
  808. package/templates/action-puzzle/.claude/settings.json +17 -0
  809. package/templates/action-puzzle/.mcp.json +10 -0
  810. package/templates/action-puzzle/CLAUDE.md +120 -0
  811. package/templates/action-puzzle/Makefile +125 -0
  812. package/templates/action-puzzle/PLAN.md +388 -0
  813. package/templates/action-puzzle/README.md +240 -0
  814. package/templates/action-puzzle/expect.json +25 -0
  815. package/templates/action-puzzle/src/cave.c +280 -0
  816. package/templates/action-puzzle/src/cave.h +80 -0
  817. package/templates/action-puzzle/src/gen_autopilot.h +20 -0
  818. package/templates/action-puzzle/src/gen_caves.h +59 -0
  819. package/templates/action-puzzle/src/gen_notes.h +16 -0
  820. package/templates/action-puzzle/src/hiscore.c +152 -0
  821. package/templates/action-puzzle/src/hiscore.h +41 -0
  822. package/templates/action-puzzle/src/level.c +64 -0
  823. package/templates/action-puzzle/src/level.h +24 -0
  824. package/templates/action-puzzle/src/main.c +599 -0
  825. package/templates/action-puzzle/src/render.c +239 -0
  826. package/templates/action-puzzle/src/render.h +31 -0
  827. package/templates/action-puzzle/src/sound.c +158 -0
  828. package/templates/action-puzzle/src/sound.h +22 -0
  829. package/templates/action-puzzle/tools/disk_check.py +77 -0
  830. package/templates/action-puzzle/tools/drive.py +106 -0
  831. package/templates/action-puzzle/tools/gen.py +454 -0
  832. package/templates/action-puzzle/tools/model_check.py +49 -0
  833. package/templates/action-puzzle/tools/verdict_codes.py +24 -0
  834. package/templates/adventure/.claude/settings.json +17 -0
  835. package/templates/adventure/.mcp.json +10 -0
  836. package/templates/adventure/CLAUDE.md +118 -0
  837. package/templates/adventure/Makefile +113 -0
  838. package/templates/adventure/PLAN.md +396 -0
  839. package/templates/adventure/README.md +277 -0
  840. package/templates/adventure/expect.json +25 -0
  841. package/templates/adventure/src/engine.c +543 -0
  842. package/templates/adventure/src/engine.h +48 -0
  843. package/templates/adventure/src/gen_script.h +141 -0
  844. package/templates/adventure/src/gen_world.h +511 -0
  845. package/templates/adventure/src/main.c +439 -0
  846. package/templates/adventure/src/picture.c +83 -0
  847. package/templates/adventure/src/picture.h +16 -0
  848. package/templates/adventure/src/save.c +159 -0
  849. package/templates/adventure/src/save.h +25 -0
  850. package/templates/adventure/src/sound.c +71 -0
  851. package/templates/adventure/src/sound.h +16 -0
  852. package/templates/adventure/src/text.c +349 -0
  853. package/templates/adventure/src/text.h +40 -0
  854. package/templates/adventure/tools/disk_check.py +128 -0
  855. package/templates/adventure/tools/drive.py +119 -0
  856. package/templates/adventure/tools/gen.py +1033 -0
  857. package/templates/adventure/tools/world.py +356 -0
  858. package/templates/beat-em-up/.claude/settings.json +17 -0
  859. package/templates/beat-em-up/.mcp.json +10 -0
  860. package/templates/beat-em-up/CLAUDE.md +136 -0
  861. package/templates/beat-em-up/Makefile +96 -0
  862. package/templates/beat-em-up/PLAN.md +502 -0
  863. package/templates/beat-em-up/README.md +315 -0
  864. package/templates/beat-em-up/expect-gameover.json +8 -0
  865. package/templates/beat-em-up/expect.json +29 -0
  866. package/templates/beat-em-up/src/anim.c +70 -0
  867. package/templates/beat-em-up/src/art.c +344 -0
  868. package/templates/beat-em-up/src/autopilot.h +154 -0
  869. package/templates/beat-em-up/src/brute.c +273 -0
  870. package/templates/beat-em-up/src/enemy.c +281 -0
  871. package/templates/beat-em-up/src/engine.asm +512 -0
  872. package/templates/beat-em-up/src/fighter.c +384 -0
  873. package/templates/beat-em-up/src/game.h +269 -0
  874. package/templates/beat-em-up/src/hud.c +135 -0
  875. package/templates/beat-em-up/src/main.c +341 -0
  876. package/templates/beat-em-up/src/sound.c +44 -0
  877. package/templates/beat-em-up/src/street.c +93 -0
  878. package/templates/beat-em-up/src/verdict.h +523 -0
  879. package/templates/beat-em-up/src/view.c +362 -0
  880. package/templates/beat-em-up/tools/drive.py +105 -0
  881. package/templates/beat-em-up/tools/flickercheck.py +273 -0
  882. package/templates/demo/.claude/settings.json +17 -0
  883. package/templates/demo/.mcp.json +10 -0
  884. package/templates/demo/CLAUDE.md +129 -0
  885. package/templates/demo/Makefile +66 -0
  886. package/templates/demo/PLAN.md +401 -0
  887. package/templates/demo/README.md +322 -0
  888. package/templates/demo/expect.json +945 -0
  889. package/templates/demo/src/config.asm +80 -0
  890. package/templates/demo/src/framework.asm +390 -0
  891. package/templates/demo/src/main.asm +139 -0
  892. package/templates/demo/src/music.asm +197 -0
  893. package/templates/demo/src/part_main.asm +279 -0
  894. package/templates/demo/src/part_title.asm +79 -0
  895. package/templates/demo/src/parts.asm +43 -0
  896. package/templates/demo/src/tables.asm +73 -0
  897. package/templates/demo/src/verdict.asm +179 -0
  898. package/templates/demo/tools/audio.py +80 -0
  899. package/templates/demo/tools/gen_expect.py +167 -0
  900. package/templates/demo/tools/probe.py +95 -0
  901. package/templates/hello/.claude/settings.json +17 -0
  902. package/templates/hello/.mcp.json +10 -0
  903. package/templates/hello/CLAUDE.md +100 -0
  904. package/templates/hello/Makefile +38 -0
  905. package/templates/hello/PLAN.md +200 -0
  906. package/templates/hello/expect.json +20 -0
  907. package/templates/hello/src/main.c +161 -0
  908. package/templates/hello/src/sprite.asm +27 -0
  909. package/templates/hello-kick/.claude/settings.json +17 -0
  910. package/templates/hello-kick/.mcp.json +10 -0
  911. package/templates/hello-kick/CLAUDE.md +100 -0
  912. package/templates/hello-kick/Makefile +17 -0
  913. package/templates/hello-kick/PLAN.md +199 -0
  914. package/templates/hello-kick/expect.json +20 -0
  915. package/templates/hello-kick/src/main.asm +233 -0
  916. package/templates/platformer/.claude/settings.json +17 -0
  917. package/templates/platformer/.mcp.json +10 -0
  918. package/templates/platformer/CLAUDE.md +125 -0
  919. package/templates/platformer/Makefile +86 -0
  920. package/templates/platformer/PLAN.md +360 -0
  921. package/templates/platformer/README.md +277 -0
  922. package/templates/platformer/expect.json +32 -0
  923. package/templates/platformer/src/actors.c +289 -0
  924. package/templates/platformer/src/anim.c +51 -0
  925. package/templates/platformer/src/art.c +212 -0
  926. package/templates/platformer/src/autopilot.h +30 -0
  927. package/templates/platformer/src/engine.asm +253 -0
  928. package/templates/platformer/src/game.h +248 -0
  929. package/templates/platformer/src/hud.c +90 -0
  930. package/templates/platformer/src/level.c +184 -0
  931. package/templates/platformer/src/main.c +306 -0
  932. package/templates/platformer/src/player.c +268 -0
  933. package/templates/platformer/src/sound.c +42 -0
  934. package/templates/platformer/src/verdict.h +206 -0
  935. package/templates/platformer/src/view.c +331 -0
  936. package/templates/platformer/stage-expect.json +6 -0
  937. package/templates/platformer/tools/drive.py +112 -0
  938. package/templates/platformer/tools/tearcheck.py +229 -0
  939. package/templates/shmup-vertical/.claude/settings.json +17 -0
  940. package/templates/shmup-vertical/.mcp.json +10 -0
  941. package/templates/shmup-vertical/CLAUDE.md +137 -0
  942. package/templates/shmup-vertical/Makefile +131 -0
  943. package/templates/shmup-vertical/PLAN.md +569 -0
  944. package/templates/shmup-vertical/README.md +189 -0
  945. package/templates/shmup-vertical/expect.json +38 -0
  946. package/templates/shmup-vertical/src/bullets.c +158 -0
  947. package/templates/shmup-vertical/src/bullets.h +35 -0
  948. package/templates/shmup-vertical/src/display.c +239 -0
  949. package/templates/shmup-vertical/src/display.h +40 -0
  950. package/templates/shmup-vertical/src/game.h +85 -0
  951. package/templates/shmup-vertical/src/glyph.asm +358 -0
  952. package/templates/shmup-vertical/src/hiscore.c +141 -0
  953. package/templates/shmup-vertical/src/hiscore.h +16 -0
  954. package/templates/shmup-vertical/src/hit.asm +180 -0
  955. package/templates/shmup-vertical/src/hitbox.c +59 -0
  956. package/templates/shmup-vertical/src/hitbox.h +25 -0
  957. package/templates/shmup-vertical/src/kernel.asm +330 -0
  958. package/templates/shmup-vertical/src/level.c +174 -0
  959. package/templates/shmup-vertical/src/level.h +27 -0
  960. package/templates/shmup-vertical/src/main.c +824 -0
  961. package/templates/shmup-vertical/src/mux.asm +321 -0
  962. package/templates/shmup-vertical/src/sound.asm +255 -0
  963. package/templates/shmup-vertical/src/step.asm +169 -0
  964. package/templates/shmup-vertical/src/waves.c +195 -0
  965. package/templates/shmup-vertical/src/waves.h +33 -0
  966. package/templates/shmup-vertical/stage-expect.json +6 -0
  967. package/templates/shmup-vertical/tools/drive.py +152 -0
  968. package/templates/shmup-vertical/tools/joytest.py +159 -0
  969. package/templates/shmup-vertical/tools/meter.py +15 -0
  970. package/templates/shmup-vertical/tools/phases.py +73 -0
@@ -0,0 +1,723 @@
1
+ ---
2
+ recipe: bfs-distance-map
3
+ toolchain: oscar64
4
+ output_format: PRG
5
+ region: both
6
+ techniques: [bfs_distance_map]
7
+ file_formats: [PRG]
8
+ uses_registers: [D011, D020, D021, DC04, DC05, DC06, DC07, DC0E, DC0F]
9
+ uses_kernal: []
10
+ ---
11
+
12
+ <!-- doc-type: recipe -->
13
+
14
+ # Oscar64 BFS Distance Map: one time-sliced flood from the player, four chasers stepping downhill
15
+
16
+ ## Synopsis
17
+
18
+ A 40 by 22 tile maze, a player that follows a scripted route, and four
19
+ chasers that never search. A breadth-first flood from the player's cell
20
+ gives every open cell its distance in one byte (255 for a wall or an
21
+ unvisited cell). The flood runs from a ring queue, 32 cells per frame,
22
+ into a second map; when the queue empties the two maps swap, so the
23
+ chasers always read a complete map. A new flood starts when the player
24
+ has changed cell since the last one began. Each chaser steps to the
25
+ neighbour with the lowest distance every fourth frame, ties broken up,
26
+ left, down, right. With `SHOW_DIST 1` every cell shows its distance's
27
+ units digit in a colour band as the flood reaches it. The verdict
28
+ compares the live map byte for byte with a map computed in Python and
29
+ compiled in, then requires all four chasers to reach the player's cell
30
+ within a bounded number of frames with no step onto a wall. `$02FF` =
31
+ `01` and a green border on pass, `02` and red on fail. This is the
32
+ `bfs_distance_map` technique in `docs/techniques/logic.md`; the
33
+ result-byte contract is `headless-verify.md`.
34
+
35
+ ## Source
36
+
37
+ ```c
38
+ // bfs-distance-map.c
39
+ //
40
+ // A breadth-first flood over a 40 by 22 tile maze gives every open cell
41
+ // its distance from the player, one byte per cell, 255 for a wall or an
42
+ // unvisited cell. The flood runs from a ring queue, SLICE cells per
43
+ // frame, into a work map; when the queue empties the work map becomes
44
+ // the live map the chasers read. A new flood starts when the player has
45
+ // changed cell since the last one began. Four chasers step to the
46
+ // neighbour with the lowest distance every CHASE_EVERY frames, ties
47
+ // broken up, left, down, right. The player follows a scripted route,
48
+ // one cell every PLAYER_EVERY frames, then stops.
49
+ // Verdict: after the player stops and the next flood completes, the
50
+ // live map is compared byte for byte with a map computed in Python and
51
+ // compiled in, and its checksum shown; then all four chasers must reach
52
+ // the player's cell within MAX_WAIT frames, and no chaser may ever stand
53
+ // on a wall. $02FF = 01 and a green border on pass, 02 and red on fail.
54
+ // Row 0: worst slice, last full flood, frames per flood, worst chaser
55
+ // pass, all CIA1 cycles. Row 1: checksum, mismatches, wall steps,
56
+ // frames from the stop to the last arrival, result. Row 2: floods run
57
+ // and the worst whole iteration (must stay under one frame).
58
+ // SHOW_DIST 1 draws each cell's distance as a digit (units) in a colour
59
+ // band as the flood reaches it; 0 leaves the floor as dots.
60
+ // Build: oscar64 -tm=c64 -O2 -o=bfs-distance-map.prg bfs-distance-map.c
61
+ #include <c64/vic.h>
62
+ #include <c64/cia.h>
63
+ #include <string.h>
64
+
65
+ #define SCREEN ((char *)0x0400)
66
+ #define COLOUR ((char *)0xd800)
67
+ #define RESULT (*(volatile char *)0x02ff)
68
+ #define CODE_PASS 0x01
69
+ #define CODE_FAIL 0x02
70
+
71
+ #define SHOW_DIST 1
72
+ #define SLICE 32 // cells expanded per frame
73
+ #define PLAYER_EVERY 2 // frames per player cell
74
+ #define CHASE_EVERY 4 // frames per chaser cell
75
+ #define MAX_WAIT 400 // frames allowed after the player stops
76
+ #define NCHASE 4
77
+
78
+ // Map rows 0-21 are screen rows 3-24. '#' wall, '.' open.
79
+ #define MAP_ROW0 3
80
+ #define MW 40
81
+ #define MH 22
82
+ #define UNSEEN 255
83
+ const char maze[MH][MW + 1] = {
84
+ "########################################", // 0
85
+ "#........#........#..........#........##", // 1
86
+ "#.######.#.######.#.########.#.######.##", // 2
87
+ "#.#......#.#....#.#........#.#.#......##", // 3
88
+ "#.#.########.##.#.########.#.#.#.###.###", // 4
89
+ "#.#..........#..#..........#...#...#...#", // 5
90
+ "#.##########.#.###########.#####.#.#####", // 6
91
+ "#............#.............#.....#.....#", // 7
92
+ "######.#######.###########.#.#####.###.#", // 8
93
+ "#......#.......#...........#.#.......#.#", // 9
94
+ "#.######.#####.#.#########.#.#.#####.#.#", // 10
95
+ "#........#.....#.#.......#...#.#...#...#", // 11
96
+ "#.########.#####.#.#####.#####.#.#.###.#", // 12
97
+ "#.#........#.....#.#...#.......#.#.....#", // 13
98
+ "#.#.########.#####.#.#.#########.#####.#", // 14
99
+ "#.#........#.......#.#...........#.....#", // 15
100
+ "#.########.#########.#.#########.#.###.#", // 16
101
+ "#..........#.........#.........#.#...#.#", // 17
102
+ "#.#########.#########...#######.#.....##", // 18
103
+ "#.........#...........#.......#...#.#..#", // 19
104
+ "#.#######.#.#########.#######.#####.####", // 20
105
+ "########################################", // 21
106
+ };
107
+
108
+ // The player's route: one letter per cell moved.
109
+ #define START_X 1
110
+ #define START_Y 1
111
+ const char route[] = "DDDDDDRRRRRRRRRRRUUUURRRDDLDDRRRRRRRRRRRRDDLLLLLLLLLL";
112
+
113
+ // Chaser start cells.
114
+ const char start_cx[NCHASE] = { 37, 1, 38, 14 };
115
+ const char start_cy[NCHASE] = { 1, 20, 19, 11 };
116
+
117
+ // Expected distance map from the player's final cell (16, 9), computed
118
+ // by bfs_model.py (Python, plain BFS). Checksum $C077.
119
+ #define EXP_SUM 0xc077
120
+ const char exp_map[MH * MW] = {
121
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
122
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
123
+ 255, 53, 54, 55, 56, 55, 54, 53, 52, 255, 34, 33, 32, 31, 30, 29, 28, 27, 255, 25,
124
+ 26, 27, 28, 29, 30, 31, 32, 33, 34, 255, 40, 39, 38, 37, 36, 35, 34, 33, 255, 255,
125
+ 255, 52, 255, 255, 255, 255, 255, 255, 51, 255, 35, 255, 255, 255, 255, 255, 255, 26, 255, 24,
126
+ 255, 255, 255, 255, 255, 255, 255, 255, 35, 255, 41, 255, 255, 255, 255, 255, 255, 32, 255, 255,
127
+ 255, 51, 255, 45, 46, 47, 48, 49, 50, 255, 36, 255, 32, 31, 30, 29, 255, 25, 255, 23,
128
+ 22, 21, 20, 19, 18, 17, 16, 255, 36, 255, 42, 255, 26, 27, 28, 29, 30, 31, 255, 255,
129
+ 255, 50, 255, 44, 255, 255, 255, 255, 255, 255, 255, 255, 33, 255, 255, 28, 255, 24, 255, 255,
130
+ 255, 255, 255, 255, 255, 255, 15, 255, 37, 255, 41, 255, 25, 255, 255, 255, 31, 255, 255, 255,
131
+ 255, 49, 255, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 255, 26, 27, 255, 23, 22, 21,
132
+ 20, 19, 18, 17, 16, 15, 14, 255, 38, 39, 40, 255, 24, 25, 26, 255, 32, 33, 34, 255,
133
+ 255, 48, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 35, 255, 25, 255, 255, 255, 255, 255,
134
+ 255, 255, 255, 255, 255, 255, 13, 255, 255, 255, 255, 255, 23, 255, 27, 255, 255, 255, 255, 255,
135
+ 255, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 255, 24, 23, 22, 21, 20, 19,
136
+ 18, 17, 16, 15, 14, 13, 12, 255, 18, 19, 20, 21, 22, 255, 28, 29, 30, 31, 32, 255,
137
+ 255, 255, 255, 255, 255, 255, 43, 255, 255, 255, 255, 255, 255, 255, 25, 255, 255, 255, 255, 255,
138
+ 255, 255, 255, 255, 255, 255, 11, 255, 17, 255, 255, 255, 255, 255, 29, 255, 255, 255, 33, 255,
139
+ 255, 43, 44, 45, 46, 45, 44, 255, 32, 31, 30, 29, 28, 27, 26, 255, 0, 1, 2, 3,
140
+ 4, 5, 6, 7, 8, 9, 10, 255, 16, 255, 34, 33, 32, 31, 30, 31, 32, 255, 34, 255,
141
+ 255, 42, 255, 255, 255, 255, 255, 255, 33, 255, 255, 255, 255, 255, 27, 255, 1, 255, 255, 255,
142
+ 255, 255, 255, 255, 255, 255, 11, 255, 15, 255, 35, 255, 255, 255, 255, 255, 33, 255, 35, 255,
143
+ 255, 41, 40, 39, 38, 37, 36, 35, 34, 255, 32, 31, 30, 29, 28, 255, 2, 255, 20, 21,
144
+ 22, 23, 24, 25, 26, 255, 12, 13, 14, 255, 36, 255, 46, 45, 44, 255, 34, 35, 36, 255,
145
+ 255, 42, 255, 255, 255, 255, 255, 255, 255, 255, 33, 255, 255, 255, 255, 255, 3, 255, 19, 255,
146
+ 255, 255, 255, 255, 27, 255, 255, 255, 255, 255, 35, 255, 47, 255, 43, 255, 255, 255, 37, 255,
147
+ 255, 43, 255, 41, 40, 39, 38, 37, 36, 35, 34, 255, 8, 7, 6, 5, 4, 255, 18, 255,
148
+ 64, 63, 62, 255, 28, 29, 30, 31, 32, 33, 34, 255, 48, 255, 42, 41, 40, 39, 38, 255,
149
+ 255, 44, 255, 42, 255, 255, 255, 255, 255, 255, 255, 255, 9, 255, 255, 255, 255, 255, 17, 255,
150
+ 65, 255, 61, 255, 255, 255, 255, 255, 255, 255, 255, 255, 49, 255, 255, 255, 255, 255, 39, 255,
151
+ 255, 45, 255, 43, 44, 45, 46, 47, 48, 49, 50, 255, 10, 11, 12, 13, 14, 15, 16, 255,
152
+ 66, 255, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 255, 44, 43, 42, 41, 40, 255,
153
+ 255, 46, 255, 255, 255, 255, 255, 255, 255, 255, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255,
154
+ 67, 255, 61, 255, 255, 255, 255, 255, 255, 255, 255, 255, 51, 255, 45, 255, 255, 255, 41, 255,
155
+ 255, 47, 48, 49, 50, 51, 52, 53, 54, 53, 52, 255, 76, 75, 74, 73, 72, 71, 70, 69,
156
+ 68, 255, 62, 63, 64, 65, 66, 67, 68, 69, 70, 255, 52, 255, 46, 47, 48, 255, 42, 255,
157
+ 255, 48, 255, 255, 255, 255, 255, 255, 255, 255, 255, 76, 255, 255, 255, 255, 255, 255, 255, 255,
158
+ 255, 64, 63, 64, 255, 255, 255, 255, 255, 255, 255, 52, 255, 48, 47, 48, 49, 50, 255, 255,
159
+ 255, 49, 50, 51, 52, 53, 54, 55, 56, 57, 255, 75, 74, 73, 72, 71, 70, 69, 68, 67,
160
+ 66, 65, 255, 65, 66, 67, 68, 69, 70, 71, 255, 51, 50, 49, 255, 49, 255, 51, 52, 255,
161
+ 255, 50, 255, 255, 255, 255, 255, 255, 255, 58, 255, 76, 255, 255, 255, 255, 255, 255, 255, 255,
162
+ 255, 66, 255, 255, 255, 255, 255, 255, 255, 72, 255, 255, 255, 255, 255, 50, 255, 255, 255, 255,
163
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
164
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
165
+ };
166
+
167
+ // --- distance maps and the ring queue ---------------------------------------
168
+ char solid[MH * MW]; // 1 where the maze has a wall
169
+ char map_a[MH * MW], map_b[MH * MW];
170
+ char *live = map_a; // complete map the chasers read
171
+ char *work = map_b; // map the flood is writing
172
+ unsigned row_off[MH];
173
+
174
+ char qx[256], qy[256]; // ring queue; byte indices wrap
175
+ char qhead, qtail;
176
+ bool flood_on;
177
+ char flood_px, flood_py; // player cell the flood started from
178
+ char flood_frames;
179
+ unsigned long flood_cycles;
180
+
181
+ unsigned clear_pos; // bytes of work cleared so far
182
+ #define CLEAR_CHUNK 440 // per frame; two frames for the map
183
+
184
+ // A flood starts with the clear of its work map, CLEAR_CHUNK bytes per
185
+ // frame, so the 880-byte clear never shares a frame with a full slice.
186
+ // The seed cell is written when the clear is complete.
187
+ void flood_begin(char px, char py)
188
+ {
189
+ clear_pos = 0;
190
+ flood_px = px; flood_py = py;
191
+ flood_on = true;
192
+ flood_frames = 0;
193
+ flood_cycles = 0;
194
+ }
195
+
196
+ // Digit and colour per distance, built at start: units digit, colour by
197
+ // band of eight, 255 shown as a dot in dark grey.
198
+ char dig_ch[256], dig_col[256];
199
+ const char band_col[8] = { VCOL_WHITE, VCOL_YELLOW, VCOL_LT_GREEN, VCOL_CYAN,
200
+ VCOL_LT_BLUE, VCOL_PURPLE, VCOL_LT_RED, VCOL_ORANGE };
201
+
202
+ static inline void try_cell(char x, char y, unsigned o, char d)
203
+ {
204
+ if (!solid[o] && work[o] == UNSEEN) {
205
+ work[o] = d;
206
+ qx[qtail] = x; qy[qtail] = y;
207
+ qtail++;
208
+ }
209
+ }
210
+
211
+ // Expand up to SLICE queued cells. Returns true when the flood finished.
212
+ bool flood_slice(void)
213
+ {
214
+ if (clear_pos < MH * MW) {
215
+ memset(work + clear_pos, UNSEEN, CLEAR_CHUNK);
216
+ clear_pos += CLEAR_CHUNK;
217
+ if (clear_pos == MH * MW) {
218
+ work[row_off[flood_py] + flood_px] = 0;
219
+ qx[0] = flood_px; qy[0] = flood_py;
220
+ qhead = 0; qtail = 1;
221
+ }
222
+ return false;
223
+ }
224
+ char n = 0;
225
+ while (qhead != qtail && n < SLICE) {
226
+ char x = qx[qhead], y = qy[qhead];
227
+ qhead++;
228
+ unsigned o = row_off[y] + x;
229
+ char d = work[o] + 1;
230
+ try_cell(x, y - 1, o - MW, d);
231
+ try_cell(x - 1, y, o - 1, d);
232
+ try_cell(x, y + 1, o + MW, d);
233
+ try_cell(x + 1, y, o + 1, d);
234
+ #if SHOW_DIST
235
+ SCREEN[o + MAP_ROW0 * 40] = dig_ch[d - 1];
236
+ COLOUR[o + MAP_ROW0 * 40] = dig_col[d - 1];
237
+ #endif
238
+ n++;
239
+ }
240
+ if (qhead != qtail)
241
+ return false;
242
+ char *t = live; live = work; work = t;
243
+ flood_on = false;
244
+ return true;
245
+ }
246
+
247
+ // --- CIA1 timer B: cycles between start and stop ------------------------------
248
+ static inline void timer_start(void)
249
+ {
250
+ cia1.crb = 0x00;
251
+ cia1.tb = 0xffff;
252
+ cia1.crb = 0x11;
253
+ }
254
+
255
+ static inline unsigned timer_stop(void)
256
+ {
257
+ cia1.crb = 0x00;
258
+ return 0xffff - cia1.tb;
259
+ }
260
+
261
+ // --- actors -------------------------------------------------------------------
262
+ char px, py;
263
+ char cx[NCHASE], cy[NCHASE];
264
+ char under_ch[NCHASE + 1], under_col[NCHASE + 1];
265
+ const char actor_col[NCHASE + 1] = { VCOL_WHITE, VCOL_CYAN, VCOL_LT_RED, VCOL_LT_GREEN, VCOL_YELLOW };
266
+ unsigned wall_steps;
267
+
268
+ // One downhill step: the neighbour with the lowest live distance, only
269
+ // if lower than the chaser's own; ties go up, left, down, right.
270
+ void chaser_step(char i)
271
+ {
272
+ char x = cx[i], y = cy[i];
273
+ unsigned o = row_off[y] + x;
274
+ char best = live[o], bx = x, by = y, d;
275
+ d = live[o - MW]; if (d < best) { best = d; bx = x; by = y - 1; }
276
+ d = live[o - 1]; if (d < best) { best = d; bx = x - 1; by = y; }
277
+ d = live[o + MW]; if (d < best) { best = d; bx = x; by = y + 1; }
278
+ d = live[o + 1]; if (d < best) { best = d; bx = x + 1; by = y; }
279
+ cx[i] = bx; cy[i] = by;
280
+ if (solid[row_off[by] + bx])
281
+ wall_steps++;
282
+ }
283
+
284
+ static inline unsigned cell_off(char x, char y)
285
+ {
286
+ return row_off[y] + x + MAP_ROW0 * 40;
287
+ }
288
+
289
+ void actors_lift(void)
290
+ {
291
+ for (char i = 0; i < NCHASE; i++) {
292
+ unsigned o = cell_off(cx[i], cy[i]);
293
+ SCREEN[o] = under_ch[i]; COLOUR[o] = under_col[i];
294
+ }
295
+ unsigned o = cell_off(px, py);
296
+ SCREEN[o] = under_ch[NCHASE]; COLOUR[o] = under_col[NCHASE];
297
+ }
298
+
299
+ void actors_draw(void)
300
+ {
301
+ unsigned o = cell_off(px, py);
302
+ under_ch[NCHASE] = SCREEN[o]; under_col[NCHASE] = COLOUR[o];
303
+ SCREEN[o] = 0x53; COLOUR[o] = actor_col[NCHASE]; // heart
304
+ for (char i = 0; i < NCHASE; i++) {
305
+ o = cell_off(cx[i], cy[i]);
306
+ under_ch[i] = SCREEN[o]; under_col[i] = COLOUR[o];
307
+ SCREEN[o] = 0x51; COLOUR[o] = actor_col[i]; // ball
308
+ }
309
+ }
310
+
311
+ // --- HUD ----------------------------------------------------------------------
312
+ // Indexed on purpose: with the pointer-walking form (*p++ = *s++) Oscar64
313
+ // 1.32.271 at -O2 inlined the first call of this program without
314
+ // clearing Y, so its label landed 40-odd cells away (seen in the listing:
315
+ // no LDY #0 before the first STA (zp),y loop; the second call had one).
316
+ void put_str(char *p, const char *s)
317
+ {
318
+ for (char i = 0; s[i]; i++)
319
+ p[i] = s[i];
320
+ }
321
+
322
+ void put_dec(char *p, unsigned long v, char digits)
323
+ {
324
+ for (char i = digits; i > 0; i--) {
325
+ p[i - 1] = 0x30 + (char)(v % 10);
326
+ v /= 10;
327
+ }
328
+ }
329
+
330
+ void put_hex(char *p, unsigned v)
331
+ {
332
+ for (char i = 4; i > 0; i--) {
333
+ char n = v & 15;
334
+ p[i - 1] = n < 10 ? 0x30 + n : 0x01 + n - 10;
335
+ v >>= 4;
336
+ }
337
+ }
338
+
339
+ unsigned checksum(const char *m)
340
+ {
341
+ char a = 0, c = 0;
342
+ for (unsigned i = 0; i < MH * MW; i++) {
343
+ a += m[i];
344
+ c += a;
345
+ }
346
+ return ((unsigned)c << 8) | a;
347
+ }
348
+
349
+ int main(void)
350
+ {
351
+ __asm { sei }
352
+ vic.color_border = VCOL_BLACK;
353
+ vic.color_back = VCOL_BLACK;
354
+ memset(SCREEN, 0x20, 1000);
355
+ memset(COLOUR, VCOL_LT_GREY, 1000);
356
+ for (char y = 0; y < MH; y++)
357
+ row_off[y] = (unsigned)y * MW;
358
+ for (unsigned i = 0; i < 256; i++) {
359
+ dig_ch[i] = 0x30 + (char)(i % 10);
360
+ dig_col[i] = band_col[(i >> 3) & 7];
361
+ }
362
+ dig_ch[UNSEEN] = 0x2e; dig_col[UNSEEN] = VCOL_DARK_GREY;
363
+ memset(map_a, UNSEEN, MH * MW);
364
+ for (char y = 0; y < MH; y++)
365
+ for (char x = 0; x < MW; x++) {
366
+ unsigned o = cell_off(x, y);
367
+ bool wall = maze[y][x] == '#';
368
+ solid[row_off[y] + x] = wall;
369
+ if (wall) { SCREEN[o] = 0xa0; COLOUR[o] = VCOL_BLUE; }
370
+ else { SCREEN[o] = 0x2e; COLOUR[o] = VCOL_DARK_GREY; }
371
+ }
372
+
373
+ put_str(SCREEN, s"sl fl fr ch");
374
+ put_str(SCREEN + 40, s"sum mis wall t r");
375
+ put_str(SCREEN + 80, s"floods it");
376
+
377
+ px = START_X; py = START_Y;
378
+ for (char i = 0; i < NCHASE; i++) { cx[i] = start_cx[i]; cy[i] = start_cy[i]; }
379
+ actors_draw();
380
+
381
+ unsigned frame = 0, t_slice = 0, t_chase = 0, floods = 0, wait = 0, t_it = 0;
382
+ unsigned long t_flood = 0;
383
+ char fr_flood = 0, ri = 0, fault = 0;
384
+ unsigned mismatch = 0, sum = 0;
385
+ bool stopped = false, checked = false, done = false, hud = false;
386
+
387
+ for (;;) {
388
+ vic_waitFrame();
389
+ if (done)
390
+ continue;
391
+ frame++;
392
+ cia1.cra = 0x00; cia1.ta = 0xffff; cia1.cra = 0x11; // timer A: whole iteration
393
+ actors_lift();
394
+
395
+ // Flood: continue the slice in progress, or start one if the
396
+ // player has moved since the last began.
397
+ if (!flood_on && (px != flood_px || py != flood_py || floods == 0)) {
398
+ flood_begin(px, py);
399
+ floods++;
400
+ }
401
+ if (flood_on) {
402
+ flood_frames++;
403
+ timer_start();
404
+ bool fin = flood_slice();
405
+ unsigned t = timer_stop();
406
+ if (t > t_slice) t_slice = t;
407
+ flood_cycles += t;
408
+ if (fin) {
409
+ t_flood = flood_cycles;
410
+ fr_flood = flood_frames;
411
+ hud = true;
412
+ }
413
+ }
414
+
415
+ // Player along the route, then stop.
416
+ if (!stopped && (frame % PLAYER_EVERY) == 0) {
417
+ char c = route[ri];
418
+ if (c == 0)
419
+ stopped = true;
420
+ else {
421
+ if (c == 'U') py--;
422
+ else if (c == 'D') py++;
423
+ else if (c == 'L') px--;
424
+ else px++;
425
+ ri++;
426
+ }
427
+ }
428
+
429
+ // Chasers downhill on the live map.
430
+ if ((frame % CHASE_EVERY) == 0) {
431
+ timer_start();
432
+ for (char i = 0; i < NCHASE; i++)
433
+ chaser_step(i);
434
+ unsigned t = timer_stop();
435
+ if (t > t_chase) t_chase = t;
436
+ }
437
+ actors_draw();
438
+ cia1.cra = 0x00;
439
+ unsigned t_this = 0xffff - cia1.ta;
440
+ if (t_this > t_it) t_it = t_this;
441
+
442
+ // HUD, outside the timed work; the 32-bit decimal print is slow.
443
+ if (hud) {
444
+ hud = false;
445
+ put_dec(SCREEN + 3, t_slice, 5);
446
+ put_dec(SCREEN + 12, t_flood, 7);
447
+ put_dec(SCREEN + 23, fr_flood, 2);
448
+ put_dec(SCREEN + 29, t_chase, 4);
449
+ put_dec(SCREEN + 87, floods, 3);
450
+ put_dec(SCREEN + 94, t_it, 5);
451
+ }
452
+
453
+ // Verdict.
454
+ if (stopped) {
455
+ wait++;
456
+ if (!checked && !flood_on && flood_px == px && flood_py == py) {
457
+ checked = true;
458
+ for (unsigned i = 0; i < MH * MW; i++)
459
+ if (live[i] != exp_map[i]) mismatch++;
460
+ sum = checksum(live);
461
+ put_hex(SCREEN + 44, sum);
462
+ put_dec(SCREEN + 53, mismatch, 3);
463
+ }
464
+ char here = 0;
465
+ for (char i = 0; i < NCHASE; i++)
466
+ if (cx[i] == px && cy[i] == py) here++;
467
+ if (checked && (here == NCHASE || wait > MAX_WAIT)) {
468
+ done = true;
469
+ if (mismatch || sum != EXP_SUM) fault = 1;
470
+ else if (wall_steps) fault = 2;
471
+ else if (here != NCHASE) fault = 3;
472
+ put_dec(SCREEN + 62, wall_steps, 3);
473
+ put_dec(SCREEN + 68, wait, 4);
474
+ char code = fault ? CODE_FAIL : CODE_PASS;
475
+ RESULT = code;
476
+ vic.color_border = fault ? VCOL_RED : VCOL_GREEN;
477
+ SCREEN[75] = 0x30 + code;
478
+ SCREEN[76] = 0x30 + fault;
479
+ }
480
+ }
481
+ }
482
+ return 0;
483
+ }
484
+ ```
485
+
486
+ ## Build
487
+
488
+ ```bash
489
+ oscar64 -tm=c64 -O2 -o=bfs-distance-map.prg bfs-distance-map.c
490
+ ```
491
+
492
+ Oscar64 1.32.271 builds it with no warnings; the PRG is 4,952 bytes.
493
+
494
+ The expected map and its checksum come from this script (Python 3),
495
+ which floods the same maze from the route's last cell with a plain
496
+ queue. It prints `route 53 steps, ends at (16, 9); open cells 404,
497
+ popped 404`, `max distance 76; checksum $C077`, the four chasers' start
498
+ distances (33, 50, 52, 28) and the `exp_map` initialiser the listing
499
+ compiles in.
500
+
501
+ ```text
502
+ # bfs_model.py: the reference for bfs-distance-map.c. Same maze, same
503
+ # route, a plain breadth-first flood from the player's final cell. Prints
504
+ # the expected distance map as C initialisers and its checksum.
505
+ from collections import deque
506
+
507
+ MAZE = [
508
+ "########################################", # 0
509
+ "#........#........#..........#........##", # 1
510
+ "#.######.#.######.#.########.#.######.##", # 2
511
+ "#.#......#.#....#.#........#.#.#......##", # 3
512
+ "#.#.########.##.#.########.#.#.#.###.###", # 4
513
+ "#.#..........#..#..........#...#...#...#", # 5
514
+ "#.##########.#.###########.#####.#.#####", # 6
515
+ "#............#.............#.....#.....#", # 7
516
+ "######.#######.###########.#.#####.###.#", # 8
517
+ "#......#.......#...........#.#.......#.#", # 9
518
+ "#.######.#####.#.#########.#.#.#####.#.#", # 10
519
+ "#........#.....#.#.......#...#.#...#...#", # 11
520
+ "#.########.#####.#.#####.#####.#.#.###.#", # 12
521
+ "#.#........#.....#.#...#.......#.#.....#", # 13
522
+ "#.#.########.#####.#.#.#########.#####.#", # 14
523
+ "#.#........#.......#.#...........#.....#", # 15
524
+ "#.########.#########.#.#########.#.###.#", # 16
525
+ "#..........#.........#.........#.#...#.#", # 17
526
+ "#.#########.#########...#######.#.....##", # 18
527
+ "#.........#...........#.......#...#.#..#", # 19
528
+ "#.#######.#.#########.#######.#####.####", # 20
529
+ "########################################", # 21
530
+ ]
531
+ W, H = 40, 22
532
+ UNSEEN = 255
533
+
534
+ # The player's scripted route: start cell, then one letter per cell moved.
535
+ START = (1, 1)
536
+ ROUTE = "DDDDDDRRRRRRRRRRRUUUURRRDDLDDRRRRRRRRRRRRDDLLLLLLLLLL"
537
+ CHASERS = [(37, 1), (1, 20), (38, 19), (14, 11)]
538
+ DIRS = [(0, -1), (-1, 0), (0, 1), (1, 0)] # up, left, down, right (tie order)
539
+
540
+
541
+ def check_maze():
542
+ assert len(MAZE) == H
543
+ for r in MAZE:
544
+ assert len(r) == W, (len(r), r)
545
+ assert set(r) <= {"#", "."}
546
+ assert r[0] == "#" and r[-1] == "#"
547
+ assert MAZE[0] == "#" * W and MAZE[-1] == "#" * W
548
+
549
+
550
+ def walk(start, route):
551
+ x, y = start
552
+ cells = [(x, y)]
553
+ for c in route:
554
+ dx, dy = {"U": (0, -1), "L": (-1, 0), "D": (0, 1), "R": (1, 0)}[c]
555
+ x, y = x + dx, y + dy
556
+ assert MAZE[y][x] == ".", ("route hits wall at", x, y)
557
+ cells.append((x, y))
558
+ return cells
559
+
560
+
561
+ def flood(px, py):
562
+ d = [[UNSEEN] * W for _ in range(H)]
563
+ d[py][px] = 0
564
+ q = deque([(px, py)])
565
+ popped = 0
566
+ while q:
567
+ x, y = q.popleft()
568
+ popped += 1
569
+ for dx, dy in DIRS:
570
+ nx, ny = x + dx, y + dy
571
+ if MAZE[ny][nx] == "." and d[ny][nx] == UNSEEN:
572
+ d[ny][nx] = d[y][x] + 1
573
+ q.append((nx, ny))
574
+ return d, popped
575
+
576
+
577
+ def checksum(d):
578
+ # two running byte sums: a += byte, c += a, both mod 256; result c:a
579
+ a = c = 0
580
+ for y in range(H):
581
+ for x in range(W):
582
+ a = (a + d[y][x]) & 0xFF
583
+ c = (c + a) & 0xFF
584
+ return (c << 8) | a
585
+
586
+
587
+ def main():
588
+ check_maze()
589
+ cells = walk(START, ROUTE)
590
+ px, py = cells[-1]
591
+ d, popped = flood(px, py)
592
+ open_cells = sum(r.count(".") for r in MAZE)
593
+ print(f"route {len(ROUTE)} steps, ends at ({px}, {py}); open cells {open_cells}, popped {popped}")
594
+ print(f"max distance {max(v for r in d for v in r if v != UNSEEN)}; checksum ${checksum(d):04X}")
595
+ for cx, cy in CHASERS:
596
+ assert MAZE[cy][cx] == "."
597
+ print(f"chaser ({cx}, {cy}) distance {d[cy][cx]}")
598
+ print("const char exp_map[MH * MW] = {")
599
+ for y in range(H):
600
+ for half in (0, 20):
601
+ print(" " + ", ".join(f"{v:3d}" for v in d[y][half:half + 20]) + ",")
602
+ print("};")
603
+
604
+
605
+ if __name__ == "__main__":
606
+ main()
607
+ ```
608
+
609
+ One Oscar64 fault shaped the listing. With `put_str` written as
610
+ `while (*s) *p++ = *s++;`, Oscar64 1.32.271 at `-O2` inlined the first
611
+ call in `main` without an `LDY #0` before its `STA (zp),y` loop, so the
612
+ first HUD label landed wherever the maze loop had left Y; the second and
613
+ third calls got the `LDY`. The listing's indexed form
614
+ (`p[i] = s[i]`) compiles correctly. Seen in the `.asm` listing and on
615
+ screen; not reduced to a minimal case here.
616
+
617
+ ## Expected output
618
+
619
+ Black background, blue wall blocks, and after the first flood every open
620
+ cell shows a digit, the units digit of its distance from the player,
621
+ coloured by band of eight: white 0 to 7, yellow 8 to 15, light green,
622
+ cyan, light blue, purple, light red, orange, then white again from 64.
623
+ The player is a yellow heart, the chasers are balls in white, cyan,
624
+ light red and light green. Rows 0 to 2 are the HUD.
625
+
626
+ At the pinned 6,500,000 cycles the player has finished its route and
627
+ stands at (16, 9) (screen row 12, column 16); the last flood is complete
628
+ and the chasers are closing in, one of them already on the player's
629
+ cell on NTSC. The HUD reads (measured in VICE x64sc 3.10, decoded
630
+ against the character ROM):
631
+
632
+ | Row | PAL | NTSC |
633
+ |---|---|---|
634
+ | 0 | `SL 10655 FL 0140341 FR 15 CH 1220` | `SL 10915 FL 0144026 FR 15 CH 1220` |
635
+ | 1 | `SUM C077 MIS 000 WALL T R` | same |
636
+ | 2 | `FLOODS 009 IT 13196` | `FLOODS 009 IT 13456` |
637
+
638
+ `SL` is the worst flood slice in CIA1 cycles (32 cells expanded and
639
+ drawn), `FL` the last complete flood (the sum of its slices), `FR` the
640
+ frames it took (two clearing the work map, thirteen expanding), `CH` the
641
+ worst pass of four chaser steps, `IT` the worst whole iteration (lift
642
+ actors, flood slice, player, chasers, draw; the HUD prints are outside
643
+ it). `SUM` is the live map's checksum, equal to the model's `$C077`, and
644
+ `MIS 000` says no byte of the 880 differs from `exp_map`. `WALL`, `T`
645
+ and `R` are filled in at the verdict.
646
+
647
+ Screenshots at 6,500,000 cycles, each identical over two runs:
648
+ `screenshots/bfs-distance-map.png` (PAL) and
649
+ `screenshots/bfs-distance-map-ntsc.png` (NTSC). Measured with PIL
650
+ against the character ROM: every open cell not under an actor shows the
651
+ units digit of the model's distance (399 cells on PAL, 400 on NTSC,
652
+ none wrong), the actor glyphs cover the rest (five cells on PAL, four on
653
+ NTSC where one chaser has arrived), and all 476 wall cells are reverse
654
+ blocks. The script:
655
+
656
+ ```text
657
+ from PIL import Image
658
+ import bfs_model as m
659
+ rom = open('chargen-901225-01.bin', 'rb').read()
660
+ G = {tuple(rom[c*8:c*8+8]): c for c in range(128)}
661
+ def check(png, ntsc):
662
+ top = 23 if ntsc else 35 # PNG row of text row 0
663
+ px = Image.open(png).convert('RGB').load()
664
+ d, _ = m.flood(*m.walk(m.START, m.ROUTE)[-1])
665
+ ok = bad = 0
666
+ for y in range(22):
667
+ for x in range(40):
668
+ bits = tuple(sum((px[32+8*x+i, top+8*(y+3)+j] != (0, 0, 0)) << (7-i)
669
+ for i in range(8)) for j in range(8))
670
+ c = G.get(bits)
671
+ if d[y][x] == 255 or c in (0x51, 0x53):
672
+ continue # wall, or an actor on top
673
+ if c == 0x30 + d[y][x] % 10: ok += 1
674
+ else: bad += 1
675
+ return ok, bad
676
+ assert check('bfs-distance-map.png', False) == (399, 0)
677
+ ```
678
+
679
+ The verdict comes 145 frames after the player stops, at about
680
+ 8,200,000 cycles on PAL. At 9,000,000 cycles both models show
681
+ `WALL 000 T 0145 R 10` and a green border, (98, 213, 50) on PAL and
682
+ (114, 189, 103) on NTSC, with `$02FF` = `01`: the map matched, no chaser
683
+ ever stood on a wall, and all four reached the player's cell.
684
+
685
+ A build with `SHOW_DIST 0` (no digit drawing) reads `SL 08710 FL
686
+ 0115912 IT 11246` on PAL and `SL 09010 FL 0119513 IT 11503` on NTSC,
687
+ with the same verdict. The NTSC slice is higher on both builds because
688
+ the iteration runs past the vertical blank into the badlines, and the
689
+ CIA counts the stolen cycles (arithmetic, rung 3; the two models'
690
+ figures differ by 260 on the digit build).
691
+
692
+ ## Why this works
693
+
694
+ One flood serves every chaser. Breadth-first order visits cells in
695
+ non-decreasing distance, so the first time a cell is reached its
696
+ distance is final and it never needs revisiting: 404 open cells cost
697
+ 404 pops and at most four neighbour tests each. Every chaser then makes
698
+ one decision from four byte reads, 1,220 cycles for all four including
699
+ the timer. A per-enemy search would cost the flood again for each one.
700
+
701
+ Two maps make the slicing safe. The flood writes the work map over
702
+ fifteen frames while the chasers read the live map from the previous
703
+ flood; the swap is one pointer exchange in the frame the queue empties.
704
+ The player moves one cell every two frames, so the live map is at most
705
+ about eight cells stale, and a chaser stepping downhill on a slightly
706
+ old map still moves toward where the player was, then corrects when the
707
+ next map lands. The 880-byte clear of the work map is the first two
708
+ frames of each flood, 440 bytes each, so it never shares a frame with
709
+ a full 32-cell slice; when it did, the worst iteration was 19,226
710
+ cycles, over an NTSC frame.
711
+
712
+ The ring queue is 256 entries of x and y with byte indices that wrap
713
+ on their own. A breadth-first frontier on a 40 by 22 grid stays far
714
+ below 256 cells (the whole open set is 404 and the frontier is one or
715
+ two rings of it), so no overflow test is needed. Walls are never queued
716
+ because `solid` is tested before `work`; walls stay 255 in the map, and
717
+ a chaser only moves to a strictly lower value, so it can never pick a
718
+ wall or dither between equal cells. The tie order up, left, down, right
719
+ is fixed, so two runs make the same picture.
720
+
721
+ Distances are drawn as the flood pops each cell, one character and one
722
+ colour byte per cell, spread over the same frames as the flood; the
723
+ field is never redrawn whole.