2026-04-01 17:34:21 +08:00
|
|
|
import { describe, it, expect } from 'vitest';
|
2026-04-02 15:59:27 +08:00
|
|
|
import { createRNG } from '@/utils/rng';
|
2026-04-01 17:34:21 +08:00
|
|
|
|
|
|
|
|
describe('createRNG', () => {
|
|
|
|
|
it('should create RNG with default seed', () => {
|
|
|
|
|
const rng = createRNG();
|
|
|
|
|
expect(rng.getSeed()).toBe(1);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should create RNG with custom seed', () => {
|
|
|
|
|
const rng = createRNG(12345);
|
|
|
|
|
expect(rng.getSeed()).toBe(12345);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should generate numbers in range [0, 1)', () => {
|
|
|
|
|
const rng = createRNG(42);
|
|
|
|
|
for (let i = 0; i < 100; i++) {
|
|
|
|
|
const num = rng.next();
|
|
|
|
|
expect(num).toBeGreaterThanOrEqual(0);
|
|
|
|
|
expect(num).toBeLessThan(1);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should generate numbers with max parameter', () => {
|
|
|
|
|
const rng = createRNG(42);
|
|
|
|
|
for (let i = 0; i < 100; i++) {
|
|
|
|
|
const num = rng.next(100);
|
|
|
|
|
expect(num).toBeGreaterThanOrEqual(0);
|
|
|
|
|
expect(num).toBeLessThan(100);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should generate integers in range [0, max)', () => {
|
|
|
|
|
const rng = createRNG(42);
|
|
|
|
|
for (let i = 0; i < 100; i++) {
|
|
|
|
|
const num = rng.nextInt(10);
|
|
|
|
|
expect(Number.isInteger(num)).toBe(true);
|
|
|
|
|
expect(num).toBeGreaterThanOrEqual(0);
|
|
|
|
|
expect(num).toBeLessThan(10);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should be deterministic with same seed', () => {
|
|
|
|
|
const rng1 = createRNG(12345);
|
|
|
|
|
const rng2 = createRNG(12345);
|
|
|
|
|
|
|
|
|
|
const sequence1 = Array.from({ length: 10 }, () => rng1.next());
|
|
|
|
|
const sequence2 = Array.from({ length: 10 }, () => rng2.next());
|
|
|
|
|
|
|
|
|
|
expect(sequence1).toEqual(sequence2);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should produce different sequences with different seeds', () => {
|
|
|
|
|
const rng1 = createRNG(12345);
|
|
|
|
|
const rng2 = createRNG(54321);
|
|
|
|
|
|
|
|
|
|
const sequence1 = Array.from({ length: 10 }, () => rng1.next());
|
|
|
|
|
const sequence2 = Array.from({ length: 10 }, () => rng2.next());
|
|
|
|
|
|
|
|
|
|
expect(sequence1).not.toEqual(sequence2);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should reset seed with setSeed', () => {
|
|
|
|
|
const rng = createRNG(42);
|
|
|
|
|
const firstSequence = Array.from({ length: 5 }, () => rng.next());
|
|
|
|
|
|
|
|
|
|
rng.setSeed(42);
|
|
|
|
|
const secondSequence = Array.from({ length: 5 }, () => rng.next());
|
|
|
|
|
|
|
|
|
|
expect(firstSequence).toEqual(secondSequence);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should generate uniformly distributed integers', () => {
|
|
|
|
|
const rng = createRNG(42);
|
|
|
|
|
const buckets = new Array(10).fill(0);
|
|
|
|
|
const iterations = 10000;
|
|
|
|
|
|
|
|
|
|
for (let i = 0; i < iterations; i++) {
|
|
|
|
|
const num = rng.nextInt(10);
|
|
|
|
|
buckets[num]++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 每个桶应该大约有 10% 的值
|
|
|
|
|
const expected = iterations / 10;
|
|
|
|
|
const tolerance = expected * 0.3; // 30% 容差
|
|
|
|
|
|
|
|
|
|
buckets.forEach((count, index) => {
|
|
|
|
|
expect(count).toBeGreaterThan(expected - tolerance);
|
|
|
|
|
expect(count).toBeLessThan(expected + tolerance);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|