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