From c93a6a4743af9ee72f12bb18b210f9523c6c50d1 Mon Sep 17 00:00:00 2001 From: David Blajda Date: Fri, 23 Aug 2019 01:50:10 +0000 Subject: :WIP: Implement random walks --- src/main.rs | 110 +++++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 91 insertions(+), 19 deletions(-) diff --git a/src/main.rs b/src/main.rs index 3232cec..7bba3d8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,6 +18,7 @@ enum LevelBuilderError { InvalidRoomId, } + mod Direction { pub const NONE: u8 = 0; pub const UP: u8 = 1 << 0; @@ -25,6 +26,12 @@ mod Direction { pub const DOWN: u8 = 1 << 2; pub const LEFT: u8 = 1 << 3; + #[derive(Debug)] + pub enum Error { + Underflow, + Overflow, + } + pub fn opposite(dir: u8) -> u8 { match dir { UP => DOWN, @@ -35,15 +42,16 @@ mod Direction { } } - pub fn step(dir: u8, point: &mut (u32, u32)) { - match dir { - UP => point.1 -= 1, - RIGHT => point.0 += 1, - DOWN => point.1 += 1, - LEFT => point.0 -= 1, + pub fn step_towards(dir: u8, point: (u32, u32)) -> Result<(u32, u32), Error> { + let p = match dir { + UP => if point.1 > 0 { (point.0, point.1 - 1) } else { return Err(Error::Underflow) }, + RIGHT => (point.0 + 1, point.1), + DOWN => (point.0, point.1 + 1), + LEFT => if point.0 > 0 { (point.0 - 1, point.1) } else { return Err(Error::Underflow) }, _ => unreachable!() }; + Ok(p) } } @@ -377,26 +385,50 @@ fn create_deadend(level: &mut Level, rng: &mut R) -> Result<(), Ok(()) } +fn empty_neighbours(level: &Level, x: u32, y:u32, options: &mut [u8; 4], neighbours: &mut usize) { + let region = &level.region; + if y > 0 && region.get(x, y - 1).unwrap().is_none() { + options[*neighbours] = Direction::UP; + *neighbours += 1; + } + + if x + 1 < region.width() && region.get(x + 1, y).unwrap().is_none() { + options[*neighbours] = Direction::RIGHT; + *neighbours += 1; + } + + if y + 1 < region.height() && region.get(x, y + 1).unwrap().is_none() { + options[*neighbours] = Direction::DOWN; + *neighbours += 1; + } + + if x > 0 && region.get(x - 1, y).unwrap().is_none() { + options[*neighbours] = Direction::LEFT; + *neighbours += 1; + } +} + fn random_walk(level: &mut Level, rng: &mut R) -> Result<(), u32> { let mut iterations = 0; const max_iterations: u32 = 128; let mut neighbours = 0; - let region = &mut level.region; let mut options = [0; 4]; let mut x = 0; let mut y = 0; while neighbours <= 0 && iterations < max_iterations { neighbours = 0; - x = rng.gen_range(0, region.width() - 4) + 2; - y = rng.gen_range(0, region.height() - 4) + 2; + x = rng.gen_range(0, level.region.width() - 4) + 2; + y = rng.gen_range(0, level.region.height() - 4) + 2; - if let Some(tile) = region.get(x, y)? { + if let Some(tile) = level.region.get(x, y)? { if tile.flags & TILE_IS_PATH != 0 { + empty_neighbours(level, x, y, &mut options, &mut neighbours); + /* if region.get(x, y - 1)?.is_none() { options[neighbours] = Direction::UP; - neighbours = neighbours + 1; + neighbours += 1; } if region.get(x + 1, y)?.is_none() { @@ -413,6 +445,7 @@ fn random_walk(level: &mut Level, rng: &mut R) -> Result<(), u3 options[neighbours] = Direction::LEFT; neighbours = neighbours + 1; } + */ } } iterations = iterations + 1; @@ -424,19 +457,56 @@ fn random_walk(level: &mut Level, rng: &mut R) -> Result<(), u3 let direction = options[rng.gen_range(0, neighbours)]; println!("dir x {} y {} -> {}",x, y, direction); - if let Some(tile) = region.get_mut(x, y)? { + if let Some(tile) = level.region.get_mut(x, y)? { println!("is some"); tile.connections |= direction; println!("{}", tile.connections); }; let mut pos = (x, y); - Direction::step(direction, &mut pos); - println!("{:?}", &mut pos); - - region.set(pos.0, pos.1, Some(Tile { id: 1, room: 8, flags: TILE_IS_PATH, connections: Direction::opposite(direction)})); + pos = Direction::step_towards(direction, pos).unwrap(); + level.region.set(pos.0, pos.1, Some(Tile { id: 1, room: 8, flags: TILE_IS_PATH, connections: Direction::opposite(direction)})); let mut iterations = rng.gen_range(0, 2); + while iterations >= 0 { + neighbours = 0; + empty_neighbours(level, pos.0, pos.1, &mut options, &mut neighbours); + + if neighbours <= 0 { + return Ok(()); + } + + let direction = options[rng.gen_range(0, neighbours)]; + let mut length = rng.gen_range(0, 2) + 1; + println!("len {}", length); + while length > 0 { + let old_pos = pos.clone(); + let m_pos = Direction::step_towards(direction, pos); + if let Err(_) = m_pos { + break; + } else { + pos = m_pos.unwrap(); + } + + match level.region.get(pos.0, pos.1) { + Ok(tile) => { + if tile.is_none() { + level.region.set(pos.0, pos.1, Some(Tile { id: 1, room: 8, flags: TILE_IS_PATH, connections: Direction::opposite(direction)})); + if let Some(tile) = level.region.get_mut(old_pos.0, old_pos.1)? { + tile.connections |= direction; + } + } + }, + Err(_) => { + pos = old_pos; + length = 0; + } + } + length += -1; + } + iterations += -1; + } + Ok(()) } @@ -455,7 +525,7 @@ fn print_level(level: &Level) { } /*Requires additonal info for proper rendering*/ -fn print_level2(level: &Level) { +fn pretty_print(level: &Level) { let region = &level.region; @@ -526,7 +596,7 @@ fn main() { println!("Hello, world!"); let mut thread_rng = thread_rng(); //18 - let mut rng = SmallRng::from_seed([19;16]); + let mut rng = SmallRng::from_seed([18;16]); let mut template:VecRegion> = Region::new_with(3, 3); @@ -560,9 +630,11 @@ fn main() { let res = connect_rooms(&mut level, 3, 2, &mut rng); create_deadend(&mut level, &mut rng); random_walk(&mut level, &mut rng); + random_walk(&mut level, &mut rng); + random_walk(&mut level, &mut rng); //create_deadend(&mut level, &mut rng); println!("{:?}", res); print_level(&level); - print_level2(&level); + pretty_print(&level); //println!("{:?}", level); } -- cgit v1.2.3