rust/landgen/src/maze.rs
changeset 16102 5d302b12d837
parent 16087 de01be16df95
equal deleted inserted replaced
16101:a4cbc6926439 16102:5d302b12d837
     1 use crate::outline_template_based::outline::OutlinePoints;
     1 use crate::outline_template_based::outline::OutlinePoints;
     2 use crate::{LandGenerationParameters, LandGenerator};
     2 use crate::{LandGenerationParameters, LandGenerator};
     3 use integral_geometry::{Point, Polygon, Rect, Size};
     3 use integral_geometry::{Point, Polygon, Rect, Size};
     4 use land2d::Land2D;
     4 use land2d::Land2D;
     5 use rand::Rng;
     5 use rand::Rng;
       
     6 use vec2d::Vec2D;
     6 
     7 
     7 #[derive(Clone)]
     8 #[derive(Clone)]
     8 pub struct MazeTemplate {
     9 pub struct MazeTemplate {
     9     pub width: usize,
    10     pub width: u32,
    10     pub height: usize,
    11     pub height: u32,
    11     pub cell_size: usize,
    12     pub cell_size: u32,
    12     pub inverted: bool,
    13     pub inverted: bool,
    13     pub distortion_limiting_factor: u32,
    14     pub distortion_limiting_factor: u32,
    14     pub braidness: u32,
    15     pub braidness: u32,
    15 }
    16 }
    16 
    17 
    19     braidness: u32,
    20     braidness: u32,
    20     off: Point,
    21     off: Point,
    21     num_cells: Size,
    22     num_cells: Size,
    22     num_edges: Size,
    23     num_edges: Size,
    23     seen_cells: Size,
    24     seen_cells: Size,
    24     cell_size: usize,
    25     cell_size: u32,
    25     seen_list: Vec<Vec<Option<usize>>>,
    26     seen_list: Vec2D<Option<usize>>,
    26     walls: Vec<Vec<Vec<bool>>>,
    27     walls: Vec<Vec2D<bool>>,
    27     edge_list: Vec<Vec<Vec<bool>>>,
    28     edge_list: Vec<Vec2D<bool>>,
    28     last_cell: Vec<Point>,
    29     last_cell: Vec<Point>,
    29     came_from: Vec<Vec<Point>>,
    30     came_from: Vec<Vec<Point>>,
    30     came_from_pos: Vec<i32>,
    31     came_from_pos: Vec<i32>,
    31 }
    32 }
    32 
    33 
    78 }
    79 }
    79 
    80 
    80 impl Maze {
    81 impl Maze {
    81     pub fn new(
    82     pub fn new(
    82         size: &Size,
    83         size: &Size,
    83         cell_size: usize,
    84         cell_size: u32,
    84         num_steps: usize,
    85         num_steps: usize,
    85         inverted: bool,
    86         inverted: bool,
    86         braidness: u32,
    87         braidness: u32,
    87         random_numbers: &mut impl Rng,
    88         random_numbers: &mut impl Rng,
    88     ) -> Self {
    89     ) -> Self {
    94         let num_edges = Size::new(num_cells.width - 1, num_cells.height - 1);
    95         let num_edges = Size::new(num_cells.width - 1, num_cells.height - 1);
    95         let seen_cells = Size::new(num_cells.width / 2, num_cells.height / 2);
    96         let seen_cells = Size::new(num_cells.width / 2, num_cells.height / 2);
    96 
    97 
    97         let mut last_cell = vec![Point::diag(0); num_steps];
    98         let mut last_cell = vec![Point::diag(0); num_steps];
    98         let came_from_pos = vec![0; num_steps];
    99         let came_from_pos = vec![0; num_steps];
    99         let came_from = vec![vec![Point::diag(0); num_steps]; num_cells.area()];
   100         let came_from = vec![vec![Point::diag(0); num_steps]; num_cells.area() as usize];
   100 
   101 
   101         let seen_list = vec![vec![None as Option<usize>; seen_cells.width]; seen_cells.height];
   102         let seen_list = Vec2D::new(&seen_cells, None);
   102         let walls = vec![vec![vec![true; seen_cells.width]; seen_cells.height]; 2];
   103         let walls = vec![Vec2D::new(&seen_cells, true); 2];
   103         let edge_list = vec![vec![vec![false; num_cells.width]; num_cells.height]; 2];
   104         let edge_list = vec![Vec2D::new(&num_cells, false); 2];
   104 
   105 
   105         for current_step in 0..num_steps {
   106         for current_step in 0..num_steps {
   106             let x = random_numbers.gen_range(0..seen_cells.width - 1) / num_steps;
   107             let x = random_numbers.random_range(0..seen_cells.width as i32 - 1) / num_steps as i32;
   107             last_cell[current_step] = Point::new(
   108             last_cell[current_step] = Point::new(
   108                 (x + current_step * seen_cells.width / num_steps) as i32,
   109                 x + current_step as i32 * seen_cells.width as i32 / num_steps as i32,
   109                 random_numbers.gen_range(0..seen_cells.height) as i32,
   110                 random_numbers.random_range(..seen_cells.height) as i32,
   110             );
   111             );
   111         }
   112         }
   112 
   113 
   113         let off_x = ((size.width - num_cells.width * cell_size) / 2) as i32;
   114         let off_x = ((size.width - num_cells.width * cell_size) / 2) as i32;
   114         let off_y = ((size.height - num_cells.height * cell_size) / 2) as i32;
   115         let off_y = ((size.height - num_cells.height * cell_size) / 2) as i32;
   139         let mut dir = start_dir;
   140         let mut dir = start_dir;
   140         loop {
   141         loop {
   141             let p = self.last_cell[current_step];
   142             let p = self.last_cell[current_step];
   142             self.seen_list[p.y as usize][p.x as usize] = Some(current_step);
   143             self.seen_list[p.y as usize][p.x as usize] = Some(current_step);
   143 
   144 
   144             let next_dir_clockwise = random_numbers.gen();
   145             let next_dir_clockwise = random_numbers.random();
   145 
   146 
   146             for _ in 0..5 {
   147             for _ in 0..5 {
   147                 let sp = p + dir.0;
   148                 let sp = p + dir.0;
   148                 let when_seen = if sp.x < 0
   149                 let when_seen = if sp.x < 0
   149                     || sp.x >= self.seen_cells.width as i32
   150                     || sp.x >= self.seen_cells.width as i32
   156                 };
   157                 };
   157 
   158 
   158                 match when_seen {
   159                 match when_seen {
   159                     Some(a) if a == current_step => {
   160                     Some(a) if a == current_step => {
   160                         // try another direction
   161                         // try another direction
   161                         if !self.inverted && random_numbers.gen_range(0..self.braidness) == 0 {
   162                         if !self.inverted && random_numbers.random_range(..self.braidness) == 0 {
   162                             if dir.0.x == -1 && p.x > 0 {
   163                             if dir.0.x == -1 && p.x > 0 {
   163                                 self.walls[dir.orientation()][p.y as usize][p.x as usize - 1] =
   164                                 self.walls[dir.orientation()][p.y as usize][p.x as usize - 1] =
   164                                     false;
   165                                     false;
   165                             }
   166                             }
   166                             if dir.0.x == 1 && p.x < self.seen_cells.width as i32 - 1 {
   167                             if dir.0.x == 1 && p.x < self.seen_cells.width as i32 - 1 {
   259     }
   260     }
   260 
   261 
   261     pub fn to_islands(mut self) -> (Vec<Polygon>, Vec<Point>) {
   262     pub fn to_islands(mut self) -> (Vec<Polygon>, Vec<Point>) {
   262         let mut islands: Vec<Polygon> = vec![];
   263         let mut islands: Vec<Polygon> = vec![];
   263         let mut polygon: Vec<Point> = vec![];
   264         let mut polygon: Vec<Point> = vec![];
   264         let mut maze = vec![vec![false; self.num_cells.width]; self.num_cells.height];
   265         let mut maze = Vec2D::new(&self.num_cells, false);
   265 
   266 
   266         for x in 0..self.seen_cells.width {
   267         for x in 0..self.seen_cells.width as usize {
   267             for y in 0..self.seen_cells.height {
   268             for y in 0..self.seen_cells.height as usize {
   268                 if self.seen_list[y][x].is_some() {
   269                 if self.seen_list[y][x].is_some() {
   269                     maze[y * 2 + 1][x * 2 + 1] = true;
   270                     maze[y * 2 + 1][x * 2 + 1] = true;
   270                 }
   271                 }
   271             }
   272             }
   272 
   273 
   273             for y in 0..self.seen_cells.height - 1 {
   274             for y in 0..self.seen_cells.height as usize - 1 {
   274                 if !self.walls[0][y][x] {
   275                 if !self.walls[0][y][x] {
   275                     maze[y * 2 + 2][x * 2 + 1] = true;
   276                     maze[y * 2 + 2][x * 2 + 1] = true;
   276                 }
   277                 }
   277             }
   278             }
   278         }
   279         }
   279 
   280 
   280         for x in 0..self.seen_cells.width - 1 {
   281         for x in 0..self.seen_cells.width as usize - 1 {
   281             for y in 0..self.seen_cells.height {
   282             for y in 0..self.seen_cells.height as usize {
   282                 if !self.walls[1][y][x] {
   283                 if !self.walls[1][y][x] {
   283                     maze[y * 2 + 1][x * 2 + 2] = true;
   284                     maze[y * 2 + 1][x * 2 + 2] = true;
   284                 }
   285                 }
   285             }
   286             }
   286         }
   287         }
   287 
   288 
   288         for x in 0..self.num_edges.width {
   289         for x in 0..self.num_edges.width as usize {
   289             for y in 0..self.num_cells.height {
   290             for y in 0..self.num_cells.height as usize {
   290                 self.edge_list[0][y][x] = maze[y][x] != maze[y][x + 1];
   291                 self.edge_list[0][y][x] = maze[y][x] != maze[y][x + 1];
   291             }
   292             }
   292         }
   293         }
   293 
   294 
   294         for x in 0..self.num_cells.width {
   295         for x in 0..self.num_cells.width as usize {
   295             for y in 0..self.num_edges.height {
   296             for y in 0..self.num_edges.height as usize {
   296                 self.edge_list[1][y][x] = maze[y][x] != maze[y + 1][x];
   297                 self.edge_list[1][y][x] = maze[y][x] != maze[y + 1][x];
   297             }
   298             }
   298         }
   299         }
   299 
   300 
   300         let mut fill_points = vec![];
   301         let mut fill_points = vec![];
   301 
   302 
   302         for x in 0..self.num_edges.width {
   303         for x in 0..self.num_edges.width as usize {
   303             for y in 0..self.num_cells.height {
   304             for y in 0..self.num_cells.height as usize {
   304                 if self.edge_list[0][y][x] {
   305                 if self.edge_list[0][y][x] {
   305                     self.edge_list[0][y][x] = false;
   306                     self.edge_list[0][y][x] = false;
   306                     self.add_vertex(Point::new(x as i32 + 1, y as i32 + 1), &mut polygon);
   307                     self.add_vertex(Point::new(x as i32 + 1, y as i32 + 1), &mut polygon);
   307                     self.add_vertex(Point::new(x as i32 + 1, y as i32), &mut polygon);
   308                     self.add_vertex(Point::new(x as i32 + 1, y as i32), &mut polygon);
   308                     self.add_edge(
   309                     self.add_edge(
   326                     polygon.clear();
   327                     polygon.clear();
   327                 }
   328                 }
   328             }
   329             }
   329         }
   330         }
   330 
   331 
   331         for x in 0..self.num_cells.width {
   332         for x in 0..self.num_cells.width as usize {
   332             for y in 0..self.num_cells.height {
   333             for y in 0..self.num_cells.height as usize {
   333                 if maze[y][x] {
   334                 if maze[y][x] {
   334                     let half_cell = self.cell_size / 2;
   335                     let half_cell = self.cell_size / 2;
   335                     let fill_point = Point::new(
   336                     let fill_point = Point::new(
   336                         (x * self.cell_size + half_cell) as i32 + self.off.x,
   337                         (x as u32 * self.cell_size + half_cell) as i32 + self.off.x,
   337                         (y * self.cell_size + half_cell) as i32 + self.off.y,
   338                         (y as u32 * self.cell_size + half_cell) as i32 + self.off.y,
   338                     );
   339                     );
   339                     islands.push(Polygon::new(&[fill_point]));
   340                     islands.push(Polygon::new(&[fill_point]));
   340                     fill_points.push(fill_point);
   341                     fill_points.push(fill_point);
   341 
   342 
   342                     let mut points = vec![(x, y)];
   343                     let mut points = vec![(x, y)];
   346                             maze[y][x] = false;
   347                             maze[y][x] = false;
   347 
   348 
   348                             if x > 0 {
   349                             if x > 0 {
   349                                 points.push((x - 1, y));
   350                                 points.push((x - 1, y));
   350                             }
   351                             }
   351                             if x < self.num_cells.width - 1 {
   352                             if x < self.num_cells.width as usize - 1 {
   352                                 points.push((x + 1, y));
   353                                 points.push((x + 1, y));
   353                             }
   354                             }
   354                             if y > 0 {
   355                             if y > 0 {
   355                                 points.push((x, y - 1));
   356                                 points.push((x, y - 1));
   356                             }
   357                             }
   357                             if y < self.num_cells.height - 1 {
   358                             if y < self.num_cells.height as usize - 1 {
   358                                 points.push((x, y + 1));
   359                                 points.push((x, y + 1));
   359                             }
   360                             }
   360                         }
   361                         }
   361                     }
   362                     }
   362                 }
   363                 }
   369 
   370 
   370 pub struct MazeLandGenerator {
   371 pub struct MazeLandGenerator {
   371     maze_template: MazeTemplate,
   372     maze_template: MazeTemplate,
   372 }
   373 }
   373 
   374 
   374 fn prev_odd(num: usize) -> usize {
   375 fn prev_odd(num: u32) -> u32 {
   375     if num & 1 == 0 {
   376     if num & 1 == 0 {
   376         num - 1
   377         num - 1
   377     } else {
   378     } else {
   378         num
   379         num
   379     }
   380     }
   407         while !done {
   408         while !done {
   408             done = true;
   409             done = true;
   409 
   410 
   410             for current_step in 0..num_steps {
   411             for current_step in 0..num_steps {
   411                 if !step_done[current_step] {
   412                 if !step_done[current_step] {
   412                     let dir = Direction::new(random_numbers.gen());
   413                     let dir = Direction::new(random_numbers.random_range(..4));
   413                     step_done[current_step] = maze.see_cell(current_step, dir, random_numbers);
   414                     step_done[current_step] = maze.see_cell(current_step, dir, random_numbers);
   414                     done = false;
   415                     done = false;
   415                 }
   416                 }
   416             }
   417             }
   417         }
   418         }