From 3c0ce13781240f52180c9846ed19c486499d4578 Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Tue, 7 Oct 2025 13:27:13 -0400 Subject: add some functionality to Pos --- dungeon/src/map.rs | 5 +++- dungeon/src/pos.rs | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 76 insertions(+), 5 deletions(-) (limited to 'dungeon') diff --git a/dungeon/src/map.rs b/dungeon/src/map.rs index cb602e8..bb83ba9 100644 --- a/dungeon/src/map.rs +++ b/dungeon/src/map.rs @@ -6,8 +6,11 @@ use crate::pos::{Direction, Pos}; /// `MAP_SIZE` is the size of the size of the dungeon grid. pub const MAP_SIZE: u16 = 100; +/// `MAP_SIZE` as a usize +pub const MAP_SIZE_USIZE: usize = MAP_SIZE as usize; + /// The number of tiles in the dungeon grid -pub const TILE_COUNT: usize = MAP_SIZE as usize * MAP_SIZE as usize; +pub const TILE_COUNT: usize = MAP_SIZE_USIZE * MAP_SIZE_USIZE; /// The `EntityKind` represents what kind of entity this is. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] diff --git a/dungeon/src/pos.rs b/dungeon/src/pos.rs index e953ea4..1d4526b 100644 --- a/dungeon/src/pos.rs +++ b/dungeon/src/pos.rs @@ -2,7 +2,18 @@ //! entity or objects position and facing direction inside the //! dungeon grid. -use crate::map::MAP_SIZE; +use crate::{MAP_SIZE_USIZE, map::MAP_SIZE}; + +macro_rules! downcast { + ($usize:expr, $type:ty) => { + if $usize > <$type>::MAX as usize { + None + } else { + #[expect(clippy::cast_possible_truncation)] + Some($usize as $type) + } + }; +} /// The `Direction` type represents a direction an entity /// or any position object is facing inside the dungeon map. @@ -92,11 +103,11 @@ impl Pos { /// # Examples /// /// ``` - /// use dungeon::{Pos, MAP_SIZE}; + /// use dungeon::{Pos, MAP_SIZE_USIZE}; /// /// let pos = Pos::new(1,2).unwrap(); /// let idx = pos.idx(); - /// assert_eq!(idx, 1 + 2 * MAP_SIZE as usize); + /// assert_eq!(idx, 1 + 2 * MAP_SIZE_USIZE); /// ``` #[must_use] pub const fn idx(self) -> usize { @@ -105,6 +116,37 @@ impl Pos { idx as usize } + /// Converse an index into a possible x and y position + /// + /// # Examples + /// + /// ``` + /// use dungeon::{Pos}; + /// + /// let idx_pos = Pos::from_idx(17); + /// let pos = Pos::new(17, 0); + /// + /// assert_eq!(idx_pos, pos); + /// ``` + /// + /// ``` + /// use dungeon::{Pos}; + /// + /// let idx_pos = Pos::from_idx(170); + /// let pos = Pos::new(70, 1); + /// + /// assert_eq!(idx_pos, pos); + /// ``` + #[must_use] + pub const fn from_idx(idx: usize) -> Option { + let x = downcast!(idx % MAP_SIZE_USIZE, u16); + let y = downcast!(idx / MAP_SIZE_USIZE, u16); + match (x, y) { + (Some(a), Some(b)) => Self::new(a, b), + _ => None, + } + } + /// Steps `Pos` one space in the `Direction` `dir`. /// /// Returns `None` if the position goes out of the map. @@ -140,8 +182,24 @@ impl Pos { } /// Returns of the given position is on the border of the map + /// + /// ``` + /// use dungeon::{Pos, MAP_SIZE}; + /// + /// let pos1 = Pos::new(0, 17).unwrap(); + /// let pos2 = Pos::new(1, 17).unwrap(); + /// let pos3 = Pos::new(MAP_SIZE - 1, 17).unwrap(); + /// let pos4 = Pos::new(55, MAP_SIZE - 1).unwrap(); + /// let pos5 = Pos::new(55, 0).unwrap(); + /// + /// assert!(pos1.is_border()); + /// assert!(!pos2.is_border()); + /// assert!(pos3.is_border()); + /// assert!(pos4.is_border()); + /// assert!(pos5.is_border()); + /// ``` #[must_use] - pub fn is_border(&self) -> bool { + pub const fn is_border(&self) -> bool { self.0 == 0 || self.0 == MAP_SIZE - 1 || self.1 == 0 || self.1 == MAP_SIZE - 1 } @@ -151,6 +209,16 @@ impl Pos { } } impl Default for Pos { + /// Returns a default postion at the origin (0,0) + /// + /// ``` + /// use dungeon::Pos; + /// + /// let pos = Pos::default(); + /// + /// assert_eq!(pos.xy(), (0, 0)); + /// ``` + /// fn default() -> Self { const DEFAULT: Pos = Pos::new_const::<0, 0>(); DEFAULT -- cgit v1.2.3-freya