1use rand::rngs::StdRng;
2use rand::{Rng, SeedableRng};
3
4#[derive(Debug, Clone)]
6pub struct GameRng {
7 rng: StdRng,
8}
9
10impl GameRng {
11 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 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 pub fn gen_bool(&mut self, probability: f64) -> bool {
32 self.rng.gen_bool(probability)
33 }
34
35 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 pub fn get_seed(&self) -> Option<u64> {
46 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 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 assert!(twos > 800 && twos < 950);
90 assert!(fours > 50 && fours < 200);
91 }
92}