initiative_core/world/
mod.rs

1pub mod demographics;
2pub mod npc;
3pub mod place;
4pub mod thing;
5
6pub use command::{ParsedThing, WorldCommand};
7pub use demographics::Demographics;
8pub use field::Field;
9
10mod command;
11mod field;
12mod word;
13
14use rand::Rng;
15
16pub trait Generate: Default {
17    fn generate(rng: &mut impl Rng, demographics: &Demographics) -> Self {
18        let mut result = Self::default();
19        result.regenerate(rng, demographics);
20        result
21    }
22
23    fn regenerate(&mut self, rng: &mut impl Rng, demographics: &Demographics);
24}
25
26fn weighted_index_from_tuple<'a, T>(rng: &mut impl Rng, input: &'a [(T, usize)]) -> &'a T {
27    let total = input.iter().map(|(_, n)| n).sum();
28
29    if total == 0 {
30        panic!("Empty input.");
31    }
32
33    let target = rng.gen_range(0..total);
34    let mut acc = 0;
35
36    for (value, frequency) in input {
37        acc += frequency;
38        if acc > target {
39            return value;
40        }
41    }
42
43    unreachable!();
44}
45
46#[cfg(test)]
47mod test {
48    use super::*;
49    use rand::prelude::*;
50
51    #[test]
52    fn weighted_index_from_tuple_test() {
53        let input = [('a', 1), ('b', 3), ('c', 5)];
54        let mut rng = SmallRng::seed_from_u64(0);
55        assert_eq!(
56            vec!['c', 'c', 'c', 'c', 'c', 'c', 'b', 'c', 'b', 'a'],
57            (0..10)
58                .map(|_| weighted_index_from_tuple(&mut rng, &input[..]))
59                .copied()
60                .collect::<Vec<_>>()
61        );
62    }
63
64    #[test]
65    fn weighted_index_from_tuple_test_one() {
66        let input = [(true, 1)];
67        let mut rng = SmallRng::seed_from_u64(0);
68        assert_eq!(
69            vec![true, true, true],
70            (0..3)
71                .map(|_| weighted_index_from_tuple(&mut rng, &input[..]))
72                .copied()
73                .collect::<Vec<_>>()
74        );
75    }
76
77    #[test]
78    #[should_panic]
79    fn weighted_index_from_tuple_test_empty() {
80        let input: [(bool, usize); 0] = [];
81        weighted_index_from_tuple(&mut SmallRng::seed_from_u64(0), &input[..]);
82    }
83
84    #[test]
85    #[should_panic]
86    fn weighted_index_from_tuple_test_zero() {
87        let input = [(true, 0), (false, 0)];
88        weighted_index_from_tuple(&mut SmallRng::seed_from_u64(0), &input[..]);
89    }
90}