use crate::MyResult;
use std::{
cell::RefCell,
time::{SystemTime, UNIX_EPOCH},
};
pub struct XorShiftRng {
state: u64,
}
impl XorShiftRng {
fn new(seed: u64) -> Self {
XorShiftRng { state: seed }
}
fn generate(&mut self) -> u64 {
let mut x = self.state;
x ^= x >> 12; x ^= x << 25; x ^= x >> 27; self.state = x;
x.wrapping_mul(0x2545F4914F6CDD1D)
}
}
fn get_seed() -> u64 {
let nanos = SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("Time went backwards, system clock is unreliable")
.as_nanos() as u64;
if nanos == 0 { 1 } else { nanos }
}
thread_local!(
static THREAD_RNG: RefCell<XorShiftRng> = RefCell::new(XorShiftRng::new(get_seed()));
);
pub fn rand() -> u64 {
THREAD_RNG.with(|rng| rng.borrow_mut().generate())
}
pub fn random_in_range(min: u64, max: u64) -> MyResult<u64> {
if min > max {
let msg = format!("min ({min}) must be less than or equal to max ({max})");
return Err(msg.into());
}
let range_size = max.wrapping_sub(min).wrapping_add(1);
if range_size == 0 {
return Ok(rand());
}
let rejection_threshold = (u64::MAX / range_size) * range_size;
const MAX_RETRIES: u32 = 100;
for _ in 0..MAX_RETRIES {
let value = rand();
if value < rejection_threshold {
return Ok(min + (value % range_size));
}
}
Ok(min + (rand() % range_size))
}
pub trait Shuffle {
fn shuffle(&mut self);
}
impl<T> Shuffle for &mut [T] {
fn shuffle(&mut self) {
let len = self.len();
for i in (1..len).rev() {
let j = random_in_range(0, i as u64).unwrap() as usize;
self.swap(i, j);
}
}
}
impl<T> Shuffle for Vec<T> {
fn shuffle(&mut self) {
self.as_mut_slice().shuffle();
}
}
#[cfg(test)]
mod test_random {
use super::*; use std::collections::HashSet;
#[test]
fn gen_random() {
let mut numbers = HashSet::new();
for n in 0..1000 {
let random = rand();
println!("random number {n:3}: {random}");
if !numbers.insert(random) {
eprintln!("Error: {random}");
panic!("Not random!");
}
}
println!("numbers: {numbers:#?}");
assert_eq!(numbers.len(), 1000);
}
#[test]
fn shuffle_preserves_elements() {
let mut original: Vec<u32> = (1..=100).collect();
let mut shuffled = original.clone();
shuffled.shuffle();
println!("original: {original:?}");
println!("shuffled: {shuffled:?}");
assert_eq!(original.len(), shuffled.len());
assert_ne!(
original, shuffled,
"Shuffle should change the order (highly likely)."
);
original.sort();
shuffled.sort();
assert_eq!(
original, shuffled,
"A valid shuffle must preserve all original elements."
);
}
#[test]
fn random_in_range_bounds() -> MyResult<()> {
let min = 100;
let max = 200;
for _ in 0..10_000 {
let val = random_in_range(min, max)?;
assert!(
val >= min && val <= max,
"Value {val} is outside the range [{min}, {max}]"
);
}
Ok(())
}
#[test]
fn random_integers() -> MyResult<()> {
let value: u64 = random_in_range(1, 20)?;
println!("integer: {value:?}");
let integers: Vec<u64> = (0..100)
.map(|_| random_in_range(1, 20))
.collect::<Result<Vec<u64>, _>>()?;
println!("integers: {integers:?}");
let condition_a = integers.iter().min() >= Some(&1);
let condition_b = integers.iter().max() <= Some(&20);
assert!(condition_a);
assert!(condition_b);
assert_eq!(integers.len(), 100);
Ok(())
}
#[test]
fn random_in_range_errors_on_invalid_range() -> MyResult<()> {
let result = random_in_range(21, 20).map_err(|err| {
eprintln!("{err}");
err
});
assert!(result.is_err());
assert_eq!(
result.unwrap_err().to_string(),
"min (21) must be less than or equal to max (20)"
);
Ok(())
}
#[test]
fn shuffle_empty_and_single_element() {
let mut empty_vec: Vec<u32> = Vec::new();
empty_vec.shuffle();
assert!(empty_vec.is_empty());
let mut single_vec = vec![42];
single_vec.shuffle();
assert_eq!(single_vec, vec![42]); }
#[test]
fn shuffle_multiple_times() {
let original: Vec<u32> = (1..=10).collect();
let mut first_shuffle = original.clone();
first_shuffle.shuffle();
let mut second_shuffle = original.clone();
second_shuffle.shuffle();
assert_ne!(first_shuffle, original);
assert_ne!(second_shuffle, original);
assert_ne!(
first_shuffle, second_shuffle,
"Two shuffles produced the same result, which is highly unlikely."
);
}
}