use rand::prelude::SliceRandom; use rand::Rng; use rand::rngs::ThreadRng; pub const LEVEL_WIDTH: usize = 50; pub const LEVEL_HEIGHT: usize = 25; #[derive(Copy, Clone, Debug, PartialEq)] pub enum LevelElement { Wall, Floor, StairDown, StairUp, } #[derive(Copy, Clone, Debug, PartialEq)] pub enum RoomType { Start, End, StairUp, StairDown, BasicRoom, EmptyRoom, } #[derive(Copy, Clone, Debug, PartialEq)] pub struct Level { pub(crate) structure: [[LevelElement; LEVEL_HEIGHT]; LEVEL_WIDTH], pub(crate) start_x: usize, pub(crate) start_y: usize, } impl Level { const ROOM_WIDTH: usize = 7; const ROOM_HEIGHT: usize = 6; const ROOMS_VERTICAL: usize = 7; const ROOMS_HORIZONTAL: usize = 4; fn draw_room(&mut self, rng: &mut ThreadRng, row: usize, col: usize) { let width = rng.gen_range(3..6); let offset_x = rng.gen_range(0..(Level::ROOM_WIDTH - width)); let height = rng.gen_range(3..5); let offset_y = rng.gen_range(0..(Level::ROOM_HEIGHT - height)); for r in offset_y..offset_y + height { for c in offset_x..offset_x + width { self.structure[1 + col * Level::ROOM_WIDTH + c][1 + row * Level::ROOM_HEIGHT + r] = LevelElement::Floor; } } } fn draw_stair(&mut self, element: LevelElement, row: usize, col: usize) { for r in 0..Level::ROOM_HEIGHT - 1 { for c in 0..Level::ROOM_WIDTH - 1 { self.structure[1 + col * Level::ROOM_WIDTH + c][1 + row * Level::ROOM_HEIGHT + r] = LevelElement::Floor; } } self.structure[1 + col * Level::ROOM_WIDTH + 2][1 + row * Level::ROOM_HEIGHT + 2] = element; } pub fn new() -> Level { let mut s = [[LevelElement::Wall; LEVEL_HEIGHT]; LEVEL_WIDTH]; Level { structure: s, start_x: 1, start_y: 1 } } pub fn generate(&mut self, level: usize) { let mut rooms: Vec = Vec::with_capacity(Level::ROOMS_HORIZONTAL * Level::ROOMS_VERTICAL); if level > 0 { rooms.push(RoomType::StairUp); } if level < 24 { rooms.push(RoomType::StairDown); } let mut rng = rand::thread_rng(); for _ in rooms.len()..Level::ROOMS_HORIZONTAL * Level::ROOMS_VERTICAL { match rng.gen_range(1..=6) { 1..=3 => { rooms.push(RoomType::EmptyRoom) } _ => { rooms.push(RoomType::BasicRoom) } } } rooms.shuffle(&mut rng); for (idx, room) in rooms.iter().enumerate() { let row = idx / Level::ROOMS_VERTICAL; let col = idx % Level::ROOMS_VERTICAL; match room { RoomType::EmptyRoom => {} RoomType::StairUp => { self.draw_stair(LevelElement::StairUp, row, col) } RoomType::StairDown => { self.draw_stair(LevelElement::StairDown, row, col) } RoomType::BasicRoom => { self.draw_room(&mut rng, row, col) } RoomType::Start => {} RoomType::End => {} }; } } pub fn get_element(&self, x: i16, y: i16) -> Option { if x < 0 || y < 0 { return None; } if x >= LEVEL_WIDTH as i16 || y >= LEVEL_HEIGHT as i16 { return None; } Some(self.structure[x as usize][y as usize]) } } #[test] fn test_get_element() { let l = Level::new(); assert_eq!(l.get_element(0, 0).unwrap(), LevelElement::Wall); assert_eq!(l.get_element(4, 4).unwrap(), LevelElement::StairDown); assert_eq!(l.get_element(49, 24).unwrap(), LevelElement::Wall); assert_eq!(l.get_element(50, 25), None); }