cargo fmt
This commit is contained in:
parent
efad0132ff
commit
ffaad6cf48
|
@ -1,6 +1,5 @@
|
|||
use rand::prelude::*;
|
||||
use mapgen::*;
|
||||
|
||||
use rand::prelude::*;
|
||||
|
||||
fn main() {
|
||||
let mut rng = StdRng::seed_from_u64(907647352);
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
use rand::prelude::*;
|
||||
use mapgen::*;
|
||||
|
||||
use rand::prelude::*;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
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 gen = BspRooms::<NoData>::new();
|
||||
let map = gen.modify_map(&mut rng, &Map::new(80, 50));
|
||||
|
|
|
@ -1,17 +1,10 @@
|
|||
use mapgen::{
|
||||
MapBuilder,
|
||||
NoData,
|
||||
filter::{
|
||||
NoiseGenerator,
|
||||
CellularAutomata,
|
||||
CullUnreachable,
|
||||
AreaStartingPosition,
|
||||
XStart,
|
||||
YStart,
|
||||
AreaStartingPosition, CellularAutomata, CullUnreachable, NoiseGenerator, XStart, YStart,
|
||||
},
|
||||
MapBuilder, NoData,
|
||||
};
|
||||
|
||||
|
||||
fn main() {
|
||||
let map = MapBuilder::<NoData>::new(20, 20)
|
||||
.with(NoiseGenerator::uniform())
|
||||
|
|
|
@ -25,10 +25,9 @@
|
|||
//! ---
|
||||
//!
|
||||
|
||||
use std::{collections::VecDeque, marker::PhantomData};
|
||||
use std::f32::MAX;
|
||||
use super::map::{BuilderData, Map};
|
||||
|
||||
use std::f32::MAX;
|
||||
use std::{collections::VecDeque, marker::PhantomData};
|
||||
|
||||
/// Representation of a Dijkstra flow map.
|
||||
/// map is a vector of floats, having a size equal to size_x * size_y (one per tile).
|
||||
|
@ -79,8 +78,12 @@ impl<D: BuilderData> DijkstraMap<D> {
|
|||
let idx = self.xy_idx(x, y);
|
||||
let new_depth = depth + add_depth;
|
||||
let prev_depth = self.tiles[idx];
|
||||
if new_depth >= prev_depth { continue; }
|
||||
if new_depth >= self.max_depth { continue; }
|
||||
if new_depth >= prev_depth {
|
||||
continue;
|
||||
}
|
||||
if new_depth >= self.max_depth {
|
||||
continue;
|
||||
}
|
||||
self.tiles[idx] = new_depth;
|
||||
open_list.push_back(((x, y), new_depth));
|
||||
}
|
||||
|
@ -112,7 +115,13 @@ mod tests {
|
|||
map.starting_point = Some(Point::new(8, 1));
|
||||
let dm = DijkstraMap::new(&map);
|
||||
|
||||
println!("{:?}", &dm.tiles.iter().map(|&v| if v == f32::MAX {9.0} else {v}).collect::<Vec<f32>>());
|
||||
println!(
|
||||
"{:?}",
|
||||
&dm.tiles
|
||||
.iter()
|
||||
.map(|&v| if v == f32::MAX { 9.0 } else { v })
|
||||
.collect::<Vec<f32>>()
|
||||
);
|
||||
|
||||
assert_eq!(dm.size_x, 10);
|
||||
assert_eq!(dm.size_y, 3);
|
||||
|
@ -139,10 +148,9 @@ mod tests {
|
|||
let mut map = Map::<NoData>::from_string(map_str);
|
||||
map.starting_point = Some(Point::new(2, 2));
|
||||
let dm = DijkstraMap::new(&map);
|
||||
let expected = [MAX, MAX, MAX, MAX,
|
||||
MAX, 1.45, 1.0, MAX,
|
||||
MAX, 1.0, 0.0, MAX,
|
||||
MAX, MAX, MAX, MAX];
|
||||
let expected = [
|
||||
MAX, MAX, MAX, MAX, MAX, 1.45, 1.0, MAX, MAX, 1.0, 0.0, MAX, MAX, MAX, MAX, MAX,
|
||||
];
|
||||
|
||||
assert_eq!(dm.tiles, expected);
|
||||
}
|
||||
|
@ -158,10 +166,11 @@ mod tests {
|
|||
let mut map = Map::<NoData>::from_string(map_str);
|
||||
map.starting_point = Some(Point::new(8, 2));
|
||||
let dm = DijkstraMap::new(&map);
|
||||
let expected = [MAX, MAX, MAX, MAX, MAX, MAX, MAX, MAX, MAX, MAX,
|
||||
MAX, 7.45, 6.45, 5.45, 4.45, 3.45, 2.45, 1.45, 1.0, MAX,
|
||||
MAX, 7.9, 6.9, MAX, 4.0, 3.0, 2.0, 1.0, 0.0, MAX,
|
||||
MAX, MAX, MAX, MAX, MAX, MAX, MAX, MAX, MAX, MAX];
|
||||
let expected = [
|
||||
MAX, MAX, MAX, MAX, MAX, MAX, MAX, MAX, MAX, MAX, MAX, 7.45, 6.45, 5.45, 4.45, 3.45,
|
||||
2.45, 1.45, 1.0, MAX, MAX, 7.9, 6.9, MAX, 4.0, 3.0, 2.0, 1.0, 0.0, MAX, MAX, MAX, MAX,
|
||||
MAX, MAX, MAX, MAX, MAX, MAX, MAX,
|
||||
];
|
||||
|
||||
for (v, e) in dm.tiles.iter().zip(expected.iter()) {
|
||||
assert!(f32::abs(v - e) <= 0.01);
|
||||
|
|
|
@ -22,12 +22,11 @@
|
|||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use rand::prelude::*;
|
||||
use crate::{BuilderData, MapFilter};
|
||||
use crate::geometry::{Point, Rect};
|
||||
use crate::random::Rng;
|
||||
use crate::Map;
|
||||
|
||||
use crate::{BuilderData, MapFilter};
|
||||
use rand::prelude::*;
|
||||
|
||||
pub struct BspInterior<D: BuilderData> {
|
||||
min_room_size: usize,
|
||||
|
@ -41,7 +40,6 @@ impl<D: BuilderData> MapFilter<D> for BspInterior<D> {
|
|||
}
|
||||
|
||||
impl<D: BuilderData> BspInterior<D> {
|
||||
|
||||
pub fn new() -> Box<BspInterior<D>> {
|
||||
Box::new(BspInterior {
|
||||
min_room_size: 8,
|
||||
|
@ -95,22 +93,29 @@ impl<D: BuilderData> BspInterior<D> {
|
|||
// Horizontal split
|
||||
let h1 = Rect::new(rect.x1, rect.y1, half_width - 1, height);
|
||||
rects.push(h1);
|
||||
if half_width > self.min_room_size { self.add_subrects(h1, rng, rects); }
|
||||
if half_width > self.min_room_size {
|
||||
self.add_subrects(h1, rng, rects);
|
||||
}
|
||||
let h2 = Rect::new(rect.x1 + half_width, rect.y1, half_width, height);
|
||||
rects.push(h2);
|
||||
if half_width > self.min_room_size { self.add_subrects(h2, rng, rects); }
|
||||
if half_width > self.min_room_size {
|
||||
self.add_subrects(h2, rng, rects);
|
||||
}
|
||||
} else {
|
||||
// Vertical split
|
||||
let v1 = Rect::new(rect.x1, rect.y1, width, half_height - 1);
|
||||
rects.push(v1);
|
||||
if half_height > self.min_room_size { self.add_subrects(v1, rng, rects); }
|
||||
if half_height > self.min_room_size {
|
||||
self.add_subrects(v1, rng, rects);
|
||||
}
|
||||
let v2 = Rect::new(rect.x1, rect.y1 + half_height, width, half_height);
|
||||
rects.push(v2);
|
||||
if half_height > self.min_room_size { self.add_subrects(v2, rng, rects); }
|
||||
if half_height > self.min_room_size {
|
||||
self.add_subrects(v2, rng, rects);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// ------------------------------------------------------------------------------------------------
|
||||
/// Module unit tests
|
||||
|
@ -118,7 +123,7 @@ impl<D: BuilderData> BspInterior<D> {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{Map, map::NoData};
|
||||
use crate::{map::NoData, Map};
|
||||
|
||||
#[test]
|
||||
fn no_corridors_on_borders() {
|
||||
|
@ -134,5 +139,4 @@ mod tests {
|
|||
assert!(map.at(79, j).is_blocked());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -20,13 +20,12 @@
|
|||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use rand::prelude::*;
|
||||
use crate::BuilderData;
|
||||
use crate::MapFilter;
|
||||
use crate::geometry::Rect;
|
||||
use crate::random::Rng;
|
||||
use crate::BuilderData;
|
||||
use crate::Map;
|
||||
|
||||
use crate::MapFilter;
|
||||
use rand::prelude::*;
|
||||
|
||||
pub struct BspRooms<D: BuilderData> {
|
||||
max_split: usize,
|
||||
|
@ -78,15 +77,32 @@ impl<D: BuilderData> BspRooms<D> {
|
|||
let half_height = usize::max(height / 2, 1);
|
||||
|
||||
rects.push(Rect::new(rect.x1, rect.y1, half_width, half_height));
|
||||
rects.push(Rect::new( rect.x1, rect.y1 + half_height, half_width, half_height ));
|
||||
rects.push(Rect::new( rect.x1 + half_width, rect.y1, half_width, half_height ));
|
||||
rects.push(Rect::new( rect.x1 + half_width, rect.y1 + half_height, half_width, half_height ));
|
||||
rects.push(Rect::new(
|
||||
rect.x1,
|
||||
rect.y1 + half_height,
|
||||
half_width,
|
||||
half_height,
|
||||
));
|
||||
rects.push(Rect::new(
|
||||
rect.x1 + half_width,
|
||||
rect.y1,
|
||||
half_width,
|
||||
half_height,
|
||||
));
|
||||
rects.push(Rect::new(
|
||||
rect.x1 + half_width,
|
||||
rect.y1 + half_height,
|
||||
half_width,
|
||||
half_height,
|
||||
));
|
||||
|
||||
rects
|
||||
}
|
||||
|
||||
fn get_random_rect(&self, rng: &mut StdRng, rects: &Vec<Rect>) -> Rect {
|
||||
if rects.len() == 1 { return rects[0]; }
|
||||
if rects.len() == 1 {
|
||||
return rects[0];
|
||||
}
|
||||
let idx = rng.random_range(0, rects.len());
|
||||
rects[idx]
|
||||
}
|
||||
|
@ -117,15 +133,25 @@ impl<D: BuilderData> BspRooms<D> {
|
|||
let mut can_build = true;
|
||||
|
||||
for r in map.rooms.iter() {
|
||||
if r.intersect(&rect) { can_build = false; }
|
||||
if r.intersect(&rect) {
|
||||
can_build = false;
|
||||
}
|
||||
}
|
||||
|
||||
for y in expanded.y1..=expanded.y2 {
|
||||
for x in expanded.x1..=expanded.x2 {
|
||||
if x > map.width - 2 { can_build = false; }
|
||||
if y > map.height - 2 { can_build = false; }
|
||||
if x < 1 { can_build = false; }
|
||||
if y < 1 { can_build = false; }
|
||||
if x > map.width - 2 {
|
||||
can_build = false;
|
||||
}
|
||||
if y > map.height - 2 {
|
||||
can_build = false;
|
||||
}
|
||||
if x < 1 {
|
||||
can_build = false;
|
||||
}
|
||||
if y < 1 {
|
||||
can_build = false;
|
||||
}
|
||||
if can_build {
|
||||
if map.at(x as usize, y as usize).is_walkable() {
|
||||
can_build = false;
|
||||
|
@ -160,5 +186,4 @@ mod tests {
|
|||
assert!(map.at(79, j).is_blocked());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -23,11 +23,10 @@
|
|||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use rand::prelude::*;
|
||||
use crate::BuilderData;
|
||||
use crate::MapFilter;
|
||||
use crate::{Map, Tile};
|
||||
|
||||
use rand::prelude::*;
|
||||
|
||||
/// Map filter
|
||||
pub struct CellularAutomata<D: BuilderData> {
|
||||
|
@ -59,7 +58,6 @@ impl<D: BuilderData> CellularAutomata<D> {
|
|||
|
||||
new_map
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn apply_iteration<D: BuilderData>(map: &Map<D>) -> Map<D> {
|
||||
|
@ -68,17 +66,23 @@ fn apply_iteration<D: BuilderData>(map: &Map<D>) -> Map<D> {
|
|||
for y in 1..map.height - 1 {
|
||||
for x in 1..map.width - 1 {
|
||||
let idxs = [
|
||||
(x-1, y-1), (x, y-1), (x+1, y-1),
|
||||
(x-1, y), (x+1, y),
|
||||
(x-1, y+1), (x, y+1), (x+1, y+1)];
|
||||
let neighbors = idxs.iter()
|
||||
(x - 1, y - 1),
|
||||
(x, y - 1),
|
||||
(x + 1, y - 1),
|
||||
(x - 1, y),
|
||||
(x + 1, y),
|
||||
(x - 1, y + 1),
|
||||
(x, y + 1),
|
||||
(x + 1, y + 1),
|
||||
];
|
||||
let neighbors = idxs
|
||||
.iter()
|
||||
.filter(|(x, y)| map.at(*x, *y).is_blocked())
|
||||
.count();
|
||||
|
||||
if neighbors > 4 || neighbors == 0 {
|
||||
new_map.set_tile(x, y, Tile::wall())
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
new_map.set_tile(x, y, Tile::floor());
|
||||
}
|
||||
}
|
||||
|
@ -103,7 +107,6 @@ mod tests {
|
|||
assert!(new_map.at(1, 1).is_blocked());
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_iteration_floor() {
|
||||
let mut map = Map::<NoData>::new(3, 3);
|
||||
|
@ -115,5 +118,4 @@ mod tests {
|
|||
let new_map = apply_iteration(&map);
|
||||
assert!(new_map.at(1, 1).is_walkable());
|
||||
}
|
||||
|
||||
}
|
|
@ -6,11 +6,10 @@
|
|||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use rand::prelude::StdRng;
|
||||
use crate::dijkstra::DijkstraMap;
|
||||
use crate::MapFilter;
|
||||
use crate::{BuilderData, Map, Tile};
|
||||
use crate::dijkstra::DijkstraMap;
|
||||
|
||||
use rand::prelude::StdRng;
|
||||
|
||||
/// Remove unreachable areas from the map.
|
||||
pub struct CullUnreachable<D: BuilderData> {
|
||||
|
@ -53,11 +52,11 @@ impl<D: BuilderData> CullUnreachable<D> {
|
|||
/// ------------------------------------------------------------------------------------------------
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use rand::prelude::*;
|
||||
use super::*;
|
||||
use super::MapFilter;
|
||||
use super::*;
|
||||
use crate::geometry::Point;
|
||||
use crate::map::{Map, NoData};
|
||||
use rand::prelude::*;
|
||||
|
||||
#[test]
|
||||
fn test_culling() {
|
||||
|
@ -75,7 +74,6 @@ mod tests {
|
|||
";
|
||||
let expected_map = Map::<NoData>::from_string(expected_map_str);
|
||||
|
||||
|
||||
let modifier = CullUnreachable::new();
|
||||
let mut rng = StdRng::seed_from_u64(0);
|
||||
let new_map = modifier.modify_map(&mut rng, &map);
|
||||
|
|
|
@ -4,15 +4,14 @@
|
|||
//! It means that starting point have to be set before this Modyfier will start.
|
||||
//!
|
||||
|
||||
use crate::dijkstra::DijkstraMap;
|
||||
use crate::geometry::Point;
|
||||
use crate::BuilderData;
|
||||
use crate::Map;
|
||||
use crate::MapFilter;
|
||||
use rand::prelude::StdRng;
|
||||
use std::f32;
|
||||
use std::marker::PhantomData;
|
||||
use rand::prelude::StdRng;
|
||||
use crate::BuilderData;
|
||||
use crate::geometry::Point;
|
||||
use crate::MapFilter;
|
||||
use crate::Map;
|
||||
use crate::dijkstra::DijkstraMap;
|
||||
|
||||
|
||||
/// Add exist position to the map based on the distance from the start point.
|
||||
pub struct DistantExit<D: BuilderData> {
|
||||
|
@ -57,11 +56,11 @@ impl<D: BuilderData> DistantExit<D> {
|
|||
/// ------------------------------------------------------------------------------------------------
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use rand::prelude::*;
|
||||
use super::*;
|
||||
use super::MapFilter;
|
||||
use super::*;
|
||||
use crate::geometry::Point;
|
||||
use crate::map::{Map, NoData};
|
||||
use rand::prelude::*;
|
||||
|
||||
#[test]
|
||||
fn test_exit() {
|
||||
|
|
|
@ -15,18 +15,20 @@
|
|||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use rand::prelude::*;
|
||||
use crate::MapFilter;
|
||||
use crate::{
|
||||
BuilderData,
|
||||
map::{Map, Symmetry, Tile},
|
||||
geometry::Point,
|
||||
random::Rng
|
||||
map::{Map, Symmetry, Tile},
|
||||
random::Rng,
|
||||
BuilderData,
|
||||
};
|
||||
|
||||
use rand::prelude::*;
|
||||
|
||||
#[derive(PartialEq, Copy, Clone)]
|
||||
pub enum DrunkSpawnMode { StartingPoint, Random }
|
||||
pub enum DrunkSpawnMode {
|
||||
StartingPoint,
|
||||
Random,
|
||||
}
|
||||
|
||||
pub struct DrunkardsWalk<D: BuilderData> {
|
||||
spawn_mode: DrunkSpawnMode,
|
||||
|
@ -44,12 +46,13 @@ impl<D: BuilderData> MapFilter<D> for DrunkardsWalk<D> {
|
|||
}
|
||||
|
||||
impl<D: BuilderData> DrunkardsWalk<D> {
|
||||
pub fn new( spawn_mode: DrunkSpawnMode,
|
||||
pub fn new(
|
||||
spawn_mode: DrunkSpawnMode,
|
||||
drunken_lifetime: i32,
|
||||
floor_percent: f32,
|
||||
brush_size: usize,
|
||||
symmetry: Symmetry) -> Box<DrunkardsWalk<D>>
|
||||
{
|
||||
symmetry: Symmetry,
|
||||
) -> Box<DrunkardsWalk<D>> {
|
||||
Box::new(DrunkardsWalk {
|
||||
spawn_mode,
|
||||
drunken_lifetime,
|
||||
|
@ -116,10 +119,26 @@ impl<D: BuilderData> DrunkardsWalk<D> {
|
|||
|
||||
let stagger_direction = rng.roll_dice(1, 4);
|
||||
match stagger_direction {
|
||||
1 => { if drunk_x > 1 { drunk_x -= 1; } }
|
||||
2 => { if drunk_x < new_map.width-2 { drunk_x += 1; } }
|
||||
3 => { if drunk_y > 1 { drunk_y -=1; } }
|
||||
_ => { if drunk_y < new_map.height-2 { drunk_y += 1; } }
|
||||
1 => {
|
||||
if drunk_x > 1 {
|
||||
drunk_x -= 1;
|
||||
}
|
||||
}
|
||||
2 => {
|
||||
if drunk_x < new_map.width - 2 {
|
||||
drunk_x += 1;
|
||||
}
|
||||
}
|
||||
3 => {
|
||||
if drunk_y > 1 {
|
||||
drunk_y -= 1;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
if drunk_y < new_map.height - 2 {
|
||||
drunk_y += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
drunk_life -= 1;
|
||||
|
|
|
@ -15,13 +15,12 @@
|
|||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use rand::prelude::*;
|
||||
use crate::MapFilter;
|
||||
use crate::{
|
||||
map::{BuilderData, Map, Tile},
|
||||
random::Rng
|
||||
random::Rng,
|
||||
};
|
||||
|
||||
use rand::prelude::*;
|
||||
|
||||
pub struct MazeBuilder<D: BuilderData> {
|
||||
phantom: PhantomData<D>,
|
||||
|
@ -70,7 +69,7 @@ impl Cell {
|
|||
row,
|
||||
column,
|
||||
walls: [true, true, true, true],
|
||||
visited: false
|
||||
visited: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -81,16 +80,13 @@ impl Cell {
|
|||
if x == 1 {
|
||||
self.walls[LEFT] = false;
|
||||
next.walls[RIGHT] = false;
|
||||
}
|
||||
else if x == -1 {
|
||||
} else if x == -1 {
|
||||
self.walls[RIGHT] = false;
|
||||
next.walls[LEFT] = false;
|
||||
}
|
||||
else if y == 1 {
|
||||
} else if y == 1 {
|
||||
self.walls[TOP] = false;
|
||||
next.walls[BOTTOM] = false;
|
||||
}
|
||||
else if y == -1 {
|
||||
} else if y == -1 {
|
||||
self.walls[BOTTOM] = false;
|
||||
next.walls[TOP] = false;
|
||||
}
|
||||
|
@ -146,7 +142,7 @@ impl<'a, D: BuilderData> Grid<'a, D> {
|
|||
self.calculate_index(current_row - 1, current_column),
|
||||
self.calculate_index(current_row, current_column + 1),
|
||||
self.calculate_index(current_row + 1, current_column),
|
||||
self.calculate_index(current_row, current_column - 1)
|
||||
self.calculate_index(current_row, current_column - 1),
|
||||
];
|
||||
|
||||
for i in neighbor_indices.iter() {
|
||||
|
@ -209,17 +205,27 @@ impl<'a, D: BuilderData> Grid<'a, D> {
|
|||
|
||||
fn copy_to_map(&self, map: &mut Map<D>) {
|
||||
// Clear the map
|
||||
for i in map.tiles.iter_mut() { *i = Tile::wall(); }
|
||||
for i in map.tiles.iter_mut() {
|
||||
*i = Tile::wall();
|
||||
}
|
||||
|
||||
for cell in self.cells.iter() {
|
||||
let x = (cell.column as usize + 1) * 2;
|
||||
let y = (cell.row as usize + 1) * 2;
|
||||
|
||||
map.set_tile(x, y, Tile::floor());
|
||||
if !cell.walls[TOP] { map.set_tile(x, y-1, Tile::floor()) }
|
||||
if !cell.walls[RIGHT] { map.set_tile(x+1, y, Tile::floor()) }
|
||||
if !cell.walls[BOTTOM] { map.set_tile(x, y+1, Tile::floor()) }
|
||||
if !cell.walls[LEFT] { map.set_tile(x-1, y, Tile::floor()) }
|
||||
if !cell.walls[TOP] {
|
||||
map.set_tile(x, y - 1, Tile::floor())
|
||||
}
|
||||
if !cell.walls[RIGHT] {
|
||||
map.set_tile(x + 1, y, Tile::floor())
|
||||
}
|
||||
if !cell.walls[BOTTOM] {
|
||||
map.set_tile(x, y + 1, Tile::floor())
|
||||
}
|
||||
if !cell.walls[LEFT] {
|
||||
map.set_tile(x - 1, y, Tile::floor())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,8 +9,8 @@ pub mod distant_exit;
|
|||
pub mod drunkard;
|
||||
pub mod maze;
|
||||
pub mod noise_generator;
|
||||
pub mod simple_rooms;
|
||||
pub mod rooms_corridors_nearest;
|
||||
pub mod simple_rooms;
|
||||
pub mod starting_point;
|
||||
pub mod voronoi;
|
||||
|
||||
|
@ -22,8 +22,7 @@ pub use distant_exit::DistantExit;
|
|||
pub use drunkard::DrunkardsWalk;
|
||||
pub use maze::MazeBuilder;
|
||||
pub use noise_generator::NoiseGenerator;
|
||||
pub use simple_rooms::SimpleRooms;
|
||||
pub use rooms_corridors_nearest::NearestCorridors;
|
||||
pub use simple_rooms::SimpleRooms;
|
||||
pub use starting_point::{AreaStartingPosition, XStart, YStart};
|
||||
pub use voronoi::VoronoiHive;
|
||||
|
||||
|
|
|
@ -18,10 +18,9 @@
|
|||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use rand::prelude::*;
|
||||
use crate::MapFilter;
|
||||
use crate::{BuilderData, Map, Tile};
|
||||
|
||||
use rand::prelude::*;
|
||||
|
||||
/// Map noise generator
|
||||
pub struct NoiseGenerator<D: BuilderData> {
|
||||
|
@ -59,12 +58,14 @@ impl<D: BuilderData> NoiseGenerator<D> {
|
|||
for y in 1..new_map.height - 1 {
|
||||
for x in 1..new_map.width - 1 {
|
||||
let roll = rng.next_u32() % 100;
|
||||
if roll > p { new_map.set_tile(x, y, Tile::floor()) }
|
||||
else { new_map.set_tile(x, y, Tile::wall()) }
|
||||
if roll > p {
|
||||
new_map.set_tile(x, y, Tile::floor())
|
||||
} else {
|
||||
new_map.set_tile(x, y, Tile::wall())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
new_map
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
//! Connect nearest rooms on the map with corridors
|
||||
//!
|
||||
use rand::prelude::StdRng;
|
||||
use crate::BuilderData;
|
||||
use crate::MapFilter;
|
||||
use crate::Map;
|
||||
use crate::MapFilter;
|
||||
use rand::prelude::StdRng;
|
||||
use std::collections::HashSet;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
|
||||
pub struct NearestCorridors<D: BuilderData> {
|
||||
phantom: PhantomData<D>,
|
||||
}
|
||||
|
@ -19,7 +18,6 @@ impl<D: BuilderData> MapFilter<D> for NearestCorridors<D> {
|
|||
}
|
||||
|
||||
impl<D: BuilderData> NearestCorridors<D> {
|
||||
|
||||
pub fn new() -> Box<NearestCorridors<D>> {
|
||||
Box::new(NearestCorridors {
|
||||
phantom: PhantomData,
|
||||
|
|
|
@ -20,13 +20,12 @@
|
|||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use rand::prelude::*;
|
||||
use crate::BuilderData;
|
||||
use crate::MapFilter;
|
||||
use crate::geometry::Rect;
|
||||
use crate::random::Rng;
|
||||
use crate::BuilderData;
|
||||
use crate::Map;
|
||||
|
||||
use crate::MapFilter;
|
||||
use rand::prelude::*;
|
||||
|
||||
pub struct SimpleRooms<D: BuilderData> {
|
||||
max_rooms: usize,
|
||||
|
@ -41,7 +40,6 @@ impl<D: BuilderData> MapFilter<D> for SimpleRooms<D> {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
impl<D: BuilderData> SimpleRooms<D> {
|
||||
pub fn new() -> Box<SimpleRooms<D>> {
|
||||
Box::new(SimpleRooms {
|
||||
|
|
|
@ -22,18 +22,25 @@
|
|||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use rand::prelude::StdRng;
|
||||
use crate::BuilderData;
|
||||
use crate::MapFilter;
|
||||
use crate::geometry::Point;
|
||||
use crate::BuilderData;
|
||||
use crate::Map;
|
||||
|
||||
use crate::MapFilter;
|
||||
use rand::prelude::StdRng;
|
||||
|
||||
/// Initial x region position
|
||||
pub enum XStart { LEFT, CENTER, RIGHT }
|
||||
pub enum XStart {
|
||||
LEFT,
|
||||
CENTER,
|
||||
RIGHT,
|
||||
}
|
||||
|
||||
/// Initial y region position
|
||||
pub enum YStart { TOP, CENTER, BOTTOM }
|
||||
pub enum YStart {
|
||||
TOP,
|
||||
CENTER,
|
||||
BOTTOM,
|
||||
}
|
||||
|
||||
/// Add starting position to the map
|
||||
pub struct AreaStartingPosition<D: BuilderData> {
|
||||
|
@ -52,7 +59,8 @@ impl<D: BuilderData> AreaStartingPosition<D> {
|
|||
/// Create new modifier with given region
|
||||
pub fn new(x: XStart, y: YStart) -> Box<AreaStartingPosition<D>> {
|
||||
Box::new(AreaStartingPosition {
|
||||
x, y,
|
||||
x,
|
||||
y,
|
||||
phantom: PhantomData,
|
||||
})
|
||||
}
|
||||
|
@ -61,25 +69,23 @@ impl<D: BuilderData> AreaStartingPosition<D> {
|
|||
let seed_x = match self.x {
|
||||
XStart::LEFT => 1,
|
||||
XStart::CENTER => map.width / 2,
|
||||
XStart::RIGHT => map.width - 2
|
||||
XStart::RIGHT => map.width - 2,
|
||||
};
|
||||
|
||||
let seed_y = match self.y {
|
||||
YStart::TOP => 1,
|
||||
YStart::CENTER => map.height / 2,
|
||||
YStart::BOTTOM => map.height - 2
|
||||
YStart::BOTTOM => map.height - 2,
|
||||
};
|
||||
|
||||
let mut available_floors: Vec<(usize, f32)> = Vec::new();
|
||||
for (idx, tiletype) in map.tiles.iter().enumerate() {
|
||||
if tiletype.is_walkable() {
|
||||
available_floors.push(
|
||||
(
|
||||
available_floors.push((
|
||||
idx,
|
||||
Point::new(idx % map.width, idx / map.width)
|
||||
.distance_to(&Point::new(seed_x, seed_y))
|
||||
)
|
||||
);
|
||||
.distance_to(&Point::new(seed_x, seed_y)),
|
||||
));
|
||||
}
|
||||
}
|
||||
if available_floors.is_empty() {
|
||||
|
@ -102,11 +108,11 @@ impl<D: BuilderData> AreaStartingPosition<D> {
|
|||
/// ------------------------------------------------------------------------------------------------
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use rand::prelude::*;
|
||||
use super::*;
|
||||
use super::MapFilter;
|
||||
use super::*;
|
||||
use crate::geometry::Point;
|
||||
use crate::map::{Map, NoData};
|
||||
use rand::prelude::*;
|
||||
|
||||
#[test]
|
||||
fn test_exit() {
|
||||
|
|
|
@ -15,21 +15,19 @@
|
|||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use rand::prelude::*;
|
||||
use crate::MapFilter;
|
||||
use crate::{
|
||||
geometry::Point,
|
||||
map::{BuilderData, Map, Tile},
|
||||
random::Rng,
|
||||
geometry::Point,
|
||||
};
|
||||
|
||||
use rand::prelude::*;
|
||||
|
||||
pub struct VoronoiHive<D: BuilderData> {
|
||||
n_seeds: usize,
|
||||
phantom: PhantomData<D>,
|
||||
}
|
||||
|
||||
|
||||
impl<D: BuilderData> MapFilter<D> for VoronoiHive<D> {
|
||||
fn modify_map(&self, rng: &mut StdRng, map: &Map<D>) -> Map<D> {
|
||||
self.build(rng, map)
|
||||
|
@ -69,10 +67,18 @@ impl<D: BuilderData> VoronoiHive<D> {
|
|||
let mut neighbors = 0;
|
||||
let my_idx = new_map.xy_idx(x, y);
|
||||
let my_seed = voronoi_membership[my_idx];
|
||||
if voronoi_membership[new_map.xy_idx(x-1, y)] != my_seed { neighbors += 1; }
|
||||
if voronoi_membership[new_map.xy_idx(x+1, y)] != my_seed { neighbors += 1; }
|
||||
if voronoi_membership[new_map.xy_idx(x, y-1)] != my_seed { neighbors += 1; }
|
||||
if voronoi_membership[new_map.xy_idx(x, y+1)] != my_seed { neighbors += 1; }
|
||||
if voronoi_membership[new_map.xy_idx(x - 1, y)] != my_seed {
|
||||
neighbors += 1;
|
||||
}
|
||||
if voronoi_membership[new_map.xy_idx(x + 1, y)] != my_seed {
|
||||
neighbors += 1;
|
||||
}
|
||||
if voronoi_membership[new_map.xy_idx(x, y - 1)] != my_seed {
|
||||
neighbors += 1;
|
||||
}
|
||||
if voronoi_membership[new_map.xy_idx(x, y + 1)] != my_seed {
|
||||
neighbors += 1;
|
||||
}
|
||||
|
||||
if neighbors < 2 {
|
||||
new_map.set_tile(x, y, Tile::floor());
|
||||
|
@ -98,5 +104,4 @@ impl<D: BuilderData> VoronoiHive<D> {
|
|||
|
||||
seeds
|
||||
}
|
||||
|
||||
}
|
|
@ -5,7 +5,7 @@
|
|||
#[derive(Default, PartialEq, Copy, Clone, Debug, Eq, Hash)]
|
||||
pub struct Point {
|
||||
pub x: usize,
|
||||
pub y: usize
|
||||
pub y: usize,
|
||||
}
|
||||
|
||||
impl Point {
|
||||
|
@ -33,12 +33,17 @@ pub struct Rect {
|
|||
pub x1: usize,
|
||||
pub x2: usize,
|
||||
pub y1: usize,
|
||||
pub y2 : usize
|
||||
pub y2: usize,
|
||||
}
|
||||
|
||||
impl Rect {
|
||||
pub fn new(x: usize, y: usize, width: usize, height: usize) -> Rect {
|
||||
Rect{x1:x, y1:y, x2:x+width, y2:y+height}
|
||||
Rect {
|
||||
x1: x,
|
||||
y1: y,
|
||||
x2: x + width,
|
||||
y2: y + height,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_i32(x: i32, y: i32, width: i32, height: i32) -> Rect {
|
||||
|
@ -80,7 +85,11 @@ impl Rect {
|
|||
/// assert_eq!(usize_abs(3, 5), 2);
|
||||
/// ```
|
||||
pub fn usize_abs(x: usize, y: usize) -> usize {
|
||||
if x >= y {x - y} else {y - x}
|
||||
if x >= y {
|
||||
x - y
|
||||
} else {
|
||||
y - x
|
||||
}
|
||||
}
|
||||
|
||||
/// ------------------------------------------------------------------------------------------------
|
||||
|
@ -111,5 +120,4 @@ mod tests {
|
|||
assert_eq!(rect1.width(), 40);
|
||||
assert_eq!(rect1.height(), 30);
|
||||
}
|
||||
|
||||
}
|
15
src/lib.rs
15
src/lib.rs
|
@ -33,15 +33,14 @@ pub mod geometry;
|
|||
pub mod map;
|
||||
pub mod metric;
|
||||
|
||||
pub use map::{BuilderData, Map, NoData, Symmetry, Tile};
|
||||
pub use filter::*;
|
||||
pub use map::{BuilderData, Map, NoData, Symmetry, Tile};
|
||||
|
||||
pub(crate) mod dijkstra;
|
||||
pub(crate) mod random;
|
||||
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
use rand::prelude::*;
|
||||
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
/// Trait which should be implemented by map modifier.
|
||||
/// Modifier takes initiall map and apply changes to it.
|
||||
|
@ -73,7 +72,9 @@ impl<D: BuilderData> MapBuilder<D> {
|
|||
|
||||
/// Build map using random number seeded with system time
|
||||
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);
|
||||
self.build_with_rng(&mut rng)
|
||||
}
|
||||
|
@ -89,7 +90,6 @@ impl<D: BuilderData> MapBuilder<D> {
|
|||
|
||||
map
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// ------------------------------------------------------------------------------------------------
|
||||
|
@ -101,9 +101,7 @@ mod tests {
|
|||
|
||||
use super::*;
|
||||
use filter::{
|
||||
CellularAutomata,
|
||||
NoiseGenerator,
|
||||
{AreaStartingPosition, XStart, YStart},
|
||||
CellularAutomata, NoiseGenerator, {AreaStartingPosition, XStart, YStart},
|
||||
};
|
||||
|
||||
#[test]
|
||||
|
@ -118,5 +116,4 @@ mod tests {
|
|||
assert_eq!(map.height, 50);
|
||||
assert_eq!(map.starting_point.is_some(), true);
|
||||
}
|
||||
|
||||
}
|
63
src/map.rs
63
src/map.rs
|
@ -7,9 +7,8 @@
|
|||
//! specific game.
|
||||
//!
|
||||
|
||||
use super::geometry::{usize_abs, Point, Rect};
|
||||
use std::fmt;
|
||||
use super::geometry::{Point, Rect, usize_abs};
|
||||
|
||||
|
||||
#[derive(PartialEq, Copy, Clone, Debug, Eq, Hash)]
|
||||
pub struct Tile {
|
||||
|
@ -18,8 +17,12 @@ pub struct Tile {
|
|||
}
|
||||
|
||||
#[derive(PartialEq, Copy, Clone)]
|
||||
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 {}
|
||||
|
@ -70,7 +73,6 @@ impl Tile {
|
|||
}
|
||||
|
||||
impl<D: BuilderData> Map<D> {
|
||||
|
||||
/// Generates an empty map, consisting entirely of solid walls
|
||||
pub fn new(width: usize, height: usize) -> Map<D> {
|
||||
let map_tile_count = width * height;
|
||||
|
@ -82,17 +84,23 @@ impl<D: BuilderData> Map<D> {
|
|||
exit_point: None,
|
||||
rooms: Vec::new(),
|
||||
corridors: Vec::new(),
|
||||
data: Default::default()
|
||||
data: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create map from given string
|
||||
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())
|
||||
.filter(|l| l.len() > 0)
|
||||
.collect();
|
||||
let cols = lines.iter().map(|l| l.len()).max().get_or_insert(1).to_owned();
|
||||
let cols = lines
|
||||
.iter()
|
||||
.map(|l| l.len())
|
||||
.max()
|
||||
.get_or_insert(1)
|
||||
.to_owned();
|
||||
let rows = lines.len();
|
||||
let mut map = Map::new(cols, rows);
|
||||
|
||||
|
@ -122,16 +130,32 @@ impl<D: BuilderData> Map<D> {
|
|||
let mut exits = Vec::new();
|
||||
|
||||
// Cardinal directions
|
||||
if x > 0 && self.is_exit_valid(x-1, y) { exits.push((x-1, y, 1.0)) };
|
||||
if self.is_exit_valid(x+1, y) { exits.push((x+1, y, 1.0)) };
|
||||
if y > 0 && self.is_exit_valid(x, y-1) { exits.push((x, y-1, 1.0)) };
|
||||
if self.is_exit_valid(x, y+1) { exits.push((x, y+1, 1.0)) };
|
||||
if x > 0 && self.is_exit_valid(x - 1, y) {
|
||||
exits.push((x - 1, y, 1.0))
|
||||
};
|
||||
if self.is_exit_valid(x + 1, y) {
|
||||
exits.push((x + 1, y, 1.0))
|
||||
};
|
||||
if y > 0 && self.is_exit_valid(x, y - 1) {
|
||||
exits.push((x, y - 1, 1.0))
|
||||
};
|
||||
if self.is_exit_valid(x, y + 1) {
|
||||
exits.push((x, y + 1, 1.0))
|
||||
};
|
||||
|
||||
// Diagonals
|
||||
if x > 0 && y > 0 && self.is_exit_valid(x-1, y-1) { exits.push((x-1, y-1, 1.45)); }
|
||||
if y > 0 && self.is_exit_valid(x+1, y-1) { exits.push((x+1, y-1, 1.45)); }
|
||||
if x > 0 && self.is_exit_valid(x-1, y+1) { exits.push((x-1, y+1, 1.45)); }
|
||||
if self.is_exit_valid(x+1, y+1) { exits.push((x+1, y+1, 1.45)); }
|
||||
if x > 0 && y > 0 && self.is_exit_valid(x - 1, y - 1) {
|
||||
exits.push((x - 1, y - 1, 1.45));
|
||||
}
|
||||
if y > 0 && self.is_exit_valid(x + 1, y - 1) {
|
||||
exits.push((x + 1, y - 1, 1.45));
|
||||
}
|
||||
if x > 0 && self.is_exit_valid(x - 1, y + 1) {
|
||||
exits.push((x - 1, y + 1, 1.45));
|
||||
}
|
||||
if self.is_exit_valid(x + 1, y + 1) {
|
||||
exits.push((x + 1, y + 1, 1.45));
|
||||
}
|
||||
|
||||
exits
|
||||
}
|
||||
|
@ -236,7 +260,11 @@ impl<D: BuilderData> Map<D> {
|
|||
let half_brush_size = brush_size / 2;
|
||||
for brush_y in y - half_brush_size..y + half_brush_size {
|
||||
for brush_x in x - half_brush_size..x + half_brush_size {
|
||||
if brush_x > 1 && brush_x < self.width-1 && brush_y > 1 && brush_y < self.height-1 {
|
||||
if brush_x > 1
|
||||
&& brush_x < self.width - 1
|
||||
&& brush_y > 1
|
||||
&& brush_y < self.height - 1
|
||||
{
|
||||
self.set_tile(brush_x, brush_y, Tile::floor());
|
||||
}
|
||||
}
|
||||
|
@ -347,7 +375,6 @@ mod tests {
|
|||
assert_eq!(map.tiles, expected_map.tiles);
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_available_exists() {
|
||||
let map_str = "
|
||||
|
|
|
@ -4,28 +4,24 @@
|
|||
//! and the provide generator score as an average.
|
||||
//!
|
||||
|
||||
use super::BuilderData;
|
||||
use super::map::Map;
|
||||
use super::dijkstra::DijkstraMap;
|
||||
|
||||
use super::map::Map;
|
||||
use super::BuilderData;
|
||||
|
||||
/// This metric calculates the percentage of walkable cells (Floor).
|
||||
/// If this number is very low (like < 10%) then it means that the map
|
||||
/// is probably to degenerated and shouldn't be used
|
||||
pub fn density<D>(map: &Map<D>) -> f32 {
|
||||
let floor_count = map.tiles.iter()
|
||||
.filter(|&t| t.is_walkable())
|
||||
.count();
|
||||
let floor_count = map.tiles.iter().filter(|&t| t.is_walkable()).count();
|
||||
floor_count as f32 / map.tiles.len() as f32
|
||||
}
|
||||
|
||||
|
||||
/// Calculate the length of the shortes path from the starting point
|
||||
/// to the exit.
|
||||
/// If this path is very short, then the map is probably degenerated.
|
||||
pub fn path_length<D: BuilderData>(map: &Map<D>) -> f32 {
|
||||
if map.starting_point.is_none() {
|
||||
return 0.0
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
match map.exit_point {
|
||||
|
@ -33,10 +29,9 @@ pub fn path_length<D: BuilderData>(map: &Map<D>) -> f32 {
|
|||
Some(exit) => {
|
||||
let dijkstra = DijkstraMap::new(map);
|
||||
dijkstra.tiles[map.xy_idx(exit.x, exit.y)]
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// ------------------------------------------------------------------------------------------------
|
||||
/// Module unit tests
|
||||
|
@ -46,7 +41,6 @@ mod tests {
|
|||
use super::*;
|
||||
use crate::{geometry::Point, map::NoData};
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_density_no_floor() {
|
||||
let map = Map::<NoData>::new(10, 10);
|
||||
|
|
|
@ -29,8 +29,8 @@ impl Rng for StdRng {
|
|||
/// ------------------------------------------------------------------------------------------------
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use rand::prelude::*;
|
||||
use super::Rng;
|
||||
use rand::prelude::*;
|
||||
|
||||
#[test]
|
||||
fn test_range() {
|
||||
|
@ -64,5 +64,4 @@ mod tests {
|
|||
assert_eq!(min, 1);
|
||||
assert_eq!(max, 7);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user