1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
use num::rational::Ratio;
use num::{Bounded, Integer};
use rand;
use rand::distributions::range::SampleRange;
use rand::Rng;
use std::fmt::Display;
pub trait Choose<T> {
fn choose(&self) -> Option<&T>;
fn choose_index(&self) -> Option<usize>;
fn choose_enumerate(&self) -> Option<(usize, &T)>;
}
impl<T> Choose<T> for Vec<T> {
fn choose(&self) -> Option<&T> {
rand::thread_rng().choose(self)
}
fn choose_index(&self) -> Option<usize> {
if !self.is_empty() {
Some(rand_int(0, self.len() - 1))
} else {
None
}
}
fn choose_enumerate(&self) -> Option<(usize, &T)> {
let i = self.choose_index();
match i {
Some(i) => Some((i, &self[i])),
None => None,
}
}
}
pub fn rand_int<T>(x: T, y: T) -> T
where
T: Integer + SampleRange,
{
rand::thread_rng().gen_range(x, y + T::one())
}
pub fn rand_ratio<T>(x: T, y: T, d: T) -> Ratio<T>
where
T: Clone + Copy + Integer + SampleRange,
{
Ratio::new(rand_int(x * d, y * d), d)
}
pub fn dice<T>(x: T, y: T) -> bool
where
T: Copy + Display + Integer + SampleRange,
{
debug_assert!(x <= y, format!("Assert failed: dice({}, {})", x, y));
rand_int(T::one(), y) <= x
}
pub fn chance<T>(x: Ratio<T>) -> bool
where
T: Bounded + Clone + Copy + Integer + SampleRange,
{
let max = T::max_value() - T::one();
Ratio::new(rand_int(T::min_value(), max), max) <= x
}
#[cfg(test)]
mod tests {
use super::*;
use crate::util::math::between;
#[test]
fn test_rand_int() {
for _ in 1..100 {
let (a, b) = (rand_int(0, 1000), rand_int(0, 1000));
assert!(between(rand_int(a.min(b), a.max(b)), a, b))
}
}
#[test]
fn test_dice() {
for _ in 1..100 {
assert!(!dice(0, rand_int(1, 100)));
}
}
}