use alloc::vec::Vec;
use rand::{
distributions::{
uniform::{SampleRange, SampleUniform},
Distribution, Standard,
},
Rng as _, SeedableRng as _,
};
use rand_chacha::ChaCha8Rng as ChaCha;
pub type Seed = [u8; 32];
#[derive(Copy, Clone)]
pub enum SeedOpt {
U64(u64),
Seed(Seed),
Entropy,
}
impl From<Option<u64>> for SeedOpt {
fn from(opt: Option<u64>) -> Self {
match opt {
Some(seed) => Self::U64(seed),
None => Self::Entropy,
}
}
}
impl From<u64> for SeedOpt {
fn from(seed: u64) -> Self {
Self::U64(seed)
}
}
impl From<Seed> for SeedOpt {
fn from(seed: Seed) -> Self {
Self::Seed(seed)
}
}
#[derive(Clone, Debug)]
pub struct Rng {
rng: ChaCha,
}
impl Rng {
pub fn new(seed: SeedOpt) -> Self {
let rng = match seed {
SeedOpt::Seed(seed) => ChaCha::from_seed(seed),
SeedOpt::U64(seed) => ChaCha::seed_from_u64(seed),
SeedOpt::Entropy => ChaCha::from_entropy(),
};
Self { rng }
}
#[inline]
pub fn seed(&self) -> Seed {
self.rng.get_seed()
}
pub fn stream(&mut self, n: usize) -> Vec<Self> {
let stream = self.rng.get_stream();
self.rng.set_stream(stream.wrapping_add(n as _));
(0..n)
.map(|i| {
let mut rng = self.clone();
rng.rng.set_stream(stream.wrapping_add(i as _));
rng
})
.collect()
}
pub fn gen_with<R>(&mut self, f: impl FnOnce(&mut ChaCha) -> R) -> R {
f(&mut self.rng)
}
pub fn gen<T>(&mut self) -> T
where
Standard: Distribution<T>,
{
self.rng.gen()
}
#[inline]
pub fn rand(&mut self) -> f64 {
self.ub(1.)
}
#[inline]
pub fn maybe(&mut self, p: f64) -> bool {
self.rng.gen_bool(p)
}
#[inline]
pub fn range<T, R>(&mut self, range: R) -> T
where
T: SampleUniform,
R: SampleRange<T>,
{
self.rng.gen_range(range)
}
#[inline]
pub fn sample<T, D>(&mut self, distr: D) -> T
where
D: Distribution<T>,
{
self.rng.sample(distr)
}
#[inline]
pub fn ub<U>(&mut self, ub: U) -> U
where
U: Default + SampleUniform,
core::ops::Range<U>: SampleRange<U>,
{
self.range(U::default()..ub)
}
#[inline]
pub fn clamp<T, R>(&mut self, v: T, range: R) -> T
where
T: SampleUniform + PartialOrd,
R: SampleRange<T> + core::ops::RangeBounds<T>,
{
if range.contains(&v) {
v
} else {
self.range(range)
}
}
#[inline]
pub fn normal<F>(&mut self, mean: F, std: F) -> F
where
F: num_traits::Float,
rand_distr::StandardNormal: Distribution<F>,
{
self.sample(rand_distr::Normal::new(mean, std).unwrap())
}
pub fn shuffle<S: rand::seq::SliceRandom + ?Sized>(&mut self, s: &mut S) {
s.shuffle(&mut self.rng);
}
pub fn choose<'a, S: rand::seq::SliceRandom + ?Sized>(&mut self, s: &'a S) -> &'a S::Item {
s.choose(&mut self.rng).expect("Empty slice")
}
pub fn array<A, C, const N: usize>(&mut self, candi: C) -> [A; N]
where
A: Default + Copy + PartialEq + SampleUniform,
C: IntoIterator<Item = A>,
{
let mut candi = candi.into_iter().collect::<Vec<_>>();
self.shuffle(candi.as_mut_slice());
candi[..N].try_into().expect("candi.len() < N")
}
}