-
Notifications
You must be signed in to change notification settings - Fork 0
Closed
Labels
featureNew functionalityNew functionalitytestingBuild, tests and CI related features and issuesBuild, tests and CI related features and issues
Description
Implement seedable RNG interface with xorshift128+ implementation and MockRNG for deterministic testing.
Rationale
Deterministic testing of dice rolls requires:
- Seedable RNG — Same seed produces identical sequence (reproducible tests)
- MockRNG — Return predefined values for exact test control
The RNG interface also enables:
- Reproducible rolls for debugging
- User-provided seeds for "fair" rolls
- Dependency injection in consumer code
References
- PRD.md Section 3.5 — RNG interface definition
- PLAN.md Phase 3 — RNG implementation details
- xorshift128+ algorithm — PRNG algorithm
Things to Consider
- Bounds:
nextInt(min, max)must be inclusive[min, max] - Distribution: Verify uniform distribution across range
- Seed types: Support both string and number seeds
- Export for consumers: RNG types should be part of public API
Implementation
Important
This is not a step-by-step guide — it's a functional checklist ordered logically.
Files to Create
-
/src/rng/interface.ts— RNG interface:interface RNG { next(): number; // Returns [0, 1) nextInt(min: number, max: number): number; // Returns [min, max] inclusive }
-
/src/rng/xorshift.ts— SeededRNG implementation:class SeededRNG implements RNG { constructor(seed?: string | number) { /* xorshift128+ state init */ } next(): number { /* [0, 1) */ } nextInt(min: number, max: number): number { /* [min, max] */ } }
-
/src/rng/mock.ts— MockRNG for testing:function createMockRng(values: number[]): RNG { let index = 0; return { next: () => values[index++] / 100, // Normalize to [0, 1) nextInt: (min, max) => values[index++], // Return exact value }; }
-
/src/rng/rng.test.ts— Comprehensive RNG tests
Test Cases
// Seedable reproducibility
const rng1 = new SeededRNG('test-seed');
const rng2 = new SeededRNG('test-seed');
expect(rng1.nextInt(1, 6)).toBe(rng2.nextInt(1, 6));
// Distribution coverage
const rng = new SeededRNG(42);
const values = new Set(Array.from({ length: 1000 }, () => rng.nextInt(1, 6)));
expect(values).toEqual(new Set([1, 2, 3, 4, 5, 6]));
// MockRNG determinism
const mock = createMockRng([4, 2, 6]);
expect(mock.nextInt(1, 6)).toBe(4);
expect(mock.nextInt(1, 6)).toBe(2);
expect(mock.nextInt(1, 6)).toBe(6);
// Bounds inclusivity
const boundRng = new SeededRNG(123);
const results = Array.from({ length: 10000 }, () => boundRng.nextInt(1, 20));
expect(Math.min(...results)).toBe(1);
expect(Math.max(...results)).toBe(20);Acceptance Criteria
-
SeededRNGproduces reproducible sequences from seed -
MockRNGreturns exact predefined values in order -
nextInt(min, max)bounds are inclusive[min, max] - Both string and number seeds work
- Distribution is uniform (statistical test)
- RNG types exported for library consumers
- All test cases pass
Drafted with AI assistance
Metadata
Metadata
Assignees
Labels
featureNew functionalityNew functionalitytestingBuild, tests and CI related features and issuesBuild, tests and CI related features and issues