src/rng.rs 1.4 K · 54 lines · raw · history

1 use serde::{Deserialize, Serialize};
2 use std::ops::Range;
3
4 use bevy::prelude::*;
5
6 #[derive(Resource, Clone, Debug, Serialize, Deserialize)]
7 pub struct SimRng(u64);
8
9 impl SimRng {
10 pub fn new(seed: u64) -> Self {
11 Self(seed)
12 }
13
14 pub fn next_u64(&mut self) -> u64 {
15 self.0 = self.0.wrapping_add(0x9E37_79B9_7F4A_7C15);
16 let mut z = self.0;
17 z = (z ^ (z >> 30)).wrapping_mul(0xBF58_476D_1CE4_E5B9);
18 z = (z ^ (z >> 27)).wrapping_mul(0x94D0_49BB_1331_11EB);
19 z ^ (z >> 31)
20 }
21
22 pub fn range_i32(&mut self, range: Range<i32>) -> i32 {
23 let span = (range.end - range.start) as u64;
24 range.start + (self.next_u64() % span) as i32
25 }
26
27 pub fn range_f32(&mut self, range: Range<f32>) -> f32 {
28 let unit = (self.next_u64() >> 40) as f32 / (1u64 << 24) as f32;
29 range.start + unit * (range.end - range.start)
30 }
31 }
32
33 #[cfg(test)]
34 mod tests {
35 use super::*;
36
37 #[test]
38 fn same_seed_gives_same_sequence_so_simulations_are_reproducible() {
39 let mut a = SimRng::new(7);
40 let mut b = SimRng::new(7);
41 for _ in 0..100 {
42 assert_eq!(a.next_u64(), b.next_u64());
43 }
44 }
45
46 #[test]
47 fn ranges_stay_within_bounds() {
48 let mut rng = SimRng::new(1);
49 for _ in 0..1000 {
50 assert!((-3..4).contains(&rng.range_i32(-3..4)));
51 assert!((1.0..2.5).contains(&rng.range_f32(1.0..2.5)));
52 }
53 }
54 }