diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e86b15e..38306c40 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ Unreleased ========== +### Additions: + +- Add function `Direction::iter` which returns an iterator over all the `Direction` enum values +- Add function `RoomXY::neighbors` which returns an iterator over all the valid neighbors of + a given `RoomXY` position + 0.21.0 (2024-05-14) =================== diff --git a/src/constants/small_enums.rs b/src/constants/small_enums.rs index 59d7f1f1..e4d9709d 100644 --- a/src/constants/small_enums.rs +++ b/src/constants/small_enums.rs @@ -1,5 +1,5 @@ //! Various constants translated as small enums. -use std::{borrow::Cow, fmt}; +use std::{borrow::Cow, fmt, slice::Iter}; use enum_iterator::Sequence; use js_sys::JsString; @@ -193,6 +193,48 @@ impl Direction { pub fn rot_ccw(self) -> Self { self.multi_rot(-1) } + + /// Returns an iterator over all 8 direction constants, in clockwise order. + /// + /// Example usage: + /// + /// ``` + /// use screeps::Direction; + /// + /// for dir in Direction::iter() { + /// println!("{:?}", dir); + /// } + /// ``` + /// + /// Alternatively: + /// ``` + /// use screeps::Direction; + /// let mut dirs = Direction::iter(); + /// + /// assert_eq!(dirs.next(), Some(&Direction::Top)); + /// assert_eq!(dirs.next(), Some(&Direction::TopRight)); + /// assert_eq!(dirs.next(), Some(&Direction::Right)); + /// assert_eq!(dirs.next(), Some(&Direction::BottomRight)); + /// assert_eq!(dirs.next(), Some(&Direction::Bottom)); + /// assert_eq!(dirs.next(), Some(&Direction::BottomLeft)); + /// assert_eq!(dirs.next(), Some(&Direction::Left)); + /// assert_eq!(dirs.next(), Some(&Direction::TopLeft)); + /// assert_eq!(dirs.next(), None); + /// ``` + pub fn iter() -> Iter<'static, Direction> { + use crate::Direction::*; + static DIRECTIONS: [Direction; 8] = [ + Top, + TopRight, + Right, + BottomRight, + Bottom, + BottomLeft, + Left, + TopLeft, + ]; + DIRECTIONS.iter() + } } impl JsCollectionIntoValue for Direction { diff --git a/src/local/room_xy.rs b/src/local/room_xy.rs index 86d77dbf..368c9156 100644 --- a/src/local/room_xy.rs +++ b/src/local/room_xy.rs @@ -184,6 +184,49 @@ impl RoomXY { let (dx, dy) = rhs.into(); self.saturating_add((dx as i8, dy as i8)) } + + /// Get all the valid neighbors of a given `RoomXY`. + /// + /// Example usage: + /// + /// ``` + /// use screeps::local::RoomXY; + /// + /// let zero_zero = unsafe { RoomXY::unchecked_new(0, 0) }; + /// let zero_one = unsafe { RoomXY::unchecked_new(0, 1) }; + /// let one_zero = unsafe { RoomXY::unchecked_new(1, 0) }; + /// let one_one = unsafe { RoomXY::unchecked_new(1, 1) }; + /// + /// let zero_two = unsafe { RoomXY::unchecked_new(0, 2) }; + /// let one_two = unsafe { RoomXY::unchecked_new(1, 2) }; + /// let two_two = unsafe { RoomXY::unchecked_new(2, 2) }; + /// let two_one = unsafe { RoomXY::unchecked_new(2, 1) }; + /// let two_zero = unsafe { RoomXY::unchecked_new(2, 0) }; + /// + /// let zero_zero_neighbors = zero_zero.neighbors(); + /// + /// assert_eq!(zero_zero_neighbors.len(), 3); + /// assert!(zero_zero_neighbors.contains(&zero_one)); + /// assert!(zero_zero_neighbors.contains(&one_one)); + /// assert!(zero_zero_neighbors.contains(&one_zero)); + /// + /// let one_one_neighbors = one_one.neighbors(); + /// + /// assert_eq!(one_one_neighbors.len(), 8); + /// assert!(one_one_neighbors.contains(&zero_zero)); + /// assert!(one_one_neighbors.contains(&zero_one)); + /// assert!(one_one_neighbors.contains(&one_zero)); + /// assert!(one_one_neighbors.contains(&zero_two)); + /// assert!(one_one_neighbors.contains(&one_two)); + /// assert!(one_one_neighbors.contains(&two_two)); + /// assert!(one_one_neighbors.contains(&two_one)); + /// assert!(one_one_neighbors.contains(&two_zero)); + /// ``` + pub fn neighbors(self) -> Vec { + Direction::iter() + .filter_map(|dir| self.checked_add_direction(*dir)) + .collect() + } } impl fmt::Display for RoomXY {