rust/landgen/src/wavefront_collapse/wavefront_collapse.rs
branchtransitional_engine
changeset 15917 60b5639cc3a5
parent 15916 e82de0410da5
child 15918 9bd828451d77
equal deleted inserted replaced
15916:e82de0410da5 15917:60b5639cc3a5
     1 use integral_geometry::Size;
     1 use integral_geometry::Size;
     2 use std::collections::{HashMap, HashSet};
     2 use std::collections::HashSet;
     3 use vec2d::Vec2D;
     3 use vec2d::Vec2D;
     4 
     4 
     5 #[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
     5 #[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
     6 pub enum Tile {
     6 pub enum Tile {
     7     Empty,
     7     Empty,
     8     Outside,
     8     Outside,
     9     Numbered(u32),
     9     Numbered(usize),
    10 }
    10 }
    11 
    11 
    12 impl Tile {
    12 impl Tile {
    13     fn is(&self, i: u32) -> bool {
    13     fn is(&self, i: usize) -> bool {
    14         *self == Tile::Numbered(i)
    14         *self == Tile::Numbered(i)
    15     }
    15     }
    16 
    16 
    17     fn is_empty(&self) -> bool {
    17     fn is_empty(&self) -> bool {
    18         match self {
    18         match self {
    20             Tile::Outside => true,
    20             Tile::Outside => true,
    21             _ => false,
    21             _ => false,
    22         }
    22         }
    23     }
    23     }
    24 
    24 
    25     fn is_empty_or(&self, i: u32) -> bool {
    25     fn is_empty_or(&self, i: usize) -> bool {
    26         match self {
    26         match self {
    27             Tile::Numbered(n) => *n == i,
    27             Tile::Numbered(n) => *n == i,
    28             Tile::Empty => true,
    28             Tile::Empty => true,
    29             _ => false,
    29             _ => false,
    30         }
    30         }
    31     }
    31     }
    32 
    32 
    33     fn is_void_or(&self, i: u32) -> bool {
    33     fn is_void_or(&self, i: usize) -> bool {
    34         match self {
    34         match self {
    35             Tile::Numbered(n) => *n == i,
    35             Tile::Numbered(n) => *n == i,
    36             _ => true,
    36             _ => true,
    37         }
    37         }
    38     }
    38     }
    42     fn default() -> Self {
    42     fn default() -> Self {
    43         Tile::Outside
    43         Tile::Outside
    44     }
    44     }
    45 }
    45 }
    46 
    46 
       
    47 #[derive(Debug)]
    47 pub struct CollapseRule {
    48 pub struct CollapseRule {
    48     tile: Tile,
    49     pub tile: Tile,
    49     right: HashSet<Tile>,
    50     pub right: HashSet<Tile>,
    50     bottom: HashSet<Tile>,
    51     pub bottom: HashSet<Tile>,
    51     left: HashSet<Tile>,
    52     pub left: HashSet<Tile>,
    52     top: HashSet<Tile>,
    53     pub top: HashSet<Tile>,
    53 }
    54 }
    54 
    55 
    55 pub struct WavefrontCollapse {
    56 pub struct WavefrontCollapse {
    56     rules: Vec<CollapseRule>,
    57     rules: Vec<CollapseRule>,
    57     grid: Vec2D<Tile>,
    58     grid: Vec2D<Tile>,
    78         seed_fn(&mut self.grid);
    79         seed_fn(&mut self.grid);
    79 
    80 
    80         while self.collapse_step(random_numbers) {}
    81         while self.collapse_step(random_numbers) {}
    81     }
    82     }
    82 
    83 
    83     fn add_rule(&mut self, rule: CollapseRule) {
    84     pub fn set_rules(&mut self, rules: Vec<CollapseRule>) {
       
    85         self.rules = rules;
       
    86     }
       
    87 
       
    88     pub fn add_rule(&mut self, rule: CollapseRule) {
    84         self.rules.push(rule);
    89         self.rules.push(rule);
    85     }
    90     }
    86 
    91 
    87     fn get_tile(&self, y: usize, x: usize) -> Tile {
    92     fn get_tile(&self, y: usize, x: usize) -> Tile {
    88         self.grid.get(y, x).map(|p| *p).unwrap_or_default()
    93         self.grid.get(y, x).map(|p| *p).unwrap_or_default()
   118                             }
   123                             }
   119                         })
   124                         })
   120                         .collect();
   125                         .collect();
   121 
   126 
   122                     let entropy = possibilities.len();
   127                     let entropy = possibilities.len();
   123                     if entropy > 0 && entropy <= tiles_to_collapse.0 {
   128                     if entropy > 0 {
   124                         let entry = (
   129                         if entropy <= tiles_to_collapse.0 {
   125                             y,
   130                             let entry = (
   126                             x,
   131                                 y,
   127                             possibilities
   132                                 x,
   128                                 [random_numbers.next().unwrap_or_default() as usize % entropy],
   133                                 possibilities
   129                         );
   134                                     [random_numbers.next().unwrap_or_default() as usize % entropy],
       
   135                             );
   130 
   136 
   131                         if entropy < tiles_to_collapse.0 {
   137                             if entropy < tiles_to_collapse.0 {
   132                             tiles_to_collapse = (entropy, vec![entry])
   138                                 tiles_to_collapse = (entropy, vec![entry])
   133                         } else {
   139                             } else {
   134                             tiles_to_collapse.1.push(entry)
   140                                 tiles_to_collapse.1.push(entry)
       
   141                             }
   135                         }
   142                         }
   136                     } else {
   143                     } else {
   137                         todo!("no collapse possible")
   144                         println!("We're here: {}, {}", x, y);
       
   145                         println!(
       
   146                             "Neighbour tiles are: {:?} {:?} {:?} {:?}",
       
   147                             right_tile, bottom_tile, left_tile, top_tile
       
   148                         );
       
   149                         println!("Rules are: {:?}", self.rules);
       
   150 
       
   151                         todo!("no collapse possible - what to do?")
   138                     }
   152                     }
   139                 }
   153                 }
   140             }
   154             }
   141         }
   155         }
   142 
   156 
   155             true
   169             true
   156         } else {
   170         } else {
   157             false
   171             false
   158         }
   172         }
   159     }
   173     }
       
   174 
       
   175     pub fn grid(&self) -> &Vec2D<Tile> {
       
   176         &self.grid
       
   177     }
   160 }
   178 }
   161 
   179 
   162 #[cfg(test)]
   180 #[cfg(test)]
   163 mod tests {
   181 mod tests {
   164     use super::{Tile, WavefrontCollapse};
   182     use super::{Tile, WavefrontCollapse};
   166     use vec2d::Vec2D;
   184     use vec2d::Vec2D;
   167 
   185 
   168     #[test]
   186     #[test]
   169     fn test_wavefront_collapse() {
   187     fn test_wavefront_collapse() {
   170         let size = Size::new(4, 4);
   188         let size = Size::new(4, 4);
   171         let mut rnd = [0u32; 64].into_iter();
   189         let mut rnd = [0u32; 64].into_iter().cycle();
   172         let mut wfc = WavefrontCollapse::default();
   190         let mut wfc = WavefrontCollapse::default();
       
   191 
       
   192         wfc.generate_map(&size, |_| {}, &mut rnd);
   173 
   193 
   174         let empty_land = Vec2D::new(&size, Tile::Empty);
   194         let empty_land = Vec2D::new(&size, Tile::Empty);
   175 
   195 
   176         assert_eq!(empty_land.as_slice(), wfc.grid.as_slice());
   196         assert_eq!(empty_land.as_slice(), wfc.grid().as_slice());
   177     }
   197     }
   178 }
   198 }