PlyOracle
Algorithms & Numeric
A negamax + alpha-beta tic-tac-toe AI
playing itself. Negamax folds minimax into one routine by negating the returned
score at each ply (score = -negamax(child), a G_SUB 0,x), with
a running G_SMAX for the best move and an alpha-beta cutoff that prunes the
search. That alternating-sign recursion is a shape the battery other recursive demos never
produce. Compiler stress-test #92.
Self-running — the AI plays itself; HUD tallies X / O wins and draws.
Click the screen to focus, then watch. Tab away and it pauses.
Cleanup handlers are how C code does RAII-style resource release (closing files, freeing locks) without a destructor. Correctly duplicating them onto every exit edge — and only those edges, in the right order — is a real obligation of the front-end + backend, and this demo checks it end to end on the 65816.
Compiler stress-test
| Item | What it exercises |
|---|---|
| negate-on-return | Negamax collapses minimax into one routine by observing that your best score is the negation of your opponent reply: score = -negamax(child). That unary minus on a function return value is a G_SUB 0,x the backend must emit on the recursion return path — a shape the battery other recursive demos (#17, #18) never produce. |
| running max + cutoff | Each node keeps the best child score with a running G_SMAX and maintains an alpha window; the moment alpha meets beta it breaks out of the move loop (the alpha-beta cutoff), producing a branch-heavy prune control-flow graph interleaved with the recursion. |
| bitboard tic-tac-toe | The board is two 9-bit masks; win detection is eight line-mask ANDs. Both players are driven by the same negamax, so you watch the search play itself. A search-depth cap keeps the full-width tree inside the SNES frame budget without changing the recursion shape. |
| exact minimax | Everything is integer, so the chosen moves are deterministic and bit-identical host vs target. A single wrong negation, max, or mis-pruned branch would pick a different move and diverge the self-play CRC. |
Written in C with the llvm-mos 65816 toolchain and verified against
bsnes-jg and MAME. Hit Verify fidelity to reproduce the build gate's WRAM assert
(negamax CRC 0x6146 — a fold of the self-play move sequence) live in this tab.
No far pointers — host == default == +mos-a16 == +mos-xy16,
-verify clean.