thedes_gen/
matter.rs

1use std::array;
2
3use rand::Rng;
4use rand_distr::Distribution;
5use thedes_domain::matter::Biome;
6
7use super::random::ProabilityWeight;
8
9#[derive(Debug, Clone)]
10pub struct BiomeDistr {
11    cumulative_weights: [ProabilityWeight; Biome::COUNT],
12}
13
14impl Default for BiomeDistr {
15    fn default() -> Self {
16        Self::new(|ground| match ground {
17            Biome::Plains => 11,
18            Biome::Desert => 5,
19            Biome::Wasteland => 4,
20        })
21    }
22}
23
24impl BiomeDistr {
25    pub fn new<F>(mut density_function: F) -> Self
26    where
27        F: FnMut(Biome) -> ProabilityWeight,
28    {
29        let mut accumuled_weight = 0;
30        let cumulative_weights = array::from_fn(|i| {
31            accumuled_weight += density_function(Biome::ALL[i]);
32            accumuled_weight
33        });
34        Self { cumulative_weights }
35    }
36}
37
38impl Distribution<Biome> for BiomeDistr {
39    fn sample<R>(&self, rng: &mut R) -> Biome
40    where
41        R: Rng + ?Sized,
42    {
43        let last_cumulative_weight =
44            self.cumulative_weights[self.cumulative_weights.len() - 1];
45        let sampled_weight = rng.random_range(0 .. last_cumulative_weight);
46        for (i, cumulative_weight) in
47            self.cumulative_weights.into_iter().enumerate()
48        {
49            if sampled_weight < cumulative_weight {
50                return Biome::ALL[i];
51            }
52        }
53        panic!("sampled weight {sampled_weight} is out of requested bounds")
54    }
55}