From 600e4bcc3b4d32117da55660a18e3d3a5654182c Mon Sep 17 00:00:00 2001 From: tobi Date: Fri, 19 Apr 2024 00:23:42 +0200 Subject: [PATCH] Add new blocktypes and remove copy derives --- src/generator.rs | 4 +-- src/grid_render.rs | 5 +++- src/map.rs | 65 ++++++++++++++++++++++++++++++++++------------ src/position.rs | 6 ++--- src/random.rs | 6 +++-- src/walker.rs | 4 +-- 6 files changed, 64 insertions(+), 26 deletions(-) diff --git a/src/generator.rs b/src/generator.rs index 0aeb73a..ee44a43 100644 --- a/src/generator.rs +++ b/src/generator.rs @@ -97,10 +97,10 @@ impl Generator { let mut view = self.map.grid.slice_mut(s![start_x..end_x, start_y..end_y]); view.map_inplace(|elem| *elem = BlockType::Empty); - let platform = margin.saturating_sub(1); // also corresponds to a 'margin' + let platform_margin = margin.saturating_sub(1); let mut view = self.map.grid.slice_mut(s![ - pos.x - platform..pos.x + platform + 1, + pos.x - platform_margin..pos.x + platform_margin + 1, pos.y + 1..pos.y + 2 ]); view.map_inplace(|elem| *elem = BlockType::Hookable); diff --git a/src/grid_render.rs b/src/grid_render.rs index 1fad67a..9458a95 100644 --- a/src/grid_render.rs +++ b/src/grid_render.rs @@ -9,6 +9,9 @@ fn blocktype_to_color(value: &BlockType) -> Color { BlockType::Hookable => colors::BROWN, BlockType::Freeze => Color::new(0.0, 0.0, 0.0, 0.8), BlockType::Empty => Color::new(0.0, 0.0, 0.0, 0.1), + BlockType::Finish => Color::new(1.0, 0.1, 0.1, 1.0), + BlockType::Start => Color::new(0.1, 1.0, 0.1, 1.0), + BlockType::Spawn => Color::new(0.5, 0.5, 0.0, 1.0), } } @@ -48,7 +51,7 @@ pub fn draw_chunked_grid( for x in x_start..x_end { for y in y_start..y_end { - let value = grid[[x, y]]; + let value = &grid[[x, y]]; draw_rectangle(x as f32, y as f32, 1.0, 1.0, blocktype_to_color(&value)); } } diff --git a/src/map.rs b/src/map.rs index 502c0cd..0ee44a9 100644 --- a/src/map.rs +++ b/src/map.rs @@ -1,15 +1,32 @@ use crate::{position::Position, walker::CuteWalker}; -use ndarray::Array2; +use ndarray::{s, Array2}; use std::path::PathBuf; use twmap::{GameLayer, GameTile, TileFlags, TilemapLayer, TwMap}; const CHUNK_SIZE: usize = 5; -#[derive(Debug, Clone, Copy, PartialEq)] +#[derive(Debug, Clone, PartialEq)] pub enum BlockType { Empty, Hookable, Freeze, + Spawn, + Start, + Finish, +} + +impl BlockType { + /// maps BlockType to tw game layer id for map export + fn to_tw_game_id(&self) -> u8 { + match self { + BlockType::Empty => 0, + BlockType::Hookable => 1, + BlockType::Freeze => 9, + BlockType::Spawn => 192, + BlockType::Start => 33, + BlockType::Finish => 34, + } + } } pub enum KernelType { @@ -83,17 +100,24 @@ impl Map { for ((kernel_x, kernel_y), kernel_active) in kernel.vector.indexed_iter() { let absolute_pos = Position::new(root_pos.x + kernel_x, root_pos.y + kernel_y); if *kernel_active { - let current_type = self.grid[absolute_pos.as_index()]; + let current_type = &self.grid[absolute_pos.as_index()]; + let new_type = match (&kernel_type, current_type) { // inner kernel removes everything - (KernelType::Inner, _) => BlockType::Empty, + (KernelType::Inner, BlockType::Hookable) => Some(BlockType::Empty), + (KernelType::Inner, BlockType::Freeze) => Some(BlockType::Empty), // outer kernel will turn hookables to freeze - (KernelType::Outer, BlockType::Hookable) => BlockType::Freeze, - (KernelType::Outer, BlockType::Freeze) => BlockType::Freeze, - (KernelType::Outer, BlockType::Empty) => BlockType::Empty, + (KernelType::Outer, BlockType::Hookable) => Some(BlockType::Freeze), + (KernelType::Outer, BlockType::Freeze) => Some(BlockType::Freeze), + + // ignore everything else + (_, _) => None, }; - self.grid[absolute_pos.as_index()] = new_type; + + if let Some(new_type) = new_type { + self.grid[absolute_pos.as_index()] = new_type; + } let chunk_pos = self.pos_to_chunk_pos(absolute_pos); self.chunk_edited[chunk_pos.as_index()] = true; @@ -125,18 +149,27 @@ impl Map { // modify game layer for ((x, y), value) in self.grid.indexed_iter() { - game_layer[[y, x]] = match value { - BlockType::Empty => GameTile::new(0, TileFlags::empty()), - BlockType::Hookable => GameTile::new(1, TileFlags::empty()), - BlockType::Freeze => GameTile::new(9, TileFlags::empty()), - }; + game_layer[[y, x]] = GameTile::new(value.to_tw_game_id(), TileFlags::empty()) } - // set spawn at initial position TODO: - game_layer[[self.spawn.y, self.spawn.x]] = GameTile::new(192, TileFlags::empty()); - // save map println!("exporting map to {:?}", &path); map.save_file(path).expect("saving failed"); } + + pub fn pos_in_bounds(&self, pos: &Position) -> bool { + // we dont have to check for lower bound, because of usize + pos.x < self.width && pos.y < self.height + } + + pub fn set_area(&mut self, top_left: &Position, bot_right: &Position, value: &BlockType) { + let valid_area = self.pos_in_bounds(top_left) && self.pos_in_bounds(bot_right); + + if valid_area { + let mut view = self + .grid + .slice_mut(s![top_left.x..bot_right.x, top_left.y..bot_right.y]); + view.map_inplace(|elem| *elem = value.clone()); + } + } } diff --git a/src/position.rs b/src/position.rs index ed7b06c..0739f37 100644 --- a/src/position.rs +++ b/src/position.rs @@ -13,7 +13,7 @@ pub struct Position { pub y: usize, } -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Clone)] pub enum ShiftDirection { Up, Right, @@ -30,7 +30,7 @@ impl Position { [self.x, self.y] } - pub fn shift(&mut self, shift: ShiftDirection, map: &Map) -> Result<(), &'static str> { + pub fn shift(&mut self, shift: &ShiftDirection, map: &Map) -> Result<(), &'static str> { if !self.is_shift_valid(&shift, map) { return Err("invalid shift"); } @@ -91,7 +91,7 @@ impl Position { shifts.sort_by_cached_key(|shift| { let mut shifted_pos = self.clone(); - if let Ok(()) = shifted_pos.shift(*shift, map) { + if let Ok(()) = shifted_pos.shift(shift, map) { shifted_pos.distance_squared(goal) } else { // assign maximum distance to invalid shifts diff --git a/src/random.rs b/src/random.rs index 9e1eef3..416bdab 100644 --- a/src/random.rs +++ b/src/random.rs @@ -77,9 +77,11 @@ impl Random { } /// sample a shift based on weight distribution - pub fn sample_move(&mut self, shifts: [ShiftDirection; 4]) -> ShiftDirection { + pub fn sample_move(&mut self, shifts: &[ShiftDirection; 4]) -> ShiftDirection { let index = self.weighted_dist.sample(&mut self.gen); - *shifts.get(index).expect("out of bounds") + let shift = shifts.get(index).expect("out of bounds"); + + shift.clone() } pub fn with_probability(&mut self, probability: f32) -> bool { diff --git a/src/walker.rs b/src/walker.rs index fef1fc2..83be1bc 100644 --- a/src/walker.rs +++ b/src/walker.rs @@ -65,10 +65,10 @@ impl CuteWalker { let goal = self.goal.as_ref().ok_or("Error: Goal is None")?; let shifts = self.pos.get_rated_shifts(goal, map); - let sampled_shift = rnd.sample_move(shifts); + let sampled_shift = rnd.sample_move(&shifts); // apply that shift - self.pos.shift(sampled_shift, map)?; + self.pos.shift(&sampled_shift, map)?; self.steps += 1; // remove blocks using a kernel at current position