explodorama / files / test / ruleCompare.test.ts
ruleCompare.test.ts
| 1 | import { describe, expect, it } from 'vitest' |
| 2 | import { readFileSync } from 'node:fs' |
| 3 | import { compareRules, type Engine } from '../src/sim/ruleCompare' |
| 4 | import type { RunRecord } from '../src/sim/record' |
| 5 | import { newRun } from '../src/sim/state' |
| 6 | import { step } from '../src/sim/turn' |
| 7 | |
| 8 | const record = JSON.parse(readFileSync(new URL('./fixtures/q101-bomb-pass.json', import.meta.url), 'utf8')) as RunRecord |
| 9 | const today: Engine = { newRun, step } |
| 10 | |
| 11 | describe('comparing two versions of the rules (Q103)', () => { |
| 12 | it('finds no split when both versions are the same', () => { |
| 13 | const c = compareRules(today, today, record) |
| 14 | expect(c.split).toBeNull() |
| 15 | expect(c.red.results).toHaveLength(record.actions.length) |
| 16 | expect(c.blue.refused).toBeNull() |
| 17 | }) |
| 18 | |
| 19 | it('finds the first turn where one version plays differently', () => { |
| 20 | // A version that refuses the 60th turn of the run stands in for a rules change. |
| 21 | const strict: Engine = { |
| 22 | newRun, |
| 23 | step: (s, a) => { |
| 24 | if (s.runTurns === 60 && a.id !== 'choose' && a.id !== 'continue') throw new Error('not allowed in this version') |
| 25 | return step(s, a) |
| 26 | }, |
| 27 | } |
| 28 | const c = compareRules(today, strict, record) |
| 29 | expect(c.split).not.toBeNull() |
| 30 | expect(c.why).toContain("blue's rules refuse it") |
| 31 | expect(c.blue.refused?.at).toBe(c.split) |
| 32 | expect(c.red.refused).toBeNull() |
| 33 | }) |
| 34 | |
| 35 | it('finds a split in the game itself when a rule changes what happens', () => { |
| 36 | // A version in which a Wait also costs a coin. |
| 37 | const taxed: Engine = { |
| 38 | newRun, |
| 39 | step: (s, a) => { |
| 40 | const r = step(s, a) |
| 41 | if (a.id === 'wait' && r.state.coins > 0) r.state.coins-- |
| 42 | return r |
| 43 | }, |
| 44 | } |
| 45 | const c = compareRules(today, taxed, record) |
| 46 | expect(c.split).not.toBeNull() |
| 47 | expect(c.why).toMatch(/coins/) |
| 48 | // Before that turn the games agree: replaying up to it gives the same states. |
| 49 | expect(c.red.results[c.split! - 1]!.state.coins).toBe(c.blue.results[c.split! - 1]!.state.coins) |
| 50 | }) |
| 51 | }) |