use std::cell::RefCell;
use std::time::{SystemTime, UNIX_EPOCH};
struct RngState {
state: u64,
}
impl RngState {
fn from_seed(seed: u64) -> Self {
Self { state: seed | 1 }
}
fn new() -> Self {
let seed = SystemTime::now()
.duration_since(UNIX_EPOCH)
.map(|d| d.as_nanos() as u64)
.unwrap_or(0x9E3779B97F4A7C15);
Self::from_seed(seed)
}
fn next_u64(&mut self) -> u64 {
let mut x = self.state;
x ^= x >> 12;
x ^= x << 25;
x ^= x >> 27;
self.state = x;
x.wrapping_mul(0x2545_F491_4F6C_DD1D)
}
}
thread_local! {
static RNG: RefCell<RngState> = RefCell::new(RngState::new());
}
pub fn rand_range(min: i32, max: i32) -> i32 {
let (lo, hi) = if min <= max { (min, max) } else { (max, min) };
let span = (hi - lo) as u64 + 1;
RNG.with(|r| {
let v = r.borrow_mut().next_u64();
lo + (v % span) as i32
})
}
pub fn rand_f32() -> f32 {
RNG.with(|r| {
let v = r.borrow_mut().next_u64();
(v >> 40) as f32 / (1u32 << 24) as f32
})
}
pub fn seed_rng(seed: u64) {
RNG.with(|r| *r.borrow_mut() = RngState::from_seed(seed));
}