From 278b549094951ea6ab65eda654445c47b83110eb Mon Sep 17 00:00:00 2001 From: klangner Date: Tue, 22 Sep 2020 20:38:37 +0200 Subject: [PATCH] refactoring API --- src/{map_builder => filter}/bsp_interior.rs | 44 +++--- src/{map_builder => filter}/bsp_rooms.rs | 38 +++-- .../cellular_automata.rs | 49 +++---- .../cull_unreachable.rs | 6 +- src/{map_builder => filter}/distant_exit.rs | 6 +- src/filter/drunkard.rs | 130 +++++++++++++++++ src/{map_builder => filter}/mod.rs | 49 ++++--- .../rooms_corridors_nearest.rs | 4 +- src/{map_builder => filter}/simple_rooms.rs | 40 +++-- src/{map_builder => filter}/starting_point.rs | 15 +- src/lib.rs | 5 +- src/map_builder/drunkard.rs | 137 ------------------ 12 files changed, 251 insertions(+), 272 deletions(-) rename src/{map_builder => filter}/bsp_interior.rs (73%) rename src/{map_builder => filter}/bsp_rooms.rs (82%) rename src/{map_builder => filter}/cellular_automata.rs (70%) rename src/{map_builder => filter}/cull_unreachable.rs (95%) rename src/{map_builder => filter}/distant_exit.rs (95%) create mode 100644 src/filter/drunkard.rs rename src/{map_builder => filter}/mod.rs (72%) rename src/{map_builder => filter}/rooms_corridors_nearest.rs (95%) rename src/{map_builder => filter}/simple_rooms.rs (52%) rename src/{map_builder => filter}/starting_point.rs (90%) delete mode 100644 src/map_builder/drunkard.rs diff --git a/src/map_builder/bsp_interior.rs b/src/filter/bsp_interior.rs similarity index 73% rename from src/map_builder/bsp_interior.rs rename to src/filter/bsp_interior.rs index 72f900c..b42f147 100644 --- a/src/map_builder/bsp_interior.rs +++ b/src/filter/bsp_interior.rs @@ -6,14 +6,14 @@ //! Example generator usage: //! ``` //! use rand::prelude::*; -//! use mapgen::map_builder::{ -//! MapGenerator, -//! bsp_interior::BspInteriorGen +//! use mapgen::{Map, MapFilter}; +//! use mapgen::filter::{ +//! BspInterior //! }; //! //! let mut rng = StdRng::seed_from_u64(100); -//! let gen = BspInteriorGen::new(); -//! let map = gen.generate_map(80, 50, &mut rng); +//! let gen = BspInterior::new(); +//! let map = gen.modify_map(&mut rng, &Map::new(80, 50)); //! //! assert_eq!(map.width, 80); //! assert_eq!(map.height, 50); @@ -21,34 +21,34 @@ //! use rand::prelude::*; -use super::MapGenerator; +use super::MapFilter; use crate::geometry::{Point, Rect}; use crate::random::Rng; use crate::map::Map; -pub struct BspInteriorGen { +pub struct BspInterior { min_room_size: usize, } -impl MapGenerator for BspInteriorGen { - fn generate_map(&self, width: usize, height: usize, rng : &mut StdRng) -> Map { - self.build(rng, width, height) +impl MapFilter for BspInterior { + fn modify_map(&self, rng: &mut StdRng, map: &Map) -> Map { + self.build(rng, map) } } -impl BspInteriorGen { +impl BspInterior { - pub fn new() -> Box { - Box::new(BspInteriorGen{ + pub fn new() -> Box { + Box::new(BspInterior{ min_room_size: 8, }) } - fn build(&self, rng: &mut StdRng, width: usize, height: usize) -> Map { - let mut map = Map::new(width, height); + fn build(&self, rng: &mut StdRng, map: &Map) -> Map { + let mut new_map = map.clone(); let mut rects: Vec = Vec::new(); - rects.push( Rect::new(1, 1, map.width-2, map.height-2) ); + rects.push( Rect::new(1, 1, new_map.width-2, new_map.height-2) ); let first_room = rects[0]; // Divide the first room self.add_subrects(first_room, rng, &mut rects); @@ -56,21 +56,21 @@ impl BspInteriorGen { let rooms_copy = rects.clone(); for r in rooms_copy.iter() { let room = *r; - map.add_room(room); + new_map.add_room(room); } // Now we want corridors - for i in 0..map.rooms.len()-1 { - let room = map.rooms[i]; - let next_room = map.rooms[i+1]; + for i in 0..new_map.rooms.len()-1 { + let room = new_map.rooms[i]; + let next_room = new_map.rooms[i+1]; let start_x = room.x1 + rng.random_range(1, room.width()); let start_y = room.y1 + rng.random_range(1, room.height()); let end_x = next_room.x1 + (rng.random_range(1, next_room.width())); let end_y = next_room.y1 + (rng.random_range(1, next_room.width())); - map.add_corridor(Point::new(start_x, start_y), Point::new(end_x, end_y)); + new_map.add_corridor(Point::new(start_x, start_y), Point::new(end_x, end_y)); } - map + new_map } fn add_subrects(&self, rect: Rect, rng: &mut StdRng, rects: &mut Vec) { diff --git a/src/map_builder/bsp_rooms.rs b/src/filter/bsp_rooms.rs similarity index 82% rename from src/map_builder/bsp_rooms.rs rename to src/filter/bsp_rooms.rs index 67bf461..8c6fa91 100644 --- a/src/map_builder/bsp_rooms.rs +++ b/src/filter/bsp_rooms.rs @@ -6,14 +6,12 @@ //! Example generator usage: //! ``` //! use rand::prelude::*; -//! use mapgen::map_builder::{ -//! MapGenerator, -//! bsp_rooms::BspRoomsGen -//! }; +//! use mapgen::{Map, MapFilter}; +//! use mapgen::filter::BspRooms; //! //! let mut rng = StdRng::seed_from_u64(100); -//! let gen = BspRoomsGen::new(); -//! let map = gen.generate_map(80, 50, &mut rng); +//! let gen = BspRooms::new(); +//! let map = gen.modify_map(&mut rng, &Map::new(80, 50)); //! //! assert_eq!(map.width, 80); //! assert_eq!(map.height, 50); @@ -21,34 +19,34 @@ //! use rand::prelude::*; -use super::MapGenerator; +use super::MapFilter; use crate::geometry::Rect; use crate::random::Rng; use crate::map::{Map, TileType}; -pub struct BspRoomsGen { +pub struct BspRooms { max_split: usize, } -impl MapGenerator for BspRoomsGen { - fn generate_map(&self, width: usize, height: usize, rng : &mut StdRng) -> Map { - self.build_rooms(width, height, rng) +impl MapFilter for BspRooms { + fn modify_map(&self, rng: &mut StdRng, map: &Map) -> Map { + self.build_rooms(map, rng) } } -impl BspRoomsGen { - pub fn new() -> Box { - Box::new(BspRoomsGen { +impl BspRooms { + pub fn new() -> Box { + Box::new(BspRooms { max_split: 240, }) } - fn build_rooms(&self, width: usize, height: usize, rng : &mut StdRng) -> Map { - let mut map = Map::new(width, height); + fn build_rooms(&self, map: &Map, rng : &mut StdRng) -> Map { + let mut new_map = map.clone(); let mut rects: Vec = Vec::new(); // Start with a single map-sized rectangle - rects.push( Rect::new(2, 2, width-5, height-5) ); + rects.push( Rect::new(2, 2, new_map.width-5, new_map.height-5) ); let first_room = rects[0]; rects.append(&mut self.split_into_subrects(first_room)); // Divide the first room @@ -59,14 +57,14 @@ impl BspRoomsGen { let rect = self.get_random_rect(rng, &rects); let candidate = self.get_random_sub_rect(rect, rng); - if self.is_possible(candidate, &map) { - map.add_room(candidate); + if self.is_possible(candidate, &new_map) { + new_map.add_room(candidate); rects.append(&mut self.split_into_subrects(rect)); } n_rooms += 1; } - map + new_map } fn split_into_subrects(&self, rect: Rect) -> Vec { diff --git a/src/map_builder/cellular_automata.rs b/src/filter/cellular_automata.rs similarity index 70% rename from src/map_builder/cellular_automata.rs rename to src/filter/cellular_automata.rs index aff6e63..a7df128 100644 --- a/src/map_builder/cellular_automata.rs +++ b/src/filter/cellular_automata.rs @@ -9,14 +9,12 @@ //! Example generator usage: //! ``` //! use rand::prelude::*; -//! use mapgen::map_builder::{ -//! MapGenerator, -//! cellular_automata::CellularAutomataGen -//! }; +//! use mapgen::{Map, MapFilter}; +//! use mapgen::filter::CellularAutomata; //! //! let mut rng = StdRng::seed_from_u64(100); -//! let gen = CellularAutomataGen::new(); -//! let map = gen.generate_map(80, 50, &mut rng); +//! let gen = CellularAutomata::new(); +//! let map = gen.modify_map(&mut rng, &Map::new(80, 50)); //! //! assert_eq!(map.width, 80); //! assert_eq!(map.height, 50); @@ -24,54 +22,47 @@ //! use rand::prelude::*; -use super::{MapGenerator, MapModifier}; +use super::MapFilter; use crate::map::{Map, TileType}; /// Map generator and modifier -pub struct CellularAutomataGen {} +pub struct CellularAutomata {} -impl MapGenerator for CellularAutomataGen { - fn generate_map(&self, width: usize, height: usize, rng : &mut StdRng) -> Map { - self.build(width, height, rng) +impl MapFilter for CellularAutomata { + fn modify_map(&self, rng: &mut StdRng, map: &Map) -> Map { + self.build(map, rng) } } -impl CellularAutomataGen { +impl CellularAutomata { /// Create generator which will create map with the given dimension. - pub fn new() -> Box { - Box::new(CellularAutomataGen {}) + pub fn new() -> Box { + Box::new(CellularAutomata {}) } /// Generate map - fn build(&self, width: usize, height: usize, rng: &mut StdRng) -> Map { - let mut map = Map::new(width, height); + fn build(&self, map: &Map, rng: &mut StdRng) -> Map { + let mut new_map = map.clone(); // First we completely randomize the map, setting 55% of it to be floor. - for y in 1..height-1 { - for x in 1..width-1 { + for y in 1..new_map.height-1 { + for x in 1..new_map.width-1 { let roll = rng.next_u32() % 100; - if roll > 55 { map.set_tile(x, y, TileType::Floor) } - else { map.set_tile(x, y, TileType::Wall) } + if roll > 55 { new_map.set_tile(x, y, TileType::Floor) } + else { new_map.set_tile(x, y, TileType::Wall) } } } // Now we iteratively apply cellular automata rules for _ in 0..15 { - map = apply_iteration(&map); + new_map = apply_iteration(&new_map); } - map + new_map } } -impl MapModifier for CellularAutomataGen { - fn modify_map(&self, _rng: &mut StdRng, map : &Map) -> Map { - apply_iteration(map) - } -} - - fn apply_iteration(map: &Map) -> Map { let mut new_map = map.clone(); diff --git a/src/map_builder/cull_unreachable.rs b/src/filter/cull_unreachable.rs similarity index 95% rename from src/map_builder/cull_unreachable.rs rename to src/filter/cull_unreachable.rs index 6124a5b..159f6c8 100644 --- a/src/map_builder/cull_unreachable.rs +++ b/src/filter/cull_unreachable.rs @@ -5,7 +5,7 @@ //! use rand::prelude::StdRng; -use super::MapModifier; +use super::MapFilter; use crate::map::{Map, TileType}; use crate::dijkstra::DijkstraMap; @@ -13,7 +13,7 @@ use crate::dijkstra::DijkstraMap; /// Remove unreachable areas from the map. pub struct CullUnreachable {} -impl MapModifier for CullUnreachable { +impl MapFilter for CullUnreachable { fn modify_map(&self, _: &mut StdRng, map: &Map) -> Map { self.build(map) } @@ -49,7 +49,7 @@ impl CullUnreachable { mod tests { use rand::prelude::*; use super::*; - use super::MapModifier; + use super::MapFilter; use crate::geometry::Point; use crate::map::Map; diff --git a/src/map_builder/distant_exit.rs b/src/filter/distant_exit.rs similarity index 95% rename from src/map_builder/distant_exit.rs rename to src/filter/distant_exit.rs index d6f3188..0aa659f 100644 --- a/src/map_builder/distant_exit.rs +++ b/src/filter/distant_exit.rs @@ -7,7 +7,7 @@ use std::f32; use rand::prelude::StdRng; use crate::geometry::Point; -use super::MapModifier; +use super::MapFilter; use crate::map::Map; use crate::dijkstra::DijkstraMap; @@ -15,7 +15,7 @@ use crate::dijkstra::DijkstraMap; /// Add exist position to the map based on the distance from the start point. pub struct DistantExit {} -impl MapModifier for DistantExit { +impl MapFilter for DistantExit { fn modify_map(&self, _: &mut StdRng, map: &Map) -> Map { self.build(map) } @@ -53,7 +53,7 @@ impl DistantExit { mod tests { use rand::prelude::*; use super::*; - use super::MapModifier; + use super::MapFilter; use crate::geometry::Point; use crate::map::Map; diff --git a/src/filter/drunkard.rs b/src/filter/drunkard.rs new file mode 100644 index 0000000..607cc0c --- /dev/null +++ b/src/filter/drunkard.rs @@ -0,0 +1,130 @@ +//! Example generator usage: +//! ``` +//! use rand::prelude::*; +//! use mapgen::{Map, MapFilter}; +//! use mapgen::filter::DrunkardsWalk; +//! +//! let mut rng = StdRng::seed_from_u64(100); +//! let gen = DrunkardsWalk::open_area(); +//! let map = gen.modify_map(&mut rng, &Map::new(80, 50)); +//! +//! assert_eq!(map.width, 80); +//! assert_eq!(map.height, 50); +//! ``` +//! + +use rand::prelude::*; +use super::MapFilter; +use crate::{ + map::{Map, Symmetry, TileType}, + geometry::Point, + random::Rng +}; + + +#[derive(PartialEq, Copy, Clone)] +pub enum DrunkSpawnMode { StartingPoint, Random } + +pub struct DrunkardsWalk { + spawn_mode : DrunkSpawnMode, + drunken_lifetime : i32, + floor_percent: f32, + brush_size: usize, + symmetry: Symmetry +} + +impl MapFilter for DrunkardsWalk { + fn modify_map(&self, rng: &mut StdRng, map: &Map) -> Map { + self.build(rng, map) + } +} + +impl DrunkardsWalk { + pub fn new( spawn_mode: DrunkSpawnMode, + drunken_lifetime: i32, + floor_percent: f32, + brush_size: usize, + symmetry: Symmetry) -> Box + { + Box::new(DrunkardsWalk{ + spawn_mode, + drunken_lifetime, + floor_percent, + brush_size, + symmetry + }) + } + + pub fn open_area() -> Box { + Self::new(DrunkSpawnMode::StartingPoint, 400, 0.5, 1, Symmetry::None) + } + + pub fn open_halls() -> Box { + Self::new(DrunkSpawnMode::Random, 400, 0.5, 1, Symmetry::None) + } + + pub fn winding_passages() -> Box { + Self::new(DrunkSpawnMode::Random, 400, 0.4, 1, Symmetry::None) + } + + pub fn fat_passages() -> Box { + Self::new(DrunkSpawnMode::Random, 400, 0.4, 2, Symmetry::None) + } + + pub fn fearful_symmetry() -> Box { + Self::new(DrunkSpawnMode::Random, 400, 0.4, 1, Symmetry::Both) + } + + fn build(&self, rng: &mut StdRng, map: &Map) -> Map { + let mut new_map = map.clone(); + // Set a central starting point + let starting_position = Point::new( new_map.width / 2, new_map.height / 2 ); + new_map.set_tile(starting_position.x, starting_position.y, TileType::Floor); + + let total_tiles = new_map.width * new_map.height; + let desired_floor_tiles = (self.floor_percent * total_tiles as f32) as usize; + let mut floor_tile_count = new_map.tiles.iter().filter(|a| **a == TileType::Floor).count(); + let mut digger_count = 0; + while floor_tile_count < desired_floor_tiles { + let mut drunk_x; + let mut drunk_y; + match self.spawn_mode { + DrunkSpawnMode::StartingPoint => { + drunk_x = starting_position.x; + drunk_y = starting_position.y; + } + DrunkSpawnMode::Random => { + if digger_count == 0 { + drunk_x = starting_position.x; + drunk_y = starting_position.y; + } else { + drunk_x = rng.roll_dice(1, new_map.width - 3) + 1; + drunk_y = rng.roll_dice(1, new_map.height - 3) + 1; + } + } + } + let mut drunk_life = self.drunken_lifetime; + + while drunk_life > 0 { + new_map.set_tile(drunk_x, drunk_y, TileType::Wall); + new_map.paint(self.symmetry, self.brush_size, drunk_x, drunk_y); + // map.exit_point = Some(Point::new(drunk_x, drunk_y)); + + let stagger_direction = rng.roll_dice(1, 4); + match stagger_direction { + 1 => { if drunk_x > 2 { drunk_x -= 1; } } + 2 => { if drunk_x < new_map.width-2 { drunk_x += 1; } } + 3 => { if drunk_y > 2 { drunk_y -=1; } } + _ => { if drunk_y < new_map.height-2 { drunk_y += 1; } } + } + + drunk_life -= 1; + } + + digger_count += 1; + floor_tile_count = new_map.tiles.iter().filter(|a| **a == TileType::Floor).count(); + } + + new_map + } +} \ No newline at end of file diff --git a/src/map_builder/mod.rs b/src/filter/mod.rs similarity index 72% rename from src/map_builder/mod.rs rename to src/filter/mod.rs index bbc9d0f..2b60d65 100644 --- a/src/map_builder/mod.rs +++ b/src/filter/mod.rs @@ -8,17 +8,15 @@ //! //! Example //! ``` -//! use mapgen::{ -//! map_builder::{ -//! MapModifier, MapBuilder, -//! cellular_automata::CellularAutomataGen, -//! starting_point::{AreaStartingPosition, XStart, YStart} -//! }, -//! map::{Map, TileType}, -//! geometry::Point, +//! use mapgen::{MapFilter, MapBuilder, Map, TileType}; +//! use mapgen::filter::{ +//! CellularAutomata, +//! starting_point::{AreaStartingPosition, XStart, YStart} //! }; +//! use mapgen::geometry::Point; //! -//! let map = MapBuilder::new(CellularAutomataGen::new()) +//! let map = MapBuilder::new() +//! .with(CellularAutomata::new()) //! .with(AreaStartingPosition::new(XStart::CENTER, YStart::CENTER)) //! .build_map(80, 50); //! @@ -38,39 +36,41 @@ pub mod simple_rooms; pub mod rooms_corridors_nearest; pub mod starting_point; +pub use bsp_interior::BspInterior; +pub use bsp_rooms::BspRooms; +pub use cellular_automata::CellularAutomata; +pub use cull_unreachable::CullUnreachable; +pub use distant_exit::DistantExit; +pub use drunkard::DrunkardsWalk; +pub use simple_rooms::SimpleRooms; +pub use rooms_corridors_nearest::NearestCorridors; +pub use starting_point::AreaStartingPosition; + use std::time::{SystemTime, UNIX_EPOCH}; use rand::prelude::*; use crate::map::Map; -/// Trait which should be implemented by any map generator which want to be used -/// by MapBuilder -pub trait MapGenerator { - fn generate_map(&self, width: usize, height: usize, rng: &mut StdRng) -> Map; -} - /// Trait which should be implemented by map modifier. /// Modifier takes initiall map and apply changes to it. -pub trait MapModifier { +pub trait MapFilter { fn modify_map(&self, rng: &mut StdRng, map: &Map) -> Map; } /// Used to chain MapBuilder and MapModifiers to create the final map. pub struct MapBuilder { - generator: Box, - modifiers: Vec>, + modifiers: Vec>, } impl MapBuilder { /// Create Map Builder with initial map generator - pub fn new(generator : Box) -> MapBuilder { + pub fn new() -> MapBuilder { MapBuilder { - generator, modifiers: Vec::new(), } } - pub fn with(&mut self, modifier : Box) -> &mut MapBuilder { + pub fn with(&mut self, modifier : Box) -> &mut MapBuilder { self.modifiers.push(modifier); self } @@ -84,7 +84,7 @@ impl MapBuilder { /// Build map using provided random number generator pub fn build_map_with_rng(&mut self, width: usize, height: usize, rng: &mut StdRng) -> Map { - let mut map = self.generator.generate_map(width, height, rng); + let mut map = Map::new(width, height); // Build additional layers in turn for modifier in self.modifiers.iter() { @@ -102,12 +102,13 @@ impl MapBuilder { #[cfg(test)] mod tests { use super::*; - use cellular_automata::CellularAutomataGen; + use cellular_automata::CellularAutomata; use starting_point::{AreaStartingPosition, XStart, YStart}; #[test] fn test_ca_map() { - let map = MapBuilder::new(CellularAutomataGen::new()) + let map = MapBuilder::new() + .with(CellularAutomata::new()) .with(AreaStartingPosition::new(XStart::CENTER, YStart::CENTER)) .build_map(80, 50); diff --git a/src/map_builder/rooms_corridors_nearest.rs b/src/filter/rooms_corridors_nearest.rs similarity index 95% rename from src/map_builder/rooms_corridors_nearest.rs rename to src/filter/rooms_corridors_nearest.rs index e036592..0d92954 100644 --- a/src/map_builder/rooms_corridors_nearest.rs +++ b/src/filter/rooms_corridors_nearest.rs @@ -1,14 +1,14 @@ //! Connect nearest rooms on the map with corridors //! use rand::prelude::StdRng; -use super::MapModifier; +use super::MapFilter; use crate::map::Map; use std::collections::HashSet; pub struct NearestCorridors {} -impl MapModifier for NearestCorridors { +impl MapFilter for NearestCorridors { fn modify_map(&self, _: &mut StdRng, map: &Map) -> Map { self.corridors(map) } diff --git a/src/map_builder/simple_rooms.rs b/src/filter/simple_rooms.rs similarity index 52% rename from src/map_builder/simple_rooms.rs rename to src/filter/simple_rooms.rs index 87215ef..24b7c4b 100644 --- a/src/map_builder/simple_rooms.rs +++ b/src/filter/simple_rooms.rs @@ -6,14 +6,12 @@ //! Example generator usage: //! ``` //! use rand::prelude::*; -//! use mapgen::map_builder::{ -//! MapGenerator, -//! simple_rooms::SimpleRoomsGen -//! }; +//! use mapgen::{MapFilter, Map}; +//! use mapgen::filter::SimpleRooms; //! //! let mut rng = StdRng::seed_from_u64(100); -//! let gen = SimpleRoomsGen::new(); -//! let map = gen.generate_map(80, 50, &mut rng); +//! let gen = SimpleRooms::new(); +//! let map = gen.modify_map(&mut rng, &Map::new(80, 50)); //! //! assert_eq!(map.width, 80); //! assert_eq!(map.height, 50); @@ -21,50 +19,50 @@ //! use rand::prelude::*; -use super::MapGenerator; +use super::MapFilter; use crate::geometry::Rect; use crate::random::Rng; use crate::map::{Map}; -pub struct SimpleRoomsGen { +pub struct SimpleRooms { max_rooms: usize, min_room_size: usize, max_room_size: usize, } -impl MapGenerator for SimpleRoomsGen { - fn generate_map(&self, width: usize, height: usize, rng : &mut StdRng) -> Map { - self.build_rooms(width, height, rng) +impl MapFilter for SimpleRooms { + fn modify_map(&self, rng: &mut StdRng, map: &Map) -> Map { + self.build_rooms(map, rng) } } -impl SimpleRoomsGen { - pub fn new() -> Box { - Box::new(SimpleRoomsGen{ +impl SimpleRooms { + pub fn new() -> Box { + Box::new(SimpleRooms{ max_rooms: 30, min_room_size: 6, max_room_size: 10 }) } - fn build_rooms(&self, width: usize, height: usize, rng : &mut StdRng) -> Map { - let mut map = Map::new(width, height); + fn build_rooms(&self, map: &Map, rng : &mut StdRng) -> Map { + let mut new_map = map.clone(); // Create room dimensions for _ in 0..self.max_rooms { let w = rng.random_range(self.min_room_size, self.max_room_size); let h = rng.random_range(self.min_room_size, self.max_room_size); - let x = rng.random_range(1, width - w); - let y = rng.random_range(1, height - h); + let x = rng.random_range(1, new_map.width - w); + let y = rng.random_range(1, new_map.height - h); let new_room = Rect::new(x, y, w, h); - let intersects = map.rooms.iter().any(|r| new_room.intersect(r)); + let intersects = new_map.rooms.iter().any(|r| new_room.intersect(r)); if !intersects { - map.add_room(new_room); + new_map.add_room(new_room); } } - map + new_map } } \ No newline at end of file diff --git a/src/map_builder/starting_point.rs b/src/filter/starting_point.rs similarity index 90% rename from src/map_builder/starting_point.rs rename to src/filter/starting_point.rs index 94c2f6e..672e58c 100644 --- a/src/map_builder/starting_point.rs +++ b/src/filter/starting_point.rs @@ -6,14 +6,9 @@ //! Example modifier usage: //! ``` //! use rand::prelude::*; -//! use mapgen::{ -//! map_builder::{ -//! MapModifier, -//! starting_point::{AreaStartingPosition, XStart, YStart}, -//! }, -//! map::{Map, TileType}, -//! geometry::Point, -//! }; +//! use mapgen::{MapFilter, Map, TileType}; +//! use mapgen::filter::starting_point::{AreaStartingPosition, XStart, YStart}; +//! use mapgen::geometry::Point; //! //! let mut rng = StdRng::seed_from_u64(100); //! let mut map = Map::new(80, 50); @@ -26,7 +21,7 @@ //! use rand::prelude::StdRng; -use super::{MapModifier}; +use super::MapFilter; use crate::geometry::Point; use crate::map::{Map, TileType}; @@ -43,7 +38,7 @@ pub struct AreaStartingPosition { y : YStart } -impl MapModifier for AreaStartingPosition { +impl MapFilter for AreaStartingPosition { fn modify_map(&self, _: &mut StdRng, map: &Map) -> Map { self.build(map) } diff --git a/src/lib.rs b/src/lib.rs index 26cb4e2..64f5b56 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,9 +4,12 @@ //! * Dungeon maps //! -pub mod map_builder; +pub mod filter; pub mod geometry; pub mod map; +pub use map::{Map, TileType}; +pub use filter::{MapFilter, MapBuilder}; + pub (crate) mod dijkstra; pub (crate) mod random; \ No newline at end of file diff --git a/src/map_builder/drunkard.rs b/src/map_builder/drunkard.rs deleted file mode 100644 index 7215a78..0000000 --- a/src/map_builder/drunkard.rs +++ /dev/null @@ -1,137 +0,0 @@ -//! Example generator usage: -//! ``` -//! use rand::prelude::*; -//! use mapgen::map_builder::{ -//! MapGenerator, -//! drunkard::DrunkardsWalkGen -//! }; -//! -//! let mut rng = StdRng::seed_from_u64(100); -//! let gen = DrunkardsWalkGen::open_area(); -//! let map = gen.generate_map(80, 50, &mut rng); -//! -//! assert_eq!(map.width, 80); -//! assert_eq!(map.height, 50); -//! ``` -//! - -use rand::prelude::*; -use super::MapGenerator; -use crate::{ - map::{Map, Symmetry, TileType}, - geometry::Point, - random::Rng -}; - - -#[derive(PartialEq, Copy, Clone)] -pub enum DrunkSpawnMode { StartingPoint, Random } - -pub struct DrunkardsWalkGen { - spawn_mode : DrunkSpawnMode, - drunken_lifetime : i32, - floor_percent: f32, - brush_size: usize, - symmetry: Symmetry -} - -impl MapGenerator for DrunkardsWalkGen { - fn generate_map(&self, width: usize, height: usize, rng: &mut StdRng) -> Map { - self.build(rng, width, height) - } -} - -impl DrunkardsWalkGen { - pub fn new( spawn_mode: DrunkSpawnMode, - drunken_lifetime: i32, - floor_percent: f32, - brush_size: usize, - symmetry: Symmetry) -> Box - { - Box::new(DrunkardsWalkGen{ - spawn_mode, - drunken_lifetime, - floor_percent, - brush_size, - symmetry - }) - } - - pub fn open_area() -> Box { - DrunkardsWalkGen::new(DrunkSpawnMode::StartingPoint, 400, 0.5, 1, Symmetry::None) - } - - pub fn open_halls() -> Box { - DrunkardsWalkGen::new(DrunkSpawnMode::Random, 400, 0.5, 1, Symmetry::None) - } - - pub fn winding_passages() -> Box { - DrunkardsWalkGen::new(DrunkSpawnMode::Random, 400, 0.4, 1, Symmetry::None) - } - - pub fn fat_passages() -> Box { - DrunkardsWalkGen::new(DrunkSpawnMode::Random, 400, 0.4, 2, Symmetry::None) - } - - pub fn fearful_symmetry() -> Box { - DrunkardsWalkGen::new(DrunkSpawnMode::Random, 400, 0.4, 1, Symmetry::Both) - } - - fn build(&self, rng: &mut StdRng, width: usize, height: usize) -> Map { - let mut map = Map::new(width, height); - // Set a central starting point - let starting_position = Point::new( map.width / 2, map.height / 2 ); - map.set_tile(starting_position.x, starting_position.y, TileType::Floor); - - let total_tiles = map.width * map.height; - let desired_floor_tiles = (self.floor_percent * total_tiles as f32) as usize; - let mut floor_tile_count = map.tiles.iter().filter(|a| **a == TileType::Floor).count(); - let mut digger_count = 0; - while floor_tile_count < desired_floor_tiles { - let mut drunk_x; - let mut drunk_y; - match self.spawn_mode { - DrunkSpawnMode::StartingPoint => { - drunk_x = starting_position.x; - drunk_y = starting_position.y; - } - DrunkSpawnMode::Random => { - if digger_count == 0 { - drunk_x = starting_position.x; - drunk_y = starting_position.y; - } else { - drunk_x = rng.roll_dice(1, map.width - 3) + 1; - drunk_y = rng.roll_dice(1, map.height - 3) + 1; - } - } - } - let mut drunk_life = self.drunken_lifetime; - - while drunk_life > 0 { - map.set_tile(drunk_x, drunk_y, TileType::Wall); - map.paint(self.symmetry, self.brush_size, drunk_x, drunk_y); - // map.exit_point = Some(Point::new(drunk_x, drunk_y)); - - let stagger_direction = rng.roll_dice(1, 4); - match stagger_direction { - 1 => { if drunk_x > 2 { drunk_x -= 1; } } - 2 => { if drunk_x < map.width-2 { drunk_x += 1; } } - 3 => { if drunk_y > 2 { drunk_y -=1; } } - _ => { if drunk_y < map.height-2 { drunk_y += 1; } } - } - - drunk_life -= 1; - } - - digger_count += 1; - // for t in map.tiles.iter_mut() { - // if *t == TileType::DownStairs { - // *t = TileType::Floor; - // } - // } - floor_tile_count = map.tiles.iter().filter(|a| **a == TileType::Floor).count(); - } - - map - } -} \ No newline at end of file