# HG changeset patch # User unC0Rr # Date 1737493855 -3600 # Node ID 2acea266d2974b8615ea8dd688cda406f3fb17b7 # Parent de01be16df95f00788ecbf3d2190e35a52163e77 Fix generation in corners by extending outline edge definitions diff -r de01be16df95 -r 2acea266d297 rust/landgen/Cargo.toml --- a/rust/landgen/Cargo.toml Sat Jan 18 16:57:26 2025 +0100 +++ b/rust/landgen/Cargo.toml Tue Jan 21 22:10:55 2025 +0100 @@ -8,7 +8,6 @@ integral-geometry = { path = "../integral-geometry" } land2d = { path = "../land2d" } vec2d = { path = "../vec2d" } -itertools = "0.14" png = "0.17" rand = "0.8" diff -r de01be16df95 -r 2acea266d297 rust/landgen/src/wavefront_collapse/generator.rs --- 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, pub symmetrical: Option, } -#[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, } -#[derive(Clone)] -pub struct NonStrictEdgesDescription { - pub top: Option, - pub right: Option, - pub bottom: Option, - pub left: Option, +#[derive(Debug, Clone)] +pub struct ComplexEdgeDescription { + pub begin: Option, + pub fill: Option, + pub end: Option, } -#[derive(Clone)] +#[derive(Debug, Clone)] +pub struct NonStrictComplexEdgesDescription { + pub top: Option, + pub right: Option, + pub bottom: Option, + pub left: Option, +} + +#[derive(Debug, Clone)] pub struct TemplateDescription { pub size: Size, pub tiles: Vec, - 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 { let [grid_top_edge, grid_right_edge, grid_bottom_edge, grid_left_edge]: [Option< - Edge, + [Option>; 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::::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)); diff -r de01be16df95 -r 2acea266d297 rust/landgen/src/wavefront_collapse/wavefront_collapse.rs --- a/rust/landgen/src/wavefront_collapse/wavefront_collapse.rs Sat Jan 18 16:57:26 2025 +0100 +++ b/rust/landgen/src/wavefront_collapse/wavefront_collapse.rs Tue Jan 21 22:10:55 2025 +0100 @@ -8,16 +8,12 @@ #[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)] pub enum Tile { Empty, - Outside, + OutsideBegin, + OutsideFill, + OutsideEnd, Numbered(usize), } -impl Default for Tile { - fn default() -> Self { - Tile::Outside - } -} - #[derive(Debug)] pub struct CollapseRule { pub weight: u32, @@ -83,11 +79,38 @@ x }; - self.grid.get(y, x).copied().unwrap_or_default() + self.grid.get(y, x).copied().unwrap_or_else(|| { + let x_out = x >= self.grid.width(); + + if x_out { + let y_at_begin = y == 0; + let y_at_end = y.wrapping_add(1) == self.grid.height(); + if y_at_begin { + Tile::OutsideBegin + } else if y_at_end { + Tile::OutsideEnd + } else { + Tile::OutsideFill + } + } else { + // if not x, then it is y + + let x_at_begin = x == 0; + let x_at_end = x.wrapping_add(1) == self.grid.width(); + + if x_at_begin { + Tile::OutsideBegin + } else if x_at_end { + Tile::OutsideEnd + } else { + Tile::OutsideFill + } + } + }) } fn collapse_step(&mut self, random_numbers: &mut impl Rng) -> bool { - let mut tiles_to_collapse = (usize::max_value(), Vec::new()); + let mut tiles_to_collapse = (usize::MAX, Vec::new()); // Iterate through the tiles in the land for x in 0..self.grid.width() { @@ -96,8 +119,8 @@ if let Tile::Empty = current_tile { // calc entropy - let right_tile = self.get_tile(y, x + 1); - let bottom_tile = self.get_tile(y + 1, x); + let right_tile = self.get_tile(y, x.wrapping_add(1)); + let bottom_tile = self.get_tile(y.wrapping_add(1), x); let left_tile = self.get_tile(y, x.wrapping_sub(1)); let top_tile = self.get_tile(y.wrapping_sub(1), x); diff -r de01be16df95 -r 2acea266d297 rust/mapgen/Cargo.toml --- a/rust/mapgen/Cargo.toml Sat Jan 18 16:57:26 2025 +0100 +++ b/rust/mapgen/Cargo.toml Tue Jan 21 22:10:55 2025 +0100 @@ -2,7 +2,7 @@ name = "mapgen" version = "0.1.0" authors = ["Hedgewars Project"] -edition = "2018" +edition = "2021" [dependencies] vec2d = { path = "../vec2d" } @@ -13,6 +13,6 @@ rand = "0.8" serde = "1.0" -serde_yaml = "0.8" +serde_yaml = "0.9" serde_derive = "1.0" -png = "0.13" \ No newline at end of file +png = "0.13" diff -r de01be16df95 -r 2acea266d297 rust/mapgen/src/template/wavefront_collapse.rs --- a/rust/mapgen/src/template/wavefront_collapse.rs Sat Jan 18 16:57:26 2025 +0100 +++ b/rust/mapgen/src/template/wavefront_collapse.rs Tue Jan 21 22:10:55 2025 +0100 @@ -5,7 +5,7 @@ use std::collections::hash_map::HashMap; -#[derive(Deserialize)] +#[derive(Debug, Deserialize)] #[serde(remote = "EdgeDescription")] pub struct EdgeDesc { pub name: String, @@ -13,7 +13,7 @@ pub symmetrical: Option, } -#[derive(Deserialize)] +#[derive(Debug, Deserialize)] #[serde(remote = "EdgesDescription")] pub struct EdgesDesc { #[serde(with = "EdgeDesc")] @@ -26,7 +26,7 @@ pub left: EdgeDescription, } -#[derive(Deserialize)] +#[derive(Debug, Deserialize)] #[serde(remote = "TileDescription")] pub struct TileDesc { pub name: String, @@ -40,20 +40,26 @@ pub can_rotate270: Option, } -#[derive(Deserialize)] +#[derive(Debug, Deserialize)] pub struct TileDescriptionHelper(#[serde(with = "TileDesc")] TileDescription); -#[derive(Deserialize)] +#[derive(Debug, Deserialize)] pub struct EdgeDescriptionHelper(#[serde(with = "EdgeDesc")] EdgeDescription); -#[derive(Deserialize)] -pub struct NonStrictEdgesDesc { - pub top: Option, - pub right: Option, - pub bottom: Option, - pub left: Option, +#[derive(Debug, Deserialize)] +pub struct ComplexEdgeDesc { + pub begin: Option, + pub fill: Option, + pub end: Option, +} +#[derive(Debug, Deserialize)] +pub struct NonStrictComplexEdgesDesc { + pub top: Option, + pub right: Option, + pub bottom: Option, + pub left: Option, } -#[derive(Deserialize)] +#[derive(Debug, Deserialize)] pub struct TemplateDesc { pub width: usize, pub height: usize, @@ -62,11 +68,11 @@ pub put_girders: bool, pub max_hedgehogs: u8, pub wrap: bool, - pub edges: Option, + pub edges: Option, pub tiles: Vec, } -#[derive(Deserialize)] +#[derive(Debug, Deserialize)] pub struct TemplateCollectionDesc { pub templates: Vec, pub template_types: HashMap>, @@ -74,14 +80,14 @@ impl From<&TemplateDesc> for TemplateDescription { fn from(desc: &TemplateDesc) -> Self { - let [top, right, bottom, left] = if let Some(edges) = &desc.edges { + let [top, right, bottom, left]:[Option; 4] = if let Some(edges) = &desc.edges { [ - edges.top.as_ref(), - edges.right.as_ref(), - edges.bottom.as_ref(), - edges.left.as_ref(), + &edges.top, + &edges.right, + &edges.bottom, + &edges.left, ] - .map(|e| e.map(|EdgeDescriptionHelper(e)| e.clone())) + .map(|e| e.as_ref().map(Into::into)) } else { [None, None, None, None] }; @@ -94,7 +100,7 @@ .map(|TileDescriptionHelper(t)| t.clone()) .collect(), wrap: desc.wrap, - edges: NonStrictEdgesDescription { + edges: NonStrictComplexEdgesDescription { top, right, bottom, @@ -103,3 +109,13 @@ } } } + +impl From<&ComplexEdgeDesc> for ComplexEdgeDescription { + fn from(value: &ComplexEdgeDesc) -> Self { + Self { + begin: value.begin.as_ref().map(|EdgeDescriptionHelper(e)| e.clone()), + fill: value.fill.as_ref().map(|EdgeDescriptionHelper(e)| e.clone()), + end: value.end.as_ref().map(|EdgeDescriptionHelper(e)| e.clone()), + } + } +} diff -r de01be16df95 -r 2acea266d297 share/hedgewars/Data/wfc_templates.yaml --- a/share/hedgewars/Data/wfc_templates.yaml Sat Jan 18 16:57:26 2025 +0100 +++ b/share/hedgewars/Data/wfc_templates.yaml Tue Jan 21 22:10:55 2025 +0100 @@ -12,9 +12,34 @@ wrap: true edges: bottom: - name: "ff" - symmetrical: true + fill: + name: "ff" + symmetrical: true + top: + fill: + name: "ff" + symmetrical: true tiles: &template_00_tiles + - name: "120_filled.png" + edges: + top: + name: "ff" + symmetrical: true + right: + name: "ff" + symmetrical: true + bottom: + name: "ff" + symmetrical: true + left: + name: "ff" + symmetrical: true + is_negative: true + can_mirror: false + can_flip: false + can_rotate90: false + can_rotate180: false + can_rotate270: false - name: "120_bar.png" edges: top: @@ -33,7 +58,27 @@ can_flip: false can_rotate90: true can_rotate180: true - can_rotate270: true + can_rotate270: true + - name: "120_filled.png" + edges: + top: + name: "ee" + symmetrical: true + right: + name: "ee" + symmetrical: true + bottom: + name: "ee" + symmetrical: true + left: + name: "ee" + symmetrical: true + is_negative: false + can_mirror: false + can_flip: false + can_rotate90: false + can_rotate180: false + can_rotate270: false - name: "120_corner.png" edges: top: @@ -72,46 +117,6 @@ can_rotate90: true can_rotate180: true can_rotate270: true - - name: "120_filled.png" - edges: - top: - name: "ff" - symmetrical: true - right: - name: "ff" - symmetrical: true - bottom: - name: "ff" - symmetrical: true - left: - name: "ff" - symmetrical: true - is_negative: true - can_mirror: false - can_flip: false - can_rotate90: false - can_rotate180: false - can_rotate270: false - - name: "120_filled.png" - edges: - top: - name: "ee" - symmetrical: true - right: - name: "ee" - symmetrical: true - bottom: - name: "ee" - symmetrical: true - left: - name: "ee" - symmetrical: true - is_negative: false - can_mirror: false - can_flip: false - can_rotate90: false - can_rotate180: false - can_rotate270: false - name: "120_two_corners.png" edges: top: @@ -141,17 +146,44 @@ wrap: false edges: &open_edges top: - name: "ee" - symmetrical: true + begin: + name: "ee" + symmetrical: true + fill: + name: "ee" + symmetrical: true + end: + name: "ee" + symmetrical: true right: - name: "ee" - symmetrical: true + begin: + name: "ee" + symmetrical: true + fill: + name: "ee" + symmetrical: true + end: + name: "ee" + symmetrical: true bottom: - name: "ff" - symmetrical: true + begin: + name: "fe" + reversed: true + fill: + name: "ff" + symmetrical: true + end: + name: "fe" left: - name: "ee" - symmetrical: true + begin: + name: "ee" + symmetrical: true + fill: + name: "ee" + symmetrical: true + end: + name: "ee" + symmetrical: true tiles: *template_00_tiles - &template_02