summaryrefslogtreecommitdiff
path: root/dungeon/src/rng.rs
diff options
context:
space:
mode:
Diffstat (limited to 'dungeon/src/rng.rs')
-rw-r--r--dungeon/src/rng.rs74
1 files changed, 74 insertions, 0 deletions
diff --git a/dungeon/src/rng.rs b/dungeon/src/rng.rs
new file mode 100644
index 0000000..bb9151b
--- /dev/null
+++ b/dungeon/src/rng.rs
@@ -0,0 +1,74 @@
+//! 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);
+ }
+}