From 610722a1bfd91e0ef527d5f593a60228d31cf2ed Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Wed, 23 Mar 2022 21:52:37 +0000 Subject: [PATCH] Extract the random number generator --- agb/src/hash_map.rs | 9 ++++----- agb/src/rng.rs | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 5 deletions(-) create mode 100644 agb/src/rng.rs diff --git a/agb/src/hash_map.rs b/agb/src/hash_map.rs index fe9ee3a..9009478 100644 --- a/agb/src/hash_map.rs +++ b/agb/src/hash_map.rs @@ -831,7 +831,7 @@ mod test { use core::cell::RefCell; use super::*; - use crate::Gba; + use crate::{rng, Gba}; #[test_case] fn can_store_and_retrieve_8_elements(_gba: &mut Gba) { @@ -956,14 +956,13 @@ mod test { #[test_case] fn extreme_case(_gba: &mut Gba) { let mut map = HashMap::new(); - let mut rng = crate::rng::RandomNumberGenerator::new(); let mut answers: [Option; 128] = [None; 128]; for _ in 0..5_000 { - let command = rng.next().rem_euclid(2); - let key = rng.next().rem_euclid(answers.len() as i32); - let value = rng.next(); + let command = rng::next().rem_euclid(2); + let key = rng::next().rem_euclid(answers.len() as i32); + let value = rng::next(); match command { 0 => { diff --git a/agb/src/rng.rs b/agb/src/rng.rs new file mode 100644 index 0000000..57bc440 --- /dev/null +++ b/agb/src/rng.rs @@ -0,0 +1,41 @@ +use core::cell::RefCell; + +use bare_metal::Mutex; + +use crate::interrupt::free; + +pub struct RandomNumberGenerator { + state: [u32; 4], +} + +impl RandomNumberGenerator { + pub const fn new() -> Self { + Self { + state: [1014776995, 476057059, 3301633994, 706340607], + } + } + + pub fn next(&mut self) -> i32 { + let result = (self.state[0].wrapping_add(self.state[3])) + .rotate_left(7) + .wrapping_mul(9); + let t = self.state[1].wrapping_shr(9); + + self.state[2] ^= self.state[0]; + self.state[3] ^= self.state[1]; + self.state[1] ^= self.state[2]; + self.state[0] ^= self.state[3]; + + self.state[2] ^= t; + self.state[3] = self.state[3].rotate_left(11); + + result as i32 + } +} + +static GLOBAL_RNG: Mutex> = + Mutex::new(RefCell::new(RandomNumberGenerator::new())); + +pub fn next() -> i32 { + free(|cs| GLOBAL_RNG.borrow(*cs).borrow_mut().next()) +}