import fs from 'node:fs' // Fixture regeneration aid (see scripts/fixtures/README.md). Written during the 2026-11-11 build, kept for reference. // Writes into fixtures/ unless FIXTURES_OUT names another directory (with a trailing slash). const FIX = process.env.FIXTURES_OUT ?? new URL('../../fixtures/', import.meta.url).pathname const SOL = new URL('../../js/solutions/', import.meta.url).href const HERE = new URL('./', import.meta.url).pathname const S = SOL const { update } = await import(S + 'game.js') const { Action } = await import(S + 'model.js') const p = (x, y) => ({ x, y }) const base = { width: 10, height: 10, snake: [p(5, 5), p(4, 5), p(3, 5)], dir: 'Right', nextDir: 'Right', apple: p(0, 0), seed: 1, score: 0, status: 'Playing', frame: 0, queued: null, } const pending = { ...base, nextDir: 'Up' } const queuedLeft = { ...pending, queued: 'Left' } const atTop = { ...queuedLeft, snake: [p(5, 0), p(4, 0), p(3, 0)] } const cases = [ ['turn-with-no-turn-pending-sets-next-dir', base, Action.Turn('Up')], ['turn-straight-back-with-no-turn-pending-is-ignored', base, Action.Turn('Left')], ['perpendicular-key-while-a-turn-is-pending-is-queued', pending, Action.Turn('Left')], ['key-in-the-current-direction-while-a-turn-is-pending-is-queued', pending, Action.Turn('Right')], ['a-later-key-replaces-the-queued-one', queuedLeft, Action.Turn('Right')], ['repeating-the-pending-turn-changes-nothing', queuedLeft, Action.Turn('Up')], ['reversing-the-pending-turn-changes-nothing', queuedLeft, Action.Turn('Down')], ['turn-while-paused-with-a-turn-pending-is-not-queued', { ...pending, status: 'Paused' }, Action.Turn('Left')], ['tick-moves-then-takes-the-queued-turn', queuedLeft, Action.Tick], ['tick-with-nothing-queued-leaves-next-dir', pending, Action.Tick], ['frame-step-takes-the-queued-turn', { ...queuedLeft, frame: 7 }, Action.Frame], ['frame-without-a-step-keeps-the-queue', { ...queuedLeft, frame: 3 }, Action.Frame], ['tick-that-ends-the-game-keeps-the-queue', atTop, Action.Tick], ['tick-while-paused-keeps-the-queue', { ...queuedLeft, status: 'Paused' }, Action.Tick], ['toggle-pause-keeps-the-queue', queuedLeft, Action.TogglePause], ['restart-clears-the-queue', queuedLeft, Action.Restart], ].map(([name, s, a]) => ({ name, args: [s, a], expected: update(s, a) })) const f = FIX + 'm10-update.json' const fx = JSON.parse(fs.readFileSync(f, 'utf8')) const names = new Set(cases.map((c) => c.name)) const out = { ...fx, cases: [...fx.cases.filter((c) => !names.has(c.name)), ...cases] } fs.writeFileSync(f, JSON.stringify(out, null, 2) + '\n') for (const c of cases) { const [s] = c.args; const e = c.expected; console.log(c.name.padEnd(66), `${s.status} d=${s.dir} n=${s.nextDir} q=${s.queued} head=${JSON.stringify(s.snake[0])} f=${s.frame} -> ${e.status} d=${e.dir} n=${e.nextDir} q=${e.queued} head=${JSON.stringify(e.snake[0])} f=${e.frame} apple=${JSON.stringify(e.apple)} seed=${e.seed}`) }