Add ability to associate arbitrary BuilderData
with maps.
I'm finding that, for best results, I need to integrate everything into my map generation process. So for instance, object/monster spawns need to run as a filter so they can influence future steps. This associates a `Clone + Default` type with maps and makes it available to filters. `NoData` exists for the current behavior. All examples/tests/demos have been updated accordingly.
This commit is contained in:
parent
1ef42b11ad
commit
957dcca447
|
@ -1,7 +1,7 @@
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
use web_sys;
|
use web_sys;
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
use mapgen::{Map, MapBuilder, geometry::Point};
|
use mapgen::{Map, MapBuilder, NoData, geometry::Point};
|
||||||
use mapgen::filter::*;
|
use mapgen::filter::*;
|
||||||
use mapgen::metric;
|
use mapgen::metric;
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ pub struct World {
|
||||||
width: u32,
|
width: u32,
|
||||||
height: u32,
|
height: u32,
|
||||||
tiles: Vec<Cell>,
|
tiles: Vec<Cell>,
|
||||||
map: Map,
|
map: Map<NoData>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
|
@ -32,7 +32,7 @@ pub struct Position {
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
impl World {
|
impl World {
|
||||||
|
|
||||||
fn new(width: u32, height: u32, map: Map) -> World {
|
fn new(width: u32, height: u32, map: Map<NoData>) -> World {
|
||||||
let tiles = (0..map.tiles.len())
|
let tiles = (0..map.tiles.len())
|
||||||
.map(|i| if map.tiles[i].is_walkable() {Cell::Floor} else {Cell::Wall})
|
.map(|i| if map.tiles[i].is_walkable() {Cell::Floor} else {Cell::Wall})
|
||||||
.collect();
|
.collect();
|
||||||
|
@ -176,7 +176,7 @@ impl World {
|
||||||
div.set_inner_html(&info);
|
div.set_inner_html(&info);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_map_metrics(map: &Map) {
|
fn print_map_metrics(map: &Map<NoData>) {
|
||||||
let window = web_sys::window().expect("no global `window` exists");
|
let window = web_sys::window().expect("no global `window` exists");
|
||||||
let document = window.document().expect("should have a document on window");
|
let document = window.document().expect("should have a document on window");
|
||||||
let div = document.get_element_by_id("map-metrics").expect("Need div with id: map-metrics");
|
let div = document.get_element_by_id("map-metrics").expect("Need div with id: map-metrics");
|
||||||
|
|
|
@ -4,7 +4,7 @@ use mapgen::*;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut rng = StdRng::seed_from_u64(907647352);
|
let mut rng = StdRng::seed_from_u64(907647352);
|
||||||
let gen = BspInterior::new();
|
let gen = BspInterior::<NoData>::new();
|
||||||
let map = gen.modify_map(&mut rng, &Map::new(20, 10));
|
let map = gen.modify_map(&mut rng, &Map::new(20, 10));
|
||||||
println!("{:}", &map);
|
println!("{:}", &map);
|
||||||
}
|
}
|
|
@ -6,7 +6,7 @@ use mapgen::*;
|
||||||
fn main() {
|
fn main() {
|
||||||
let system_time = SystemTime::now().duration_since(UNIX_EPOCH).expect("Can't access system time");
|
let system_time = SystemTime::now().duration_since(UNIX_EPOCH).expect("Can't access system time");
|
||||||
let mut rng = StdRng::seed_from_u64(system_time.as_millis() as u64);
|
let mut rng = StdRng::seed_from_u64(system_time.as_millis() as u64);
|
||||||
let gen = BspRooms::new();
|
let gen = BspRooms::<NoData>::new();
|
||||||
let map = gen.modify_map(&mut rng, &Map::new(80, 50));
|
let map = gen.modify_map(&mut rng, &Map::new(80, 50));
|
||||||
println!("{:}", &map);
|
println!("{:}", &map);
|
||||||
}
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
use mapgen::{
|
use mapgen::{
|
||||||
MapBuilder,
|
MapBuilder,
|
||||||
|
NoData,
|
||||||
filter::{
|
filter::{
|
||||||
NoiseGenerator,
|
NoiseGenerator,
|
||||||
CellularAutomata,
|
CellularAutomata,
|
||||||
|
@ -12,7 +13,7 @@ use mapgen::{
|
||||||
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let map = MapBuilder::new(20, 20)
|
let map = MapBuilder::<NoData>::new(20, 20)
|
||||||
.with(NoiseGenerator::uniform())
|
.with(NoiseGenerator::uniform())
|
||||||
.with(CellularAutomata::new())
|
.with(CellularAutomata::new())
|
||||||
.with(AreaStartingPosition::new(XStart::CENTER, YStart::CENTER))
|
.with(AreaStartingPosition::new(XStart::CENTER, YStart::CENTER))
|
||||||
|
|
|
@ -25,25 +25,26 @@
|
||||||
//! ---
|
//! ---
|
||||||
//!
|
//!
|
||||||
|
|
||||||
use std::collections::VecDeque;
|
use std::{collections::VecDeque, marker::PhantomData};
|
||||||
use std::f32::MAX;
|
use std::f32::MAX;
|
||||||
use super::map::Map;
|
use super::map::{BuilderData, Map};
|
||||||
|
|
||||||
|
|
||||||
/// Representation of a Dijkstra flow map.
|
/// Representation of a Dijkstra flow map.
|
||||||
/// map is a vector of floats, having a size equal to size_x * size_y (one per tile).
|
/// map is a vector of floats, having a size equal to size_x * size_y (one per tile).
|
||||||
/// size_x and size_y are stored for overflow avoidance.
|
/// size_x and size_y are stored for overflow avoidance.
|
||||||
/// max_depth is the maximum number of iterations this search shall support.
|
/// max_depth is the maximum number of iterations this search shall support.
|
||||||
pub struct DijkstraMap {
|
pub struct DijkstraMap<D> {
|
||||||
pub tiles: Vec<f32>,
|
pub tiles: Vec<f32>,
|
||||||
size_x: usize,
|
size_x: usize,
|
||||||
size_y: usize,
|
size_y: usize,
|
||||||
max_depth: f32,
|
max_depth: f32,
|
||||||
|
phantom: PhantomData<D>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DijkstraMap {
|
impl<D: BuilderData> DijkstraMap<D> {
|
||||||
//! Construct a new Dijkstra map, ready to run.
|
//! Construct a new Dijkstra map, ready to run.
|
||||||
pub fn new(map: &Map) -> DijkstraMap {
|
pub fn new(map: &Map<D>) -> DijkstraMap<D> {
|
||||||
let len = map.width * map.height;
|
let len = map.width * map.height;
|
||||||
let tiles = vec![MAX; len];
|
let tiles = vec![MAX; len];
|
||||||
let mut d = DijkstraMap {
|
let mut d = DijkstraMap {
|
||||||
|
@ -51,6 +52,7 @@ impl DijkstraMap {
|
||||||
size_x: map.width,
|
size_x: map.width,
|
||||||
size_y: map.height,
|
size_y: map.height,
|
||||||
max_depth: len as f32,
|
max_depth: len as f32,
|
||||||
|
phantom: PhantomData,
|
||||||
};
|
};
|
||||||
d.build(map);
|
d.build(map);
|
||||||
d
|
d
|
||||||
|
@ -61,7 +63,7 @@ impl DijkstraMap {
|
||||||
/// depth is further than the current depth.
|
/// depth is further than the current depth.
|
||||||
/// WARNING: Will give incorrect results when used with non-uniform exit costs. Much slower
|
/// WARNING: Will give incorrect results when used with non-uniform exit costs. Much slower
|
||||||
/// algorithm required to support that.
|
/// algorithm required to support that.
|
||||||
fn build(&mut self, map: &Map) {
|
fn build(&mut self, map: &Map<D>) {
|
||||||
let mapsize: usize = (self.size_x * self.size_y) as usize;
|
let mapsize: usize = (self.size_x * self.size_y) as usize;
|
||||||
let mut open_list: VecDeque<((usize, usize), f32)> = VecDeque::with_capacity(mapsize);
|
let mut open_list: VecDeque<((usize, usize), f32)> = VecDeque::with_capacity(mapsize);
|
||||||
|
|
||||||
|
@ -97,7 +99,7 @@ impl DijkstraMap {
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::geometry::Point;
|
use crate::geometry::Point;
|
||||||
use crate::map::Map;
|
use crate::map::{Map, NoData};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_culling() {
|
fn test_culling() {
|
||||||
|
@ -106,7 +108,7 @@ mod tests {
|
||||||
# # #
|
# # #
|
||||||
##########
|
##########
|
||||||
";
|
";
|
||||||
let mut map = Map::from_string(map_str);
|
let mut map = Map::<NoData>::from_string(map_str);
|
||||||
map.starting_point = Some(Point::new(8, 1));
|
map.starting_point = Some(Point::new(8, 1));
|
||||||
let dm = DijkstraMap::new(&map);
|
let dm = DijkstraMap::new(&map);
|
||||||
|
|
||||||
|
@ -134,7 +136,7 @@ mod tests {
|
||||||
# #
|
# #
|
||||||
####
|
####
|
||||||
";
|
";
|
||||||
let mut map = Map::from_string(map_str);
|
let mut map = Map::<NoData>::from_string(map_str);
|
||||||
map.starting_point = Some(Point::new(2, 2));
|
map.starting_point = Some(Point::new(2, 2));
|
||||||
let dm = DijkstraMap::new(&map);
|
let dm = DijkstraMap::new(&map);
|
||||||
let expected = [MAX, MAX, MAX, MAX,
|
let expected = [MAX, MAX, MAX, MAX,
|
||||||
|
@ -153,7 +155,7 @@ mod tests {
|
||||||
# # #
|
# # #
|
||||||
##########
|
##########
|
||||||
";
|
";
|
||||||
let mut map = Map::from_string(map_str);
|
let mut map = Map::<NoData>::from_string(map_str);
|
||||||
map.starting_point = Some(Point::new(8, 2));
|
map.starting_point = Some(Point::new(8, 2));
|
||||||
let dm = DijkstraMap::new(&map);
|
let dm = DijkstraMap::new(&map);
|
||||||
let expected = [MAX, MAX, MAX, MAX, MAX, MAX, MAX, MAX, MAX, MAX,
|
let expected = [MAX, MAX, MAX, MAX, MAX, MAX, MAX, MAX, MAX, MAX,
|
||||||
|
|
|
@ -6,13 +6,13 @@
|
||||||
//! Example generator usage:
|
//! Example generator usage:
|
||||||
//! ```
|
//! ```
|
||||||
//! use rand::prelude::*;
|
//! use rand::prelude::*;
|
||||||
//! use mapgen::{Map, MapFilter};
|
//! use mapgen::{Map, MapFilter, NoData};
|
||||||
//! use mapgen::filter::{
|
//! use mapgen::filter::{
|
||||||
//! BspInterior
|
//! BspInterior
|
||||||
//! };
|
//! };
|
||||||
//!
|
//!
|
||||||
//! let mut rng = StdRng::seed_from_u64(100);
|
//! let mut rng = StdRng::seed_from_u64(100);
|
||||||
//! let gen = BspInterior::new();
|
//! let gen = BspInterior::<NoData>::new();
|
||||||
//! let map = gen.modify_map(&mut rng, &Map::new(80, 50));
|
//! let map = gen.modify_map(&mut rng, &Map::new(80, 50));
|
||||||
//!
|
//!
|
||||||
//! assert_eq!(map.width, 80);
|
//! assert_eq!(map.width, 80);
|
||||||
|
@ -20,32 +20,36 @@
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
use crate::MapFilter;
|
use crate::{BuilderData, MapFilter};
|
||||||
use crate::geometry::{Point, Rect};
|
use crate::geometry::{Point, Rect};
|
||||||
use crate::random::Rng;
|
use crate::random::Rng;
|
||||||
use crate::Map;
|
use crate::Map;
|
||||||
|
|
||||||
|
|
||||||
pub struct BspInterior {
|
pub struct BspInterior<D: BuilderData> {
|
||||||
min_room_size: usize,
|
min_room_size: usize,
|
||||||
|
phantom: PhantomData<D>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MapFilter for BspInterior {
|
impl<D: BuilderData> MapFilter<D> for BspInterior<D> {
|
||||||
fn modify_map(&self, rng: &mut StdRng, map: &Map) -> Map {
|
fn modify_map(&self, rng: &mut StdRng, map: &Map<D>) -> Map<D> {
|
||||||
self.build(rng, map)
|
self.build(rng, map)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BspInterior {
|
impl<D: BuilderData> BspInterior<D> {
|
||||||
|
|
||||||
pub fn new() -> Box<BspInterior> {
|
pub fn new() -> Box<BspInterior<D>> {
|
||||||
Box::new(BspInterior{
|
Box::new(BspInterior{
|
||||||
min_room_size: 8,
|
min_room_size: 8,
|
||||||
|
phantom: PhantomData,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build(&self, rng: &mut StdRng, map: &Map) -> Map {
|
fn build(&self, rng: &mut StdRng, map: &Map<D>) -> Map<D> {
|
||||||
let mut new_map = map.clone();
|
let mut new_map = map.clone();
|
||||||
let mut rects: Vec<Rect> = Vec::new();
|
let mut rects: Vec<Rect> = Vec::new();
|
||||||
rects.push( Rect::new(1, 1, new_map.width-2, new_map.height-2) );
|
rects.push( Rect::new(1, 1, new_map.width-2, new_map.height-2) );
|
||||||
|
@ -114,12 +118,12 @@ impl BspInterior {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{Map};
|
use crate::{Map, map::NoData};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn no_corridors_on_borders() {
|
fn no_corridors_on_borders() {
|
||||||
let mut rng = StdRng::seed_from_u64(907647352);
|
let mut rng = StdRng::seed_from_u64(907647352);
|
||||||
let gen = BspInterior::new();
|
let gen = BspInterior::<NoData>::new();
|
||||||
let map = gen.modify_map(&mut rng, &Map::new(80, 50));
|
let map = gen.modify_map(&mut rng, &Map::new(80, 50));
|
||||||
for i in 0..80 {
|
for i in 0..80 {
|
||||||
assert!(map.at(i, 0).is_blocked());
|
assert!(map.at(i, 0).is_blocked());
|
||||||
|
|
|
@ -6,11 +6,11 @@
|
||||||
//! Example generator usage:
|
//! Example generator usage:
|
||||||
//! ```
|
//! ```
|
||||||
//! use rand::prelude::*;
|
//! use rand::prelude::*;
|
||||||
//! use mapgen::{Map, MapFilter};
|
//! use mapgen::{Map, MapFilter, NoData};
|
||||||
//! use mapgen::filter::BspRooms;
|
//! use mapgen::filter::BspRooms;
|
||||||
//!
|
//!
|
||||||
//! let mut rng = StdRng::seed_from_u64(100);
|
//! let mut rng = StdRng::seed_from_u64(100);
|
||||||
//! let gen = BspRooms::new();
|
//! let gen = BspRooms::<NoData>::new();
|
||||||
//! let map = gen.modify_map(&mut rng, &Map::new(80, 50));
|
//! let map = gen.modify_map(&mut rng, &Map::new(80, 50));
|
||||||
//!
|
//!
|
||||||
//! assert_eq!(map.width, 80);
|
//! assert_eq!(map.width, 80);
|
||||||
|
@ -18,31 +18,36 @@
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
|
use crate::BuilderData;
|
||||||
use crate::MapFilter;
|
use crate::MapFilter;
|
||||||
use crate::geometry::Rect;
|
use crate::geometry::Rect;
|
||||||
use crate::random::Rng;
|
use crate::random::Rng;
|
||||||
use crate::Map;
|
use crate::Map;
|
||||||
|
|
||||||
|
|
||||||
pub struct BspRooms {
|
pub struct BspRooms<D: BuilderData> {
|
||||||
max_split: usize,
|
max_split: usize,
|
||||||
|
phantom: PhantomData<D>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MapFilter for BspRooms {
|
impl<D: BuilderData> MapFilter<D> for BspRooms<D> {
|
||||||
fn modify_map(&self, rng: &mut StdRng, map: &Map) -> Map {
|
fn modify_map(&self, rng: &mut StdRng, map: &Map<D>) -> Map<D> {
|
||||||
self.build_rooms(map, rng)
|
self.build_rooms(map, rng)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BspRooms {
|
impl<D: BuilderData> BspRooms<D> {
|
||||||
pub fn new() -> Box<BspRooms> {
|
pub fn new() -> Box<BspRooms<D>> {
|
||||||
Box::new(BspRooms {
|
Box::new(BspRooms {
|
||||||
max_split: 240,
|
max_split: 240,
|
||||||
|
phantom: PhantomData,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_rooms(&self, map: &Map, rng : &mut StdRng) -> Map {
|
fn build_rooms(&self, map: &Map<D>, rng : &mut StdRng) -> Map<D> {
|
||||||
let mut new_map = map.clone();
|
let mut new_map = map.clone();
|
||||||
let mut rects: Vec<Rect> = Vec::new();
|
let mut rects: Vec<Rect> = Vec::new();
|
||||||
// Start with a single map-sized rectangle
|
// Start with a single map-sized rectangle
|
||||||
|
@ -102,7 +107,7 @@ impl BspRooms {
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_possible(&self, rect: Rect, map: &Map) -> bool {
|
fn is_possible(&self, rect: Rect, map: &Map<D>) -> bool {
|
||||||
let mut expanded = rect;
|
let mut expanded = rect;
|
||||||
expanded.x1 -= 2;
|
expanded.x1 -= 2;
|
||||||
expanded.x2 += 2;
|
expanded.x2 += 2;
|
||||||
|
@ -139,12 +144,12 @@ impl BspRooms {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::map::Map;
|
use crate::map::{Map, NoData};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn no_corridors_on_borders() {
|
fn no_corridors_on_borders() {
|
||||||
let mut rng = StdRng::seed_from_u64(907647352);
|
let mut rng = StdRng::seed_from_u64(907647352);
|
||||||
let gen = BspRooms::new();
|
let gen = BspRooms::<NoData>::new();
|
||||||
let map = gen.modify_map(&mut rng, &Map::new(80, 50));
|
let map = gen.modify_map(&mut rng, &Map::new(80, 50));
|
||||||
for i in 0..80 {
|
for i in 0..80 {
|
||||||
assert!(map.at(i, 0).is_blocked());
|
assert!(map.at(i, 0).is_blocked());
|
||||||
|
|
|
@ -9,11 +9,11 @@
|
||||||
//! Example usage:
|
//! Example usage:
|
||||||
//! ```
|
//! ```
|
||||||
//! use rand::prelude::*;
|
//! use rand::prelude::*;
|
||||||
//! use mapgen::{Map, MapFilter};
|
//! use mapgen::{Map, MapFilter, NoData};
|
||||||
//! use mapgen::filter::CellularAutomata;
|
//! use mapgen::filter::CellularAutomata;
|
||||||
//!
|
//!
|
||||||
//! let mut rng = StdRng::seed_from_u64(100);
|
//! let mut rng = StdRng::seed_from_u64(100);
|
||||||
//! let gen = CellularAutomata::new();
|
//! let gen = CellularAutomata::<NoData>::new();
|
||||||
//! let map = gen.modify_map(&mut rng, &Map::new(80, 50));
|
//! let map = gen.modify_map(&mut rng, &Map::new(80, 50));
|
||||||
//!
|
//!
|
||||||
//! assert_eq!(map.width, 80);
|
//! assert_eq!(map.width, 80);
|
||||||
|
@ -21,30 +21,37 @@
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
|
use crate::BuilderData;
|
||||||
use crate::MapFilter;
|
use crate::MapFilter;
|
||||||
use crate::{Map, Tile};
|
use crate::{Map, Tile};
|
||||||
|
|
||||||
|
|
||||||
/// Map filter
|
/// Map filter
|
||||||
pub struct CellularAutomata {
|
pub struct CellularAutomata<D: BuilderData> {
|
||||||
num_iteraction: u32,
|
num_iteraction: u32,
|
||||||
|
phantom: PhantomData<D>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MapFilter for CellularAutomata {
|
impl<D: BuilderData> MapFilter<D> for CellularAutomata<D> {
|
||||||
fn modify_map(&self, _rng: &mut StdRng, map: &Map) -> Map {
|
fn modify_map(&self, _rng: &mut StdRng, map: &Map<D>) -> Map<D> {
|
||||||
self.build(map)
|
self.build(map)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CellularAutomata {
|
impl<D: BuilderData> CellularAutomata<D> {
|
||||||
/// Create generator which will create map with the given dimension.
|
/// Create generator which will create map with the given dimension.
|
||||||
pub fn new() -> Box<CellularAutomata> {
|
pub fn new() -> Box<CellularAutomata<D>> {
|
||||||
Box::new(CellularAutomata { num_iteraction: 15})
|
Box::new(CellularAutomata {
|
||||||
|
num_iteraction: 15,
|
||||||
|
phantom: PhantomData,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate map
|
/// Generate map
|
||||||
fn build(&self, map: &Map) -> Map {
|
fn build(&self, map: &Map<D>) -> Map<D> {
|
||||||
let mut new_map = map.clone();
|
let mut new_map = map.clone();
|
||||||
for _ in 0..self.num_iteraction {
|
for _ in 0..self.num_iteraction {
|
||||||
new_map = apply_iteration(&new_map);
|
new_map = apply_iteration(&new_map);
|
||||||
|
@ -55,7 +62,7 @@ impl CellularAutomata {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_iteration(map: &Map) -> Map {
|
fn apply_iteration<D: BuilderData>(map: &Map<D>) -> Map<D> {
|
||||||
let mut new_map = map.clone();
|
let mut new_map = map.clone();
|
||||||
|
|
||||||
for y in 1..map.height-1 {
|
for y in 1..map.height-1 {
|
||||||
|
@ -85,11 +92,13 @@ fn apply_iteration(map: &Map) -> Map {
|
||||||
/// ------------------------------------------------------------------------------------------------
|
/// ------------------------------------------------------------------------------------------------
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use crate::map::NoData;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_iteration_wal() {
|
fn test_iteration_wal() {
|
||||||
let map = Map::new(3, 3);
|
let map = Map::<NoData>::new(3, 3);
|
||||||
let new_map = apply_iteration(&map);
|
let new_map = apply_iteration(&map);
|
||||||
assert!(new_map.at(1, 1).is_blocked());
|
assert!(new_map.at(1, 1).is_blocked());
|
||||||
}
|
}
|
||||||
|
@ -97,7 +106,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_iteration_floor() {
|
fn test_iteration_floor() {
|
||||||
let mut map = Map::new(3, 3);
|
let mut map = Map::<NoData>::new(3, 3);
|
||||||
for i in 0..3 {
|
for i in 0..3 {
|
||||||
for j in 0..2 {
|
for j in 0..2 {
|
||||||
map.set_tile(i, j, Tile::floor());
|
map.set_tile(i, j, Tile::floor());
|
||||||
|
|
|
@ -4,28 +4,34 @@
|
||||||
//! It will add wall on every tile which is not accessible from the starting point.
|
//! It will add wall on every tile which is not accessible from the starting point.
|
||||||
//!
|
//!
|
||||||
|
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use rand::prelude::StdRng;
|
use rand::prelude::StdRng;
|
||||||
use crate::MapFilter;
|
use crate::MapFilter;
|
||||||
use crate::{Map, Tile};
|
use crate::{BuilderData, Map, Tile};
|
||||||
use crate::dijkstra::DijkstraMap;
|
use crate::dijkstra::DijkstraMap;
|
||||||
|
|
||||||
|
|
||||||
/// Remove unreachable areas from the map.
|
/// Remove unreachable areas from the map.
|
||||||
pub struct CullUnreachable {}
|
pub struct CullUnreachable<D: BuilderData> {
|
||||||
|
phantom: PhantomData<D>,
|
||||||
|
}
|
||||||
|
|
||||||
impl MapFilter for CullUnreachable {
|
impl<D: BuilderData> MapFilter<D> for CullUnreachable<D> {
|
||||||
fn modify_map(&self, _: &mut StdRng, map: &Map) -> Map {
|
fn modify_map(&self, _: &mut StdRng, map: &Map<D>) -> Map<D> {
|
||||||
self.build(map)
|
self.build(map)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CullUnreachable {
|
impl<D: BuilderData> CullUnreachable<D> {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn new() -> Box<CullUnreachable> {
|
pub fn new() -> Box<CullUnreachable<D>> {
|
||||||
Box::new(CullUnreachable{})
|
Box::new(CullUnreachable {
|
||||||
|
phantom: PhantomData,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build(&self, map: &Map) -> Map {
|
fn build(&self, map: &Map<D>) -> Map<D> {
|
||||||
let mut new_map = map.clone();
|
let mut new_map = map.clone();
|
||||||
|
|
||||||
let dijkstra_map = DijkstraMap::new(map);
|
let dijkstra_map = DijkstraMap::new(map);
|
||||||
|
@ -51,7 +57,7 @@ mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use super::MapFilter;
|
use super::MapFilter;
|
||||||
use crate::geometry::Point;
|
use crate::geometry::Point;
|
||||||
use crate::map::Map;
|
use crate::map::{Map, NoData};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_culling() {
|
fn test_culling() {
|
||||||
|
@ -60,14 +66,14 @@ mod tests {
|
||||||
# # #
|
# # #
|
||||||
##########
|
##########
|
||||||
";
|
";
|
||||||
let mut map = Map::from_string(map_str);
|
let mut map = Map::<NoData>::from_string(map_str);
|
||||||
map.starting_point = Some(Point::new(9, 1));
|
map.starting_point = Some(Point::new(9, 1));
|
||||||
let expected_map_str = "
|
let expected_map_str = "
|
||||||
##########
|
##########
|
||||||
#### #
|
#### #
|
||||||
##########
|
##########
|
||||||
";
|
";
|
||||||
let expected_map = Map::from_string(expected_map_str);
|
let expected_map = Map::<NoData>::from_string(expected_map_str);
|
||||||
|
|
||||||
|
|
||||||
let modifier = CullUnreachable::new();
|
let modifier = CullUnreachable::new();
|
||||||
|
|
|
@ -5,7 +5,9 @@
|
||||||
//!
|
//!
|
||||||
|
|
||||||
use std::f32;
|
use std::f32;
|
||||||
|
use std::marker::PhantomData;
|
||||||
use rand::prelude::StdRng;
|
use rand::prelude::StdRng;
|
||||||
|
use crate::BuilderData;
|
||||||
use crate::geometry::Point;
|
use crate::geometry::Point;
|
||||||
use crate::MapFilter;
|
use crate::MapFilter;
|
||||||
use crate::Map;
|
use crate::Map;
|
||||||
|
@ -13,21 +15,25 @@ use crate::dijkstra::DijkstraMap;
|
||||||
|
|
||||||
|
|
||||||
/// Add exist position to the map based on the distance from the start point.
|
/// Add exist position to the map based on the distance from the start point.
|
||||||
pub struct DistantExit {}
|
pub struct DistantExit<D: BuilderData> {
|
||||||
|
phantom: PhantomData<D>,
|
||||||
|
}
|
||||||
|
|
||||||
impl MapFilter for DistantExit {
|
impl<D: BuilderData> MapFilter<D> for DistantExit<D> {
|
||||||
fn modify_map(&self, _: &mut StdRng, map: &Map) -> Map {
|
fn modify_map(&self, _: &mut StdRng, map: &Map<D>) -> Map<D> {
|
||||||
self.build(map)
|
self.build(map)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DistantExit {
|
impl<D: BuilderData> DistantExit<D> {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn new() -> Box<DistantExit> {
|
pub fn new() -> Box<DistantExit<D>> {
|
||||||
Box::new(DistantExit{})
|
Box::new(DistantExit {
|
||||||
|
phantom: PhantomData,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build(&self, map: &Map) -> Map {
|
fn build(&self, map: &Map<D>) -> Map<D> {
|
||||||
let mut new_map = map.clone();
|
let mut new_map = map.clone();
|
||||||
|
|
||||||
let mut best_idx = 0;
|
let mut best_idx = 0;
|
||||||
|
@ -55,7 +61,7 @@ mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use super::MapFilter;
|
use super::MapFilter;
|
||||||
use crate::geometry::Point;
|
use crate::geometry::Point;
|
||||||
use crate::map::Map;
|
use crate::map::{Map, NoData};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_exit() {
|
fn test_exit() {
|
||||||
|
@ -65,7 +71,7 @@ mod tests {
|
||||||
# # #
|
# # #
|
||||||
##########
|
##########
|
||||||
";
|
";
|
||||||
let mut map = Map::from_string(map_str);
|
let mut map = Map::<NoData>::from_string(map_str);
|
||||||
map.starting_point = Some(Point::new(9, 2));
|
map.starting_point = Some(Point::new(9, 2));
|
||||||
|
|
||||||
let modifier = DistantExit::new();
|
let modifier = DistantExit::new();
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
//! Example generator usage:
|
//! Example generator usage:
|
||||||
//! ```
|
//! ```
|
||||||
//! use rand::prelude::*;
|
//! use rand::prelude::*;
|
||||||
//! use mapgen::{Map, MapFilter};
|
//! use mapgen::{Map, MapFilter, NoData};
|
||||||
//! use mapgen::filter::DrunkardsWalk;
|
//! use mapgen::filter::DrunkardsWalk;
|
||||||
//!
|
//!
|
||||||
//! let mut rng = StdRng::seed_from_u64(100);
|
//! let mut rng = StdRng::seed_from_u64(100);
|
||||||
//! let gen = DrunkardsWalk::open_area();
|
//! let gen = DrunkardsWalk::<NoData>::open_area();
|
||||||
//! let map = gen.modify_map(&mut rng, &Map::new(80, 50));
|
//! let map = gen.modify_map(&mut rng, &Map::new(80, 50));
|
||||||
//!
|
//!
|
||||||
//! assert_eq!(map.width, 80);
|
//! assert_eq!(map.width, 80);
|
||||||
|
@ -13,9 +13,12 @@
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
use crate::MapFilter;
|
use crate::MapFilter;
|
||||||
use crate::{
|
use crate::{
|
||||||
|
BuilderData,
|
||||||
map::{Map, Symmetry, Tile},
|
map::{Map, Symmetry, Tile},
|
||||||
geometry::Point,
|
geometry::Point,
|
||||||
random::Rng
|
random::Rng
|
||||||
|
@ -25,57 +28,59 @@ use crate::{
|
||||||
#[derive(PartialEq, Copy, Clone)]
|
#[derive(PartialEq, Copy, Clone)]
|
||||||
pub enum DrunkSpawnMode { StartingPoint, Random }
|
pub enum DrunkSpawnMode { StartingPoint, Random }
|
||||||
|
|
||||||
pub struct DrunkardsWalk {
|
pub struct DrunkardsWalk<D: BuilderData> {
|
||||||
spawn_mode : DrunkSpawnMode,
|
spawn_mode : DrunkSpawnMode,
|
||||||
drunken_lifetime : i32,
|
drunken_lifetime : i32,
|
||||||
floor_percent: f32,
|
floor_percent: f32,
|
||||||
brush_size: usize,
|
brush_size: usize,
|
||||||
symmetry: Symmetry
|
symmetry: Symmetry,
|
||||||
|
phantom: PhantomData<D>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MapFilter for DrunkardsWalk {
|
impl<D: BuilderData> MapFilter<D> for DrunkardsWalk<D> {
|
||||||
fn modify_map(&self, rng: &mut StdRng, map: &Map) -> Map {
|
fn modify_map(&self, rng: &mut StdRng, map: &Map<D>) -> Map<D> {
|
||||||
self.build(rng, map)
|
self.build(rng, map)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DrunkardsWalk {
|
impl<D: BuilderData> DrunkardsWalk<D> {
|
||||||
pub fn new( spawn_mode: DrunkSpawnMode,
|
pub fn new( spawn_mode: DrunkSpawnMode,
|
||||||
drunken_lifetime: i32,
|
drunken_lifetime: i32,
|
||||||
floor_percent: f32,
|
floor_percent: f32,
|
||||||
brush_size: usize,
|
brush_size: usize,
|
||||||
symmetry: Symmetry) -> Box<DrunkardsWalk>
|
symmetry: Symmetry) -> Box<DrunkardsWalk<D>>
|
||||||
{
|
{
|
||||||
Box::new(DrunkardsWalk{
|
Box::new(DrunkardsWalk{
|
||||||
spawn_mode,
|
spawn_mode,
|
||||||
drunken_lifetime,
|
drunken_lifetime,
|
||||||
floor_percent,
|
floor_percent,
|
||||||
brush_size,
|
brush_size,
|
||||||
symmetry
|
symmetry,
|
||||||
|
phantom: PhantomData,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open_area() -> Box<DrunkardsWalk> {
|
pub fn open_area() -> Box<DrunkardsWalk<D>> {
|
||||||
Self::new(DrunkSpawnMode::StartingPoint, 400, 0.5, 1, Symmetry::None)
|
Self::new(DrunkSpawnMode::StartingPoint, 400, 0.5, 1, Symmetry::None)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open_halls() -> Box<DrunkardsWalk> {
|
pub fn open_halls() -> Box<DrunkardsWalk<D>> {
|
||||||
Self::new(DrunkSpawnMode::Random, 400, 0.5, 1, Symmetry::None)
|
Self::new(DrunkSpawnMode::Random, 400, 0.5, 1, Symmetry::None)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn winding_passages() -> Box<DrunkardsWalk> {
|
pub fn winding_passages() -> Box<DrunkardsWalk<D>> {
|
||||||
Self::new(DrunkSpawnMode::Random, 400, 0.4, 1, Symmetry::None)
|
Self::new(DrunkSpawnMode::Random, 400, 0.4, 1, Symmetry::None)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fat_passages() -> Box<DrunkardsWalk> {
|
pub fn fat_passages() -> Box<DrunkardsWalk<D>> {
|
||||||
Self::new(DrunkSpawnMode::Random, 400, 0.4, 2, Symmetry::None)
|
Self::new(DrunkSpawnMode::Random, 400, 0.4, 2, Symmetry::None)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fearful_symmetry() -> Box<DrunkardsWalk> {
|
pub fn fearful_symmetry() -> Box<DrunkardsWalk<D>> {
|
||||||
Self::new(DrunkSpawnMode::Random, 400, 0.4, 1, Symmetry::Both)
|
Self::new(DrunkSpawnMode::Random, 400, 0.4, 1, Symmetry::Both)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build(&self, rng: &mut StdRng, map: &Map) -> Map {
|
fn build(&self, rng: &mut StdRng, map: &Map<D>) -> Map<D> {
|
||||||
let mut new_map = map.clone();
|
let mut new_map = map.clone();
|
||||||
// Set a central starting point
|
// Set a central starting point
|
||||||
let starting_position = Point::new( new_map.width / 2, new_map.height / 2 );
|
let starting_position = Point::new( new_map.width / 2, new_map.height / 2 );
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
//! Example generator usage:
|
//! Example generator usage:
|
||||||
//! ```
|
//! ```
|
||||||
//! use rand::prelude::*;
|
//! use rand::prelude::*;
|
||||||
//! use mapgen::{Map, MapFilter};
|
//! use mapgen::{Map, MapFilter, NoData};
|
||||||
//! use mapgen::filter::MazeBuilder;
|
//! use mapgen::filter::MazeBuilder;
|
||||||
//!
|
//!
|
||||||
//! let mut rng = StdRng::seed_from_u64(100);
|
//! let mut rng = StdRng::seed_from_u64(100);
|
||||||
//! let gen = MazeBuilder::new();
|
//! let gen = MazeBuilder::<NoData>::new();
|
||||||
//! let map = gen.modify_map(&mut rng, &Map::new(80, 50));
|
//! let map = gen.modify_map(&mut rng, &Map::new(80, 50));
|
||||||
//!
|
//!
|
||||||
//! assert_eq!(map.width, 80);
|
//! assert_eq!(map.width, 80);
|
||||||
|
@ -13,29 +13,35 @@
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
use crate::MapFilter;
|
use crate::MapFilter;
|
||||||
use crate::{
|
use crate::{
|
||||||
map::{Map, Tile},
|
map::{BuilderData, Map, Tile},
|
||||||
random::Rng
|
random::Rng
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
pub struct MazeBuilder {}
|
pub struct MazeBuilder<D: BuilderData> {
|
||||||
|
phantom: PhantomData<D>,
|
||||||
|
}
|
||||||
|
|
||||||
impl MapFilter for MazeBuilder {
|
impl<D: BuilderData> MapFilter<D> for MazeBuilder<D> {
|
||||||
fn modify_map(&self, rng: &mut StdRng, map: &Map) -> Map {
|
fn modify_map(&self, rng: &mut StdRng, map: &Map<D>) -> Map<D> {
|
||||||
self.build(rng, map)
|
self.build(rng, map)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MazeBuilder {
|
impl<D: BuilderData> MazeBuilder<D> {
|
||||||
pub fn new() -> Box<MazeBuilder> {
|
pub fn new() -> Box<MazeBuilder<D>> {
|
||||||
Box::new(MazeBuilder{})
|
Box::new(MazeBuilder {
|
||||||
|
phantom: PhantomData,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::map_entry)]
|
#[allow(clippy::map_entry)]
|
||||||
fn build(&self, rng: &mut StdRng, map: &Map) -> Map {
|
fn build(&self, rng: &mut StdRng, map: &Map<D>) -> Map<D> {
|
||||||
let mut new_map = map.clone();
|
let mut new_map = map.clone();
|
||||||
let mut maze = Grid::new((map.width as i32/ 2)-2, (map.height as i32/ 2)-2, rng);
|
let mut maze = Grid::new((map.width as i32/ 2)-2, (map.height as i32/ 2)-2, rng);
|
||||||
maze.generate_maze(&mut new_map);
|
maze.generate_maze(&mut new_map);
|
||||||
|
@ -91,24 +97,26 @@ impl Cell {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Grid<'a> {
|
struct Grid<'a, D: BuilderData> {
|
||||||
width: i32,
|
width: i32,
|
||||||
height: i32,
|
height: i32,
|
||||||
cells: Vec<Cell>,
|
cells: Vec<Cell>,
|
||||||
backtrace: Vec<usize>,
|
backtrace: Vec<usize>,
|
||||||
current: usize,
|
current: usize,
|
||||||
rng : &'a mut StdRng
|
rng : &'a mut StdRng,
|
||||||
|
phantom: PhantomData<D>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Grid<'a> {
|
impl<'a, D: BuilderData> Grid<'a, D> {
|
||||||
fn new(width: i32, height:i32, rng: &mut StdRng) -> Grid {
|
fn new(width: i32, height:i32, rng: &mut StdRng) -> Grid<D> {
|
||||||
let mut grid = Grid{
|
let mut grid = Grid{
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
cells: Vec::new(),
|
cells: Vec::new(),
|
||||||
backtrace: Vec::new(),
|
backtrace: Vec::new(),
|
||||||
current: 0,
|
current: 0,
|
||||||
rng
|
rng,
|
||||||
|
phantom: PhantomData,
|
||||||
};
|
};
|
||||||
|
|
||||||
for row in 0..height {
|
for row in 0..height {
|
||||||
|
@ -162,7 +170,7 @@ impl<'a> Grid<'a> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_maze(&mut self, map: &mut Map) {
|
fn generate_maze(&mut self, map: &mut Map<D>) {
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
loop {
|
loop {
|
||||||
self.cells[self.current].visited = true;
|
self.cells[self.current].visited = true;
|
||||||
|
@ -199,7 +207,7 @@ impl<'a> Grid<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn copy_to_map(&self, map: &mut Map) {
|
fn copy_to_map(&self, map: &mut Map<D>) {
|
||||||
// Clear the map
|
// Clear the map
|
||||||
for i in map.tiles.iter_mut() { *i = Tile::wall(); }
|
for i in map.tiles.iter_mut() { *i = Tile::wall(); }
|
||||||
|
|
||||||
|
|
|
@ -4,11 +4,11 @@
|
||||||
//! Example usage:
|
//! Example usage:
|
||||||
//! ```
|
//! ```
|
||||||
//! use rand::prelude::*;
|
//! use rand::prelude::*;
|
||||||
//! use mapgen::{Map, MapFilter};
|
//! use mapgen::{Map, MapFilter, NoData};
|
||||||
//! use mapgen::filter::NoiseGenerator;
|
//! use mapgen::filter::NoiseGenerator;
|
||||||
//!
|
//!
|
||||||
//! let mut rng = StdRng::seed_from_u64(100);
|
//! let mut rng = StdRng::seed_from_u64(100);
|
||||||
//! let gen = NoiseGenerator::uniform();
|
//! let gen = NoiseGenerator::<NoData>::uniform();
|
||||||
//! let map = gen.modify_map(&mut rng, &Map::new(80, 50));
|
//! let map = gen.modify_map(&mut rng, &Map::new(80, 50));
|
||||||
//!
|
//!
|
||||||
//! assert_eq!(map.width, 80);
|
//! assert_eq!(map.width, 80);
|
||||||
|
@ -16,39 +16,44 @@
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
use crate::MapFilter;
|
use crate::MapFilter;
|
||||||
use crate::{Map, Tile};
|
use crate::{BuilderData, Map, Tile};
|
||||||
|
|
||||||
|
|
||||||
/// Map noise generator
|
/// Map noise generator
|
||||||
pub struct NoiseGenerator {
|
pub struct NoiseGenerator<D: BuilderData> {
|
||||||
prob: f32,
|
prob: f32,
|
||||||
|
phantom: PhantomData<D>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MapFilter for NoiseGenerator {
|
impl<D: BuilderData> MapFilter<D> for NoiseGenerator<D> {
|
||||||
fn modify_map(&self, rng: &mut StdRng, map: &Map) -> Map {
|
fn modify_map(&self, rng: &mut StdRng, map: &Map<D>) -> Map<D> {
|
||||||
self.build(map, rng)
|
self.build(map, rng)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NoiseGenerator {
|
impl<D: BuilderData> NoiseGenerator<D> {
|
||||||
/// Create noise with custom probability
|
/// Create noise with custom probability
|
||||||
pub fn new(prob: f32) -> Box<NoiseGenerator> {
|
pub fn new(prob: f32) -> Box<NoiseGenerator<D>> {
|
||||||
Box::new(NoiseGenerator {
|
Box::new(NoiseGenerator {
|
||||||
prob,
|
prob,
|
||||||
|
phantom: PhantomData,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create uniform noise (Probablity 0.5)
|
/// Create uniform noise (Probablity 0.5)
|
||||||
pub fn uniform() -> Box<NoiseGenerator> {
|
pub fn uniform() -> Box<NoiseGenerator<D>> {
|
||||||
Box::new(NoiseGenerator {
|
Box::new(NoiseGenerator {
|
||||||
prob: 0.5,
|
prob: 0.5,
|
||||||
|
phantom: PhantomData,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate map
|
/// Generate map
|
||||||
fn build(&self, map: &Map, rng: &mut StdRng) -> Map {
|
fn build(&self, map: &Map<D>, rng: &mut StdRng) -> Map<D> {
|
||||||
let mut new_map = map.clone();
|
let mut new_map = map.clone();
|
||||||
let p = (self.prob * 100.0) as u32;
|
let p = (self.prob * 100.0) as u32;
|
||||||
for y in 1..new_map.height-1 {
|
for y in 1..new_map.height-1 {
|
||||||
|
|
|
@ -1,26 +1,32 @@
|
||||||
//! Connect nearest rooms on the map with corridors
|
//! Connect nearest rooms on the map with corridors
|
||||||
//!
|
//!
|
||||||
use rand::prelude::StdRng;
|
use rand::prelude::StdRng;
|
||||||
|
use crate::BuilderData;
|
||||||
use crate::MapFilter;
|
use crate::MapFilter;
|
||||||
use crate::Map;
|
use crate::Map;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
|
||||||
pub struct NearestCorridors {}
|
pub struct NearestCorridors<D: BuilderData> {
|
||||||
|
phantom: PhantomData<D>,
|
||||||
|
}
|
||||||
|
|
||||||
impl MapFilter for NearestCorridors {
|
impl<D: BuilderData> MapFilter<D> for NearestCorridors<D> {
|
||||||
fn modify_map(&self, _: &mut StdRng, map: &Map) -> Map {
|
fn modify_map(&self, _: &mut StdRng, map: &Map<D>) -> Map<D> {
|
||||||
self.corridors(map)
|
self.corridors(map)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NearestCorridors {
|
impl<D: BuilderData> NearestCorridors<D> {
|
||||||
|
|
||||||
pub fn new() -> Box<NearestCorridors> {
|
pub fn new() -> Box<NearestCorridors<D>> {
|
||||||
Box::new(NearestCorridors{})
|
Box::new(NearestCorridors {
|
||||||
|
phantom: PhantomData,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn corridors(&self, map: &Map) -> Map {
|
fn corridors(&self, map: &Map<D>) -> Map<D> {
|
||||||
let mut new_map = map.clone();
|
let mut new_map = map.clone();
|
||||||
|
|
||||||
let mut connected : HashSet<usize> = HashSet::new();
|
let mut connected : HashSet<usize> = HashSet::new();
|
||||||
|
|
|
@ -6,11 +6,11 @@
|
||||||
//! Example generator usage:
|
//! Example generator usage:
|
||||||
//! ```
|
//! ```
|
||||||
//! use rand::prelude::*;
|
//! use rand::prelude::*;
|
||||||
//! use mapgen::{MapFilter, Map};
|
//! use mapgen::{MapFilter, Map, NoData};
|
||||||
//! use mapgen::filter::SimpleRooms;
|
//! use mapgen::filter::SimpleRooms;
|
||||||
//!
|
//!
|
||||||
//! let mut rng = StdRng::seed_from_u64(100);
|
//! let mut rng = StdRng::seed_from_u64(100);
|
||||||
//! let gen = SimpleRooms::new();
|
//! let gen = SimpleRooms::<NoData>::new();
|
||||||
//! let map = gen.modify_map(&mut rng, &Map::new(80, 50));
|
//! let map = gen.modify_map(&mut rng, &Map::new(80, 50));
|
||||||
//!
|
//!
|
||||||
//! assert_eq!(map.width, 80);
|
//! assert_eq!(map.width, 80);
|
||||||
|
@ -18,36 +18,41 @@
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
|
use crate::BuilderData;
|
||||||
use crate::MapFilter;
|
use crate::MapFilter;
|
||||||
use crate::geometry::Rect;
|
use crate::geometry::Rect;
|
||||||
use crate::random::Rng;
|
use crate::random::Rng;
|
||||||
use crate::Map;
|
use crate::Map;
|
||||||
|
|
||||||
|
|
||||||
pub struct SimpleRooms {
|
pub struct SimpleRooms<D: BuilderData> {
|
||||||
max_rooms: usize,
|
max_rooms: usize,
|
||||||
min_room_size: usize,
|
min_room_size: usize,
|
||||||
max_room_size: usize,
|
max_room_size: usize,
|
||||||
|
phantom: PhantomData<D>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MapFilter for SimpleRooms {
|
impl<D: BuilderData> MapFilter<D> for SimpleRooms<D> {
|
||||||
fn modify_map(&self, rng: &mut StdRng, map: &Map) -> Map {
|
fn modify_map(&self, rng: &mut StdRng, map: &Map<D>) -> Map<D> {
|
||||||
self.build_rooms(map, rng)
|
self.build_rooms(map, rng)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl SimpleRooms {
|
impl<D: BuilderData> SimpleRooms<D> {
|
||||||
pub fn new() -> Box<SimpleRooms> {
|
pub fn new() -> Box<SimpleRooms<D>> {
|
||||||
Box::new(SimpleRooms{
|
Box::new(SimpleRooms{
|
||||||
max_rooms: 30,
|
max_rooms: 30,
|
||||||
min_room_size: 6,
|
min_room_size: 6,
|
||||||
max_room_size: 10
|
max_room_size: 10,
|
||||||
|
phantom: PhantomData,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_rooms(&self, map: &Map, rng : &mut StdRng) -> Map {
|
fn build_rooms(&self, map: &Map<D>, rng : &mut StdRng) -> Map<D> {
|
||||||
let mut new_map = map.clone();
|
let mut new_map = map.clone();
|
||||||
|
|
||||||
// Create room dimensions
|
// Create room dimensions
|
||||||
|
|
|
@ -6,12 +6,12 @@
|
||||||
//! Example modifier usage:
|
//! Example modifier usage:
|
||||||
//! ```
|
//! ```
|
||||||
//! use rand::prelude::*;
|
//! use rand::prelude::*;
|
||||||
//! use mapgen::{MapFilter, Map, Tile};
|
//! use mapgen::{MapFilter, Map, NoData, Tile};
|
||||||
//! use mapgen::filter::starting_point::{AreaStartingPosition, XStart, YStart};
|
//! use mapgen::filter::starting_point::{AreaStartingPosition, XStart, YStart};
|
||||||
//! use mapgen::geometry::Point;
|
//! use mapgen::geometry::Point;
|
||||||
//!
|
//!
|
||||||
//! let mut rng = StdRng::seed_from_u64(100);
|
//! let mut rng = StdRng::seed_from_u64(100);
|
||||||
//! let mut map = Map::new(80, 50);
|
//! let mut map = Map::<NoData>::new(80, 50);
|
||||||
//! map.set_tile(10, 10, Tile::floor());
|
//! map.set_tile(10, 10, Tile::floor());
|
||||||
//! let modifier = AreaStartingPosition::new(XStart::LEFT, YStart::TOP);
|
//! let modifier = AreaStartingPosition::new(XStart::LEFT, YStart::TOP);
|
||||||
//! let new_map = modifier.modify_map(&mut rng, &map);
|
//! let new_map = modifier.modify_map(&mut rng, &map);
|
||||||
|
@ -20,7 +20,10 @@
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use rand::prelude::StdRng;
|
use rand::prelude::StdRng;
|
||||||
|
use crate::BuilderData;
|
||||||
use crate::MapFilter;
|
use crate::MapFilter;
|
||||||
use crate::geometry::Point;
|
use crate::geometry::Point;
|
||||||
use crate::Map;
|
use crate::Map;
|
||||||
|
@ -33,26 +36,28 @@ pub enum XStart { LEFT, CENTER, RIGHT }
|
||||||
pub enum YStart { TOP, CENTER, BOTTOM }
|
pub enum YStart { TOP, CENTER, BOTTOM }
|
||||||
|
|
||||||
/// Add starting position to the map
|
/// Add starting position to the map
|
||||||
pub struct AreaStartingPosition {
|
pub struct AreaStartingPosition<D: BuilderData> {
|
||||||
x : XStart,
|
x : XStart,
|
||||||
y : YStart
|
y : YStart,
|
||||||
|
phantom: PhantomData<D>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MapFilter for AreaStartingPosition {
|
impl<D: BuilderData> MapFilter<D> for AreaStartingPosition<D> {
|
||||||
fn modify_map(&self, _: &mut StdRng, map: &Map) -> Map {
|
fn modify_map(&self, _: &mut StdRng, map: &Map<D>) -> Map<D> {
|
||||||
self.build(map)
|
self.build(map)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AreaStartingPosition {
|
impl<D: BuilderData> AreaStartingPosition<D> {
|
||||||
/// Create new modifier with given region
|
/// Create new modifier with given region
|
||||||
pub fn new(x : XStart, y : YStart) -> Box<AreaStartingPosition> {
|
pub fn new(x : XStart, y : YStart) -> Box<AreaStartingPosition<D>> {
|
||||||
Box::new(AreaStartingPosition{
|
Box::new(AreaStartingPosition{
|
||||||
x, y
|
x, y,
|
||||||
|
phantom: PhantomData,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build(&self, map : &Map) -> Map {
|
fn build(&self, map : &Map<D>) -> Map<D> {
|
||||||
let seed_x = match self.x {
|
let seed_x = match self.x {
|
||||||
XStart::LEFT => 1,
|
XStart::LEFT => 1,
|
||||||
XStart::CENTER => map.width / 2,
|
XStart::CENTER => map.width / 2,
|
||||||
|
@ -101,7 +106,7 @@ mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use super::MapFilter;
|
use super::MapFilter;
|
||||||
use crate::geometry::Point;
|
use crate::geometry::Point;
|
||||||
use crate::map::Map;
|
use crate::map::{Map, NoData};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_exit() {
|
fn test_exit() {
|
||||||
|
@ -111,7 +116,7 @@ mod tests {
|
||||||
# # # #
|
# # # #
|
||||||
##########
|
##########
|
||||||
";
|
";
|
||||||
let mut map = Map::from_string(map_str);
|
let mut map = Map::<NoData>::from_string(map_str);
|
||||||
map.starting_point = Some(Point::new(9, 2));
|
map.starting_point = Some(Point::new(9, 2));
|
||||||
|
|
||||||
let modifier = AreaStartingPosition::new(XStart::CENTER, YStart::TOP);
|
let modifier = AreaStartingPosition::new(XStart::CENTER, YStart::TOP);
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
//! Example generator usage:
|
//! Example generator usage:
|
||||||
//! ```
|
//! ```
|
||||||
//! use rand::prelude::*;
|
//! use rand::prelude::*;
|
||||||
//! use mapgen::{Map, MapFilter};
|
//! use mapgen::{Map, MapFilter, NoData};
|
||||||
//! use mapgen::filter::VoronoiHive;
|
//! use mapgen::filter::VoronoiHive;
|
||||||
//!
|
//!
|
||||||
//! let mut rng = StdRng::seed_from_u64(100);
|
//! let mut rng = StdRng::seed_from_u64(100);
|
||||||
//! let gen = VoronoiHive::new();
|
//! let gen = VoronoiHive::<NoData>::new();
|
||||||
//! let map = gen.modify_map(&mut rng, &Map::new(80, 50));
|
//! let map = gen.modify_map(&mut rng, &Map::new(80, 50));
|
||||||
//!
|
//!
|
||||||
//! assert_eq!(map.width, 80);
|
//! assert_eq!(map.width, 80);
|
||||||
|
@ -13,34 +13,38 @@
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
use crate::MapFilter;
|
use crate::MapFilter;
|
||||||
use crate::{
|
use crate::{
|
||||||
map::{Map, Tile},
|
map::{BuilderData, Map, Tile},
|
||||||
random::Rng,
|
random::Rng,
|
||||||
geometry::Point,
|
geometry::Point,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
pub struct VoronoiHive {
|
pub struct VoronoiHive<D: BuilderData> {
|
||||||
n_seeds: usize,
|
n_seeds: usize,
|
||||||
|
phantom: PhantomData<D>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl MapFilter for VoronoiHive {
|
impl<D: BuilderData> MapFilter<D> for VoronoiHive<D> {
|
||||||
fn modify_map(&self, rng: &mut StdRng, map: &Map) -> Map {
|
fn modify_map(&self, rng: &mut StdRng, map: &Map<D>) -> Map<D> {
|
||||||
self.build(rng, map)
|
self.build(rng, map)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VoronoiHive {
|
impl<D: BuilderData> VoronoiHive<D> {
|
||||||
pub fn new() -> Box<VoronoiHive> {
|
pub fn new() -> Box<VoronoiHive<D>> {
|
||||||
Box::new(VoronoiHive{
|
Box::new(VoronoiHive{
|
||||||
n_seeds: 64,
|
n_seeds: 64,
|
||||||
|
phantom: PhantomData,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build(&self, rng: &mut StdRng, map: &Map) -> Map {
|
fn build(&self, rng: &mut StdRng, map: &Map<D>) -> Map<D> {
|
||||||
let mut new_map = map.clone();
|
let mut new_map = map.clone();
|
||||||
let seeds = self.generate_seeds(rng, map.width, map.height);
|
let seeds = self.generate_seeds(rng, map.width, map.height);
|
||||||
|
|
||||||
|
|
28
src/lib.rs
28
src/lib.rs
|
@ -8,7 +8,7 @@
|
||||||
//!
|
//!
|
||||||
//! Example
|
//! Example
|
||||||
//! ```
|
//! ```
|
||||||
//! use mapgen::{MapFilter, MapBuilder, Map, Tile};
|
//! use mapgen::{MapFilter, MapBuilder, Map, NoData, Tile};
|
||||||
//! use mapgen::filter::{
|
//! use mapgen::filter::{
|
||||||
//! NoiseGenerator,
|
//! NoiseGenerator,
|
||||||
//! CellularAutomata,
|
//! CellularAutomata,
|
||||||
|
@ -16,7 +16,7 @@
|
||||||
//! };
|
//! };
|
||||||
//! use mapgen::geometry::Point;
|
//! use mapgen::geometry::Point;
|
||||||
//!
|
//!
|
||||||
//! let map = MapBuilder::new(80, 50)
|
//! let map = MapBuilder::<NoData>::new(80, 50)
|
||||||
//! .with(NoiseGenerator::uniform())
|
//! .with(NoiseGenerator::uniform())
|
||||||
//! .with(CellularAutomata::new())
|
//! .with(CellularAutomata::new())
|
||||||
//! .with(AreaStartingPosition::new(XStart::CENTER, YStart::CENTER))
|
//! .with(AreaStartingPosition::new(XStart::CENTER, YStart::CENTER))
|
||||||
|
@ -33,7 +33,7 @@ pub mod geometry;
|
||||||
pub mod map;
|
pub mod map;
|
||||||
pub mod metric;
|
pub mod metric;
|
||||||
|
|
||||||
pub use map::{Map, Symmetry, Tile};
|
pub use map::{BuilderData, Map, NoData, Symmetry, Tile};
|
||||||
pub use filter::*;
|
pub use filter::*;
|
||||||
|
|
||||||
pub (crate) mod dijkstra;
|
pub (crate) mod dijkstra;
|
||||||
|
@ -45,20 +45,20 @@ use rand::prelude::*;
|
||||||
|
|
||||||
/// Trait which should be implemented by map modifier.
|
/// Trait which should be implemented by map modifier.
|
||||||
/// Modifier takes initiall map and apply changes to it.
|
/// Modifier takes initiall map and apply changes to it.
|
||||||
pub trait MapFilter {
|
pub trait MapFilter<D: BuilderData> {
|
||||||
fn modify_map(&self, rng: &mut StdRng, map: &Map) -> Map;
|
fn modify_map(&self, rng: &mut StdRng, map: &Map<D>) -> Map<D>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Used to chain MapBuilder and MapModifiers to create the final map.
|
/// Used to chain MapBuilder and MapModifiers to create the final map.
|
||||||
pub struct MapBuilder {
|
pub struct MapBuilder<D> {
|
||||||
width: usize,
|
width: usize,
|
||||||
height: usize,
|
height: usize,
|
||||||
modifiers: Vec<Box<dyn MapFilter>>,
|
modifiers: Vec<Box<dyn MapFilter<D>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MapBuilder {
|
impl<D: BuilderData> MapBuilder<D> {
|
||||||
/// Create Map Builder with initial map generator
|
/// Create Map Builder with initial map generator
|
||||||
pub fn new(width: usize, height: usize) -> MapBuilder {
|
pub fn new(width: usize, height: usize) -> MapBuilder<D> {
|
||||||
MapBuilder {
|
MapBuilder {
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
|
@ -66,20 +66,20 @@ impl MapBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with(&mut self, modifier : Box<dyn MapFilter>) -> &mut MapBuilder {
|
pub fn with(&mut self, modifier : Box<dyn MapFilter<D>>) -> &mut MapBuilder<D> {
|
||||||
self.modifiers.push(modifier);
|
self.modifiers.push(modifier);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build map using random number seeded with system time
|
/// Build map using random number seeded with system time
|
||||||
pub fn build(&mut self) -> Map {
|
pub fn build(&mut self) -> Map<D> {
|
||||||
let system_time = SystemTime::now().duration_since(UNIX_EPOCH).expect("Can't access system time");
|
let system_time = SystemTime::now().duration_since(UNIX_EPOCH).expect("Can't access system time");
|
||||||
let mut rng = StdRng::seed_from_u64(system_time.as_millis() as u64);
|
let mut rng = StdRng::seed_from_u64(system_time.as_millis() as u64);
|
||||||
self.build_with_rng(&mut rng)
|
self.build_with_rng(&mut rng)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build map using provided random number generator
|
/// Build map using provided random number generator
|
||||||
pub fn build_with_rng(&mut self, rng: &mut StdRng) -> Map {
|
pub fn build_with_rng(&mut self, rng: &mut StdRng) -> Map<D> {
|
||||||
let mut map = Map::new(self.width, self.height);
|
let mut map = Map::new(self.width, self.height);
|
||||||
|
|
||||||
// Build additional layers in turn
|
// Build additional layers in turn
|
||||||
|
@ -97,6 +97,8 @@ impl MapBuilder {
|
||||||
/// ------------------------------------------------------------------------------------------------
|
/// ------------------------------------------------------------------------------------------------
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use crate::map::NoData;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use filter::{
|
use filter::{
|
||||||
CellularAutomata,
|
CellularAutomata,
|
||||||
|
@ -106,7 +108,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_ca_map() {
|
fn test_ca_map() {
|
||||||
let map = MapBuilder::new(80, 50)
|
let map = MapBuilder::<NoData>::new(80, 50)
|
||||||
.with(NoiseGenerator::new(0.55))
|
.with(NoiseGenerator::new(0.55))
|
||||||
.with(CellularAutomata::new())
|
.with(CellularAutomata::new())
|
||||||
.with(AreaStartingPosition::new(XStart::CENTER, YStart::CENTER))
|
.with(AreaStartingPosition::new(XStart::CENTER, YStart::CENTER))
|
||||||
|
|
37
src/map.rs
37
src/map.rs
|
@ -21,9 +21,18 @@ pub struct Tile {
|
||||||
pub enum Symmetry { None, Horizontal, Vertical, Both }
|
pub enum Symmetry { None, Horizontal, Vertical, Both }
|
||||||
|
|
||||||
|
|
||||||
|
/// Arbitrary data associated with each map
|
||||||
|
pub trait BuilderData: Clone + Default {}
|
||||||
|
|
||||||
|
/// No build data
|
||||||
|
#[derive(Clone, Debug, Default)]
|
||||||
|
pub struct NoData;
|
||||||
|
|
||||||
|
impl BuilderData for NoData {}
|
||||||
|
|
||||||
/// Map data
|
/// Map data
|
||||||
#[derive(Default, Clone)]
|
#[derive(Default, Clone)]
|
||||||
pub struct Map {
|
pub struct Map<D> {
|
||||||
pub tiles : Vec<Tile>,
|
pub tiles : Vec<Tile>,
|
||||||
pub width : usize,
|
pub width : usize,
|
||||||
pub height : usize,
|
pub height : usize,
|
||||||
|
@ -31,6 +40,7 @@ pub struct Map {
|
||||||
pub exit_point: Option<Point>,
|
pub exit_point: Option<Point>,
|
||||||
pub rooms: Vec<Rect>,
|
pub rooms: Vec<Rect>,
|
||||||
pub corridors: Vec<Vec<Point>>,
|
pub corridors: Vec<Vec<Point>>,
|
||||||
|
pub data: D,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Tile {
|
impl Tile {
|
||||||
|
@ -59,10 +69,10 @@ impl Tile {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Map {
|
impl<D: BuilderData> Map<D> {
|
||||||
|
|
||||||
/// Generates an empty map, consisting entirely of solid walls
|
/// Generates an empty map, consisting entirely of solid walls
|
||||||
pub fn new(width: usize, height: usize) -> Map {
|
pub fn new(width: usize, height: usize) -> Map<D> {
|
||||||
let map_tile_count = width*height;
|
let map_tile_count = width*height;
|
||||||
Map{
|
Map{
|
||||||
tiles : vec![Tile::wall(); map_tile_count],
|
tiles : vec![Tile::wall(); map_tile_count],
|
||||||
|
@ -71,12 +81,13 @@ impl Map {
|
||||||
starting_point: None,
|
starting_point: None,
|
||||||
exit_point: None,
|
exit_point: None,
|
||||||
rooms: Vec::new(),
|
rooms: Vec::new(),
|
||||||
corridors: Vec::new()
|
corridors: Vec::new(),
|
||||||
|
data: Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create map from given string
|
/// Create map from given string
|
||||||
pub fn from_string(map_string: &str) -> Map {
|
pub fn from_string(map_string: &str) -> Map<D> {
|
||||||
let lines: Vec<&str> = map_string.split("\n")
|
let lines: Vec<&str> = map_string.split("\n")
|
||||||
.map(|l| l.trim())
|
.map(|l| l.trim())
|
||||||
.filter(|l| l.len() > 0)
|
.filter(|l| l.len() > 0)
|
||||||
|
@ -235,7 +246,7 @@ impl Map {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Map {
|
impl<D: BuilderData> fmt::Display for Map<D> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
for y in 0..self.height {
|
for y in 0..self.height {
|
||||||
let bytes: Vec<u8> = (0..self.width)
|
let bytes: Vec<u8> = (0..self.width)
|
||||||
|
@ -257,7 +268,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_new_map() {
|
fn test_new_map() {
|
||||||
let map = Map::new(10, 10);
|
let map = Map::<NoData>::new(10, 10);
|
||||||
for i in 0..10 {
|
for i in 0..10 {
|
||||||
for j in 0..10 {
|
for j in 0..10 {
|
||||||
assert!(map.at(i, j).is_blocked);
|
assert!(map.at(i, j).is_blocked);
|
||||||
|
@ -272,7 +283,7 @@ mod tests {
|
||||||
# #
|
# #
|
||||||
##########
|
##########
|
||||||
";
|
";
|
||||||
let map = Map::from_string(map_str);
|
let map = Map::<NoData>::from_string(map_str);
|
||||||
|
|
||||||
assert_eq!(map.width, 10);
|
assert_eq!(map.width, 10);
|
||||||
assert_eq!(map.height, 3);
|
assert_eq!(map.height, 3);
|
||||||
|
@ -295,7 +306,7 @@ mod tests {
|
||||||
# #
|
# #
|
||||||
##########
|
##########
|
||||||
";
|
";
|
||||||
let map = Map::from_string(map_str);
|
let map = Map::<NoData>::from_string(map_str);
|
||||||
let exists = map.get_available_exits(1, 1);
|
let exists = map.get_available_exits(1, 1);
|
||||||
let expected_exists = vec![(2, 1, 1.0), (1, 2, 1.0), (2, 2, 1.45)];
|
let expected_exists = vec![(2, 1, 1.0), (1, 2, 1.0), (2, 2, 1.45)];
|
||||||
assert_eq!(exists, expected_exists);
|
assert_eq!(exists, expected_exists);
|
||||||
|
@ -303,7 +314,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_create_room() {
|
fn test_create_room() {
|
||||||
let mut map = Map::new(5, 5);
|
let mut map = Map::<NoData>::new(5, 5);
|
||||||
map.add_room(Rect::new(1, 1, 3, 3));
|
map.add_room(Rect::new(1, 1, 3, 3));
|
||||||
for x in 0..map.width {
|
for x in 0..map.width {
|
||||||
for y in 0..map.height {
|
for y in 0..map.height {
|
||||||
|
@ -323,13 +334,13 @@ mod tests {
|
||||||
# # #
|
# # #
|
||||||
##########
|
##########
|
||||||
";
|
";
|
||||||
let mut map = Map::from_string(map_str);
|
let mut map = Map::<NoData>::from_string(map_str);
|
||||||
let expected_map_str = "
|
let expected_map_str = "
|
||||||
##########
|
##########
|
||||||
# #
|
# #
|
||||||
##########
|
##########
|
||||||
";
|
";
|
||||||
let expected_map = Map::from_string(expected_map_str);
|
let expected_map = Map::<NoData>::from_string(expected_map_str);
|
||||||
|
|
||||||
map.add_corridor(Point::new(1, 1), Point::new(8, 1));
|
map.add_corridor(Point::new(1, 1), Point::new(8, 1));
|
||||||
|
|
||||||
|
@ -344,7 +355,7 @@ mod tests {
|
||||||
# # #
|
# # #
|
||||||
##########
|
##########
|
||||||
";
|
";
|
||||||
let map = Map::from_string(map_str);
|
let map = Map::<NoData>::from_string(map_str);
|
||||||
let exists = map.get_available_exits(0, 0);
|
let exists = map.get_available_exits(0, 0);
|
||||||
|
|
||||||
assert_eq!(exists.len(), 1);
|
assert_eq!(exists.len(), 1);
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
//! and the provide generator score as an average.
|
//! and the provide generator score as an average.
|
||||||
//!
|
//!
|
||||||
|
|
||||||
|
use super::BuilderData;
|
||||||
use super::map::Map;
|
use super::map::Map;
|
||||||
use super::dijkstra::DijkstraMap;
|
use super::dijkstra::DijkstraMap;
|
||||||
|
|
||||||
|
@ -11,7 +12,7 @@ use super::dijkstra::DijkstraMap;
|
||||||
/// This metric calculates the percentage of walkable cells (Floor).
|
/// This metric calculates the percentage of walkable cells (Floor).
|
||||||
/// If this number is very low (like < 10%) then it means that the map
|
/// If this number is very low (like < 10%) then it means that the map
|
||||||
/// is probably to degenerated and shouldn't be used
|
/// is probably to degenerated and shouldn't be used
|
||||||
pub fn density(map: &Map) -> f32 {
|
pub fn density<D>(map: &Map<D>) -> f32 {
|
||||||
let floor_count = map.tiles.iter()
|
let floor_count = map.tiles.iter()
|
||||||
.filter(|&t| t.is_walkable())
|
.filter(|&t| t.is_walkable())
|
||||||
.count();
|
.count();
|
||||||
|
@ -22,7 +23,7 @@ pub fn density(map: &Map) -> f32 {
|
||||||
/// Calculate the length of the shortes path from the starting point
|
/// Calculate the length of the shortes path from the starting point
|
||||||
/// to the exit.
|
/// to the exit.
|
||||||
/// If this path is very short, then the map is probably degenerated.
|
/// If this path is very short, then the map is probably degenerated.
|
||||||
pub fn path_length(map: &Map) -> f32 {
|
pub fn path_length<D: BuilderData>(map: &Map<D>) -> f32 {
|
||||||
if map.starting_point.is_none() {
|
if map.starting_point.is_none() {
|
||||||
return 0.0
|
return 0.0
|
||||||
}
|
}
|
||||||
|
@ -43,12 +44,12 @@ pub fn path_length(map: &Map) -> f32 {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::geometry::Point;
|
use crate::{geometry::Point, map::NoData};
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_density_no_floor() {
|
fn test_density_no_floor() {
|
||||||
let map = Map::new(10, 10);
|
let map = Map::<NoData>::new(10, 10);
|
||||||
let score = density(&map);
|
let score = density(&map);
|
||||||
assert_eq!(score, 0.0);
|
assert_eq!(score, 0.0);
|
||||||
}
|
}
|
||||||
|
@ -60,7 +61,7 @@ mod tests {
|
||||||
# ## #
|
# ## #
|
||||||
##########
|
##########
|
||||||
";
|
";
|
||||||
let map = Map::from_string(map_str);
|
let map = Map::<NoData>::from_string(map_str);
|
||||||
let score = density(&map);
|
let score = density(&map);
|
||||||
assert_eq!(score, 0.2);
|
assert_eq!(score, 0.2);
|
||||||
}
|
}
|
||||||
|
@ -72,7 +73,7 @@ mod tests {
|
||||||
# ## #
|
# ## #
|
||||||
##########
|
##########
|
||||||
";
|
";
|
||||||
let map = Map::from_string(map_str);
|
let map = Map::<NoData>::from_string(map_str);
|
||||||
let score = path_length(&map);
|
let score = path_length(&map);
|
||||||
assert_eq!(score, 0.0);
|
assert_eq!(score, 0.0);
|
||||||
}
|
}
|
||||||
|
@ -85,7 +86,7 @@ mod tests {
|
||||||
# #
|
# #
|
||||||
##########
|
##########
|
||||||
";
|
";
|
||||||
let mut map = Map::from_string(map_str);
|
let mut map = Map::<NoData>::from_string(map_str);
|
||||||
map.starting_point = Some(Point::new(1,1));
|
map.starting_point = Some(Point::new(1,1));
|
||||||
map.exit_point = Some(Point::new(8,1));
|
map.exit_point = Some(Point::new(8,1));
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user