Skip to main content

ace_sim/
rng.rs

1// region: Rng Trait
2
3/// A seeded random number generator for deterministic simulation.
4///
5/// All randomness in the simulation must flow through this trait. The same seed must produce the
6/// same sequence of values - this is what makes simulation runs reproducible and replayable.
7pub trait Rng {
8    fn next_u64(&mut self) -> u64;
9
10    /// Returns a random `u32`.
11    fn next_u32(&mut self) -> u32 {
12        self.next_u64() as u32
13    }
14
15    /// Returns a random `u8`.
16    fn next_u8(&mut self) -> u8 {
17        self.next_u64() as u8
18    }
19
20    // Returns true with probability `numerator / denominator`.
21    fn chance(&mut self, numerator: u32, denominator: u32) -> bool {
22        if denominator == 0 {
23            return false;
24        }
25
26        (self.next_u32() % denominator) < numerator
27    }
28
29    /// Returns a random `usize` in `0..len`.
30    fn index(&mut self, len: usize) -> usize {
31        if len == 0 {
32            return 0;
33        }
34
35        (self.next_u64() as usize) % len
36    }
37}
38
39// endregion: Rng Trait
40
41// region: XorShift64
42
43/// A fast, seedable Xorshift64 RNG
44///
45/// Not cryptographically secure - suitable for simulation only. Produces a full cycle of 2^64-1
46/// values before repeating
47#[derive(Debug, Clone)]
48pub struct Xorshift64 {
49    state: u64,
50}
51
52impl Xorshift64 {
53    /// Creates a new RNG with the given seed.
54    ///
55    /// Seed must be non-zero - passing 0 will be replaced with a default non-zero seed.
56    pub fn new(seed: u64) -> Self {
57        Self {
58            state: if seed == 0 {
59                0xDECA_FC0F_FEEC_AFE1
60            } else {
61                seed
62            },
63        }
64    }
65}
66
67impl Rng for Xorshift64 {
68    fn next_u64(&mut self) -> u64 {
69        let mut x = self.state;
70        x ^= x << 13;
71        x ^= x >> 7;
72        x ^= x << 17;
73        self.state = x;
74        x
75    }
76}
77
78// endregion: XorShift64