From 91b1326bd41ff5e9036136b74553653943b77e20 Mon Sep 17 00:00:00 2001 From: Kristofers Solo Date: Thu, 26 Dec 2024 18:15:46 +0200 Subject: [PATCH] feat(traits): add traits --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/builder.rs | 45 ++----- src/errors.rs | 23 ++++ src/generator/backtrack.rs | 14 +- src/generator/mod.rs | 4 +- src/lib.rs | 21 +-- src/maze.rs | 253 ++++++++++++++++++++++++++++--------- src/tile.rs | 179 +++++++++++++------------- src/traits.rs | 22 ++++ src/walls.rs | 162 +++++++++++------------- tests/builder.rs | 8 +- tests/generator.rs | 8 +- tests/maze.rs | 28 ++-- 14 files changed, 466 insertions(+), 305 deletions(-) create mode 100644 src/errors.rs create mode 100644 src/traits.rs diff --git a/Cargo.lock b/Cargo.lock index 8a5b356..0fd744f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2375,7 +2375,7 @@ checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" [[package]] name = "hexlab" -version = "0.4.0" +version = "0.5.0" dependencies = [ "bevy", "bevy_reflect", diff --git a/Cargo.toml b/Cargo.toml index db7cec4..befbd65 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "hexlab" authors = ["Kristofers Solo "] -version = "0.4.0" +version = "0.5.0" edition = "2021" description = "A hexagonal maze generation and manipulation library" repository = "https://github.com/kristoferssolo/hexlab" diff --git a/src/builder.rs b/src/builder.rs index 4c5b6a2..c1a4deb 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -1,25 +1,5 @@ -use crate::{GeneratorType, HexMaze}; +use crate::{errors::MazeBuilderError, GeneratorType, Maze}; use hexx::Hex; -use thiserror::Error; - -#[derive(Debug, Error)] -pub enum MazeBuilderError { - /// Occurs when attempting to build a maze without specifying a radius. - #[error("Radius must be specified to build a maze")] - NoRadius, - - /// Occurs when the specified radius is too large. - #[error("Radius {0} is too large. Maximum allowed radius is {1}")] - RadiusTooLarge(u32, u32), - - /// Occurs when the specified start position is outside the maze bounds. - #[error("Start position {0:?} is outside maze bounds")] - InvalidStartPosition(Hex), - - /// Occurs when maze generation fails. - #[error("Failed to generate maze: {0}")] - GenerationError(String), -} /// A builder pattern for creating hexagonal mazes. /// @@ -85,7 +65,7 @@ pub struct MazeBuilder { impl MazeBuilder { /// Creates a new [`MazeBuilder`] instance with default settings. - #[cfg_attr(not(debug_assertions), inline)] + #[inline] #[must_use] pub fn new() -> Self { Self::default() @@ -101,7 +81,7 @@ impl MazeBuilder { /// # Arguments /// /// - `radius` - The number of tiles from the center to the edge of the hexagon. - #[cfg_attr(not(debug_assertions), inline)] + #[inline] #[must_use] pub const fn with_radius(mut self, radius: u16) -> Self { self.radius = Some(radius); @@ -115,7 +95,7 @@ impl MazeBuilder { /// # Arguments /// /// - `seed` - The random seed value. - #[cfg_attr(not(debug_assertions), inline)] + #[inline] #[must_use] pub const fn with_seed(mut self, seed: u64) -> Self { self.seed = Some(seed); @@ -129,7 +109,7 @@ impl MazeBuilder { /// # Arguments /// /// - `generator_type` - The maze generation algorithm to use. - #[cfg_attr(not(debug_assertions), inline)] + #[inline] #[must_use] pub const fn with_generator(mut self, generator_type: GeneratorType) -> Self { self.generator_type = generator_type; @@ -140,7 +120,7 @@ impl MazeBuilder { /// # Arguments /// /// - `pos` - The hexagonal coordinates for the starting position. - #[cfg_attr(not(debug_assertions), inline)] + #[inline] #[must_use] pub const fn with_start_position(mut self, pos: Hex) -> Self { self.start_position = Some(pos); @@ -172,12 +152,12 @@ impl MazeBuilder { /// let maze = result.unwrap(); /// assert!(!maze.is_empty()); /// ``` - pub fn build(self) -> Result { + pub fn build(self) -> Result { let radius = self.radius.ok_or(MazeBuilderError::NoRadius)?; let mut maze = create_hex_maze(radius); if let Some(start_pos) = self.start_position { - if maze.get_tile(&start_pos).is_none() { + if maze.get(&start_pos).is_none() { return Err(MazeBuilderError::InvalidStartPosition(start_pos)); } } @@ -190,8 +170,9 @@ impl MazeBuilder { Ok(maze) } } -pub fn create_hex_maze(radius: u16) -> HexMaze { - let mut maze = HexMaze::new(); + +pub fn create_hex_maze(radius: u16) -> Maze { + let mut maze = Maze::new(); let radius = i32::from(radius); for q in -radius..=radius { @@ -199,7 +180,7 @@ pub fn create_hex_maze(radius: u16) -> HexMaze { let r2 = radius.min(-q + radius); for r in r1..=r2 { let pos = Hex::new(q, r); - maze.add_tile(pos); + maze.insert(pos); } } @@ -269,7 +250,7 @@ mod test { Hex::new(1, -2), ]; for pos in expected_positions.iter() { - assert!(maze.get_tile(pos).is_some(), "Expected tile at {:?}", pos); + assert!(maze.get(pos).is_some(), "Expected tile at {:?}", pos); } } } diff --git a/src/errors.rs b/src/errors.rs new file mode 100644 index 0000000..6b6d803 --- /dev/null +++ b/src/errors.rs @@ -0,0 +1,23 @@ +use hexx::Hex; +use thiserror::Error; + +#[derive(Debug, Error, PartialEq, Eq)] +pub enum MazeBuilderError { + /// Occurs when attempting to build a maze without specifying a radius. + #[error("Radius must be specified to build a maze")] + NoRadius, + + /// Occurs when the specified start position is outside the maze bounds. + #[error("Start position {0:?} is outside maze bounds")] + InvalidStartPosition(Hex), + + /// Occurs when maze generation fails. + #[error("Failed to generate maze: {0}")] + GenerationError(String), +} + +#[derive(Debug, Error, PartialEq, Eq)] +pub enum MazeError { + #[error("Invalid coordinate: {0:?}")] + InvalidCoordinate(Hex), +} diff --git a/src/generator/backtrack.rs b/src/generator/backtrack.rs index e59c045..79b98c6 100644 --- a/src/generator/backtrack.rs +++ b/src/generator/backtrack.rs @@ -1,9 +1,9 @@ -use crate::HexMaze; +use crate::Maze; use hexx::{EdgeDirection, Hex}; use rand::{rngs::StdRng, seq::SliceRandom, thread_rng, Rng, RngCore, SeedableRng}; use std::collections::HashSet; -pub(super) fn generate_backtracking(maze: &mut HexMaze, start_pos: Option, seed: Option) { +pub(super) fn generate_backtracking(maze: &mut Maze, start_pos: Option, seed: Option) { if maze.is_empty() { return; } @@ -21,7 +21,7 @@ pub(super) fn generate_backtracking(maze: &mut HexMaze, start_pos: Option, } fn recursive_backtrack( - maze: &mut HexMaze, + maze: &mut Maze, current: Hex, visited: &mut HashSet, rng: &mut R, @@ -32,9 +32,9 @@ fn recursive_backtrack( for direction in directions { let neighbor = current + direction; - if maze.get_tile(&neighbor).is_some() && !visited.contains(&neighbor) { - maze.remove_tile_wall(¤t, direction); - maze.remove_tile_wall(&neighbor, direction.const_neg()); + if maze.get(&neighbor).is_some() && !visited.contains(&neighbor) { + let _ = maze.remove_tile_wall(¤t, direction); + let _ = maze.remove_tile_wall(&neighbor, direction.const_neg()); recursive_backtrack(maze, neighbor, visited, rng); } } @@ -100,7 +100,7 @@ mod test { for dir in EdgeDirection::ALL_DIRECTIONS { let neighbor = current + dir; if let Some(walls) = maze.get_walls(¤t) { - if !walls.contains(dir) && maze.get_tile(&neighbor).is_some() { + if !walls.contains(&dir) && maze.get(&neighbor).is_some() { to_visit.push(neighbor); } } diff --git a/src/generator/mod.rs b/src/generator/mod.rs index 105b8f6..f4acc6e 100644 --- a/src/generator/mod.rs +++ b/src/generator/mod.rs @@ -1,5 +1,5 @@ mod backtrack; -use crate::HexMaze; +use crate::Maze; use backtrack::generate_backtracking; #[cfg(feature = "bevy")] use bevy::prelude::*; @@ -16,7 +16,7 @@ pub enum GeneratorType { RecursiveBacktracking, } impl GeneratorType { - pub fn generate(&self, maze: &mut HexMaze, start_pos: Option, seed: Option) { + pub fn generate(&self, maze: &mut Maze, start_pos: Option, seed: Option) { match self { Self::RecursiveBacktracking => generate_backtracking(maze, start_pos, seed), } diff --git a/src/lib.rs b/src/lib.rs index f0f9145..4da28a6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,7 +7,6 @@ //! - Efficient bit-flag representation of walls //! - Multiple maze generation algorithms //! - Maze builder pattern for easy maze creation - //! //! # Examples //! @@ -36,7 +35,7 @@ //! .build() //! .expect("Failed to create maze"); //! -//! assert!(maze.get_tile(&Hex::new(1, -1)).is_some()); +//! assert!(maze.get(&Hex::new(1, -1)).is_some()); //!``` //! //! Manipulating walls: @@ -45,24 +44,28 @@ //! use hexlab::prelude::*; //! //! let mut walls = Walls::empty(); -//! walls.add(EdgeDirection::FLAT_NORTH); -//! assert!(walls.contains(EdgeDirection::FLAT_NORTH)); -//! assert!(!walls.contains(EdgeDirection::FLAT_SOUTH)); +//! assert!(!walls.insert(EdgeDirection::FLAT_NORTH)); +//! assert!(walls.contains(&EdgeDirection::FLAT_NORTH)); +//! assert!(!walls.contains(&EdgeDirection::FLAT_SOUTH)); //!``` mod builder; +pub mod errors; mod generator; mod maze; mod tile; +pub mod traits; mod walls; -pub use builder::{MazeBuilder, MazeBuilderError}; +pub use builder::MazeBuilder; +pub use errors::*; pub use generator::GeneratorType; -pub use maze::HexMaze; -pub use tile::HexTile; +pub use maze::Maze; +pub use tile::Tile; +pub use traits::*; pub use walls::Walls; /// Prelude module containing commonly used types pub mod prelude { - pub use super::{GeneratorType, HexMaze, HexTile, MazeBuilder, MazeBuilderError, Walls}; + pub use super::{errors::*, traits::*, GeneratorType, Maze, MazeBuilder, Tile, Walls}; pub use hexx::{EdgeDirection, Hex, HexLayout}; } diff --git a/src/maze.rs b/src/maze.rs index 301fbc5..851e1a4 100644 --- a/src/maze.rs +++ b/src/maze.rs @@ -1,4 +1,8 @@ -use super::{HexTile, Walls}; +use super::{Tile, Walls}; +use crate::{ + errors::MazeError, + traits::{TilePosition, WallStorage}, +}; #[cfg(feature = "bevy")] use bevy::prelude::*; #[cfg(feature = "bevy_reflect")] @@ -12,15 +16,14 @@ use std::ops::{Deref, DerefMut}; /// /// This struct stores the layout of a hexagonal maze, including the positions /// of tiles and their associated walls. -#[allow(clippy::module_name_repetitions)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))] #[cfg_attr(feature = "bevy", derive(Component))] #[cfg_attr(feature = "bevy", reflect(Component))] #[derive(Debug, Clone, Default, PartialEq, Eq)] -pub struct HexMaze(HashMap); +pub struct Maze(HashMap); -impl HexMaze { +impl Maze { /// Creates a new empty maze /// /// # Examples @@ -28,18 +31,23 @@ impl HexMaze { /// ``` /// use hexlab::prelude::*; /// - /// let maze = HexMaze::new(); + /// let maze = Maze::new(); /// /// assert!(maze.is_empty()); /// assert_eq!(maze.len(), 0); /// ``` - #[cfg_attr(not(debug_assertions), inline)] + #[inline] #[must_use] pub fn new() -> Self { Self::default() } - /// Adds a new tile at the specified coordinates + /// Inserts a new tile at the specified coordinates. + /// + /// If the map did not have this key present, [`None`] is returned. + /// + /// If the map did have this key present, the value is updated, and the old + /// value is returned. /// /// # Arguments /// @@ -50,43 +58,48 @@ impl HexMaze { /// ``` /// use hexlab::prelude::*; /// - /// let mut maze = HexMaze::new(); + /// let mut maze = Maze::new(); /// let coord = Hex::ZERO; - /// maze.add_tile(coord); /// - /// assert_eq!(maze.len(), 1); - /// assert!(!maze.is_empty()); + /// assert_eq!(maze.insert(coord), None); + /// assert_eq!(maze.insert(coord), Some(Tile::new(coord))); /// ``` - pub fn add_tile(&mut self, coords: Hex) { - let tile = HexTile::new(coords); - self.0.insert(coords, tile); + pub fn insert(&mut self, coords: Hex) -> Option { + let tile = Tile::new(coords); + self.0.insert(coords, tile) } - /// Adds a wall in the specified direction at the given coordinates. + /// Adds a new tile at the specified coordinates. + /// + /// If the map did not have this key present, [`None`] is returned. + /// + /// If the map did have this key present, the value is updated, and the old + /// value is returned. + /// + /// It is recommended to use [`insert`]. + /// + /// [`insert`]: Maze::insert /// /// # Arguments /// - /// - `coord` - The hexagonal coordinates of the tile. - /// - `direction` - The direction in which to add the wall. + /// - `coords` - The hexagonal coordinates where the tile should be added. + /// - `tile` - The tile to insert to. /// /// # Examples /// /// ``` /// use hexlab::prelude::*; /// - /// let mut maze = HexMaze::new(); + /// let mut maze = Maze::new(); /// let coord = Hex::ZERO; - /// maze.add_tile(coord); + /// let tile1 = Tile::new(coord); + /// let tile2 = Tile::new(Hex::new(1, 1)); /// - /// maze.add_wall(coord, EdgeDirection::FLAT_NORTH); - /// let walls = maze.get_walls(&coord); - /// assert!(walls.is_some()); - /// assert!(walls.unwrap().contains(EdgeDirection::FLAT_NORTH)); + /// assert_eq!(maze.insert_with_tile(coord, tile1.clone()), None); + /// assert_eq!(maze.insert_with_tile(coord, tile2), Some(tile1)); /// ``` - pub fn add_wall(&mut self, coord: Hex, direction: EdgeDirection) { - if let Some(tile) = self.0.get_mut(&coord) { - tile.walls.add(direction); - } + pub fn insert_with_tile(&mut self, coords: Hex, tile: Tile) -> Option { + self.0.insert(coords, tile) } /// Returns a reference to the tile at the specified coordinates. @@ -100,20 +113,26 @@ impl HexMaze { /// ``` /// use hexlab::prelude::*; /// - /// let mut maze = HexMaze::new(); + /// let mut maze = Maze::new(); /// let coord = Hex::ZERO; - /// maze.add_tile(coord); + /// maze.insert(coord); /// - /// assert!(maze.get_tile(&coord).is_some()); - /// assert!(maze.get_tile(&Hex::new(1, 1)).is_none()); + /// assert!(maze.get(&coord).is_some()); + /// assert!(maze.get(&Hex::new(1, 1)).is_none()); /// ``` - #[cfg_attr(not(debug_assertions), inline)] + #[inline] #[must_use] - pub fn get_tile(&self, coord: &Hex) -> Option<&HexTile> { + pub fn get(&self, coord: &Hex) -> Option<&Tile> { self.0.get(coord) } - /// Returns an optional reference to the walls at the specified coordinates. + #[inline] + #[must_use] + pub fn get_mut(&mut self, coord: &Hex) -> Option<&mut Tile> { + self.0.get_mut(coord) + } + + /// Returns an optional mutable reference to the walls at the specified coordinates. /// /// # Arguments /// @@ -124,16 +143,43 @@ impl HexMaze { /// ``` /// use hexlab::prelude::*; /// - /// let mut maze = HexMaze::new(); + /// let mut maze = Maze::new(); /// let coord = Hex::new(0, 0); - /// maze.add_tile(coord); + /// maze.insert(coord); /// - /// maze.add_wall(coord, EdgeDirection::FLAT_NORTH); + /// maze.add_tile_wall(&coord, EdgeDirection::FLAT_NORTH); /// let walls = maze.get_walls(&coord).unwrap(); - /// assert!(walls.contains(EdgeDirection::FLAT_NORTH)); + /// assert!(walls.contains(&EdgeDirection::FLAT_NORTH)); /// ``` + #[inline] + #[must_use] pub fn get_walls(&self, coord: &Hex) -> Option<&Walls> { - self.0.get(coord).map(HexTile::walls) + self.0.get(coord).map(Tile::walls) + } + + /// Returns an optional mutable reference to the walls at the specified coordinates. + /// + /// # Arguments + /// + /// - `coord` - The hexagonal coordinates of the tile whose walls to retrieve. + /// + /// # Examples + /// + /// ``` + /// use hexlab::prelude::*; + /// + /// let mut maze = Maze::new(); + /// let coord = Hex::new(0, 0); + /// maze.insert(coord); + /// + /// maze.add_tile_wall(&coord, EdgeDirection::FLAT_NORTH); + /// let mut walls = maze.get_walls_mut(&coord).unwrap(); + /// assert!(walls.remove(EdgeDirection::FLAT_NORTH)); + /// ``` + #[inline] + #[must_use] + pub fn get_walls_mut(&mut self, coord: &Hex) -> Option<&mut Walls> { + self.0.get_mut(coord).map(Tile::walls_mut) } /// Returns the number of tiles in the maze. @@ -143,16 +189,16 @@ impl HexMaze { /// ``` /// use hexlab::prelude::*; /// - /// let mut maze = HexMaze::new(); + /// let mut maze = Maze::new(); /// assert_eq!(maze.len(), 0); /// - /// maze.add_tile(Hex::new(0, 0)); + /// maze.insert(Hex::new(0, 0)); /// assert_eq!(maze.len(), 1); /// - /// maze.add_tile(Hex::new(1, -1)); + /// maze.insert(Hex::new(1, -1)); /// assert_eq!(maze.len(), 2); /// ``` - #[cfg_attr(not(debug_assertions), inline)] + #[inline] #[must_use] pub fn len(&self) -> usize { self.0.len() @@ -165,54 +211,147 @@ impl HexMaze { /// ``` /// use hexlab::prelude::*; /// - /// let mut maze = HexMaze::new(); + /// let mut maze = Maze::new(); /// assert!(maze.is_empty()); /// - /// maze.add_tile(Hex::ZERO); + /// maze.insert(Hex::ZERO); /// assert!(!maze.is_empty()); /// ``` - #[cfg_attr(not(debug_assertions), inline)] + #[inline] #[must_use] pub fn is_empty(&self) -> bool { self.0.is_empty() } + /// Adds a wall from a tile in the specified direction. + /// + /// # Arguments + /// + /// - `coord` - The hexagonal coordinates of the tile. + /// - `direction` - The direction of the wall to remove. + /// + /// # Errors + /// + /// Returns `MazeError::InvalidCoordinate` if the specified coordinate does not exist in the maze. + /// + /// # Examples + /// + /// ``` + /// use hexlab::prelude::*; + /// + /// // Create a maze with a single tile at the origin + /// let mut tile = Tile::new(Hex::ZERO); + /// tile.walls_mut().toggle(Walls::all_directions()); + /// let mut maze = Maze::from([tile]); + /// + /// // Initially, the tile should have no walls + /// assert!(maze.get_walls(&Hex::ZERO).unwrap().is_empty()); + /// + /// // Add a wall to the north + /// assert!(maze.add_tile_wall(&Hex::ZERO, EdgeDirection::FLAT_NORTH).is_ok()); + /// + /// // Check that the wall was added + /// let walls = maze.get_walls(&Hex::ZERO).unwrap(); + /// assert!(walls.contains(&EdgeDirection::FLAT_NORTH)); + /// assert_eq!(walls.count(), 1); + /// + /// // Adding the same wall again should return true (no change) + /// assert_eq!(maze.add_tile_wall(&Hex::ZERO, EdgeDirection::FLAT_NORTH), Ok(true)); + /// + /// // Adding a wall to a non-existent tile should return an error + /// let invalid_coord = Hex::new(1, 1); + /// assert_eq!( + /// maze.add_tile_wall(&invalid_coord, EdgeDirection::FLAT_NORTH), + /// Err(MazeError::InvalidCoordinate(invalid_coord)) + /// ); + /// ``` + pub fn add_tile_wall( + &mut self, + coord: &Hex, + direction: EdgeDirection, + ) -> Result { + self.0 + .get_mut(coord) + .map(|tile| tile.walls.insert(direction)) + .ok_or(MazeError::InvalidCoordinate(*coord)) + } + /// Removes a wall from a tile in the specified direction. /// /// # Arguments /// /// - `coord` - The hexagonal coordinates of the tile. /// - `direction` - The direction of the wall to remove. + /// + /// # Errors + /// + /// Returns `MazeError::InvalidCoordinate` if the specified coordinate does not exist in the maze. + /// /// # Examples /// /// ``` /// use hexlab::prelude::*; /// - /// let mut maze = HexMaze::new(); + /// let mut maze = Maze::new(); /// let coord = Hex::ZERO; - /// maze.add_tile(coord); + /// maze.insert(coord); /// - /// maze.add_wall(coord, EdgeDirection::FLAT_NORTH); + /// maze.add_tile_wall(&coord, EdgeDirection::FLAT_NORTH); /// maze.remove_tile_wall(&coord, EdgeDirection::FLAT_NORTH); /// /// let walls = maze.get_walls(&coord).unwrap(); - /// assert!(!walls.contains(EdgeDirection::FLAT_NORTH)); + /// assert!(!walls.contains(&EdgeDirection::FLAT_NORTH)); /// ``` - pub fn remove_tile_wall(&mut self, coord: &Hex, direction: EdgeDirection) { - if let Some(tile) = self.0.get_mut(coord) { - tile.walls.remove(direction); - } + pub fn remove_tile_wall( + &mut self, + coord: &Hex, + direction: EdgeDirection, + ) -> Result { + self.0 + .get_mut(coord) + .map(|tile| tile.walls.remove(direction)) + .ok_or(MazeError::InvalidCoordinate(*coord)) } } -impl Deref for HexMaze { - type Target = HashMap; +impl FromIterator for Maze { + fn from_iter>(iter: T) -> Self { + Self(iter.into_iter().map(|hex| (hex, Tile::new(hex))).collect()) + } +} + +impl FromIterator for Maze { + fn from_iter>(iter: T) -> Self { + Self(iter.into_iter().map(|tile| (tile.pos(), tile)).collect()) + } +} + +impl FromIterator<(Hex, Tile)> for Maze { + fn from_iter>(iter: T) -> Self { + Self(iter.into_iter().collect()) + } +} + +impl From<[Hex; N]> for Maze { + fn from(value: [Hex; N]) -> Self { + value.into_iter().collect() + } +} + +impl From<[Tile; N]> for Maze { + fn from(value: [Tile; N]) -> Self { + value.into_iter().collect() + } +} + +impl Deref for Maze { + type Target = HashMap; fn deref(&self) -> &Self::Target { &self.0 } } -impl DerefMut for HexMaze { +impl DerefMut for Maze { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } diff --git a/src/tile.rs b/src/tile.rs index 743ff5f..af1dd3f 100644 --- a/src/tile.rs +++ b/src/tile.rs @@ -1,4 +1,7 @@ use super::Walls; +#[cfg(feature = "bevy_reflect")] +use crate::traits::WorldPositionable; +use crate::traits::{TilePosition, WallStorage}; #[cfg(feature = "bevy")] use bevy::prelude::*; use hexx::Hex; @@ -9,18 +12,90 @@ use std::fmt::Display; /// Represents a single hexagonal tile in the maze /// /// Each tile has a position and a set of walls defining its boundaries. -#[allow(clippy::module_name_repetitions)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))] #[cfg_attr(feature = "bevy", derive(Component))] #[cfg_attr(feature = "bevy", reflect(Component))] #[derive(Debug, Clone, Default, PartialEq, Eq)] -pub struct HexTile { +pub struct Tile { pub(crate) pos: Hex, pub(crate) walls: Walls, } -impl HexTile { +impl TilePosition for Tile { + /// Returns position of the tile + /// + /// # Examples + /// + /// ``` + /// use hexlab::prelude::*; + /// + /// let tile = Tile::new(Hex::new(2, -2)); + /// assert_eq!(tile.pos(), Hex::new(2, -2)); + /// ``` + #[inline] + fn pos(&self) -> Hex { + self.pos + } +} + +impl WallStorage for Tile { + /// Returns an immutable reference to the tile's walls + /// + /// # Examples + /// + /// ``` + /// use hexlab::prelude::*; + /// + /// let tile = Tile::new(Hex::ZERO); + /// assert_eq!(*tile.walls(), Walls::default()); + /// ``` + #[inline] + fn walls(&self) -> &Walls { + &self.walls + } + + /// Returns a mutable reference to the tile's walls + /// + /// # Examples + /// + /// ``` + /// use hexlab::prelude::*; + /// + /// let tile = Tile::new(Hex::ZERO); + /// assert_eq!(*tile.walls(), Walls::default()); + /// ``` + #[inline] + fn walls_mut(&mut self) -> &mut Walls { + &mut self.walls + } +} + +#[cfg(feature = "bevy_reflect")] +impl WorldPositionable for Tile { + /// Converts the tile's position to a 2D vector based on the given layout. + /// + /// # Arguments + /// + /// - `layout` - The hexagonal layout used for conversion. + #[inline] + fn to_vec2(&self, layout: &HexLayout) -> glam::Vec2 { + layout.hex_to_world_pos(self.pos) + } + + /// Converts the tile's position to a 3D vector based on the given layout. + /// + /// # Arguments + /// + /// - `layout` - The hexagonal layout used for conversion. + #[inline] + fn to_vec3(&self, layout: &HexLayout) -> glam::Vec3 { + let pos = self.to_vec2(layout); + glam::Vec3::new(pos.x, 0., pos.y) + } +} + +impl Tile { /// Creates a new tile with the given position and default walls. /// /// # Arguments @@ -32,7 +107,7 @@ impl HexTile { /// ``` /// use hexlab::prelude::*; /// - /// let tile = HexTile::new(Hex::new(1, -1)); + /// let tile = Tile::new(Hex::new(1, -1)); /// assert_eq!(tile.pos(), Hex::new(1, -1)); /// assert_eq!(*tile.walls(), Walls::default()); /// ``` @@ -43,68 +118,9 @@ impl HexTile { walls: Walls::default(), } } - - /// Returns a reference to the tile's walls - /// - /// # Examples - /// - /// ``` - /// use hexlab::prelude::*; - /// - /// let tile = HexTile::new(Hex::ZERO); - /// assert_eq!(*tile.walls(), Walls::default()); - /// ``` - #[cfg_attr(not(debug_assertions), inline)] - #[must_use] - pub const fn walls(&self) -> &Walls { - &self.walls - } - - /// Returns position of the tile - /// - /// # Examples - /// - /// ``` - /// use hexlab::prelude::*; - /// - /// let tile = HexTile::new(Hex::new(2, -2)); - /// assert_eq!(tile.pos(), Hex::new(2, -2)); - /// ``` - #[cfg_attr(not(debug_assertions), inline)] - #[must_use] - pub const fn pos(&self) -> Hex { - self.pos - } - - /// Converts the tile's position to a 2D vector based on the given layout. - /// - /// # Arguments - /// - /// - `layout` - The hexagonal layout used for conversion. - #[cfg(feature = "bevy_reflect")] - #[cfg_attr(not(debug_assertions), inline)] - #[must_use] - pub fn to_vec2(&self, layout: &HexLayout) -> glam::Vec2 { - layout.hex_to_world_pos(self.pos) - } - - /// Converts the tile's position to a 3D vector based on the given layout. - /// - /// # Arguments - /// - /// - `layout` - The hexagonal layout used for conversion. - #[cfg(feature = "bevy_reflect")] - #[cfg_attr(not(debug_assertions), inline)] - #[must_use] - pub fn to_vec3(&self, layout: &HexLayout) -> glam::Vec3 { - use glam::Vec3; - - let pos = self.to_vec2(layout); - Vec3::new(pos.x, 0., pos.y) - } } -impl From for HexTile { +impl From for Tile { fn from(value: Hex) -> Self { Self { pos: value, @@ -113,7 +129,7 @@ impl From for HexTile { } } -impl Display for HexTile { +impl Display for Tile { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "({},{})", self.pos.x, self.pos.y) } @@ -130,19 +146,6 @@ mod test { Hex::new(rng.gen(), rng.gen()) } - #[test] - fn tile_modification() { - let hex = random_hex(); - let mut tile = HexTile::new(hex); - - // Modify walls - tile.walls.remove(EdgeDirection::FLAT_TOP); - assert!(!tile.walls.contains(EdgeDirection::FLAT_TOP)); - - tile.walls.add(EdgeDirection::FLAT_TOP); - assert!(tile.walls.contains(EdgeDirection::FLAT_TOP)); - } - #[test] fn different_positions() { let positions = [Hex::ZERO, Hex::new(1, 0), Hex::new(-1, 1), Hex::new(2, -2)]; @@ -150,7 +153,7 @@ mod test { // Create tiles at different positions let tiles = positions .iter() - .map(|&pos| HexTile::new(pos)) + .map(|&pos| Tile::new(pos)) .collect::>(); // Verify each tile has correct position @@ -170,7 +173,7 @@ mod test { ]; for pos in extreme_positions { - let tile = HexTile::new(pos); + let tile = Tile::new(pos); assert_eq!(tile.pos, pos); } } @@ -178,7 +181,7 @@ mod test { #[test] fn hex_tile_creation_and_properties() { let hex = random_hex(); - let tile = HexTile::new(hex); + let tile = Tile::new(hex); assert_eq!(tile.pos(), hex); assert!(tile.walls().is_enclosed()); @@ -187,7 +190,7 @@ mod test { #[test] fn hex_tile_from_hex() { let hex = random_hex(); - let tile = HexTile::from(hex); + let tile = Tile::from(hex); assert_eq!(tile.pos, hex); assert_eq!(tile.walls, Walls::default()); @@ -196,7 +199,7 @@ mod test { #[test] fn hex_hex_into_tile() { let hex = random_hex(); - let tile: HexTile = hex.into(); + let tile: Tile = hex.into(); assert_eq!(tile.pos, hex); assert_eq!(tile.walls, Walls::default()); @@ -204,16 +207,16 @@ mod test { #[test] fn hex_tile_display() { - let tile = HexTile::new(Hex::new(3, -3)); + let tile = Tile::new(Hex::new(3, -3)); assert_eq!(format!("{tile}"), "(3,-3)"); } #[test] fn hex_tile_wall_modifications() { - let mut tile = HexTile::new(Hex::ZERO); + let mut tile = Tile::new(Hex::ZERO); for direction in EdgeDirection::ALL_DIRECTIONS { - tile.walls.add(direction); + tile.walls.insert(direction); } assert_eq!(tile.walls.count(), 6); @@ -231,7 +234,7 @@ mod test { #[test] fn hex_tile_to_vec2() { let layout = HexLayout::default(); - let tile = HexTile::new(Hex::new(1, 0)); + let tile = Tile::new(Hex::new(1, 0)); let vec2 = tile.to_vec2(&layout); assert_eq!(vec2, Vec2::new(1.5, -0.8660254)); } @@ -239,7 +242,7 @@ mod test { #[test] fn hex_tile_to_vec3() { let layout = HexLayout::default(); - let tile = HexTile::new(Hex::new(0, 1)); + let tile = Tile::new(Hex::new(0, 1)); let vec3 = tile.to_vec3(&layout); assert_eq!(vec3, Vec3::new(0.0, 0.0, -1.7320508)); } diff --git a/src/traits.rs b/src/traits.rs new file mode 100644 index 0000000..e231c5f --- /dev/null +++ b/src/traits.rs @@ -0,0 +1,22 @@ +use crate::Walls; +use hexx::Hex; + +pub trait TilePosition { + /// Returns position of the tile + #[must_use] + fn pos(&self) -> Hex; +} + +#[cfg(feature = "bevy_reflect")] +pub trait WorldPositionable { + #[must_use] + fn to_vec2(&self, layout: &hexx::HexLayout) -> glam::Vec2; + #[must_use] + fn to_vec3(&self, layout: &hexx::HexLayout) -> glam::Vec3; +} + +pub trait WallStorage { + #[must_use] + fn walls(&self) -> &Walls; + fn walls_mut(&mut self) -> &mut Walls; +} diff --git a/src/walls.rs b/src/walls.rs index 190b02a..b7e0ae1 100644 --- a/src/walls.rs +++ b/src/walls.rs @@ -16,15 +16,15 @@ use hexx::EdgeDirection; /// /// // Create a hexagon with all walls /// let walls = Walls::new(); -/// assert!(walls.is_closed()); +/// assert!(walls.is_enclosed()); /// /// // Create a hexagon with no walls /// let mut walls = Walls::empty(); /// assert!(walls.is_empty()); /// /// // Add specific walls -/// walls.add(EdgeDirection::FLAT_NORTH); -/// walls.add(EdgeDirection::FLAT_SOUTH); +/// walls.insert(EdgeDirection::FLAT_NORTH); +/// walls.insert(EdgeDirection::FLAT_SOUTH); /// assert_eq!(walls.count(), 2); /// ``` #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] @@ -47,7 +47,7 @@ impl Walls { /// let walls = Walls::new(); /// assert!(walls.is_enclosed()); /// ``` - #[cfg_attr(not(debug_assertions), inline)] + #[inline] #[must_use] pub fn new() -> Self { Self::default() @@ -63,7 +63,7 @@ impl Walls { /// let walls = Walls::empty(); /// assert!(walls.is_empty()); /// ``` - #[cfg_attr(not(debug_assertions), inline)] + #[inline] #[must_use] pub const fn empty() -> Self { Self(0) @@ -79,17 +79,21 @@ impl Walls { /// let walls = Walls::empty(); /// assert!(walls.is_empty()); /// ``` - #[cfg_attr(not(debug_assertions), inline)] + #[inline] #[must_use] pub const fn is_empty(&self) -> bool { self.0 == 0 } - /// Adds a wall in the specified direction. + /// Insert a wall in the specified direction. /// /// # Arguments /// - /// - `direction` - The direction in which to add the wall. + /// - `direction` - The direction in which to insert the wall. + /// + /// # Returns + /// + /// Returns `true` if a wall was present, `false` otherwise. /// /// # Examples /// @@ -99,22 +103,24 @@ impl Walls { /// let mut walls = Walls::empty(); /// assert_eq!(walls.count(), 0); /// - /// walls.add(1); + /// assert!(!walls.insert(1)); /// assert_eq!(walls.count(), 1); /// - /// walls.add(1); + /// assert!(walls.insert(1)); /// assert_eq!(walls.count(), 1); /// - /// walls.add(EdgeDirection::FLAT_NORTH); + /// assert!(!walls.insert(EdgeDirection::FLAT_NORTH)); /// assert_eq!(walls.count(), 2); - /// /// ``` - #[cfg_attr(not(debug_assertions), inline)] - pub fn add(&mut self, direction: T) + #[inline] + pub fn insert(&mut self, direction: T) -> bool where T: Into + Copy, { - self.0 |= direction.into().0; + let mask = direction.into().0; + let was_present = self.0 & mask != 0; + self.0 |= mask; + was_present } /// Removes a wall in the specified direction. @@ -123,6 +129,10 @@ impl Walls { /// /// - `direction` - The direction from which to remove the wall. /// + /// # Returns + /// + /// Returns `true` if a wall was present and removed, `false` otherwise. + /// /// # Examples /// /// ``` @@ -139,16 +149,15 @@ impl Walls { /// assert!(walls.remove(EdgeDirection::FLAT_NORTH)); /// assert_eq!(walls.count(), 4); /// ``` - #[cfg_attr(not(debug_assertions), inline)] + #[inline] pub fn remove(&mut self, direction: T) -> bool where T: Into + Copy, { - let was_removed = self.contains(direction); - if was_removed { - self.0 &= !direction.into().0; - } - was_removed + let mask = direction.into().0; + let was_present = self.0 & mask != 0; + self.0 &= !mask; + was_present } /// Checks if there is a wall in the specified direction. @@ -163,17 +172,17 @@ impl Walls { /// use hexlab::prelude::*; /// /// let mut walls = Walls::empty(); - /// walls.add(EdgeDirection::FLAT_NORTH); + /// walls.insert(EdgeDirection::FLAT_NORTH); /// - /// assert!(walls.contains(EdgeDirection::FLAT_NORTH)); - /// assert!(!walls.contains(EdgeDirection::FLAT_SOUTH)); + /// assert!(walls.contains(&EdgeDirection::FLAT_NORTH)); + /// assert!(!walls.contains(&EdgeDirection::FLAT_SOUTH)); /// ``` - #[cfg_attr(not(debug_assertions), inline)] - pub fn contains(&self, other: T) -> bool + #[inline] + pub fn contains(&self, direction: &T) -> bool where T: Into + Copy, { - self.0 & other.into().0 != 0 + self.0 & (*direction).into().0 != 0 } /// Returns the raw bit representation of the walls @@ -189,7 +198,7 @@ impl Walls { /// let walls = Walls::empty(); /// assert_eq!(walls.as_bits(), 0); /// ``` - #[cfg_attr(not(debug_assertions), inline)] + #[inline] #[must_use] pub const fn as_bits(&self) -> u8 { self.0 @@ -205,13 +214,13 @@ impl Walls { /// let mut walls = Walls::empty(); /// assert!(walls.is_empty()); /// - /// walls.add(0); + /// walls.insert(0); /// assert_eq!(walls.count(), 1); /// - /// walls.add(1); + /// walls.insert(1); /// assert_eq!(walls.count(), 2); /// ``` - #[cfg_attr(not(debug_assertions), inline)] + #[inline] #[must_use] pub fn count(&self) -> u8 { u8::try_from(self.0.count_ones()).unwrap_or_default() @@ -226,7 +235,7 @@ impl Walls { /// /// assert_eq!(Walls::all_directions().as_bits(), 0b11_1111); /// ``` - #[cfg_attr(not(debug_assertions), inline)] + #[inline] #[must_use] pub const fn all_directions() -> Self { Self(0b11_1111) @@ -262,29 +271,10 @@ impl Walls { where T: Into + Copy, { - let is_present = self.contains(direction); - if is_present { - self.remove(direction); - } else { - self.add(direction); - } - is_present - } - - /// Checks if walls are present in all six directions. - /// - /// # Returns - /// - /// `true` if the hexagon has all possible walls, making it completely enclosed. - /// - /// # Deprecated - /// - /// This method is deprecated since version 0.4.0. Use `is_enclosed()` instead. - #[cfg_attr(not(debug_assertions), inline)] - #[must_use] - #[deprecated(since = "0.4.0", note = "use `walls::Walls::is_enclosed()`")] - pub fn is_closed(&self) -> bool { - self.is_enclosed() + let mask = direction.into().0; + let was_present = self.0 & mask != 0; + self.0 ^= mask; + was_present } /// Checks if walls are present in all six directions. @@ -304,7 +294,7 @@ impl Walls { /// walls.remove(0); /// assert!(!walls.is_enclosed()); /// ``` - #[cfg_attr(not(debug_assertions), inline)] + #[inline] #[must_use] pub fn is_enclosed(&self) -> bool { self.count() == 6 @@ -317,7 +307,7 @@ impl Walls { /// /// # Arguments /// - /// - `other` - The walls to add, specified as a `Walls` instance or any type + /// - `other` - The walls to insert, specified as a `Walls` instance or any type /// that can be converted into `Walls`. /// /// @@ -329,10 +319,10 @@ impl Walls { /// let mut walls = Walls::empty(); /// walls.fill([EdgeDirection::FLAT_NORTH ,EdgeDirection::FLAT_SOUTH, EdgeDirection::FLAT_SOUTH_EAST]); /// - /// assert!(walls.contains(EdgeDirection::FLAT_SOUTH)); + /// assert!(walls.contains(&EdgeDirection::FLAT_SOUTH)); /// assert_eq!(walls.count(), 3); /// ``` - #[cfg_attr(not(debug_assertions), inline)] + #[inline] pub fn fill(&mut self, other: T) where T: Into, @@ -398,15 +388,15 @@ mod test { #[test] fn as_bits_single_wall() { let mut walls = Walls::empty(); - walls.add(EdgeDirection::FLAT_NORTH); + walls.insert(EdgeDirection::FLAT_NORTH); assert_eq!(walls.as_bits(), 0b010000); } #[test] fn as_bits_multiple_walls() { let mut walls = Walls::empty(); - walls.add(EdgeDirection::FLAT_NORTH); - walls.add(EdgeDirection::FLAT_SOUTH); + walls.insert(EdgeDirection::FLAT_NORTH); + walls.insert(EdgeDirection::FLAT_SOUTH); assert_eq!(walls.as_bits(), 0b010010); } @@ -432,12 +422,12 @@ mod test { assert_eq!(walls.as_bits(), 0); } - // add + // insert #[test] - fn add_single_wall() { + fn insert_single_wall() { let mut walls = Walls::empty(); - walls.add(EdgeDirection::FLAT_NORTH); - assert!(walls.contains(EdgeDirection::FLAT_NORTH)); + walls.insert(EdgeDirection::FLAT_NORTH); + assert!(walls.contains(&EdgeDirection::FLAT_NORTH)); assert_eq!(walls.count(), 1); } @@ -446,30 +436,30 @@ mod test { fn remove_existing_wall() { let mut walls = Walls::new(); assert!(walls.remove(EdgeDirection::FLAT_NORTH)); - assert!(!walls.contains(EdgeDirection::FLAT_NORTH)); + assert!(!walls.contains(&EdgeDirection::FLAT_NORTH)); } #[test] fn remove_nonexistent_wall() { let mut walls = Walls::empty(); assert!(!walls.remove(EdgeDirection::FLAT_NORTH)); - walls.add(EdgeDirection::FLAT_NORTH); + walls.insert(EdgeDirection::FLAT_NORTH); assert!(walls.remove(EdgeDirection::FLAT_NORTH)); } // toggle #[test] - fn toggle_adds_wall() { + fn toggle_wall() { let mut walls = Walls::empty(); assert!(!walls.toggle(EdgeDirection::FLAT_NORTH)); - assert!(walls.contains(EdgeDirection::FLAT_NORTH)); + assert!(walls.contains(&EdgeDirection::FLAT_NORTH)); } #[test] fn toggle_removes_wall() { let mut walls = Walls::new(); assert!(walls.toggle(EdgeDirection::FLAT_NORTH)); - assert!(!walls.contains(EdgeDirection::FLAT_NORTH)); + assert!(!walls.contains(&EdgeDirection::FLAT_NORTH)); } // fill @@ -477,41 +467,41 @@ mod test { fn fill_adds_multiple_walls() { let mut walls = Walls::empty(); walls.fill([EdgeDirection::FLAT_NORTH, EdgeDirection::FLAT_SOUTH]); - assert!(walls.contains(EdgeDirection::FLAT_NORTH)); - assert!(walls.contains(EdgeDirection::FLAT_SOUTH)); + assert!(walls.contains(&EdgeDirection::FLAT_NORTH)); + assert!(walls.contains(&EdgeDirection::FLAT_SOUTH)); assert_eq!(walls.count(), 2); } #[test] fn fill_preserves_existing_walls() { let mut walls = Walls::empty(); - walls.add(EdgeDirection::FLAT_NORTH); + walls.insert(EdgeDirection::FLAT_NORTH); walls.fill([EdgeDirection::FLAT_SOUTH, EdgeDirection::FLAT_SOUTH_EAST]); - assert!(walls.contains(EdgeDirection::FLAT_NORTH)); - assert!(walls.contains(EdgeDirection::FLAT_SOUTH)); - assert!(walls.contains(EdgeDirection::FLAT_SOUTH_EAST)); + assert!(walls.contains(&EdgeDirection::FLAT_NORTH)); + assert!(walls.contains(&EdgeDirection::FLAT_SOUTH)); + assert!(walls.contains(&EdgeDirection::FLAT_SOUTH_EAST)); assert_eq!(walls.count(), 3); } #[test] fn from_edge_direction_conversion() { let walls: Walls = EdgeDirection::FLAT_NORTH.into(); - assert!(walls.contains(EdgeDirection::FLAT_NORTH)); + assert!(walls.contains(&EdgeDirection::FLAT_NORTH)); assert_eq!(walls.count(), 1); } #[test] fn from_u8_conversion() { let walls: Walls = 0u8.into(); - assert!(walls.contains(EdgeDirection::FLAT_SOUTH_EAST)); + assert!(walls.contains(&EdgeDirection::FLAT_SOUTH_EAST)); assert_eq!(walls.count(), 1); } #[test] fn from_array_conversion() { let walls: Walls = [EdgeDirection::FLAT_NORTH, EdgeDirection::FLAT_SOUTH].into(); - assert!(walls.contains(EdgeDirection::FLAT_NORTH)); - assert!(walls.contains(EdgeDirection::FLAT_SOUTH)); + assert!(walls.contains(&EdgeDirection::FLAT_NORTH)); + assert!(walls.contains(&EdgeDirection::FLAT_SOUTH)); assert_eq!(walls.count(), 2); } @@ -542,8 +532,8 @@ mod test { ]; let walls: Walls = directions.into_iter().collect(); assert_eq!(walls.count(), 2); - assert!(walls.contains(EdgeDirection::FLAT_NORTH)); - assert!(walls.contains(EdgeDirection::FLAT_SOUTH)); + assert!(walls.contains(&EdgeDirection::FLAT_NORTH)); + assert!(walls.contains(&EdgeDirection::FLAT_SOUTH)); } #[test] @@ -551,14 +541,14 @@ mod test { let mut walls = Walls::empty(); // Test single bit operations - walls.add(EdgeDirection::FLAT_NORTH); + walls.insert(EdgeDirection::FLAT_NORTH); assert_eq!(walls.as_bits(), 0b010000); - walls.add(EdgeDirection::FLAT_SOUTH); + walls.insert(EdgeDirection::FLAT_SOUTH); assert_eq!(walls.as_bits(), 0b010010); // Test removing middle bit - walls.add(EdgeDirection::FLAT_SOUTH_EAST); + walls.insert(EdgeDirection::FLAT_SOUTH_EAST); assert_eq!(walls.as_bits(), 0b010011); walls.remove(EdgeDirection::FLAT_SOUTH); assert_eq!(walls.as_bits(), 0b010001); diff --git a/tests/builder.rs b/tests/builder.rs index df33480..c1920f0 100644 --- a/tests/builder.rs +++ b/tests/builder.rs @@ -29,7 +29,7 @@ fn valid_start_position(#[case] start_pos: Hex) { .with_radius(3) .with_start_position(start_pos) .build()); - assert_some!(maze.get_tile(&start_pos)); + assert_some!(maze.get(&start_pos)); } #[test] @@ -67,13 +67,13 @@ fn maze_connectivity() { let maze = assert_ok!(MazeBuilder::new().with_radius(3).build()); // Helper function to count accessible neighbors - fn count_accessible_neighbors(maze: &HexMaze, pos: Hex) -> usize { + fn count_accessible_neighbors(maze: &Maze, pos: Hex) -> usize { hexx::EdgeDirection::ALL_DIRECTIONS .iter() .filter(|&&dir| { let neighbor = pos + dir; if let Some(walls) = maze.get_walls(&pos) { - !walls.contains(dir) && maze.get_tile(&neighbor).is_some() + !walls.contains(&dir) && maze.get(&neighbor).is_some() } else { false } @@ -107,7 +107,7 @@ fn maze_boundaries() { let pos = Hex::new(q, r); if q.abs() + r.abs() <= radius { assert!( - maze.get_tile(&pos).is_some(), + maze.get(&pos).is_some(), "Expected tile at {:?} to exist", pos ); diff --git a/tests/generator.rs b/tests/generator.rs index b823266..babf64a 100644 --- a/tests/generator.rs +++ b/tests/generator.rs @@ -10,12 +10,12 @@ fn generator_type( #[case] start_pos: Option, #[case] seed: Option, ) { - let mut maze = HexMaze::new(); + let mut maze = Maze::new(); for q in -3..=3 { for r in -3..=3 { let hex = Hex::new(q, r); if hex.length() <= 3 { - maze.add_tile(hex); + maze.insert(hex); } } } @@ -36,7 +36,7 @@ fn generator_type( for dir in EdgeDirection::ALL_DIRECTIONS { let neighbor = current + dir; if let Some(walls) = maze.get_walls(¤t) { - if !walls.contains(dir) && maze.get_tile(&neighbor).is_some() { + if !walls.contains(&dir) && maze.get(&neighbor).is_some() { to_visit.push(neighbor); } } @@ -57,7 +57,7 @@ fn generator_type( #[test] fn test_empty_maze() { - let mut maze = HexMaze::new(); + let mut maze = Maze::new(); GeneratorType::RecursiveBacktracking.generate(&mut maze, None, None); assert!( maze.is_empty(), diff --git a/tests/maze.rs b/tests/maze.rs index 89fc225..cd1b06f 100644 --- a/tests/maze.rs +++ b/tests/maze.rs @@ -2,28 +2,28 @@ use hexlab::prelude::*; #[test] fn hex_maze_creation_and_basic_operations() { - let mut maze = HexMaze::new(); + let mut maze = Maze::new(); assert!(maze.is_empty()); let center = Hex::ZERO; - maze.add_tile(center); + maze.insert(center); assert_eq!(maze.len(), 1); assert!(!maze.is_empty()); - let tile = maze.get_tile(¢er); + let tile = maze.get(¢er); assert!(tile.is_some()); assert_eq!(tile.unwrap().pos(), center); } #[test] fn hex_maze_wall_operations() { - let mut maze = HexMaze::new(); + let mut maze = Maze::new(); let center = Hex::ZERO; - maze.add_tile(center); + maze.insert(center); // Add walls for direction in EdgeDirection::ALL_DIRECTIONS { - maze.add_wall(center, direction); + let _ = maze.add_tile_wall(¢er, direction); } let walls = maze.get_walls(¢er).unwrap(); @@ -31,7 +31,7 @@ fn hex_maze_wall_operations() { // Remove walls for direction in EdgeDirection::ALL_DIRECTIONS { - maze.remove_tile_wall(¢er, direction); + let _ = maze.remove_tile_wall(¢er, direction); } let walls = maze.get_walls(¢er).unwrap(); @@ -40,29 +40,29 @@ fn hex_maze_wall_operations() { #[test] fn hex_maze_multiple_tiles() { - let mut maze = HexMaze::new(); + let mut maze = Maze::new(); let tiles = [Hex::ZERO, Hex::new(1, -1), Hex::new(0, 1), Hex::new(-1, 1)]; for &tile in &tiles { - maze.add_tile(tile); + maze.insert(tile); } assert_eq!(maze.len(), tiles.len()); for &tile in &tiles { - assert!(maze.get_tile(&tile).is_some()); + assert!(maze.get(&tile).is_some()); } } #[test] fn hex_maze_edge_cases() { - let mut maze = HexMaze::new(); + let mut maze = Maze::new(); let non_existent = Hex::new(10, 10); // Operations on non-existent tiles should not panic - maze.add_wall(non_existent, EdgeDirection::FLAT_NORTH); - maze.remove_tile_wall(&non_existent, EdgeDirection::FLAT_NORTH); + let _ = maze.add_tile_wall(&non_existent, EdgeDirection::FLAT_NORTH); + let _ = maze.remove_tile_wall(&non_existent, EdgeDirection::FLAT_NORTH); - assert!(maze.get_tile(&non_existent).is_none()); + assert!(maze.get(&non_existent).is_none()); assert!(maze.get_walls(&non_existent).is_none()); }