rusty2048_core/
rng.rs

1use rand::rngs::StdRng;
2use rand::{Rng, SeedableRng};
3
4/// Game random number generator with seed support
5#[derive(Debug, Clone)]
6pub struct GameRng {
7    rng: StdRng,
8}
9
10impl GameRng {
11    /// Create a new RNG with optional seed
12    pub fn new(seed: Option<u64>) -> Self {
13        let rng = if let Some(seed) = seed {
14            StdRng::seed_from_u64(seed)
15        } else {
16            StdRng::from_entropy()
17        };
18
19        Self { rng }
20    }
21
22    /// Generate a random value between 0 and max (exclusive)
23    pub fn gen_range(&mut self, max: usize) -> usize {
24        if max == 0 {
25            return 0;
26        }
27        self.rng.gen_range(0..max)
28    }
29
30    /// Generate a random boolean with given probability
31    pub fn gen_bool(&mut self, probability: f64) -> bool {
32        self.rng.gen_bool(probability)
33    }
34
35    /// Generate a random tile value (2 or 4 with 90/10 probability)
36    pub fn gen_tile_value(&mut self) -> u32 {
37        if self.gen_bool(0.9) {
38            2
39        } else {
40            4
41        }
42    }
43
44    /// Get the current seed (if available)
45    pub fn get_seed(&self) -> Option<u64> {
46        // Note: This is a simplified implementation
47        // In a real implementation, you'd need to store the seed separately
48        None
49    }
50}
51
52impl Default for GameRng {
53    fn default() -> Self {
54        Self::new(None)
55    }
56}
57
58#[cfg(test)]
59mod tests {
60    use super::*;
61
62    #[test]
63    fn test_rng_with_seed() {
64        let mut rng1 = GameRng::new(Some(42));
65        let mut rng2 = GameRng::new(Some(42));
66
67        // Same seed should produce same sequence
68        for _ in 0..10 {
69            assert_eq!(rng1.gen_range(100), rng2.gen_range(100));
70        }
71    }
72
73    #[test]
74    fn test_tile_value_generation() {
75        let mut rng = GameRng::new(Some(123));
76        let mut twos = 0;
77        let mut fours = 0;
78
79        for _ in 0..1000 {
80            let value = rng.gen_tile_value();
81            match value {
82                2 => twos += 1,
83                4 => fours += 1,
84                _ => panic!("Unexpected tile value: {}", value),
85            }
86        }
87
88        // Should be roughly 90% twos and 10% fours
89        assert!(twos > 800 && twos < 950);
90        assert!(fours > 50 && fours < 200);
91    }
92}