--- 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());
}
}