mcts_lib/
random.rs

1use rand::{Rng, random};
2
3const MULTIPLIER_A: i64 = 1103515245;
4const INCREMENT_C: i64 = 12345;
5const DEFAULT_SEED: i64 = 3819201;
6
7/// A trait for random number generation.
8///
9/// This allows for different random number generation strategies to be used with the MCTS search,
10/// which is particularly useful for testing and ensuring reproducibility.
11pub trait RandomGenerator: Default {
12    /// Returns the next random `i32`.
13    fn next(&mut self) -> i32;
14    /// Returns a random `i32` within the specified range (exclusive of `to`).
15    fn next_range(&mut self, from: i32, to: i32) -> i32;
16
17    /// Selects a random element from a vector.
18    fn get_random_from_vec<'a, K>(&mut self, vec: &'a Vec<K>) -> &'a K {
19        vec.get(self.next_range(0, vec.len() as i32) as usize)
20            .unwrap()
21    }
22}
23
24/// A `RandomGenerator` that uses the `rand` crate for random number generation.
25pub struct StandardRandomGenerator;
26
27impl Default for StandardRandomGenerator {
28    fn default() -> Self {
29        StandardRandomGenerator
30    }
31}
32
33impl RandomGenerator for StandardRandomGenerator {
34    fn next(&mut self) -> i32 {
35        random()
36    }
37
38    fn next_range(&mut self, from: i32, to: i32) -> i32 {
39        rand::rng().random_range(from..to)
40    }
41}
42
43/// A deterministic pseudo-random number generator.
44///
45/// This generator is useful for testing, as it will always produce the same sequence of numbers
46/// for a given seed.
47pub struct CustomNumberGenerator {
48    seed: i64,
49}
50
51impl Default for CustomNumberGenerator {
52    fn default() -> Self {
53        CustomNumberGenerator::new(DEFAULT_SEED)
54    }
55}
56
57impl RandomGenerator for CustomNumberGenerator {
58    fn next(&mut self) -> i32 {
59        self.seed = (self.seed * MULTIPLIER_A + INCREMENT_C) % (i32::MAX as i64);
60        self.seed as i32
61    }
62
63    fn next_range(&mut self, from: i32, to: i32) -> i32 {
64        (self.next() % (to - from)).abs() + from
65    }
66}
67
68impl CustomNumberGenerator {
69    /// Creates a new `CustomNumberGenerator` with the specified seed.
70    pub const fn new(seed: i64) -> Self {
71        Self { seed }
72    }
73}
74
75#[cfg(test)]
76mod tests {
77    use crate::random::{CustomNumberGenerator, RandomGenerator};
78
79    #[test]
80    fn outputs_same_numbers() {
81        let mut crg = CustomNumberGenerator::new(42);
82        assert_eq!(crg.next_range(0, 10), 8);
83        assert_eq!(crg.next_range(0, 10), 4);
84        assert_eq!(crg.next_range(0, 10), 1);
85        assert_eq!(crg.next_range(0, 10), 2);
86        assert_eq!(crg.next_range(0, 10), 4);
87    }
88
89    #[test]
90    fn random_from_vec_should_be_same() {
91        let vec = vec![432, 6542, 534, 6, 13, 645, 88, 2352, 345, 2667, 8287];
92        let mut crg = CustomNumberGenerator::default();
93        assert_eq!(*crg.get_random_from_vec(&vec), 6);
94        assert_eq!(*crg.get_random_from_vec(&vec), 2667);
95        assert_eq!(*crg.get_random_from_vec(&vec), 534);
96        assert_eq!(*crg.get_random_from_vec(&vec), 8287);
97        assert_eq!(*crg.get_random_from_vec(&vec), 6);
98    }
99}