refactoring API

This commit is contained in:
klangner 2020-09-22 20:38:37 +02:00
parent a75f565cbb
commit 278b549094
12 changed files with 251 additions and 272 deletions

View File

@ -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<BspInteriorGen> {
Box::new(BspInteriorGen{
pub fn new() -> Box<BspInterior> {
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<Rect> = 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<Rect>) {

View File

@ -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<BspRoomsGen> {
Box::new(BspRoomsGen {
impl BspRooms {
pub fn new() -> Box<BspRooms> {
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<Rect> = 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<Rect> {

View File

@ -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<CellularAutomataGen> {
Box::new(CellularAutomataGen {})
pub fn new() -> Box<CellularAutomata> {
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();

View File

@ -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;

View File

@ -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;

130
src/filter/drunkard.rs Normal file
View File

@ -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<DrunkardsWalk>
{
Box::new(DrunkardsWalk{
spawn_mode,
drunken_lifetime,
floor_percent,
brush_size,
symmetry
})
}
pub fn open_area() -> Box<DrunkardsWalk> {
Self::new(DrunkSpawnMode::StartingPoint, 400, 0.5, 1, Symmetry::None)
}
pub fn open_halls() -> Box<DrunkardsWalk> {
Self::new(DrunkSpawnMode::Random, 400, 0.5, 1, Symmetry::None)
}
pub fn winding_passages() -> Box<DrunkardsWalk> {
Self::new(DrunkSpawnMode::Random, 400, 0.4, 1, Symmetry::None)
}
pub fn fat_passages() -> Box<DrunkardsWalk> {
Self::new(DrunkSpawnMode::Random, 400, 0.4, 2, Symmetry::None)
}
pub fn fearful_symmetry() -> Box<DrunkardsWalk> {
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
}
}

View File

@ -8,17 +8,15 @@
//!
//! Example
//! ```
//! use mapgen::{
//! map_builder::{
//! MapModifier, MapBuilder,
//! cellular_automata::CellularAutomataGen,
//! use mapgen::{MapFilter, MapBuilder, Map, TileType};
//! use mapgen::filter::{
//! CellularAutomata,
//! starting_point::{AreaStartingPosition, XStart, YStart}
//! },
//! map::{Map, TileType},
//! geometry::Point,
//! };
//! 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<dyn MapGenerator>,
modifiers: Vec<Box<dyn MapModifier>>,
modifiers: Vec<Box<dyn MapFilter>>,
}
impl MapBuilder {
/// Create Map Builder with initial map generator
pub fn new(generator : Box<dyn MapGenerator>) -> MapBuilder {
pub fn new() -> MapBuilder {
MapBuilder {
generator,
modifiers: Vec::new(),
}
}
pub fn with(&mut self, modifier : Box<dyn MapModifier>) -> &mut MapBuilder {
pub fn with(&mut self, modifier : Box<dyn MapFilter>) -> &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);

View File

@ -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)
}

View File

@ -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<SimpleRoomsGen> {
Box::new(SimpleRoomsGen{
impl SimpleRooms {
pub fn new() -> Box<SimpleRooms> {
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
}
}

View File

@ -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)
}

View File

@ -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;

View File

@ -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<DrunkardsWalkGen>
{
Box::new(DrunkardsWalkGen{
spawn_mode,
drunken_lifetime,
floor_percent,
brush_size,
symmetry
})
}
pub fn open_area() -> Box<DrunkardsWalkGen> {
DrunkardsWalkGen::new(DrunkSpawnMode::StartingPoint, 400, 0.5, 1, Symmetry::None)
}
pub fn open_halls() -> Box<DrunkardsWalkGen> {
DrunkardsWalkGen::new(DrunkSpawnMode::Random, 400, 0.5, 1, Symmetry::None)
}
pub fn winding_passages() -> Box<DrunkardsWalkGen> {
DrunkardsWalkGen::new(DrunkSpawnMode::Random, 400, 0.4, 1, Symmetry::None)
}
pub fn fat_passages() -> Box<DrunkardsWalkGen> {
DrunkardsWalkGen::new(DrunkSpawnMode::Random, 400, 0.4, 2, Symmetry::None)
}
pub fn fearful_symmetry() -> Box<DrunkardsWalkGen> {
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
}
}