rust/landgen/src/wavefront_collapse/generator.rs
changeset 16059 2acea266d297
parent 16058 de01be16df95
child 16062 288df7b85efc
--- a/rust/landgen/src/wavefront_collapse/generator.rs	Sat Jan 18 16:57:26 2025 +0100
+++ b/rust/landgen/src/wavefront_collapse/generator.rs	Tue Jan 21 22:10:55 2025 +0100
@@ -9,14 +9,14 @@
 use std::io::{BufReader, Result};
 use std::path::{Path, PathBuf};
 
-#[derive(Clone)]
+#[derive(Debug, Clone)]
 pub struct EdgeDescription {
     pub name: String,
     pub reversed: Option<bool>,
     pub symmetrical: Option<bool>,
 }
 
-#[derive(Clone)]
+#[derive(Debug, Clone)]
 pub struct EdgesDescription {
     pub top: EdgeDescription,
     pub right: EdgeDescription,
@@ -24,7 +24,7 @@
     pub left: EdgeDescription,
 }
 
-#[derive(Clone)]
+#[derive(Debug, Clone)]
 pub struct TileDescription {
     pub name: String,
     pub edges: EdgesDescription,
@@ -36,19 +36,26 @@
     pub can_rotate270: Option<bool>,
 }
 
-#[derive(Clone)]
-pub struct NonStrictEdgesDescription {
-    pub top: Option<EdgeDescription>,
-    pub right: Option<EdgeDescription>,
-    pub bottom: Option<EdgeDescription>,
-    pub left: Option<EdgeDescription>,
+#[derive(Debug, Clone)]
+pub struct ComplexEdgeDescription {
+    pub begin: Option<EdgeDescription>,
+    pub fill: Option<EdgeDescription>,
+    pub end: Option<EdgeDescription>,
 }
 
-#[derive(Clone)]
+#[derive(Debug, Clone)]
+pub struct NonStrictComplexEdgesDescription {
+    pub top: Option<ComplexEdgeDescription>,
+    pub right: Option<ComplexEdgeDescription>,
+    pub bottom: Option<ComplexEdgeDescription>,
+    pub left: Option<ComplexEdgeDescription>,
+}
+
+#[derive(Debug, Clone)]
 pub struct TemplateDescription {
     pub size: Size,
     pub tiles: Vec<TileDescription>,
-    pub edges: NonStrictEdgesDescription,
+    pub edges: NonStrictComplexEdgesDescription,
     pub wrap: bool,
 }
 
@@ -79,7 +86,7 @@
                 .as_path(),
         )?;
         let decoder = Decoder::new(BufReader::new(file));
-        let mut reader = decoder.read_info().unwrap();
+        let mut reader = decoder.read_info()?;
 
         let info = reader.info();
         let mut tiles_image = vec2d::Vec2D::new(
@@ -88,7 +95,7 @@
         );
 
         let mut buf = vec![0; reader.output_buffer_size()];
-        let info = reader.next_frame(&mut buf).unwrap();
+        let info = reader.next_frame(&mut buf)?;
         let bytes = &buf[..info.buffer_size()];
 
         let mut tiles_image_pixels = tiles_image.as_mut_slice().iter_mut();
@@ -183,14 +190,14 @@
         probability_distribution_factor: i32,
     ) -> Vec<CollapseRule> {
         let [grid_top_edge, grid_right_edge, grid_bottom_edge, grid_left_edge]: [Option<
-            Edge<String>,
+            [Option<Edge<String>>; 3],
         >; 4] = [
             self.template.edges.top.as_ref(),
             self.template.edges.right.as_ref(),
             self.template.edges.bottom.as_ref(),
             self.template.edges.left.as_ref(),
         ]
-        .map(|opt| opt.map(|d| d.into()));
+        .map(|opt| opt.map(|d| [&d.begin, &d.fill, &d.end].map(|e| e.as_ref().map(Into::into))));
 
         let mut rules = Vec::<CollapseRule>::new();
 
@@ -201,34 +208,32 @@
             let mut left = default_connection.clone();
             let mut top = default_connection.clone();
 
+            let iteration = [
+                (&grid_top_edge, tile.top_edge(), &mut top),
+                (&grid_right_edge, tile.right_edge(), &mut right),
+                (&grid_bottom_edge, tile.bottom_edge(), &mut bottom),
+                (&grid_left_edge, tile.left_edge(), &mut left),
+            ];
+
             // compatibility with grid edges
-            if grid_top_edge
-                .as_ref()
-                .map(|e| e.is_compatible(tile.top_edge()))
-                .unwrap_or(true)
-            {
-                top.insert(Tile::Outside);
-            }
-            if grid_right_edge
-                .as_ref()
-                .map(|e| e.is_compatible(tile.right_edge()))
-                .unwrap_or(true)
-            {
-                right.insert(Tile::Outside);
-            }
-            if grid_bottom_edge
-                .as_ref()
-                .map(|e| e.is_compatible(tile.bottom_edge()))
-                .unwrap_or(true)
-            {
-                bottom.insert(Tile::Outside);
-            }
-            if grid_left_edge
-                .as_ref()
-                .map(|e| e.is_compatible(tile.left_edge()))
-                .unwrap_or(true)
-            {
-                left.insert(Tile::Outside);
+            for (edge, tile_edge, set) in iteration {
+                for (is_compatible, tile) in edge
+                    .as_ref()
+                    .map(|e| {
+                        e.clone().map(|ed| {
+                            ed.as_ref()
+                                .map(|e| e.is_compatible(tile_edge))
+                                .unwrap_or(true)
+                        })
+                    })
+                    .unwrap_or([true, true, true])
+                    .into_iter()
+                    .zip([Tile::OutsideBegin, Tile::OutsideFill, Tile::OutsideEnd].into_iter())
+                {
+                    if is_compatible {
+                        set.insert(tile);
+                    }
+                }
             }
 
             // compatibility with itself
@@ -244,21 +249,25 @@
 
             // compatibility with previously defined tiles
             for p in 0..i {
+                // Check left edge
                 if tiles[p].left_edge().is_compatible(tile.right_edge()) {
                     rules[p].left.insert(Tile::Numbered(i));
                     right.insert(Tile::Numbered(p));
                 }
 
+                // Check right edge
                 if tiles[p].right_edge().is_compatible(tile.left_edge()) {
                     rules[p].right.insert(Tile::Numbered(i));
                     left.insert(Tile::Numbered(p));
                 }
 
+                // Check top edge
                 if tiles[p].top_edge().is_compatible(tile.bottom_edge()) {
                     rules[p].top.insert(Tile::Numbered(i));
                     bottom.insert(Tile::Numbered(p));
                 }
 
+                // Check bottom edge
                 if tiles[p].bottom_edge().is_compatible(tile.top_edge()) {
                     rules[p].bottom.insert(Tile::Numbered(i));
                     top.insert(Tile::Numbered(p));