summaryrefslogtreecommitdiff
path: root/dungeon/src/pos.rs
diff options
context:
space:
mode:
authorFreya Murphy <freya@freyacat.org>2025-10-07 11:01:19 -0400
committerFreya Murphy <freya@freyacat.org>2025-10-08 19:37:15 -0400
commitb11f074ceba10af62b35b414ecaa51a8f13c6550 (patch)
treed12979f7eeb384f94b145ea763a97dcde353745b /dungeon/src/pos.rs
parentInitial commit (diff)
downloadDungeonCrawl-b11f074ceba10af62b35b414ecaa51a8f13c6550.tar.gz
DungeonCrawl-b11f074ceba10af62b35b414ecaa51a8f13c6550.tar.bz2
DungeonCrawl-b11f074ceba10af62b35b414ecaa51a8f13c6550.zip
initial baseline
Diffstat (limited to 'dungeon/src/pos.rs')
-rw-r--r--dungeon/src/pos.rs122
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,
+ }
+ }
+}