Add WIP for generation of rules transitional_engine
authorunC0Rr
Fri, 03 Feb 2023 15:59:18 +0100
branchtransitional_engine
changeset 15947 60b5639cc3a5
parent 15946 e82de0410da5
child 15948 9bd828451d77
Add WIP for generation of rules
rust/landgen/src/wavefront_collapse/generator.rs
rust/landgen/src/wavefront_collapse/tile_image.rs
rust/landgen/src/wavefront_collapse/wavefront_collapse.rs
--- a/rust/landgen/src/wavefront_collapse/generator.rs	Fri Feb 03 14:44:33 2023 +0100
+++ b/rust/landgen/src/wavefront_collapse/generator.rs	Fri Feb 03 15:59:18 2023 +0100
@@ -1,20 +1,17 @@
 use super::tile_image::{Edge, TileImage};
-use super::wavefront_collapse::WavefrontCollapse;
+use super::wavefront_collapse::{CollapseRule, Tile, WavefrontCollapse};
 use crate::{LandGenerationParameters, LandGenerator};
 use integral_geometry::Size;
 use png::Decoder;
+use std::collections::HashSet;
 use std::fs::File;
 use std::io::BufReader;
 
-pub struct WavefrontCollapseLandGenerator {
-    wfc: WavefrontCollapse,
-}
+pub struct WavefrontCollapseLandGenerator {}
 
 impl WavefrontCollapseLandGenerator {
     pub fn new() -> Self {
-        Self {
-            wfc: WavefrontCollapse::default(),
-        }
+        Self {}
     }
 
     pub fn load_template<T: Copy + PartialEq + Default>(
@@ -75,7 +72,62 @@
     ) -> land2d::Land2D<T> {
         let tiles = self.load_template(parameters);
 
-        todo!()
+        let mut rules = Vec::<CollapseRule>::new();
+
+        let default_connection = HashSet::from_iter(vec![Tile::Outside, Tile::Empty].into_iter());
+        for (i, tile) in tiles.iter().enumerate() {
+            let mut right = default_connection.clone();
+            let mut bottom = default_connection.clone();
+            let mut left = default_connection.clone();
+            let mut top = default_connection.clone();
+
+            for p in 0..i {
+                if tiles[p].left_edge() == tile.right_edge() {
+                    rules[p].left.insert(Tile::Numbered(i));
+                    right.insert(Tile::Numbered(p));
+                }
+
+                if tiles[p].right_edge() == tile.left_edge() {
+                    rules[p].right.insert(Tile::Numbered(i));
+                    left.insert(Tile::Numbered(p));
+                }
+
+                if tiles[p].top_edge() == tile.bottom_edge() {
+                    rules[p].top.insert(Tile::Numbered(i));
+                    bottom.insert(Tile::Numbered(p));
+                }
+
+                if tiles[p].bottom_edge() == tile.top_edge() {
+                    rules[p].bottom.insert(Tile::Numbered(i));
+                    top.insert(Tile::Numbered(p));
+                }
+            }
+
+            rules.push(CollapseRule {
+                tile: Tile::Numbered(i),
+                top,
+                right,
+                bottom,
+                left,
+            });
+        }
+
+        let mut wfc = WavefrontCollapse::default();
+        wfc.set_rules(rules);
+
+        wfc.generate_map(&Size::new(40, 20), |_| {}, random_numbers);
+
+        let grid = wfc.grid();
+
+        for r in 0..grid.height() {
+            for c in 0..grid.width() {
+                print!("{:?}", grid.get(r, c));
+            }
+
+            println!();
+        }
+
+        todo!("build result")
     }
 }
 
--- a/rust/landgen/src/wavefront_collapse/tile_image.rs	Fri Feb 03 14:44:33 2023 +0100
+++ b/rust/landgen/src/wavefront_collapse/tile_image.rs	Fri Feb 03 15:59:18 2023 +0100
@@ -2,7 +2,7 @@
 use std::rc::Rc;
 use vec2d::Vec2D;
 
-#[derive(PartialEq, Clone)]
+#[derive(PartialEq, Clone, Debug)]
 pub struct Edge<I: PartialEq + Clone> {
     id: I,
     symmetrical: bool,
@@ -109,7 +109,78 @@
             left: self.bottom.clone(),
         }
     }
+
+    pub fn right_edge(&self) -> &Edge<I> {
+        &self.right
+    }
+
+    pub fn bottom_edge(&self) -> &Edge<I> {
+        &self.bottom
+    }
+
+    pub fn left_edge(&self) -> &Edge<I> {
+        &self.left
+    }
+
+    pub fn top_edge(&self) -> &Edge<I> {
+        &self.top
+    }
 }
 
 #[cfg(test)]
