//! Implements rng using the xoshiro256++ algorithm use rand::{ SeedableRng, rand_core::{RngCore, le}, }; /// Deterministic pseudo random number generator. /// /// Is is a copy of `SmallRng` from `rand`, but is gurenteed /// to be reproducible across versions and platforms. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct DungeonRng { s: [u64; 4], } impl SeedableRng for DungeonRng { // Fix to 256 bits. Changing this is a breaking change! type Seed = [u8; 32]; #[inline] fn from_seed(seed: Self::Seed) -> Self { let mut state = [0; 4]; le::read_u64_into(&seed, &mut state); Self { s: state } } #[inline] fn seed_from_u64(mut state: u64) -> Self { const PHI: u64 = 0x9e3779b97f4a7c15; let mut s = [0; 4]; for i in &mut s { state = state.wrapping_add(PHI); let mut z = state; z = (z ^ (z >> 30)).wrapping_mul(0xbf58476d1ce4e5b9); z = (z ^ (z >> 27)).wrapping_mul(0x94d049bb133111eb); z = z ^ (z >> 31); *i = z; } Self { s } } } impl RngCore for DungeonRng { #[inline] fn next_u32(&mut self) -> u32 { let val = self.next_u64(); (val >> 32) as u32 } #[inline] fn next_u64(&mut self) -> u64 { let res = self.s[0] .wrapping_add(self.s[3]) .rotate_left(23) .wrapping_add(self.s[0]); let t = self.s[1] << 17; self.s[2] ^= self.s[0]; self.s[3] ^= self.s[1]; self.s[1] ^= self.s[2]; self.s[0] ^= self.s[3]; self.s[2] ^= t; self.s[3] = self.s[3].rotate_left(45); res } #[inline] fn fill_bytes(&mut self, dst: &mut [u8]) { le::fill_bytes_via_next(self, dst); } }