Skip to main content

fusee_sim/
rng.rs

1//! A small seeded generator (SplitMix64). Every random choice in a simulation
2//! comes from one of these, so a seed reproduces a run exactly.
3
4#[derive(Clone, Debug)]
5pub struct Rng(u64);
6
7impl Rng {
8    pub fn new(seed: u64) -> Self {
9        Self(seed ^ 0x9e37_79b9_7f4a_7c15)
10    }
11
12    pub fn next(&mut self) -> u64 {
13        self.0 = self.0.wrapping_add(0x9e37_79b9_7f4a_7c15);
14        let mut z = self.0;
15        z = (z ^ (z >> 30)).wrapping_mul(0xbf58_476d_1ce4_e5b9);
16        z = (z ^ (z >> 27)).wrapping_mul(0x94d0_49bb_1331_11eb);
17        z ^ (z >> 31)
18    }
19
20    /// Uniform in `0..n` (`n > 0`).
21    pub fn below(&mut self, n: u64) -> u64 {
22        if n == 0 {
23            return 0;
24        }
25        self.next() % n
26    }
27
28    pub fn chance(&mut self, per_mille: u32) -> bool {
29        self.below(1000) < u64::from(per_mille)
30    }
31
32    pub fn shuffle<T>(&mut self, v: &mut [T]) {
33        for i in (1..v.len()).rev() {
34            let j = self.below(i as u64 + 1) as usize;
35            v.swap(i, j);
36        }
37    }
38
39    pub fn fork(&mut self) -> Self {
40        Self::new(self.next())
41    }
42}