From 1fa7432dfebd79638ca4212196a9f221e47d0ffc Mon Sep 17 00:00:00 2001 From: Llywelwyn Date: Sun, 1 Oct 2023 20:56:46 +0100 Subject: [PATCH] room accretion - initial --- src/map_builders/mod.rs | 2 + src/map_builders/room_accretion/consts.rs | 110 +++++++++++++++ src/map_builders/room_accretion/mod.rs | 161 ++++++++++++++++++++++ 3 files changed, 273 insertions(+) create mode 100644 src/map_builders/room_accretion/consts.rs create mode 100644 src/map_builders/room_accretion/mod.rs diff --git a/src/map_builders/mod.rs b/src/map_builders/mod.rs index 7b38efe..70a3c0f 100644 --- a/src/map_builders/mod.rs +++ b/src/map_builders/mod.rs @@ -1,6 +1,8 @@ use super::{ spawner, Map, Position, Rect, TileType }; use bracket_lib::prelude::*; +mod room_accretion; +use room_accretion::RoomAccretionBuilder; mod bsp_dungeon; use bsp_dungeon::BspDungeonBuilder; mod bsp_interior; diff --git a/src/map_builders/room_accretion/consts.rs b/src/map_builders/room_accretion/consts.rs new file mode 100644 index 0000000..f4170df --- /dev/null +++ b/src/map_builders/room_accretion/consts.rs @@ -0,0 +1,110 @@ +use lazy_static::lazy_static; +use bracket_lib::prelude::*; + +pub enum Operator { + LessThan, + GreaterThan, + LessThanEqualTo, + GreaterThanEqualTo, + EqualTo, +} + +impl Operator { + pub fn eval(&self, a: i32, b: i32) -> bool { + match self { + Operator::LessThan => a < b, + Operator::GreaterThan => a > b, + Operator::LessThanEqualTo => a <= b, + Operator::GreaterThanEqualTo => a >= b, + Operator::EqualTo => a == b, + } + } + pub fn string(&self) -> &str { + match self { + Operator::LessThan => "<", + Operator::GreaterThan => ">", + Operator::LessThanEqualTo => "<=", + Operator::GreaterThanEqualTo => ">=", + Operator::EqualTo => "==", + } + } +} + +pub struct CellRules { + pub adjacent_type: i32, + pub into: i32, + pub operator: Operator, + pub n: i32, +} + +impl CellRules { + const fn new(adjacent_type: i32, into: i32, operator: Operator, n: i32) -> CellRules { + CellRules { + adjacent_type, + into, + operator, + n, + } + } +} + +lazy_static! { + pub static ref CA: Vec> = vec![ + vec![ + CellRules::new(1, 1, Operator::GreaterThanEqualTo, 5), + CellRules::new(0, 1, Operator::LessThan, 2) + ], + vec![CellRules::new(1, 1, Operator::GreaterThanEqualTo, 5)] + ]; +} + +#[derive(Debug, Copy, Clone)] +pub enum Direction { + NoDir = -1, + North = 0, + East = 1, + South = 2, + West = 3, +} + +impl Direction { + pub fn transform(&self) -> Point { + match self { + Direction::NoDir => unreachable!("Direction::NoDir should never be transformed"), + Direction::North => Point::new(0, -1), + Direction::East => Point::new(1, 0), + Direction::South => Point::new(0, 1), + Direction::West => Point::new(-1, 0), + } + } +} + +pub struct DirectionIterator { + current: Direction, +} + +impl DirectionIterator { + pub fn new() -> DirectionIterator { + DirectionIterator { + current: Direction::North, + } + } +} + +impl Iterator for DirectionIterator { + type Item = Direction; + fn next(&mut self) -> Option { + use Direction::*; + let next_direction = match self.current { + North => East, + East => South, + South => West, + West => { + return None; + } + NoDir => unreachable!("Direction::NoDir should never be iterated over."), + }; + self.current = next_direction; + Some(next_direction) + } +} diff --git a/src/map_builders/room_accretion/mod.rs b/src/map_builders/room_accretion/mod.rs new file mode 100644 index 0000000..2e003f1 --- /dev/null +++ b/src/map_builders/room_accretion/mod.rs @@ -0,0 +1,161 @@ +use super::{ BuilderMap, Map, InitialMapBuilder, TileType, Point }; +use bracket_lib::prelude::*; + +mod consts; +use consts::*; + +/// Room Accretion map builder. +pub struct RoomAccretionBuilder {} + +impl InitialMapBuilder for RoomAccretionBuilder { + #[allow(dead_code)] + fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) { + self.build(rng, build_data); + } +} + +impl RoomAccretionBuilder { + /// Constructor for Room Accretion. + pub fn new() -> Box { + Box::new(RoomAccretionBuilder {}) + } + + fn build(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) { + // + } +} + +fn grid_with_dimensions(h: usize, w: usize, value: i32) -> Vec> { + let mut grid = Vec::with_capacity(h); + for _ in 0..h { + let row = vec![value; w]; + grid.push(row); + } + grid +} + +fn in_bounds(x: i32, y: i32, build_data: &BuilderMap) -> bool { + x > 0 && x < build_data.height && y > 0 && y < build_data.width +} + +fn draw_continuous_shape_on_grid( + room: &Vec>, + top_offset: usize, + left_offset: usize, + grid: &mut Vec> +) { + for row in 0..room.len() { + for col in 0..room[0].len() { + if room[row][col] != 0 { + let target_row = row + top_offset; + let target_col = col + left_offset; + if target_row < grid.len() && target_col < grid[0].len() { + grid[target_row][target_col] = room[row][col]; + } + } + } + } +} + +struct Coordinate { + pub location: Point, + pub value: i32, +} + +fn draw_individual_coordinates_on_grid(coordinates: &Vec, grid: &mut Vec>) { + for c in coordinates { + let x = c.location.x as usize; + let y = c.location.y as usize; + if y < grid.len() && x < grid[0].len() { + grid[y][x] = c.value; + } + } +} + +fn get_cell_neighbours( + cells: &Vec>, + row: usize, + col: usize, + h: usize, + w: usize +) -> Vec { + let mut neighbours = Vec::new(); + for x in row.saturating_sub(1)..=std::cmp::min(row + 1, h - 1) { + for y in col.saturating_sub(1)..=std::cmp::min(col + 1, w - 1) { + if x != row || y != col { + neighbours.push(cells[x][y]); + } + } + } + neighbours +} + +fn make_ca_room(rng: &mut RandomNumberGenerator) -> Vec> { + let width = rng.range(5, 10); + let height = rng.range(5, 10); + let mut cells = grid_with_dimensions(height, width, 0); + cells = cells + .into_iter() + .map(|row| { + row.into_iter() + .map(|_| if rng.roll_dice(1, 2) == 1 { 1 } else { 0 }) + .collect() + }) + .collect(); + + let transform_cell = |state: i32, neighbours: &Vec| -> i32 { + let rules: &[CellRules] = &CA[state as usize]; + let mut new_state = state; + for rule in rules { + let n_neighbours = neighbours + .iter() + .filter(|&&neighbour| neighbour == rule.adjacent_type) + .count(); + if rule.operator.eval(n_neighbours as i32, rule.n) { + new_state = rule.into; + } + } + new_state + }; + + for _ in 0..5 { + let mut new_cells = vec![vec![0; width]; height]; + for row in 0..height { + for col in 0..height { + let neighbours = get_cell_neighbours(&cells, row, col, height, width); + let new_state = transform_cell(cells[row][col], &neighbours); + new_cells[row][col] = new_state; + } + } + cells = new_cells; + } + + cells +} + +fn direction_of_door( + grid: Vec>, + row: usize, + col: usize, + build_data: &BuilderMap +) -> Direction { + if grid[row][col] != 0 { + return Direction::NoDir; + } + let mut solution = Direction::NoDir; + let mut dir_iter = DirectionIterator::new(); + for dir in &mut dir_iter { + let new_col = (col as i32) + dir.transform().x; + let new_row = (row as i32) + dir.transform().y; + let opp_col = (col as i32) - dir.transform().x; + let opp_row = (row as i32) - dir.transform().y; + if + in_bounds(new_col, new_row, &build_data) && + in_bounds(new_col, new_row, &build_data) && + grid[opp_row as usize][opp_col as usize] != 0 + { + solution = dir; + } + } + return solution; +}