[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:
		
							parent
							
								
									341d8211ad
								
							
						
					
					
						commit
						153e21b693
					
				
					 1 changed files with 135 additions and 10 deletions
				
			
		| 
						 | 
				
			
			@ -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 file_index(&self) -> usize {
 | 
			
		||||
        self.file.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)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            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());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue