diff --git a/board/src/square.rs b/board/src/square.rs index 09f0d76..9f3e581 100644 --- a/board/src/square.rs +++ b/board/src/square.rs @@ -1,12 +1,13 @@ // Eryn Wells +use crate::neighbor::Direction; use std::str::FromStr; #[derive(Debug)] pub struct ParseSquareError; #[derive(Debug)] -pub struct SquareIndexOutOfBoundsError; +pub struct SquareOutOfBoundsError; #[derive(Debug, Eq, PartialEq)] pub struct Square { @@ -16,15 +17,31 @@ pub struct Square { } impl Square { - pub fn from_index(index: u8) -> Result { + pub fn from_index(index: u8) -> Result { if index >= 64 { - return Err(SquareIndexOutOfBoundsError); + return Err(SquareOutOfBoundsError); } - Ok(Square { + Ok(Square::from_index_unsafe(index)) + } + + fn from_index_unsafe(index: u8) -> Square { + Square { rank: index / 8, file: index % 8, index: index, + } + } + + pub fn from_rank_file(rank: u8, file: u8) -> Result { + if rank >= 8 || file >= 8 { + return Err(SquareOutOfBoundsError); + } + + Ok(Square { + rank, + file, + index: rank * 8 + file, }) } @@ -32,12 +49,54 @@ impl Square { s.parse() } - pub fn rank_index(&self) -> usize { - self.rank.into() - } - - pub fn file_index(&self) -> usize { - self.file.into() + pub fn neighbor(&self, direction: Direction) -> Option { + match direction { + Direction::North => Square::from_index(self.index + 8), + Direction::NorthWest => { + if self.rank < 7 { + Square::from_index(self.index + 7) + } else { + Err(SquareOutOfBoundsError) + } + } + Direction::West => { + if self.file > 0 { + Square::from_index(self.index - 1) + } else { + Err(SquareOutOfBoundsError) + } + } + Direction::SouthWest => { + if self.rank > 0 { + Square::from_index(self.index - 9) + } else { + Err(SquareOutOfBoundsError) + } + } + Direction::South => { + if self.rank > 0 { + Square::from_index(self.index - 8) + } else { + Err(SquareOutOfBoundsError) + } + } + Direction::SouthEast => { + if self.rank > 0 { + Square::from_index(self.index - 7) + } else { + Err(SquareOutOfBoundsError) + } + } + Direction::East => { + if self.file < 7 { + Square::from_index(self.index + 1) + } else { + Err(SquareOutOfBoundsError) + } + } + Direction::NorthEast => Square::from_index(self.index + 9), + } + .ok() } } @@ -117,5 +176,71 @@ mod tests { assert_eq!(sq1.file, 4); } + #[test] + fn valid_neighbors() { + let sq = Square::from_index_unsafe(28); + + assert_eq!( + sq.neighbor(Direction::North), + Some(Square::from_index_unsafe(36)) + ); + + assert_eq!( + sq.neighbor(Direction::NorthEast), + Some(Square::from_index_unsafe(37)) + ); + + assert_eq!( + sq.neighbor(Direction::East), + Some(Square::from_index_unsafe(29)) + ); + + assert_eq!( + sq.neighbor(Direction::SouthEast), + Some(Square::from_index_unsafe(21)) + ); + + assert_eq!( + sq.neighbor(Direction::South), + Some(Square::from_index_unsafe(20)) + ); + + assert_eq!( + sq.neighbor(Direction::SouthWest), + Some(Square::from_index_unsafe(19)) + ); + + assert_eq!( + sq.neighbor(Direction::West), + Some(Square::from_index_unsafe(27)) + ); + + assert_eq!( + sq.neighbor(Direction::NorthWest), + Some(Square::from_index_unsafe(35)) + ); + } + + #[test] + fn invalid_neighbors() { + let square0 = Square::from_index_unsafe(0); + assert!(square0.neighbor(Direction::West).is_none()); + assert!(square0.neighbor(Direction::SouthWest).is_none()); + assert!(square0.neighbor(Direction::South).is_none()); + + let square7 = Square::from_index_unsafe(7); + assert!(square7.neighbor(Direction::East).is_none()); + assert!(square7.neighbor(Direction::SouthEast).is_none()); + assert!(square7.neighbor(Direction::South).is_none()); + + let square56 = Square::from_index_unsafe(56); + assert!(square56.neighbor(Direction::North).is_none()); + assert!(square56.neighbor(Direction::NorthWest).is_none()); + assert!(square56.neighbor(Direction::West).is_none()); + + let square63 = Square::from_index_unsafe(63); + assert!(square63.neighbor(Direction::North).is_none()); + assert!(square63.neighbor(Direction::NorthEast).is_none()); + assert!(square63.neighbor(Direction::East).is_none()); } }