v0.1.0: 仙途家族志 · Chronicle of the Immortal Clan
家族模拟器首版:修仙/经营/战斗/外交/叙事全套系统 - Electron + React + TS + MetonaSqlark(aria+OPFS) - 水墨中国风 UI - 引擎种子随机、确定性可回放 - 19 项单元测试、端到端冒烟验证
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { Rng, seedToRng } from '../src/renderer/game/core/rng'
|
||||
|
||||
describe('Rng', () => {
|
||||
it('is deterministic for same seed', () => {
|
||||
const a = new Rng(seedToRng('hello'))
|
||||
const b = new Rng(seedToRng('hello'))
|
||||
for (let i = 0; i < 100; i++) {
|
||||
expect(a.next()).toBe(b.next())
|
||||
}
|
||||
})
|
||||
|
||||
it('differs for different seeds', () => {
|
||||
const a = new Rng(seedToRng('aaa'))
|
||||
const b = new Rng(seedToRng('bbb'))
|
||||
const seq = 20
|
||||
let diff = false
|
||||
for (let i = 0; i < seq; i++) {
|
||||
if (a.next() !== b.next()) diff = true
|
||||
}
|
||||
expect(diff).toBe(true)
|
||||
})
|
||||
|
||||
it('produces values in [0, 1)', () => {
|
||||
const rng = new Rng(seedToRng('x'))
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
const v = rng.next()
|
||||
expect(v).toBeGreaterThanOrEqual(0)
|
||||
expect(v).toBeLessThan(1)
|
||||
}
|
||||
})
|
||||
|
||||
it('int works within bounds', () => {
|
||||
const rng = new Rng(seedToRng('y'))
|
||||
for (let i = 0; i < 500; i++) {
|
||||
const v = rng.int(0, 10)
|
||||
expect(v).toBeGreaterThanOrEqual(0)
|
||||
expect(v).toBeLessThanOrEqual(10)
|
||||
expect(Number.isInteger(v)).toBe(true)
|
||||
}
|
||||
})
|
||||
|
||||
it('state roundtrip continues identically', () => {
|
||||
const a = new Rng(seedToRng('z'))
|
||||
const b = new Rng(seedToRng('z'))
|
||||
for (let i = 0; i < 10; i++) {
|
||||
a.next()
|
||||
b.next()
|
||||
}
|
||||
const snap = a.getState()
|
||||
const c = new Rng(snap)
|
||||
expect(c.next()).toBe(b.next())
|
||||
expect(c.next()).toBe(b.next())
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user