use std::usize;
use rand::prelude::IndexedRandom;
use rand::rngs::StdRng;
use rand::seq::SliceRandom;
use rand::{Rng, RngCore, SeedableRng};
pub trait RandomGenerator {
type R: RngCore + Rng;
fn gen_range_usize(&mut self, min: usize, max: usize) -> usize {
self.rng().random_range(min..max)
}
fn gen_range_f64(&mut self, min: f64, max: f64) -> f64 {
self.rng().random_range(min..max)
}
fn gen_usize(&mut self) -> usize {
self.rng().random_range(usize::MIN..usize::MAX)
}
fn gen_bool(&mut self, p: f64) -> bool {
self.rng().random_bool(p)
}
fn gen_proability(&mut self) -> f64 {
self.rng().random::<f64>()
}
fn shuffle_vec(&mut self, vector: &mut Vec<f64>) {
vector.shuffle(self.rng())
}
fn shuffle_vec_usize(&mut self, vector: &mut Vec<usize>) {
vector.shuffle(self.rng())
}
fn choose_usize<'a>(&mut self, vector: &'a [usize]) -> Option<&'a usize> {
vector.choose(self.rng())
}
fn rng(&mut self) -> &mut Self::R;
}
#[derive(Debug, Clone)]
pub struct MOORandomGenerator {
rng: StdRng,
}
impl MOORandomGenerator {
pub fn new(rng: StdRng) -> Self {
Self { rng }
}
pub fn new_from_seed(seed: Option<u64>) -> Self {
let rng = seed.map_or_else(|| StdRng::from_rng(&mut rand::rng()), StdRng::seed_from_u64);
Self { rng }
}
}
impl RandomGenerator for MOORandomGenerator {
type R = StdRng;
fn rng(&mut self) -> &mut StdRng {
&mut self.rng
}
}
pub struct TestDummyRng;
impl RngCore for TestDummyRng {
fn next_u32(&mut self) -> u32 {
unimplemented!("Not used in this test")
}
fn next_u64(&mut self) -> u64 {
unimplemented!("Not used in this test")
}
fn fill_bytes(&mut self, _dest: &mut [u8]) {
unimplemented!("Not used in this test")
}
}
pub struct NoopRandomGenerator {
dummy: TestDummyRng,
}
impl NoopRandomGenerator {
#[allow(dead_code)]
pub fn new() -> Self {
Self {
dummy: TestDummyRng,
}
}
}
impl RandomGenerator for NoopRandomGenerator {
type R = TestDummyRng;
fn rng(&mut self) -> &mut TestDummyRng {
&mut self.dummy
}
}
#[cfg(test)]
mod tests {
use super::*;
use rand::SeedableRng;
use rand::rngs::StdRng;
#[test]
fn test_gen_range_usize() {
let seed = [42u8; 32];
let mut rng = MOORandomGenerator::new(StdRng::from_seed(seed));
let min = 10;
let max = 20;
let value = rng.gen_range_usize(min, max);
assert!(
value >= min && value < max,
"gen_range_usize produced {} which is not in [{}, {})",
value,
min,
max
);
}
#[test]
fn test_gen_range_f64() {
let seed = [42u8; 32];
let mut rng = MOORandomGenerator::new(StdRng::from_seed(seed));
let min = 3.0;
let max = 10.0;
let value = rng.gen_range_f64(min, max);
assert!(
value >= min && value < max,
"gen_range_f64 produced {} which is not in [{}, {})",
value,
min,
max
);
}
#[test]
fn test_gen_bool() {
let seed = [42u8; 32];
let mut rng = MOORandomGenerator::new(StdRng::from_seed(seed));
assert!(rng.gen_bool(1.0), "gen_bool(1.0) did not return true");
assert!(!rng.gen_bool(0.0), "gen_bool(0.0) did not return false");
}
#[test]
fn test_gen_probability() {
let seed = [42u8; 32];
let mut rng = MOORandomGenerator::new(StdRng::from_seed(seed));
let prob = rng.gen_proability();
assert!(
prob >= 0.0 && prob < 1.0,
"gen_proability produced {} which is not in [0, 1)",
prob
);
}
}