initiative_core/world/npc/species/
elf.rs

1use super::{Age, Gender, Generate, Size};
2use rand::prelude::*;
3
4pub struct Species;
5
6impl Generate for Species {
7    fn gen_gender(rng: &mut impl Rng) -> Gender {
8        match rng.gen_range(1..=101) {
9            1..=50 => Gender::Feminine,
10            51..=100 => Gender::Masculine,
11            101 => Gender::NonBinaryThey,
12            _ => unreachable!(),
13        }
14    }
15
16    fn gen_age_years(rng: &mut impl Rng) -> u16 {
17        rng.gen_range(0..=800)
18    }
19
20    fn gen_years_from_age(rng: &mut impl Rng, age: &Age) -> u16 {
21        rng.gen_range(match age {
22            Age::Infant => 0..=1,
23            Age::Child => 2..=9,
24            Age::Adolescent => 10..=99,
25            Age::YoungAdult => 100..=199,
26            Age::Adult => 200..=299,
27            Age::MiddleAged => 300..=499,
28            Age::Elderly => 500..=749,
29            Age::Geriatric => 750..=800,
30        })
31    }
32
33    fn age_from_years(years: u16) -> Age {
34        match years {
35            i if i < 2 => Age::Infant,
36            i if i < 10 => Age::Child,
37            i if i < 100 => Age::Adolescent,
38            i if i < 200 => Age::YoungAdult,
39            i if i < 300 => Age::Adult,
40            i if i < 500 => Age::MiddleAged,
41            i if i < 750 => Age::Elderly,
42            _ => Age::Geriatric,
43        }
44    }
45
46    fn gen_size(rng: &mut impl Rng, _age_years: u16, _gender: &Gender) -> Size {
47        let size = rng.gen_range(1..=12) + rng.gen_range(1..=12);
48        Size::Medium {
49            height: 54 + size,
50            weight: 60 + size * 6,
51        }
52    }
53}
54
55#[cfg(test)]
56mod test_generate_for_species {
57    use super::*;
58    use std::collections::HashMap;
59
60    #[test]
61    fn gen_gender_test() {
62        let mut rng = SmallRng::seed_from_u64(0);
63        let mut genders: HashMap<String, u16> = HashMap::new();
64
65        for _ in 0..500 {
66            let gender = Species::gen_gender(&mut rng);
67            *genders.entry(format!("{}", gender)).or_default() += 1;
68        }
69
70        assert_eq!(3, genders.len());
71        assert_eq!(Some(&3), genders.get("non-binary (they/them)"));
72        assert_eq!(Some(&233), genders.get("feminine (she/her)"));
73        assert_eq!(Some(&264), genders.get("masculine (he/him)"));
74    }
75
76    #[test]
77    fn gen_age_years_test() {
78        let mut rng = SmallRng::seed_from_u64(0);
79
80        assert_eq!(
81            [358, 351, 784, 370, 718],
82            [
83                Species::gen_age_years(&mut rng),
84                Species::gen_age_years(&mut rng),
85                Species::gen_age_years(&mut rng),
86                Species::gen_age_years(&mut rng),
87                Species::gen_age_years(&mut rng),
88            ],
89        );
90    }
91
92    #[test]
93    fn gen_years_from_age_test() {
94        let ages = [
95            Age::Infant,
96            Age::Child,
97            Age::Adolescent,
98            Age::YoungAdult,
99            Age::Adult,
100            Age::MiddleAged,
101            Age::Elderly,
102            Age::Geriatric,
103        ];
104
105        for age in ages {
106            let mut rng = SmallRng::seed_from_u64(0);
107
108            for _ in 0..10 {
109                let age_years = Species::gen_years_from_age(&mut rng, &age);
110                assert_eq!(age, Species::age_from_years(age_years));
111            }
112        }
113    }
114
115    #[test]
116    fn age_from_years_test() {
117        assert_eq!(Age::Infant, Species::age_from_years(0));
118        assert_eq!(Age::Infant, Species::age_from_years(1));
119
120        assert_eq!(Age::Child, Species::age_from_years(2));
121        assert_eq!(Age::Child, Species::age_from_years(9));
122
123        assert_eq!(Age::Adolescent, Species::age_from_years(10));
124        assert_eq!(Age::Adolescent, Species::age_from_years(99));
125
126        assert_eq!(Age::YoungAdult, Species::age_from_years(100));
127        assert_eq!(Age::YoungAdult, Species::age_from_years(199));
128
129        assert_eq!(Age::Adult, Species::age_from_years(200));
130        assert_eq!(Age::Adult, Species::age_from_years(299));
131
132        assert_eq!(Age::MiddleAged, Species::age_from_years(300));
133        assert_eq!(Age::MiddleAged, Species::age_from_years(499));
134
135        assert_eq!(Age::Elderly, Species::age_from_years(500));
136        assert_eq!(Age::Elderly, Species::age_from_years(749));
137
138        assert_eq!(Age::Geriatric, Species::age_from_years(750));
139        assert_eq!(Age::Geriatric, Species::age_from_years(u16::MAX));
140    }
141
142    #[test]
143    fn gen_size_test() {
144        let mut rng = SmallRng::seed_from_u64(0);
145        let t = Gender::NonBinaryThey;
146
147        let size = |height, weight| Size::Medium { height, weight };
148
149        assert_eq!(
150            [
151                size(66, 132),
152                size(72, 168),
153                size(77, 198),
154                size(68, 144),
155                size(69, 150),
156            ],
157            [
158                Species::gen_size(&mut rng, 0, &t),
159                Species::gen_size(&mut rng, 0, &t),
160                Species::gen_size(&mut rng, 0, &t),
161                Species::gen_size(&mut rng, 0, &t),
162                Species::gen_size(&mut rng, 0, &t),
163            ]
164        );
165    }
166}