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