fuzzyworld

explodorama / files / test / scores.test.ts

scores.test.ts

Blame: the commit that last changed each line · file · history

0580e85e 2026-10-24 Pavel Safronov1import { describe, expect, it } from 'vitest'
2import { newRecord } from '../src/sim/record'
3import { addEntry, BOARD_SIZE, compareEntries, countsForScores, scoreEntry, type ScoreEntry } from '../src/sim/scores'
4import { step } from '../src/sim/turn'
5import { board } from './helpers'
6
7const entry = (over: Partial<ScoreEntry>): ScoreEntry => ({
8 format: 1, simVersion: 1, date: '2026-10-24T10:00:00.000Z', seed: 1, options: { dev: false, immortal: false },
9 won: false, level: 1, coins: 0, kills: 0, turns: 10, livesLost: 3, death: null, powers: [],
10 stats: { capacity: 1, fire: 1, fuse: 3 }, record: newRecord(1), ...over,
11})
12
13describe('the high-score board', () => {
14 it("ranks a win first, then the level, then coins, then fewer turns (user's choice)", () => {
15 const order = [
16 entry({ won: true, level: 20, coins: 1 }),
17 entry({ level: 9, coins: 0 }),
18 entry({ level: 5, coins: 50 }),
19 entry({ level: 5, coins: 20, turns: 100 }),
20 entry({ level: 5, coins: 20, turns: 200 }),
21 ]
22 expect([...order].reverse().sort(compareEntries)).toEqual(order)
23 })
24
25 it('keeps the best BOARD_SIZE, and says where a new one ranks', () => {
26 let b: ScoreEntry[] = []
27 for (let i = 1; i <= BOARD_SIZE; i++) b = addEntry(b, entry({ level: i })).board
28 const worse = addEntry(b, entry({ level: 0 }))
29 expect(worse.rank).toBe(0)
30 expect(worse.board).toHaveLength(BOARD_SIZE)
31 const best = addEntry(b, entry({ level: 99 }))
32 expect(best.rank).toBe(1)
33 })
34
35 it('an entry has what the board shows: level, coins, kills, how it ended, powers, seed and the record', () => {
36 const s = board(`
37 #####
38 #P1.#
39 #####`)
40 s.lives = 1
41 s.coins = 7
42 s.runKills = 4
43 s.powers.run = true
44 const over = step(s, { id: 'wait' }).state
45 expect(over.status).toBe('gameOver')
46 expect(countsForScores(over)).toBe(true)
47 const e = scoreEntry(over, newRecord(over.seed), new Date('2026-10-24T10:00:00Z'))
48 expect(e).toMatchObject({ won: false, level: 1, coins: 7, kills: 4, seed: over.seed, powers: ['run'] })
49 expect(e.death?.cause).toBe('blast')
50 expect(e.record.seed).toBe(over.seed)
51 })
52
53 it("an Immortal run doesn't count; a run still going doesn't either", () => {
54 const s = board(`
55 ###
56 #P#
57 ###`)
58 expect(countsForScores(s)).toBe(false)
59 expect(countsForScores({ ...s, status: 'gameOver', options: { dev: false, immortal: true } })).toBe(false)
60 expect(countsForScores({ ...s, status: 'won', options: { dev: true, immortal: false } })).toBe(true)
61 })
62
63 it('kills are counted over the run', () => {
64 const s = board(`
65 ######
66 #P.1B#
67 ######`)
68 expect(step(s, { id: 'wait' }).state.runKills).toBe(1)
69 })
70})