[board] Implement finding a neighbor of a square

Use the Direction enum to calculate the neighbor of a square with bounds checking.
Remove the unused rank_index() and file_index methods.
Add Square::from_rank_file and Square::from_index_unsafe to support tests.
Unify the Square*OutOfBounds error types
This commit is contained in:
Eryn Wells 2023-12-23 09:30:45 -07:00
parent 341d8211ad
commit 153e21b693

View file

@ -1,12 +1,13 @@
// Eryn Wells <eryn@erynwells.me>
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<Square, SquareIndexOutOfBoundsError> {
pub fn from_index(index: u8) -> Result<Square, SquareOutOfBoundsError> {
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<Square, SquareOutOfBoundsError> {
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 neighbor(&self, direction: Direction) -> Option<Square> {
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)
}
pub fn file_index(&self) -> usize {
self.file.into()
}
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());
}
}