diff options
Diffstat (limited to 'dungeon/src/pos.rs')
| -rw-r--r-- | dungeon/src/pos.rs | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/dungeon/src/pos.rs b/dungeon/src/pos.rs new file mode 100644 index 0000000..bfd994f --- /dev/null +++ b/dungeon/src/pos.rs @@ -0,0 +1,122 @@ +//! The `pos` module contains structures for representation an +//! entity or objects position and facing direction inside the +//! dungeon grid. + +use crate::map::MAP_SIZE; + +/// The `Direction` type represents a direction an entity +/// or any position object is facing inside the dungeon map. +/// Since the dungeon lives on a grid, there are only four +/// possible directions. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum Direction { + North, + South, + East, + West, +} + +/// The `Pos` type represents a 2D position inside the dungeon grid. +/// +/// The max size for the dungeon map is set by the `MAP_SIZE` constant +/// and therefore the x and y positions can be between 0 and `MAP_SIZE - 1`. +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Pos(u16, u16); +impl Pos { + /// Creates a new position from a given x and y position. + /// + /// Returns `None` if the position goes out of the map. + /// + /// # Examples + /// + /// ``` + /// use dungeon::Pos; + /// + /// let pos = Pos::new(0,0); + /// assert!(pos.is_some()); + /// ``` + /// + /// ``` + /// use dungeon::{Pos, MAP_SIZE}; + /// + /// let pos = Pos::new(MAP_SIZE, MAP_SIZE); + /// assert!(pos.is_none()) + /// ``` + #[must_use] + pub const fn new(x: u16, y: u16) -> Option<Self> { + if x >= MAP_SIZE || y >= MAP_SIZE { + None + } else { + Some(Self(x, y)) + } + } + + /// Returns the x and y positions of `Pos`. + /// + /// # Examples + /// + /// ``` + /// use dungeon::Pos; + /// + /// let pos = Pos::new(5,7).unwrap(); + /// let (x,y) = pos.xy(); + /// assert_eq!(x, 5); + /// assert_eq!(y, 7); + /// ``` + #[must_use] + pub const fn xy(self) -> (u16, u16) { + (self.0, self.1) + } + + /// Converts the x and y positions into an index of a continous list. + /// + /// # Examples + /// + /// ``` + /// use dungeon::{Pos, MAP_SIZE}; + /// + /// let pos = Pos::new(1,2).unwrap(); + /// let idx = pos.idx(); + /// assert_eq!(idx, 1 + 2 * MAP_SIZE as usize); + /// ``` + #[must_use] + pub const fn idx(self) -> usize { + let (x, y) = self.xy(); + let idx = x + y * MAP_SIZE; + idx as usize + } + + /// Steps `Pos` one space in the `Direction` `dir`. + /// + /// Returns `None` if the position goes out of the map. + /// + /// # Examples + /// + /// ``` + /// use dungeon::{Direction, Pos}; + /// + /// let pos = Pos::new(0, 1).unwrap(); + /// let new_pos = pos.step(Direction::North); + /// assert_eq!(new_pos, Pos::new(0, 0)); + /// ``` + /// + /// ``` + /// use dungeon::{Direction, Pos}; + /// + /// let pos = Pos::new(0, 1).unwrap(); + /// let new_pos = pos.step(Direction::West); + /// assert!(new_pos.is_none()); + /// ``` + #[must_use] + pub const fn step(self, dir: Direction) -> Option<Self> { + use Direction as D; + let (x, y) = self.xy(); + match dir { + D::North if y > 0 => Self::new(x, y - 1), + D::South => Self::new(x, y + 1), + D::East => Self::new(x + 1, y), + D::West if x > 0 => Self::new(x - 1, y), + _ => None, + } + } +} |