137 lines
4.3 KiB
TypeScript
137 lines
4.3 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import { createRNG, Mulberry32RNG } from '@/utils/rng';
|
|
|
|
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);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('Mulberry32RNG', () => {
|
|
it('should instantiate with default seed', () => {
|
|
const rng = new Mulberry32RNG();
|
|
expect(rng.getSeed()).toBe(1);
|
|
});
|
|
|
|
it('should instantiate with custom seed', () => {
|
|
const rng = new Mulberry32RNG(99999);
|
|
expect(rng.getSeed()).toBe(99999);
|
|
});
|
|
|
|
it('should implement RNG interface', () => {
|
|
const rng = new Mulberry32RNG(42);
|
|
|
|
// Should have all RNG methods
|
|
expect(typeof rng.next).toBe('function');
|
|
expect(typeof rng.nextInt).toBe('function');
|
|
expect(typeof rng.setSeed).toBe('function');
|
|
expect(typeof rng.getSeed).toBe('function');
|
|
});
|
|
|
|
it('should produce same results as createRNG with same seed', () => {
|
|
const factoryRng = createRNG(12345);
|
|
const directRng = new Mulberry32RNG(12345);
|
|
|
|
for (let i = 0; i < 10; i++) {
|
|
expect(factoryRng.next()).toBe(directRng.next());
|
|
expect(factoryRng.nextInt(100)).toBe(directRng.nextInt(100));
|
|
}
|
|
});
|
|
|
|
it('should allow seed changes after instantiation', () => {
|
|
const rng = new Mulberry32RNG(100);
|
|
expect(rng.getSeed()).toBe(100);
|
|
|
|
rng.setSeed(200);
|
|
expect(rng.getSeed()).toBe(200);
|
|
|
|
const value = rng.next();
|
|
expect(value).toBeGreaterThanOrEqual(0);
|
|
expect(value).toBeLessThan(1);
|
|
});
|
|
});
|