pub const BASH_RAND_MAX: u16 = 0x7fff;
pub struct Random {
pub seed: u32,
last: u16,
is_old: bool,
}
impl Random {
pub fn new(seed: u32, is_old: bool) -> Self {
Self {
seed,
last: 0,
is_old,
}
}
pub fn next_16(&mut self) -> u16 {
self.next_seed();
let result = if self.is_old {
self.seed as u16 & BASH_RAND_MAX
} else {
((self.seed >> 16) ^ (self.seed & 0xffff)) as u16 & BASH_RAND_MAX
};
if result == self.last {
self.next_16()
} else {
self.last = result;
result
}
}
pub fn next_16_n(&mut self, n: usize) -> Vec<u16> {
let mut result = Vec::with_capacity(n);
for _ in 0..n {
result.push(self.next_16());
}
result
}
pub fn skip(&mut self, n: usize) {
for _ in 0..n {
self.next_16();
}
}
pub fn next_seed(&mut self) -> u32 {
if self.seed == 0 {
self.seed = 123459876;
}
let h: i32 = self.seed as i32 / 127773;
let l: i32 = self.seed as i32 - (127773 * h);
let t: i32 = 16807 * l - 2836 * h;
self.seed = if t < 0 { t + 0x7fffffff } else { t } as u32;
self.seed
}
pub fn next_seed_n(&mut self, n: usize) -> Vec<u32> {
let mut result = Vec::with_capacity(n);
for _ in 0..n {
result.push(self.next_seed());
}
result
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn bash_52_zero() {
let mut rng = Random::new(0, false);
assert_eq!(rng.next_16_n(3), vec![20814, 24386, 149]);
}
#[test]
fn bash_52_n() {
let mut rng = Random::new(1337, false);
assert_eq!(rng.next_16_n(3), vec![24697, 15233, 8710]);
}
#[test]
fn bash_52_big() {
let mut rng = Random::new(2147483646, false);
assert_eq!(rng.next_16_n(3), vec![16807, 10791, 19566]);
}
#[test]
fn bash_50_zero() {
let mut rng = Random::new(0, true);
assert_eq!(rng.next_16_n(3), vec![20034, 24315, 12703]);
}
#[test]
fn bash_50_n() {
let mut rng = Random::new(1337, true);
assert_eq!(rng.next_16_n(3), vec![24879, 21848, 15683]);
}
#[test]
fn bash_50_big() {
let mut rng = Random::new(2147483646, true);
assert_eq!(rng.next_16_n(3), vec![15960, 17678, 21286]);
}
}