[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