notan_random/
utils.rs

1use rand::seq::SliceRandom;
2use rand::SeedableRng;
3use rand_pcg::Pcg32;
4use std::ops::{Deref, DerefMut};
5
6/// Wrapper around a random generator based on Pcg32.
7#[derive(Clone)]
8pub struct Random {
9    rng: Pcg32,
10}
11
12impl Random {
13    pub fn new(seed: u64) -> Self {
14        Self {
15            rng: Pcg32::seed_from_u64(seed),
16        }
17    }
18
19    pub fn reseed(&mut self, seed: u64) {
20        self.rng = Pcg32::seed_from_u64(seed);
21    }
22}
23
24impl Deref for Random {
25    type Target = Pcg32;
26    fn deref(&self) -> &Self::Target {
27        &self.rng
28    }
29}
30
31impl DerefMut for Random {
32    fn deref_mut(&mut self) -> &mut Self::Target {
33        &mut self.rng
34    }
35}
36
37impl Default for Random {
38    fn default() -> Self {
39        Self {
40            rng: Pcg32::from_entropy(),
41        }
42    }
43}
44
45/// Returns a random number for a predefined bag of them
46pub struct ShuffleBag<T>
47where
48    T: Sized + Clone,
49{
50    rng: Random,
51    index: usize,
52    items: Vec<T>,
53    bag: Vec<usize>,
54}
55
56impl<T> ShuffleBag<T>
57where
58    T: Sized + Clone,
59{
60    /// Create a new ShuffleBag using a random seed
61    pub fn new(capacity: usize) -> Self {
62        Self::new_with_random(Random::default(), capacity)
63    }
64
65    pub fn new_with_random(rng: Random, capacity: usize) -> Self {
66        Self {
67            rng,
68            index: 0,
69            items: vec![],
70            bag: Vec::with_capacity(capacity),
71        }
72    }
73
74    /// Adds a new value to the bag
75    pub fn add(&mut self, item: T, amount: usize) {
76        self.items.push(item);
77        let index = self.items.len() - 1;
78        self.bag.extend_from_slice(&vec![index; amount]);
79        self.reset();
80    }
81
82    /// Returns the next value from the bag
83    pub fn item(&mut self) -> Option<&T> {
84        if self.items.is_empty() {
85            return None;
86        }
87
88        if self.index >= self.bag.len() {
89            self.reset();
90        }
91
92        let item = &self.items[self.bag[self.index]];
93        self.index += 1;
94        Some(item)
95    }
96
97    /// Reset the bag to the initial state
98    pub fn reset(&mut self) {
99        self.bag.shuffle(&mut self.rng.rng);
100        self.index = 0;
101    }
102}