rust/landgen/src/wavefront_collapse/wavefront_collapse.rs
changeset 16058 de01be16df95
parent 15925 b0e8cc72bfef
child 16059 2acea266d297
--- a/rust/landgen/src/wavefront_collapse/wavefront_collapse.rs	Sat Jan 18 16:55:04 2025 +0100
+++ b/rust/landgen/src/wavefront_collapse/wavefront_collapse.rs	Sat Jan 18 16:57:26 2025 +0100
@@ -1,4 +1,7 @@
 use integral_geometry::Size;
+use rand::distributions::Distribution;
+use rand::distributions::WeightedIndex;
+use rand::Rng;
 use std::collections::HashSet;
 use vec2d::Vec2D;
 
@@ -17,6 +20,7 @@
 
 #[derive(Debug)]
 pub struct CollapseRule {
+    pub weight: u32,
     pub tile: Tile,
     pub right: HashSet<Tile>,
     pub bottom: HashSet<Tile>,
@@ -49,11 +53,11 @@
         }
     }
 
-    pub fn generate_map<I: Iterator<Item = u32>, F: FnOnce(&mut Vec2D<Tile>)>(
+    pub fn generate_map<F: FnOnce(&mut Vec2D<Tile>)>(
         &mut self,
         map_size: &Size,
         seed_fn: F,
-        random_numbers: &mut I,
+        random_numbers: &mut impl Rng,
     ) {
         self.grid = Vec2D::new(map_size, Tile::Empty);
 
@@ -82,7 +86,7 @@
         self.grid.get(y, x).copied().unwrap_or_default()
     }
 
-    fn collapse_step<I: Iterator<Item = u32>>(&mut self, random_numbers: &mut I) -> bool {
+    fn collapse_step(&mut self, random_numbers: &mut impl Rng) -> bool {
         let mut tiles_to_collapse = (usize::max_value(), Vec::new());
 
         // Iterate through the tiles in the land
@@ -97,7 +101,7 @@
                     let left_tile = self.get_tile(y, x.wrapping_sub(1));
                     let top_tile = self.get_tile(y.wrapping_sub(1), x);
 
-                    let possibilities: Vec<Tile> = self
+                    let possibilities: Vec<(u32, Tile)> = self
                         .rules
                         .iter()
                         .filter_map(|rule| {
@@ -106,7 +110,7 @@
                                 && rule.left.contains(&left_tile)
                                 && rule.top.contains(&top_tile)
                             {
-                                Some(rule.tile)
+                                Some((rule.weight, rule.tile))
                             } else {
                                 None
                             }
@@ -116,12 +120,10 @@
                     let entropy = possibilities.len();
                     if entropy > 0 {
                         if entropy <= tiles_to_collapse.0 {
-                            let entry = (
-                                y,
-                                x,
-                                possibilities
-                                    [random_numbers.next().unwrap_or_default() as usize % entropy],
-                            );
+                            let weights = possibilities.iter().map(|(weight, _)| *weight);
+                            let distribution = WeightedIndex::new(weights).unwrap();
+
+                            let entry = (y, x, possibilities[distribution.sample(random_numbers)]);
 
                             if entropy < tiles_to_collapse.0 {
                                 tiles_to_collapse = (entropy, vec![entry])
@@ -147,8 +149,10 @@
         let possibilities_number = tiles_to_collapse.len();
 
         if possibilities_number > 0 {
-            let (y, x, tile) = tiles_to_collapse
-                [random_numbers.next().unwrap_or_default() as usize % possibilities_number];
+            let weights = tiles_to_collapse.iter().map(|(_, _, (weight, _))| *weight);
+            let distribution = WeightedIndex::new(weights).unwrap();
+
+            let (y, x, (_, tile)) = tiles_to_collapse[distribution.sample(random_numbers)];
 
             *self
                 .grid