From db1c4c2d4427bc578e37b0d9433014b500ab5eeb Mon Sep 17 00:00:00 2001 From: Timothy Warren Date: Wed, 15 Dec 2021 10:45:58 -0500 Subject: [PATCH] Refactor some voronoi-based builders to use Rust builder pattern --- src/map_builders/dla.rs | 181 ++++++++++------------------ src/map_builders/drunkard.rs | 225 +++++++++++------------------------ src/map_builders/maze.rs | 99 +++------------ 3 files changed, 145 insertions(+), 360 deletions(-) diff --git a/src/map_builders/dla.rs b/src/map_builders/dla.rs index d5036c2..3e3bae8 100644 --- a/src/map_builders/dla.rs +++ b/src/map_builders/dla.rs @@ -8,6 +8,7 @@ use super::common::{ }; use super::MapBuilder; use crate::components::Position; +use crate::map_builders::{BuilderMap, InitialMapBuilder}; use crate::{spawner, Map, TileType, SHOW_MAPGEN_VISUALIZER}; #[derive(PartialEq, Copy, Clone)] @@ -18,121 +19,81 @@ pub enum DLAAlgorithm { } pub struct DLABuilder { - map: Map, - starting_position: Position, - depth: i32, - history: Vec, - noise_areas: HashMap>, algorithm: DLAAlgorithm, brush_size: i32, symmetry: Symmetry, floor_percent: f32, - spawn_list: Vec<(usize, String)>, } -impl MapBuilder for DLABuilder { - fn get_map(&self) -> Map { - self.map.clone() - } - - fn get_starting_position(&self) -> Position { - self.starting_position - } - - fn get_snapshot_history(&self) -> Vec { - self.history.clone() - } - - fn build_map(&mut self) { - self.build(); - } - - fn take_snapshot(&mut self) { - if SHOW_MAPGEN_VISUALIZER { - let mut snapshot = self.map.clone(); - for v in snapshot.revealed_tiles.iter_mut() { - *v = true; - } - self.history.push(snapshot); - } - } - - fn get_spawn_list(&self) -> &Vec<(usize, String)> { - &self.spawn_list +impl InitialMapBuilder for DLABuilder { + fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) { + self.build(rng, build_data); } } impl DLABuilder { - pub fn new(new_depth: i32) -> DLABuilder { + pub fn new() -> DLABuilder { DLABuilder { - map: Map::new(new_depth), - starting_position: Position::default(), - depth: new_depth, - history: Vec::new(), - noise_areas: HashMap::new(), algorithm: DLAAlgorithm::WalkOutwards, brush_size: 1, symmetry: Symmetry::None, floor_percent: 0.25, - spawn_list: Vec::new(), } } - pub fn walk_inwards(new_depth: i32) -> DLABuilder { - DLABuilder { + pub fn walk_inwards() -> Box { + Box::new(DLABuilder { algorithm: DLAAlgorithm::WalkInwards, - ..DLABuilder::new(new_depth) - } + ..DLABuilder::new() + }) } - pub fn walk_outwards(new_depth: i32) -> DLABuilder { - DLABuilder { + pub fn walk_outwards() -> Box { + Box::new(DLABuilder { brush_size: 2, - ..DLABuilder::new(new_depth) - } + ..DLABuilder::new() + }) } - pub fn central_attractor(new_depth: i32) -> DLABuilder { - DLABuilder { + pub fn central_attractor() -> Box { + Box::new(DLABuilder { algorithm: DLAAlgorithm::CentralAttractor, brush_size: 2, - ..DLABuilder::new(new_depth) - } + ..DLABuilder::new() + }) } - pub fn insectoid(new_depth: i32) -> DLABuilder { - DLABuilder { + pub fn insectoid() -> Box { + Box::new(DLABuilder { algorithm: DLAAlgorithm::CentralAttractor, brush_size: 2, symmetry: Symmetry::Horizontal, - ..DLABuilder::new(new_depth) - } + ..DLABuilder::new() + }) } #[allow(clippy::map_entry)] - fn build(&mut self) { - let mut rng = RandomNumberGenerator::new(); - - self.starting_position = Position { - x: self.map.width / 2, - y: self.map.height / 2, + fn build(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) { + let starting_position = Position { + x: build_data.map.width / 2, + y: build_data.map.height / 2, }; - let start_idx = self + let start_idx = build_data .map - .xy_idx(self.starting_position.x, self.starting_position.y); - self.take_snapshot(); + .xy_idx(starting_position.x, starting_position.y); + build_data.take_snapshot(); // Carve a starting seed - self.map.tiles[start_idx] = TileType::Floor; - self.map.tiles[start_idx - 1] = TileType::Floor; - self.map.tiles[start_idx + 1] = TileType::Floor; - self.map.tiles[start_idx - self.map.width as usize] = TileType::Floor; - self.map.tiles[start_idx + self.map.width as usize] = TileType::Floor; + build_data.map.tiles[start_idx] = TileType::Floor; + build_data.map.tiles[start_idx - 1] = TileType::Floor; + build_data.map.tiles[start_idx + 1] = TileType::Floor; + build_data.map.tiles[start_idx - build_data.map.width as usize] = TileType::Floor; + build_data.map.tiles[start_idx + build_data.map.width as usize] = TileType::Floor; // Random walker - let total_tiles = self.map.width * self.map.height; + let total_tiles = build_data.map.width * build_data.map.height; let desired_floor_tiles = (self.floor_percent * total_tiles as f32) as usize; - let mut floor_tile_count = self + let mut floor_tile_count = build_data .map .tiles .iter() @@ -142,13 +103,13 @@ impl DLABuilder { while floor_tile_count < desired_floor_tiles { match self.algorithm { DLAAlgorithm::WalkInwards => { - let mut digger_x = rng.roll_dice(1, self.map.width - 3) + 1; - let mut digger_y = rng.roll_dice(1, self.map.height - 3) + 1; + let mut digger_x = rng.roll_dice(1, build_data.map.width - 3) + 1; + let mut digger_y = rng.roll_dice(1, build_data.map.height - 3) + 1; let mut prev_x = digger_x; let mut prev_y = digger_y; - let mut digger_idx = self.map.xy_idx(digger_x, digger_y); + let mut digger_idx = build_data.map.xy_idx(digger_x, digger_y); - while self.map.tiles[digger_idx] == TileType::Wall { + while build_data.map.tiles[digger_idx] == TileType::Wall { prev_x = digger_x; prev_y = digger_y; @@ -160,7 +121,7 @@ impl DLABuilder { } } 2 => { - if digger_x < self.map.width - 2 { + if digger_x < build_data.map.width - 2 { digger_x += 1 } } @@ -170,17 +131,17 @@ impl DLABuilder { } } _ => { - if digger_y < self.map.height - 2 { + if digger_y < build_data.map.height - 2 { digger_y += 1 } } } - digger_idx = self.map.xy_idx(digger_x, digger_y); + digger_idx = build_data.map.xy_idx(digger_x, digger_y); } paint( - &mut self.map, + &mut build_data.map, self.symmetry, self.brush_size, prev_x, @@ -189,11 +150,11 @@ impl DLABuilder { } DLAAlgorithm::WalkOutwards => { - let mut digger_x = self.starting_position.x; - let mut digger_y = self.starting_position.y; - let mut digger_idx = self.map.xy_idx(digger_x, digger_y); + let mut digger_x = starting_position.x; + let mut digger_y = starting_position.y; + let mut digger_idx = build_data.map.xy_idx(digger_x, digger_y); - while self.map.tiles[digger_idx] == TileType::Floor { + while build_data.map.tiles[digger_idx] == TileType::Floor { let stagger_direction = rng.roll_dice(1, 4); match stagger_direction { 1 => { @@ -202,7 +163,7 @@ impl DLABuilder { } } 2 => { - if digger_x < self.map.width - 2 { + if digger_x < build_data.map.width - 2 { digger_x += 1 } } @@ -212,17 +173,17 @@ impl DLABuilder { } } _ => { - if digger_y < self.map.height - 2 { + if digger_y < build_data.map.height - 2 { digger_y += 1 } } } - digger_idx = self.map.xy_idx(digger_x, digger_y); + digger_idx = build_data.map.xy_idx(digger_x, digger_y); } paint( - &mut self.map, + &mut build_data.map, self.symmetry, self.brush_size, digger_x, @@ -231,29 +192,29 @@ impl DLABuilder { } DLAAlgorithm::CentralAttractor => { - let mut digger_x = rng.roll_dice(1, self.map.width - 3) + 1; - let mut digger_y = rng.roll_dice(1, self.map.height - 3) + 1; + let mut digger_x = rng.roll_dice(1, build_data.map.width - 3) + 1; + let mut digger_y = rng.roll_dice(1, build_data.map.height - 3) + 1; let mut prev_x = digger_x; let mut prev_y = digger_y; - let mut digger_idx = self.map.xy_idx(digger_x, digger_y); + let mut digger_idx = build_data.map.xy_idx(digger_x, digger_y); let mut path = rltk::line2d( rltk::LineAlg::Bresenham, rltk::Point::new(digger_x, digger_y), - rltk::Point::new(self.starting_position.x, self.starting_position.y), + rltk::Point::new(starting_position.x, starting_position.y), ); - while self.map.tiles[digger_idx] == TileType::Wall && !path.is_empty() { + while build_data.map.tiles[digger_idx] == TileType::Wall && !path.is_empty() { prev_x = digger_x; prev_y = digger_y; digger_x = path[0].x; digger_y = path[0].y; path.remove(0); - digger_idx = self.map.xy_idx(digger_x, digger_y); + digger_idx = build_data.map.xy_idx(digger_x, digger_y); } paint( - &mut self.map, + &mut build_data.map, self.symmetry, self.brush_size, prev_x, @@ -262,36 +223,14 @@ impl DLABuilder { } } - self.take_snapshot(); + build_data.take_snapshot(); - floor_tile_count = self + floor_tile_count = build_data .map .tiles .iter() .filter(|a| **a == TileType::Floor) .count(); } - - // Find all tiles we can reach from the starting point - let exit_tile = remove_unreachable_areas_returning_most_distant(&mut self.map, start_idx); - self.take_snapshot(); - - // Place the stairs - self.map.tiles[exit_tile] = TileType::DownStairs; - self.take_snapshot(); - - // Now we build a noise map for use in spawning entities later - self.noise_areas = generate_voronoi_spawn_regions(&self.map, &mut rng); - - // Spawn the entities - for area in self.noise_areas.iter() { - spawner::spawn_region( - &self.map, - &mut rng, - area.1, - self.depth, - &mut self.spawn_list, - ); - } } } diff --git a/src/map_builders/drunkard.rs b/src/map_builders/drunkard.rs index 9fe4bf2..f32b3fb 100644 --- a/src/map_builders/drunkard.rs +++ b/src/map_builders/drunkard.rs @@ -8,6 +8,7 @@ use super::common::{ }; use super::MapBuilder; use crate::components::Position; +use crate::map_builders::{BuilderMap, InitialMapBuilder}; use crate::{spawner, Map, TileType, SHOW_MAPGEN_VISUALIZER}; #[derive(PartialEq, Copy, Clone)] @@ -25,149 +26,91 @@ pub struct DrunkardSettings { } pub struct DrunkardsWalkBuilder { - map: Map, - starting_position: Position, - depth: i32, - history: Vec, - noise_areas: HashMap>, settings: DrunkardSettings, - spawn_list: Vec<(usize, String)>, } -impl MapBuilder for DrunkardsWalkBuilder { - fn get_map(&self) -> Map { - self.map.clone() - } - - fn get_starting_position(&self) -> Position { - self.starting_position - } - - fn get_snapshot_history(&self) -> Vec { - self.history.clone() - } - - fn build_map(&mut self) { - self.build(); - } - - fn take_snapshot(&mut self) { - if SHOW_MAPGEN_VISUALIZER { - let mut snapshot = self.map.clone(); - for v in snapshot.revealed_tiles.iter_mut() { - *v = true; - } - self.history.push(snapshot); - } - } - - fn get_spawn_list(&self) -> &Vec<(usize, String)> { - &self.spawn_list +impl InitialMapBuilder for DrunkardsWalkBuilder { + fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) { + self.build(rng, build_data); } } impl DrunkardsWalkBuilder { - pub fn new(new_depth: i32, settings: DrunkardSettings) -> DrunkardsWalkBuilder { - DrunkardsWalkBuilder { - map: Map::new(new_depth), - starting_position: Position::default(), - depth: new_depth, - history: Vec::new(), - noise_areas: HashMap::new(), - settings, - spawn_list: Vec::new(), - } + pub fn new(settings: DrunkardSettings) -> DrunkardsWalkBuilder { + DrunkardsWalkBuilder { settings } } - pub fn open_area(new_depth: i32) -> DrunkardsWalkBuilder { - DrunkardsWalkBuilder::new( - new_depth, - DrunkardSettings { - spawn_mode: DrunkSpawnMode::StaringPoint, - drunken_lifetime: 400, - floor_percent: 0.5, - brush_size: 1, - symmetry: Symmetry::None, - }, - ) + pub fn open_area() -> Box { + Box::new(DrunkardsWalkBuilder::new(DrunkardSettings { + spawn_mode: DrunkSpawnMode::StaringPoint, + drunken_lifetime: 400, + floor_percent: 0.5, + brush_size: 1, + symmetry: Symmetry::None, + })) } - pub fn open_halls(new_depth: i32) -> DrunkardsWalkBuilder { - DrunkardsWalkBuilder::new( - new_depth, - DrunkardSettings { - spawn_mode: DrunkSpawnMode::Random, - drunken_lifetime: 400, - floor_percent: 0.5, - brush_size: 1, - symmetry: Symmetry::None, - }, - ) + pub fn open_halls() -> Box { + Box::new(DrunkardsWalkBuilder::new(DrunkardSettings { + spawn_mode: DrunkSpawnMode::Random, + drunken_lifetime: 400, + floor_percent: 0.5, + brush_size: 1, + symmetry: Symmetry::None, + })) } - pub fn winding_passages(new_depth: i32) -> DrunkardsWalkBuilder { - DrunkardsWalkBuilder::new( - new_depth, - DrunkardSettings { - spawn_mode: DrunkSpawnMode::Random, - drunken_lifetime: 100, - floor_percent: 0.4, - brush_size: 1, - symmetry: Symmetry::None, - }, - ) + pub fn winding_passages() -> Box { + Box::new(DrunkardsWalkBuilder::new(DrunkardSettings { + spawn_mode: DrunkSpawnMode::Random, + drunken_lifetime: 100, + floor_percent: 0.4, + brush_size: 1, + symmetry: Symmetry::None, + })) } - pub fn fat_passages(new_depth: i32) -> DrunkardsWalkBuilder { - DrunkardsWalkBuilder::new( - new_depth, - DrunkardSettings { - spawn_mode: DrunkSpawnMode::Random, - drunken_lifetime: 100, - floor_percent: 0.4, - brush_size: 2, - symmetry: Symmetry::None, - }, - ) + pub fn fat_passages() -> Box { + Box::new(DrunkardsWalkBuilder::new(DrunkardSettings { + spawn_mode: DrunkSpawnMode::Random, + drunken_lifetime: 100, + floor_percent: 0.4, + brush_size: 2, + symmetry: Symmetry::None, + })) } - pub fn fearful_symmetry(new_depth: i32) -> DrunkardsWalkBuilder { - DrunkardsWalkBuilder::new( - new_depth, - DrunkardSettings { - spawn_mode: DrunkSpawnMode::Random, - drunken_lifetime: 100, - floor_percent: 0.4, - brush_size: 1, - symmetry: Symmetry::Both, - }, - ) + pub fn fearful_symmetry() -> Box { + Box::new(DrunkardsWalkBuilder::new(DrunkardSettings { + spawn_mode: DrunkSpawnMode::Random, + drunken_lifetime: 100, + floor_percent: 0.4, + brush_size: 1, + symmetry: Symmetry::Both, + })) } #[allow(clippy::map_entry)] - fn build(&mut self) { - let mut rng = RandomNumberGenerator::new(); - + fn build(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) { // Set a central starting point - self.starting_position = Position { - x: self.map.width / 2, - y: self.map.height / 2, + let starting_position = Position { + x: build_data.map.width / 2, + y: build_data.map.height / 2, }; - let start_idx = self + let start_idx = build_data .map - .xy_idx(self.starting_position.x, self.starting_position.y); - self.map.tiles[start_idx] = TileType::Floor; + .xy_idx(starting_position.x, starting_position.y); + build_data.map.tiles[start_idx] = TileType::Floor; - let total_tiles = self.map.width * self.map.height; + let total_tiles = build_data.map.width * build_data.map.height; let desired_floor_tiles = (self.settings.floor_percent * total_tiles as f32) as usize; - let mut floor_tile_count = self + let mut floor_tile_count = build_data .map .tiles .iter() .filter(|a| **a == TileType::Floor) .count(); let mut digger_count = 0; - let mut active_digger_count = 0; while floor_tile_count < desired_floor_tiles { let mut did_something = false; @@ -175,16 +118,16 @@ impl DrunkardsWalkBuilder { let mut drunk_y; match self.settings.spawn_mode { DrunkSpawnMode::StaringPoint => { - drunk_x = self.starting_position.x; - drunk_y = self.starting_position.y; + drunk_x = starting_position.x; + drunk_y = starting_position.y; } DrunkSpawnMode::Random => { if digger_count == 0 { - drunk_x = self.starting_position.x; - drunk_y = self.starting_position.y; + drunk_x = starting_position.x; + drunk_y = starting_position.y; } else { - drunk_x = rng.roll_dice(1, self.map.width - 3) + 1; - drunk_y = rng.roll_dice(1, self.map.height - 3) + 1; + drunk_x = rng.roll_dice(1, build_data.map.width - 3) + 1; + drunk_y = rng.roll_dice(1, build_data.map.height - 3) + 1; } } } @@ -192,19 +135,19 @@ impl DrunkardsWalkBuilder { let mut drunk_life = self.settings.drunken_lifetime; while drunk_life > 0 { - let drunk_idx = self.map.xy_idx(drunk_x, drunk_y); - if self.map.tiles[drunk_idx] == TileType::Wall { + let drunk_idx = build_data.map.xy_idx(drunk_x, drunk_y); + if build_data.map.tiles[drunk_idx] == TileType::Wall { did_something = true; } paint( - &mut self.map, + &mut build_data.map, self.settings.symmetry, self.settings.brush_size, drunk_x, drunk_y, ); - self.map.tiles[drunk_idx] = TileType::DownStairs; + build_data.map.tiles[drunk_idx] = TileType::DownStairs; let stagger_direction = rng.roll_dice(1, 4); match stagger_direction { @@ -214,7 +157,7 @@ impl DrunkardsWalkBuilder { } } 2 => { - if drunk_x < self.map.width - 2 { + if drunk_x < build_data.map.width - 2 { drunk_x += 1 } } @@ -224,7 +167,7 @@ impl DrunkardsWalkBuilder { } } _ => { - if drunk_y < self.map.height - 2 { + if drunk_y < build_data.map.height - 2 { drunk_y += 1 } } @@ -234,49 +177,21 @@ impl DrunkardsWalkBuilder { } if did_something { - self.take_snapshot(); - active_digger_count += 1; + build_data.take_snapshot(); } digger_count += 1; - for t in self.map.tiles.iter_mut() { + for t in build_data.map.tiles.iter_mut() { if *t == TileType::DownStairs { *t = TileType::Floor; } } - floor_tile_count = self + floor_tile_count = build_data .map .tiles .iter() .filter(|a| **a == TileType::Floor) .count(); } - - rltk::console::log(format!( - "{} dwarves gave up their sobriety, of whom {} actually found a wall.", - digger_count, active_digger_count - )); - - // Find all tiles we can reach from the starting point - let exit_tile = remove_unreachable_areas_returning_most_distant(&mut self.map, start_idx); - self.take_snapshot(); - - // Place the stairs - self.map.tiles[exit_tile] = TileType::DownStairs; - self.take_snapshot(); - - // Now we build a noise map for use in spawning entities later - self.noise_areas = generate_voronoi_spawn_regions(&self.map, &mut rng); - - // Spawn the entities - for area in self.noise_areas.iter() { - spawner::spawn_region( - &self.map, - &mut rng, - area.1, - self.depth, - &mut self.spawn_list, - ); - } } } diff --git a/src/map_builders/maze.rs b/src/map_builders/maze.rs index e08d447..9202c1b 100644 --- a/src/map_builders/maze.rs +++ b/src/map_builders/maze.rs @@ -6,100 +6,31 @@ use rltk::RandomNumberGenerator; use super::{ generate_voronoi_spawn_regions, remove_unreachable_areas_returning_most_distant, MapBuilder, }; +use crate::map_builders::{BuilderMap, InitialMapBuilder}; use crate::{spawner, Map, Position, TileType, SHOW_MAPGEN_VISUALIZER}; -pub struct MazeBuilder { - map: Map, - starting_position: Position, - depth: i32, - history: Vec, - noise_areas: HashMap>, - spawn_list: Vec<(usize, String)>, -} +pub struct MazeBuilder {} -impl MapBuilder for MazeBuilder { - fn get_map(&self) -> Map { - self.map.clone() - } - - fn get_starting_position(&self) -> Position { - self.starting_position - } - - fn get_snapshot_history(&self) -> Vec { - self.history.clone() - } - - fn build_map(&mut self) { - self.build(); - } - - fn take_snapshot(&mut self) { - if SHOW_MAPGEN_VISUALIZER { - let mut snapshot = self.map.clone(); - for v in snapshot.revealed_tiles.iter_mut() { - *v = true; - } - self.history.push(snapshot); - } - } - - fn get_spawn_list(&self) -> &Vec<(usize, String)> { - &self.spawn_list +impl InitialMapBuilder for MazeBuilder { + fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) { + self.build(rng, build_data); } } impl MazeBuilder { - pub fn new(new_depth: i32) -> MazeBuilder { - MazeBuilder { - map: Map::new(new_depth), - starting_position: Position::default(), - depth: new_depth, - history: Vec::new(), - noise_areas: HashMap::new(), - spawn_list: Vec::new(), - } + pub fn new() -> Box { + Box::new(MazeBuilder {}) } #[allow(clippy::map_entry)] - fn build(&mut self) { - let mut rng = RandomNumberGenerator::new(); - + fn build(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) { // Maze gen let mut maze = Grid::new( - (self.map.width / 2) - 2, - (self.map.height / 2) - 2, - &mut rng, + (build_data.map.width / 2) - 2, + (build_data.map.height / 2) - 2, + rng, ); - maze.generate_maze(self); - - self.starting_position = Position { x: 2, y: 2 }; - let start_idx = self - .map - .xy_idx(self.starting_position.x, self.starting_position.y); - self.take_snapshot(); - - // Find all tiles we can reach from the starting point - let exit_tile = remove_unreachable_areas_returning_most_distant(&mut self.map, start_idx); - self.take_snapshot(); - - // Place the stairs - self.map.tiles[exit_tile] = TileType::DownStairs; - self.take_snapshot(); - - // Now we build a noise map for use in spawning entities later - self.noise_areas = generate_voronoi_spawn_regions(&self.map, &mut rng); - - // Spawn the entities - for area in self.noise_areas.iter() { - spawner::spawn_region( - &self.map, - &mut rng, - area.1, - self.depth, - &mut self.spawn_list, - ); - } + maze.generate_maze(build_data); } } @@ -218,7 +149,7 @@ impl<'a> Grid<'a> { None } - fn generate_maze(&mut self, generator: &mut MazeBuilder) { + fn generate_maze(&mut self, build_data: &mut BuilderMap) { let mut i = 0; loop { self.cells[self.current].visited = true; @@ -250,8 +181,8 @@ impl<'a> Grid<'a> { } if i % 50 == 0 { - self.copy_to_map(&mut generator.map); - generator.take_snapshot(); + self.copy_to_map(&mut build_data.map); + build_data.take_snapshot(); } i += 1; }