import { describe, expect, it } from 'vitest'; import { DROPS_BASE, DROPS_MAX, NOTE_VALUES, rollDrops, } from '../src/rules/floorScore'; import { SeededRNG } from '../src/core/SeededRNG'; describe('the floor score', () => { it('a busier night is a messier floor, up to a limit', () => { const rng = new SeededRNG(1); expect(rollDrops(rng.stream('a'), 0).length).toBe(DROPS_BASE); expect(rollDrops(rng.stream('b'), 24).length).toBe(DROPS_BASE + 4); expect(rollDrops(rng.stream('c'), 500).length).toBe(DROPS_MAX); }); it('is deterministic per stream — the same night drops the same floor', () => { const a = rollDrops(new SeededRNG(7).stream('sweep'), 40); const b = rollDrops(new SeededRNG(7).stream('sweep'), 40); expect(a).toEqual(b); }); it('cash is real denominations; curios, phones and baggies are worth $0', () => { for (let seed = 1; seed <= 20; seed++) { for (const d of rollDrops(new SeededRNG(seed).stream('s'), 60)) { if (d.kind === 'note') expect(NOTE_VALUES).toContain(d.value); else if (d.kind === 'coins') expect(d.value).toBeGreaterThan(0); else expect(d.value).toBe(0); } } }); it('at most one baggie and one phone per night', () => { for (let seed = 1; seed <= 30; seed++) { const drops = rollDrops(new SeededRNG(seed).stream('s'), 60); expect(drops.filter((d) => d.kind === 'baggie').length).toBeLessThanOrEqual(1); expect(drops.filter((d) => d.kind === 'phone').length).toBeLessThanOrEqual(1); } }); it('every drop has words — the label IS the reward for curios', () => { for (const d of rollDrops(new SeededRNG(11).stream('s'), 30)) { expect(d.label.length).toBeGreaterThan(5); } }); });