# Task 4: Deterministic RNG **Depends on:** Task 1 ## Context Files - `.dev/2026-05-28-procgen-map-core/spec/design.md` — §4.4 (RNG) and §7 (determinism contract). - `reikhelm-core/src/lib.rs` — append the module declaration here. ## Files - Create: `reikhelm-core/src/rng.rs` — `Rng`. - Modify: `reikhelm-core/src/lib.rs` — append `pub mod rng;`. ## What to Build A deterministic RNG wrapping `rand_chacha::ChaCha8Rng` (spec §4.4). Reproducible across machines — never `thread_rng`. The keystone feature is `fork`: deriving an independent child stream from a **stable basis** (the originating seed) plus a label, so that forks are independent of draw order and of each other. The `Pipeline` (Task 6) calls `fork` once per pass; this is what makes editing the pipeline non-destructive to existing seeds (spec §7). **Critical determinism detail:** `fork`'s label→seed mixing must be stable across runs and crate versions. Do **not** use `std::collections::hash_map::DefaultHasher` (unspecified, version-unstable). Use an explicit, fixed integer mix (e.g. a splitmix64 / FNV-style combine of the base seed and the label bytes). Document the chosen mixing. ## Interface Dependencies - **Produces:** `Rng` with: - `from_seed(seed: u64) -> Self` (stores the seed as the fork basis) - `fork(&self, label: &str) -> Rng` — returns `Rng::from_seed(mix(self.basis_seed, label))`; **does not** advance `self`; order-independent. - `range(&mut self, lo: i32, hi: i32) -> i32` (half-open or inclusive — document which) - `chance(&mut self, p: f64) -> bool` - `choose<'a, T>(&mut self, items: &'a [T]) -> Option<&'a T>` - `shuffle(&mut self, items: &mut [T])` ## Tests - Same seed → identical sequence of `range` draws (reproducibility). - `fork` is **order-independent**: `r.fork("a")` produces the same stream regardless of how many values were drawn from `r` beforehand. - Distinct labels produce distinct (non-identical) streams: `fork("a") != fork("b")`. - `fork("name#0")` and `fork("name#1")` differ (the occurrence-keying scheme the pipeline relies on works). - `choose` on an empty slice returns `None`; `shuffle` is a permutation (same multiset). ## Success Criteria - [ ] `Rng` wraps ChaCha8; `fork` derives from a stable basis with an explicit (non-`DefaultHasher`) mix. - [ ] `fork` is order-independent and does not mutate the parent. - [ ] `pub mod rng;` added to `lib.rs`. - [ ] All tests pass: `cargo test -p reikhelm-core rng` ## Commit `"feat(core): deterministic ChaCha8 RNG with order-independent fork"`