use agb::input::{Button, ButtonController};
use agb::rng::RandomNumberGenerator;
pub struct SeedGen {
pub seed: [u32; 4],
}
impl Default for SeedGen {
fn default() -> SeedGen {
Self {
seed: [0x15f1c1; 4],
}
}
}
impl SeedGen {
pub fn create_rng(&self) -> RandomNumberGenerator {
RandomNumberGenerator::new_with_seed(self.seed)
}
pub fn update(&mut self, button_controller: &ButtonController) {
self.seed[1] = self.seed[1].rotate_left(1);
self.seed[1] |= button_controller.is_pressed(Button::Left) as u32;
self.seed[1] |= (button_controller.is_pressed(Button::Right) as u32) << 1;
self.seed[1] |= (button_controller.is_pressed(Button::Up) as u32) << 2;
self.seed[1] |= (button_controller.is_pressed(Button::Down) as u32) << 3;
self.seed[1] |= (button_controller.is_pressed(Button::A) as u32) << 4;
self.seed[1] |= (button_controller.is_pressed(Button::B) as u32) << 5;
self.seed[1] |= (button_controller.is_pressed(Button::L) as u32) << 6;
self.seed[1] |= (button_controller.is_pressed(Button::R) as u32) << 7;
self.seed[0] = self.seed[0].wrapping_add(1);
self.seed[2] ^= self.seed[0].wrapping_mul(0x9e3779b9);
self.seed[3] =
self.seed[3].wrapping_add(button_controller.just_pressed_vector::<i32>().x as u32);
self.seed[3] = self.seed[3].rotate_right(1);
}
}
#[inline]
pub fn next_u16(rng: &mut RandomNumberGenerator) -> u16 {
rng.next_i32() as u16
}
#[inline]
pub fn next_u16_in(rng: &mut RandomNumberGenerator, min: u16, max: u16) -> u16 {
debug_assert!(min <= max, "min must not be greater than max");
let span = (max as u32).wrapping_sub(min as u32).wrapping_add(1);
let random_val = next_u16(rng) as u32;
let scaled = (random_val * span) >> 16;
(scaled as u16) + min
}
#[cfg(test)]
mod tests {
use super::*;
#[test_case]
fn next_u16_in_stays_in_range(_gba: &mut agb::Gba) {
let mut rng = RandomNumberGenerator::new_with_seed([1, 2, 3, 4]);
for _ in 0..1000 {
let v = next_u16_in(&mut rng, 5, 10);
assert!((5..=10).contains(&v), "{v} out of range");
}
}
#[test_case]
fn next_u16_in_handles_extremes(_gba: &mut agb::Gba) {
let mut rng = RandomNumberGenerator::new_with_seed([5, 6, 7, 8]);
assert_eq!(next_u16_in(&mut rng, 7, 7), 7);
for _ in 0..100 {
next_u16_in(&mut rng, 0, u16::MAX);
next_u16_in(&mut rng, u16::MAX - 1, u16::MAX);
}
}
}