Files
functional-programming-snake/scripts/fixtures/replay-sample-bot.mjs
T
Lucas WintherandClaude Fable 5.2 5062838604 chore: keep the fixture generator scripts and the replay-sample bot
scripts/fixtures/ holds the scripts that produced the 2026-11-11
fixtures, with a README on running them safely into a copy. Run in
order they reproduce the content of every fixture they touch.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
2026-11-11 12:13:03 +01:00

41 lines
2.2 KiB
JavaScript

import { newGame } from '../../js/solutions/spawn.js'
import { update } from '../../js/solutions/game.js'
import { opposite } from '../../js/solutions/model.js'
// 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 dirs = ['Up', 'Down', 'Left', 'Right']
const play = (seed) => {
let s = newGame(seed); const actions = []
while (s.status === 'Playing' && actions.length < 600) {
const options = dirs.filter((d) => d !== opposite(s.dir)).map((d) => {
const t = update(update(s, { tag: 'Turn', dir: d }), { tag: 'Tick' })
const h = t.snake[0]
const dist = s.apple ? Math.abs(h.x - s.apple.x) + Math.abs(h.y - s.apple.y) : 0
return { d, alive: t.status !== 'GameOver', dist: dist + (d === s.dir ? -0.1 : 0) }
})
const alive = options.filter((o) => o.alive).sort((a, b) => a.dist - b.dist)
const pick = (alive[0] ?? options[0]).d
if (pick !== s.dir) { actions.push({ tag: 'Turn', dir: pick }); s = update(s, actions.at(-1)) }
actions.push({ tag: 'Tick' }); s = update(s, actions.at(-1))
}
return { seed, actions, score: s.score, status: s.status }
}
const results = []
for (let seed = 1; seed < 3000; seed++) {
const r = play(seed)
if (r.status === 'GameOver' && r.actions.length >= 150 && r.actions.length <= 400 && r.score >= 5) results.push(r)
}
console.log(results.length, results.slice(0, 15).map((r) => [r.seed, r.actions.length, r.score]))
const best = results.sort((a, b) => b.score - a.score)[0]
console.log('best', best.seed, best.actions.length, best.score)
if (process.argv[2]) {
const r = play(Number(process.argv[2]))
const { writeFileSync } = await import('node:fs')
writeFileSync(FIX + 'replay-sample.json',
'{\n "seed": ' + r.seed + ',\n "actions": [\n' + r.actions.map((a) => ' ' + JSON.stringify(a)).join(',\n') + '\n ]\n}\n')
console.log('wrote', r.seed, r.actions.length, r.score, r.status)
}