Introduce hard match option for edges to reduce backtracking default tip
authorunC0Rr
Sun, 02 Feb 2025 22:30:49 +0100
changeset 16080 2fc37552b587
parent 16079 65c017453e83
Introduce hard match option for edges to reduce backtracking
rust/landgen/src/wavefront_collapse/generator.rs
rust/landgen/src/wavefront_collapse/tile_image.rs
share/hedgewars/Data/wfc_templates.toml
--- a/rust/landgen/src/wavefront_collapse/generator.rs	Sun Feb 02 17:47:54 2025 +0100
+++ b/rust/landgen/src/wavefront_collapse/generator.rs	Sun Feb 02 22:30:49 2025 +0100
@@ -14,6 +14,7 @@
     pub name: String,
     pub reversed: Option<bool>,
     pub symmetrical: Option<bool>,
+    pub hard_match: Option<bool>,
 }
 
 #[derive(Debug, Clone)]
@@ -206,12 +207,11 @@
 
         let mut rules = Vec::<CollapseRule>::new();
 
-        let default_connection = HashSet::from_iter(vec![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();
+            let mut top = HashSet::new();
+            let mut right = HashSet::new();
+            let mut bottom = HashSet::new();
+            let mut left = HashSet::new();
 
             let iteration = [
                 (&grid_top_edge, tile.edge_set().top(), &mut top),
@@ -222,6 +222,10 @@
 
             // compatibility with grid edges
             for (edge, tile_edge, set) in iteration {
+                if !tile_edge.hard_match() {
+                    set.insert(Tile::Empty);
+                }
+
                 for (is_compatible, tile) in edge
                     .as_ref()
                     .map(|e| {
@@ -399,7 +403,11 @@
 
 impl From<&EdgeDescription> for Edge<String> {
     fn from(val: &EdgeDescription) -> Self {
-        let edge = Edge::new(val.name.clone(), val.symmetrical.unwrap_or_default());
+        let edge = Edge::new(
+            val.name.clone(),
+            val.symmetrical.unwrap_or_default(),
+            val.hard_match.unwrap_or_default(),
+        );
 
         if val.reversed.unwrap_or_default() {
             edge.reversed()
@@ -413,23 +421,36 @@
     fn from(val: T) -> Self {
         use std::cmp::Ordering;
 
-        let reversed = val.as_ref().chars().rev().collect::<String>();
+        let mut chars = val.as_ref().chars();
+        let hard_match = chars.next() == Some('!');
 
-        match val.as_ref().cmp(&reversed) {
+        let (name, reversed): (String, String) = if hard_match {
+            (chars.clone().collect(), chars.rev().collect())
+        } else {
+            (
+                val.as_ref().chars().collect(),
+                val.as_ref().chars().rev().collect(),
+            )
+        };
+
+        match name.cmp(&reversed) {
             Ordering::Less => EdgeDescription {
-                name: val.as_ref().to_owned(),
+                name,
                 symmetrical: Some(false),
                 reversed: Some(false),
+                hard_match: Some(hard_match),
             },
             Ordering::Equal => EdgeDescription {
                 name: reversed,
                 symmetrical: Some(true),
                 reversed: Some(false),
+                hard_match: Some(hard_match),
             },
             Ordering::Greater => EdgeDescription {
                 name: reversed,
                 symmetrical: Some(false),
                 reversed: Some(true),
+                hard_match: Some(hard_match),
             },
         }
     }
--- a/rust/landgen/src/wavefront_collapse/tile_image.rs	Sun Feb 02 17:47:54 2025 +0100
+++ b/rust/landgen/src/wavefront_collapse/tile_image.rs	Sun Feb 02 22:30:49 2025 +0100
@@ -8,15 +8,17 @@
     id: I,
     symmetrical: bool,
     reverse: bool,
+    hard_match: bool,
 }
 
 impl<I: PartialEq + Clone> Edge<I> {
     #[inline]
-    pub fn new(id: I, symmetrical: bool) -> Self {
+    pub fn new(id: I, symmetrical: bool, hard_match: bool) -> Self {
         Self {
             id,
             symmetrical,
             reverse: false,
+            hard_match,
         }
     }
 
@@ -26,10 +28,16 @@
             id: self.id.clone(),
             symmetrical: self.symmetrical,
             reverse: !self.symmetrical && !self.reverse,
+            hard_match: self.hard_match,
         }
     }
 
     #[inline]
+    pub fn hard_match(&self) -> bool {
+        self.hard_match
+    }
+
+    #[inline]
     pub fn is_compatible(&self, other: &Self) -> bool {
         self.id == other.id && ((self.reverse != other.reverse) || self.symmetrical)
     }
--- a/share/hedgewars/Data/wfc_templates.toml	Sun Feb 02 17:47:54 2025 +0100
+++ b/share/hedgewars/Data/wfc_templates.toml	Sun Feb 02 22:30:49 2025 +0100
@@ -127,7 +127,7 @@
 # forced space
 name = "120_filled.png"
 weight = 0
-edges = [ "E", "e", "e", "e" ]
+edges = [ "!E", "e", "e", "e" ]
 can_rotate90 = true
 can_rotate180 = true
 can_rotate270 = true
@@ -135,7 +135,7 @@
 [[tiles.Shoppa]]
 name = "120_filled.png"
 weight = 10
-edges = [ "e", "e", "first_layer_reyal_tsrif", "e" ]
+edges = [ "e", "e", "!first_layer_reyal_tsrif", "e" ]
 
 [[tiles.Shoppa]]
 name = "shoppa_bar.png"
@@ -173,7 +173,7 @@
 # first layer semicircle
 name = "shoppa_sector.png"
 weight = 5
-edges = [ "e", "sector_rotces", "first_layer_reyal_tsrif", "e" ]
+edges = [ "e", "sector_rotces", "!first_layer_reyal_tsrif", "e" ]
 anti_match = [1, 0, 0, 1]
 can_mirror = true
 
@@ -188,7 +188,7 @@
 [[tiles.Shoppa]]
 name = "shoppa_hill_center_1.png"
 weight = 0
-edges = [ "E", "E", "retnecllih", "E" ]
+edges = [ "E", "E", "!retnecllih", "E" ]
 
 [[tiles.Shoppa]]
 name = "shoppa_hill_center_2.png"
@@ -212,7 +212,7 @@
 [[tiles.Shoppa]]
 name = "shoppa_hill_side_4.png"
 weight = 6
-edges = [ "hillside4", "H", "first_layer_reyal_tsrif", "e" ]
+edges = [ "hillside4", "H", "!first_layer_reyal_tsrif", "e" ]
 anti_match = [0, 4, 0, 0]
 can_mirror = true