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}