import { describe, expect, it } from 'vitest' import { Rng, seedToRng, RngHub } from '../src/renderer/game/core/rng' describe('RNG 多种子矩阵', () => { it.each([ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j' ].map((s) => [s] as const))('种子 %s 前 5 值互异不重复零帧', (seed) => { const rng = new Rng(seedToRng(seed)) const vals = [rng.next(), rng.next(), rng.next(), rng.next(), rng.next()] expect(new Set(vals.map((v) => v.toFixed(6))).size).toBeGreaterThanOrEqual(4) }) it.each([10, 50, 100, 500, 1000].map((n) => [n] as const))('输出序列 %i 个全在 [0,1)', (n) => { const rng = new Rng(seedToRng('range-' + n)) for (let i = 0; i < n; i++) { const v = rng.next() expect(v).toBeGreaterThanOrEqual(0) expect(v).toBeLessThan(1) } }) it.each([3, 7, 20, 99, 1000].map((n) => [n] as const))('int(0,%i) 端点可达', (n) => { const rng = new Rng(seedToRng('int-' + n)) let lo = Number.MAX_SAFE_INTEGER let hi = -1 for (let i = 0; i < n * 40; i++) { const v = rng.int(0, n - 1) lo = Math.min(lo, v) hi = Math.max(hi, v) } expect(lo).toBe(0) expect(hi).toBe(n - 1) }) }) describe('RngHub 矩阵', () => { it.each([1, 2, 3].map((n) => [n] as const))('rollSeed 第%i 次格式稳定', () => { expect(RngHub.rollSeed().startsWith('seed-')).toBe(true) }) it.each([5, 20, 50].map((n) => [n] as const))('audioNoise01 %i 次均为 [0,1)', (n) => { for (let i = 0; i < n; i++) { const v = RngHub.audioNoise01() expect(v).toBeGreaterThanOrEqual(0) expect(v).toBeLessThan(1) } }) it('音频流可回放(同序)', () => { const a = RngHub.audioNoise01() const b = RngHub.audioNoise01() expect(a).not.toBe(b) }) }) describe('RigRng state 拷贝矩阵', () => { it.each(['s1', 's2', 's3'].map((s) => [s] as const))('种子 %s 状态快照后继续一致', (s) => { const rng = new Rng(seedToRng(s)) for (let i = 0; i < 10; i++) rng.next() const snap = rng.getState() const con = new Rng(snap) const r2 = new Rng(seedToRng(s)) for (let i = 0; i < 10; i++) r2.next() expect(con.next()).toBe(r2.next()) }) }) describe('pick/shuffle 矩阵', () => { it.each([['a'], ['a', 'b'], ['a', 'b', 'c'], Array.from({ length: 7 }, (_, i) => 'e' + i)])( 'pick 从 %j 不丢元素', (arr) => { const rng = new Rng(seedToRng('pick-' + arr.length)) for (let i = 0; i < 30; i++) { expect(arr).toContain(rng.pick(arr)) } } ) it.each([1, 2, 5, 12].map((n) => [n] as const))('shuffle %i 保集不变', (n) => { const rng = new Rng(seedToRng('sh-' + n)) const src = Array.from({ length: n }, (_, i) => i) const out = rng.shuffle(src) expect(out.length).toBe(n) expect([...out].sort((a, b) => a - b)).toEqual(src) }) })