-mod tests {}
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_edge_new() {
+        let edge = Edge::new(1, true);
+        assert_eq!(edge.id, 1);
+        assert_eq!(edge.symmetrical, true);
+        assert_eq!(edge.reverse, false);
+    }
+
+    #[test]
+    fn test_edge_reversed() {
+        let edge = Edge::new(1, true);
+        let reversed = edge.reversed();
+        assert_eq!(reversed.id, edge.id);
+        assert_eq!(reversed.symmetrical, edge.symmetrical);
+        assert_eq!(reversed.reverse, false);
+
+        let edge = Edge::new(1, false);
+        let reversed = edge.reversed();
+        assert_eq!(reversed.id, edge.id);
+        assert_eq!(reversed.symmetrical, edge.symmetrical);
+        assert_eq!(reversed.reverse, true);
+    }
+
+    #[test]
+    fn test_edge_equality() {
+        let edge1 = Edge::new(1, true);
+        let edge2 = Edge::new(1, true);
+        assert_eq!(edge1, edge2);
+
+        let edge1 = Edge::new(1, false);
+        let edge2 = Edge::new(1, false);
+        assert_eq!(edge1, edge2);
+
+        let edge1 = Edge::new(1, false);
+        let edge2 = Edge::new(2, false);
+        assert_ne!(edge1, edge2);
+    }
+
+    #[test]
+    fn test_edge_equality_with_reverse() {
+        let edge1 = Edge::new(1, true);
+        let edge2 = edge1.reversed();
+        assert_eq!(edge1, edge2);
+
+        let edge1 = Edge::new(1, false);
+        let edge2 = edge1.reversed();
+        assert_ne!(edge1, edge2);
+
+        let edge1 = Edge::new(1, true);
+        let edge2 = edge1.reversed().reversed();
+        assert_eq!(edge1, edge2);
+    }
+}
--- a/rust/landgen/src/wavefront_collapse/wavefront_collapse.rs	Fri Feb 03 14:44:33 2023 +0100
+++ b/rust/landgen/src/wavefront_collapse/wavefront_collapse.rs	Fri Feb 03 15:59:18 2023 +0100
@@ -1,16 +1,16 @@
 use integral_geometry::Size;
-use std::collections::{HashMap, HashSet};
+use std::collections::HashSet;
 use vec2d::Vec2D;
 
 #[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
 pub enum Tile {
     Empty,
     Outside,
-    Numbered(u32),
+    Numbered(usize),
 }
 
 impl Tile {
-    fn is(&self, i: u32) -> bool {
+    fn is(&self, i: usize) -> bool {
         *self == Tile::Numbered(i)
     }
 
@@ -22,7 +22,7 @@
         }
     }
 
-    fn is_empty_or(&self, i: u32) -> bool {
+    fn is_empty_or(&self, i: usize) -> bool {
         match self {
             Tile::Numbered(n) => *n == i,
             Tile::Empty => true,
@@ -30,7 +30,7 @@
         }
     }
 
-    fn is_void_or(&self, i: u32) -> bool {
+    fn is_void_or(&self, i: usize) -> bool {
         match self {
             Tile::Numbered(n) => *n == i,
             _ => true,
@@ -44,12 +44,13 @@
     }
 }
 
+#[derive(Debug)]
 pub struct CollapseRule {
-    tile: Tile,
-    right: HashSet<Tile>,
-    bottom: HashSet<Tile>,
-    left: HashSet<Tile>,
-    top: HashSet<Tile>,
+    pub tile: Tile,
+    pub right: HashSet<Tile>,
+    pub bottom: HashSet<Tile>,
+    pub left: HashSet<Tile>,
+    pub top: HashSet<Tile>,
 }
 
 pub struct WavefrontCollapse {
@@ -80,7 +81,11 @@
         while self.collapse_step(random_numbers) {}
     }
 
-    fn add_rule(&mut self, rule: CollapseRule) {
+    pub fn set_rules(&mut self, rules: Vec<CollapseRule>) {
+        self.rules = rules;
+    }
+
+    pub fn add_rule(&mut self, rule: CollapseRule) {
         self.rules.push(rule);
     }
 
@@ -120,21 +125,30 @@
                         .collect();
 
                     let entropy = possibilities.len();
-                    if entropy > 0 && entropy <= tiles_to_collapse.0 {
-                        let entry = (
-                            y,
-                            x,
-                            possibilities
-                                [random_numbers.next().unwrap_or_default() as usize % entropy],
-                        );
+                    if entropy > 0 {
+                        if entropy <= tiles_to_collapse.0 {
+                            let entry = (
+                                y,
+                                x,
+                                possibilities
+                                    [random_numbers.next().unwrap_or_default() as usize % entropy],
+                            );
 
-                        if entropy < tiles_to_collapse.0 {
-                            tiles_to_collapse = (entropy, vec![entry])
-                        } else {
-                            tiles_to_collapse.1.push(entry)
+                            if entropy < tiles_to_collapse.0 {
+                                tiles_to_collapse = (entropy, vec![entry])
+                            } else {
+                                tiles_to_collapse.1.push(entry)
+                            }
                         }
                     } else {
-                        todo!("no collapse possible")
+                        println!("We're here: {}, {}", x, y);
+                        println!(
+                            "Neighbour tiles are: {:?} {:?} {:?} {:?}",
+                            right_tile, bottom_tile, left_tile, top_tile
+                        );
+                        println!("Rules are: {:?}", self.rules);
+
+                        todo!("no collapse possible - what to do?")
                     }
                 }
             }
@@ -157,6 +171,10 @@
             false
         }
     }
+
+    pub fn grid(&self) -> &Vec2D<Tile> {
+        &self.grid
+    }
 }
 
 #[cfg(test)]
@@ -168,11 +186,13 @@
     #[test]
     fn test_wavefront_collapse() {
         let size = Size::new(4, 4);
-        let mut rnd = [0u32; 64].into_iter();
+        let mut rnd = [0u32; 64].into_iter().cycle();
         let mut wfc = WavefrontCollapse::default();
 
+        wfc.generate_map(&size, |_| {}, &mut rnd);
+
         let empty_land = Vec2D::new(&size, Tile::Empty);
 
-        assert_eq!(empty_land.as_slice(), wfc.grid.as_slice());
+        assert_eq!(empty_land.as_slice(), wfc.grid().as_slice());
     }
 }