pub struct Prng {
state: u64,
sealed: bool,
states: Vec<(u64, bool)>,
}
impl Prng {
pub fn new(seed: u32) -> Prng {
let mut ans = Prng {
state: 0,
sealed: true,
states: Vec::new(),
};
ans.next();
ans.state = ans.state.wrapping_add(seed as u64);
ans.next();
ans.sealed = true;
ans
}
pub fn sealed(&self) -> bool {
self.sealed
}
pub fn next(&mut self) -> u32 {
let prv = self.state;
self.state = (prv.wrapping_mul(6_364_136_223_846_793_005)).wrapping_add(1);
self.sealed = false;
let xorshifted = (((prv >> 18) ^ prv) >> 27) as u32;
let rot = (prv >> 59) as u32;
(xorshifted >> rot) | (xorshifted << ((rot.wrapping_neg()) & 31))
}
pub fn push(&mut self) {
self.states.push((self.state, self.sealed));
}
pub fn pop(&mut self) -> Option<()> {
if let Some(old) = self.states.pop() {
self.state = old.0;
self.sealed = old.1;
Some(())
} else {
None
}
}
pub fn random_usindex(&mut self, up_to: usize) -> usize {
assert!(std::mem::size_of::<usize>() <= 64);
assert!(up_to > 0);
if up_to == 1 {
0
} else {
let thresh = up_to.wrapping_neg() % up_to;
loop {
let mut p = self.next() as usize;
if up_to > 4_294_967_296 {
p <<= 32;
p += self.next() as usize;
}
if p >= thresh {
break p % up_to;
}
}
}
}
pub fn only_or_random<T: Copy>(&mut self, from: &[T]) -> Option<T> {
if from.is_empty() {
None
} else {
Some(from[self.random_usindex(from.len())])
}
}
pub fn shuffle<T>(&mut self, x: &mut [T]) {
if !x.is_empty() {
for e in 0..(x.len() - 1) {
let ee = e + self.random_usindex(x.len() - e);
x.swap(e, ee);
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn cmp_with_c() {
let mut x = Prng::new(21);
let x_out: Vec<u32> = (0..6).map(|_| x.next()).collect();
let pcg32_c_out = vec![
4046551126, 3645130801, 1491492233, 2234036793, 669229171, 981735442,
];
assert_eq!(x_out, pcg32_c_out);
let mut x = Prng::new(33198495);
let x_out: Vec<u32> = (0..6).map(|_| x.next()).collect();
let pcg32_c_out = vec![
3221354117, 560577576, 1464394025, 77867303, 6303390, 439113613,
];
assert_eq!(x_out, pcg32_c_out);
}
#[test]
fn upto() {
let mut x = Prng::new(912);
let n = 3;
let mut cc: Vec<u64> = std::iter::repeat(0).take(n).collect();
for _ in 0..100 {
cc[x.random_usindex(n)] += 1;
}
assert_eq!(cc[1], 35); assert_eq!(x.sealed(), false);
}
#[test]
fn random_element() {
let mut x = Prng::new(71);
let vv = vec!["Hello", "or", "something"];
assert_eq!(x.only_or_random(&vv).unwrap(), "or");
let ev: Vec<i64> = vec![];
assert_eq!(x.only_or_random(&ev), None);
assert_eq!(x.sealed(), false);
}
#[test]
fn only_element() {
let mut y = Prng::new(99);
let eo = vec!["only"];
assert_eq!(y.only_or_random(&eo), Some("only"));
assert_eq!(y.sealed(), true);
}
#[test]
fn shuffle() {
let mut x = Prng::new(81);
let mut v: Vec<u32> = vec![];
x.shuffle(&mut v);
assert!(x.sealed());
v.push(1);
x.shuffle(&mut v);
assert!(x.sealed());
v.push(2);
x.shuffle(&mut v);
assert!(!x.sealed());
assert_eq!(v, vec![2, 1]);
}
#[test]
fn state_stack() {
let mut x = Prng::new(99);
x.push();
let a = x.next();
for _ in 0..100 {
x.next();
}
x.push();
let b = x.next();
for _ in 0..100 {
x.next();
}
x.pop().unwrap();
assert!(!x.sealed());
assert_eq!(b, x.next());
x.pop().unwrap();
assert!(x.sealed());
assert_eq!(a, x.next());
assert!(x.pop().is_none());
}
}