pub mod algorithms;
use crate::random::algorithms::Algorithm;
use crate::random::algorithms::{ComplementaryMultiplyWithCarry, MersenneTwister};
use std::cmp::Ordering;
use std::time::SystemTime;
pub trait Rng {
fn get_i32(&mut self, min: i32, max: i32) -> i32;
fn get_f32(&mut self, min: f32, max: f32) -> f32;
fn get_f64(&mut self, min: f64, max: f64) -> f64;
fn get_i32_mean(&mut self, min: i32, max: i32, mean: i32) -> i32;
fn get_f32_mean(&mut self, min: f32, max: f32, mean: f32) -> f32;
fn get_f64_mean(&mut self, min: f64, max: f64, mean: f64) -> f64;
}
#[derive(Clone, Debug)]
pub struct Random<A: Algorithm> {
algo: A,
pub distribution: Distribution,
y2: Option<f64>,
}
impl<A: Algorithm> Random<A> {
fn default_seed() -> u64 {
let now = SystemTime::now();
let duration_since = now.duration_since(SystemTime::UNIX_EPOCH).unwrap();
duration_since.as_secs()
}
fn get_i(&mut self, mut min: i32, mut max: i32) -> i32 {
match max.cmp(&min) {
Ordering::Less => std::mem::swap(&mut min, &mut max),
Ordering::Equal => return min,
Ordering::Greater => (),
}
let delta = max - min + 1;
(self.algo.get_int() % delta as u32) as i32 + min
}
fn get_f(&mut self, mut min: f32, mut max: f32) -> f32 {
if (max - min).abs() < 0.000_001 {
return min;
} else if max < min {
std::mem::swap(&mut min, &mut max);
}
let delta = max - min;
self.algo.get_float() * delta + min
}
fn get_d(&mut self, mut min: f64, mut max: f64) -> f64 {
if (max - min).abs() < 0.000_001 {
return min;
} else if max < min {
std::mem::swap(&mut min, &mut max);
}
let delta = max - min;
self.algo.get_double() * delta + min
}
fn get_gaussian_double(&mut self, mean: f64, std_deviation: f64) -> f64 {
if let Some(y2) = self.y2.take() {
return mean + y2 * std_deviation;
}
let (x1, x2, w) = loop {
let x1 = self.algo.get_double() * 2.0 - 1.0;
let x2 = self.algo.get_double() * 2.0 - 1.0;
let w = x1.powi(2) + x2.powi(2);
if w < 1.0 {
break (x1, x2, (-2.0 * w.ln() / w).sqrt());
}
};
let y1 = x1 * w;
self.y2 = Some(x2 * w);
mean + y1 * std_deviation
}
fn get_gaussian_float(&mut self, mean: f32, std_deviation: f32) -> f32 {
self.get_gaussian_double(f64::from(mean), f64::from(std_deviation)) as f32
}
fn get_gaussian_int(&mut self, mean: i32, std_deviation: i32) -> i32 {
self.get_gaussian_double(f64::from(mean), f64::from(std_deviation))
.round() as i32
}
fn get_gaussian_double_range(&mut self, mut min: f64, mut max: f64) -> f64 {
if max < min {
std::mem::swap(&mut min, &mut max);
}
let mean = (min + max) / 2.0;
let std_deviation = (max - min) / 6.0;
self.get_gaussian_double(mean, std_deviation)
.max(min)
.min(max)
}
fn get_gaussian_float_range(&mut self, min: f32, max: f32) -> f32 {
self.get_gaussian_double_range(f64::from(min), f64::from(max)) as f32
}
fn get_gaussian_int_range(&mut self, min: i32, max: i32) -> i32 {
self.get_gaussian_double_range(f64::from(min), f64::from(max))
.round() as i32
}
fn get_gaussian_double_range_custom(&mut self, mut min: f64, mut max: f64, mean: f64) -> f64 {
if max < min {
std::mem::swap(&mut min, &mut max);
}
let d1 = max - mean;
let d2 = mean - min;
let std_deviation = d1.max(d2) / 3.0;
self.get_gaussian_double(mean, std_deviation)
.max(min)
.min(max)
}
fn get_gaussian_float_range_custom(&mut self, min: f32, max: f32, mean: f32) -> f32 {
self.get_gaussian_double_range_custom(f64::from(min), f64::from(max), f64::from(mean))
as f32
}
fn get_gaussian_int_range_custom(&mut self, min: i32, max: i32, mean: i32) -> i32 {
(self
.get_gaussian_double_range_custom(f64::from(min), f64::from(max), f64::from(mean))
.round() as i32)
.max(min)
.min(max)
}
fn get_gaussian_double_inv(&mut self, mean: f64, std_deviation: f64) -> f64 {
let num = self.get_gaussian_double(mean, std_deviation);
if num >= mean {
num - 3.0 * std_deviation
} else {
num + 3.0 * std_deviation
}
}
fn get_gaussian_float_inv(&mut self, mean: f32, std_deviation: f32) -> f32 {
let num = self.get_gaussian_double(f64::from(mean), f64::from(std_deviation));
if num >= f64::from(mean) {
(num - 3.0 * f64::from(std_deviation)) as f32
} else {
(num + 3.0 * f64::from(std_deviation)) as f32
}
}
fn get_gaussian_int_inv(&mut self, mean: i32, std_deviation: i32) -> i32 {
let num = self.get_gaussian_double(f64::from(mean), f64::from(std_deviation));
let integer = num.round() as i32;
if num >= f64::from(mean) {
integer - 3 * std_deviation
} else {
integer + 3 * std_deviation
}
}
fn get_gaussian_double_range_inv(&mut self, mut min: f64, mut max: f64) -> f64 {
if max < min {
std::mem::swap(&mut min, &mut max);
}
let mean = (min + max) / 2.0;
let std_deviation = (max - min) / 6.0;
self.get_gaussian_double_inv(mean, std_deviation)
.max(min)
.min(max)
}
fn get_gaussian_float_range_inv(&mut self, min: f32, max: f32) -> f32 {
self.get_gaussian_double_range_inv(f64::from(min), f64::from(max)) as f32
}
fn get_gaussian_int_range_inv(&mut self, min: i32, max: i32) -> i32 {
(self
.get_gaussian_double_range_inv(f64::from(min), f64::from(max))
.round() as i32)
.max(min)
.min(max)
}
fn get_gaussian_double_range_custom_inv(
&mut self,
mut min: f64,
mut max: f64,
mean: f64,
) -> f64 {
if max < min {
std::mem::swap(&mut min, &mut max);
}
let d1 = max - mean;
let d2 = mean - min;
let std_deviation = d1.max(d2) / 3.0;
self.get_gaussian_double_inv(mean, std_deviation)
.max(min)
.min(max)
}
fn get_gaussian_float_range_custom_inv(&mut self, min: f32, max: f32, mean: f32) -> f32 {
self.get_gaussian_double_range_custom_inv(f64::from(min), f64::from(max), f64::from(mean))
as f32
}
fn get_gaussian_int_range_custom_inv(&mut self, min: i32, max: i32, mean: i32) -> i32 {
(self
.get_gaussian_double_range_custom_inv(f64::from(min), f64::from(max), f64::from(mean))
.round() as i32)
.max(min)
.min(max)
}
}
impl<A: Algorithm> Rng for Random<A> {
fn get_i32(&mut self, min: i32, max: i32) -> i32 {
match self.distribution {
Distribution::Linear => self.get_i(min, max),
Distribution::Gaussian => self.get_gaussian_int(min, max),
Distribution::GaussianRange => self.get_gaussian_int_range(min, max),
Distribution::GaussianInverse => self.get_gaussian_int_inv(min, max),
Distribution::GaussianRangeInverse => self.get_gaussian_int_range_inv(min, max),
}
}
fn get_f32(&mut self, min: f32, max: f32) -> f32 {
match self.distribution {
Distribution::Linear => self.get_f(min, max),
Distribution::Gaussian => self.get_gaussian_float(min, max),
Distribution::GaussianRange => self.get_gaussian_float_range(min, max),
Distribution::GaussianInverse => self.get_gaussian_float_inv(min, max),
Distribution::GaussianRangeInverse => self.get_gaussian_float_range_inv(min, max),
}
}
fn get_f64(&mut self, min: f64, max: f64) -> f64 {
match self.distribution {
Distribution::Linear => self.get_d(min, max),
Distribution::Gaussian => self.get_gaussian_double(min, max),
Distribution::GaussianRange => self.get_gaussian_double_range(min, max),
Distribution::GaussianInverse => self.get_gaussian_double_inv(min, max),
Distribution::GaussianRangeInverse => self.get_gaussian_double_range_inv(min, max),
}
}
fn get_i32_mean(&mut self, min: i32, max: i32, mean: i32) -> i32 {
match self.distribution {
Distribution::GaussianInverse | Distribution::GaussianRangeInverse => {
self.get_gaussian_int_range_custom_inv(min, max, mean)
}
_ => self.get_gaussian_int_range_custom(min, max, mean),
}
}
fn get_f32_mean(&mut self, min: f32, max: f32, mean: f32) -> f32 {
match self.distribution {
Distribution::GaussianInverse | Distribution::GaussianRangeInverse => {
self.get_gaussian_float_range_custom_inv(min, max, mean)
}
_ => self.get_gaussian_float_range_custom(min, max, mean),
}
}
fn get_f64_mean(&mut self, min: f64, max: f64, mean: f64) -> f64 {
match self.distribution {
Distribution::GaussianInverse | Distribution::GaussianRangeInverse => {
self.get_gaussian_double_range_custom_inv(min, max, mean)
}
_ => self.get_gaussian_double_range_custom(min, max, mean),
}
}
}
impl Random<MersenneTwister> {
pub fn new_mt() -> Self {
Self::new_mt_from_seed(Self::default_seed() as u32)
}
pub fn new_mt_from_seed(seed: u32) -> Self {
Self {
algo: MersenneTwister::new(seed),
distribution: Distribution::Linear,
y2: None,
}
}
}
impl Random<ComplementaryMultiplyWithCarry> {
pub fn new_cmwc() -> Self {
Self::new_cmwc_from_seed(Self::default_seed() as u32)
}
pub fn new_cmwc_from_seed(seed: u32) -> Self {
Self {
algo: ComplementaryMultiplyWithCarry::new(seed),
distribution: Distribution::Linear,
y2: None,
}
}
}
#[derive(Clone, Copy, Debug)]
pub enum Distribution {
Linear,
Gaussian,
GaussianRange,
GaussianInverse,
GaussianRangeInverse,
}
#[derive(Debug, Copy, Clone)]
pub struct Dice {
nb_rolls: i32,
nb_faces: i32,
multiplier: f32,
add_sub: f32,
}
impl Dice {
pub fn new<S: AsRef<str>>(s: S) -> Self {
let mut s = s.as_ref();
let multiplier = if let Some(m) = s.find(|c| c == '*' || c == 'x') {
let value = s[0..m].parse::<f32>().unwrap_or_default();
s = &s[m + 1..];
value
} else {
1.0
};
let r = s
.find(|c| c == 'd' || c == 'D')
.expect("Incorrect dice specification format");
let nb_rolls = s[0..r].parse::<i32>().unwrap_or_default();
s = &s[r + 1..];
let nb_faces = if let Some(f) = s.find(|c| c == '+' || c == '-') {
let value = s[0..f].parse::<i32>().unwrap_or_default();
s = &s[f..];
value
} else {
let value = s[0..].parse::<i32>().unwrap_or_default();
s = &s[s.len()..];
value
};
let add_sub = if s.is_empty() {
0.0
} else {
s[0..].parse::<f32>().unwrap_or_default()
};
Self {
multiplier,
nb_rolls,
nb_faces,
add_sub,
}
}
pub fn roll<R: Rng>(&self, mersenne: &mut R) -> i32 {
let mut result = 0;
for _ in 0..self.nb_rolls {
result += mersenne.get_i32(1, self.nb_faces);
}
((result as f32 + self.add_sub) * self.multiplier) as i32
}
pub fn single_roll<R: Rng, S: AsRef<str>>(mersenne: &mut R, s: S) -> i32 {
Self::new(s).roll(mersenne)
}
}
#[cfg(feature = "rng_support")]
impl<A: Algorithm> rand_core::RngCore for Random<A> {
fn next_u32(&mut self) -> u32 {
self.algo.get_int()
}
fn next_u64(&mut self) -> u64 {
use rand_core::impls;
impls::next_u64_via_u32(self)
}
fn fill_bytes(&mut self, dest: &mut [u8]) {
use rand_core::impls;
impls::fill_bytes_via_next(self, dest)
}
#[allow(clippy::unit_arg)] fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> {
Ok(self.fill_bytes(dest))
}
}
#[cfg(feature = "rng_support")]
impl rand_core::SeedableRng for Random<MersenneTwister> {
type Seed = [u8; 4];
fn from_seed(seed: Self::Seed) -> Self {
let seed = u32::from(seed[0]) << 24
| u32::from(seed[1]) << 16
| u32::from(seed[2]) << 8
| u32::from(seed[3]);
Self::new_mt_from_seed(seed)
}
}
#[cfg(feature = "rng_support")]
impl rand_core::SeedableRng for Random<ComplementaryMultiplyWithCarry> {
type Seed = [u8; 4];
fn from_seed(seed: Self::Seed) -> Self {
let seed = u32::from(seed[0]) << 24
| u32::from(seed[1]) << 16
| u32::from(seed[2]) << 8
| u32::from(seed[3]);
Self::new_cmwc_from_seed(seed)
}
}