// Eryn Wells use std::str::FromStr; #[derive(Debug)] struct ParseSquareError; #[derive(Debug)] struct SquareIndexOutOfBoundsError; #[derive(Debug, Eq, PartialEq)] struct Square { rank: u8, file: u8, } impl Square { fn from_index(index: u8) -> Result { if index >= 64 { return Err(SquareIndexOutOfBoundsError); } Ok(Square { rank: index / 8, file: index % 8, }) } fn from_algebraic_string(s: &str) -> Result { s.parse() } fn rank_index(&self) -> usize { self.rank.into() } fn file_index(&self) -> usize { self.file.into() } } impl FromStr for Square { type Err = ParseSquareError; fn from_str(s: &str) -> Result { if !s.is_ascii() || s.len() != 2 { return Err(ParseSquareError); } let chars: Vec = s.chars().collect(); let rank_char = chars[0].to_ascii_lowercase(); if !rank_char.is_ascii_lowercase() { return Err(ParseSquareError); } let rank = (rank_char as u8) - ('a' as u8) + 1; if rank < 1 || rank > 8 { return Err(ParseSquareError); } let file = u8::try_from(chars[1].to_digit(10).ok_or(ParseSquareError)?) .map_err(|_| ParseSquareError)?; Ok(Square { rank: rank - 1, file: file - 1, }) } } #[cfg(test)] mod tests { use super::*; #[test] fn indexes() { let sq1 = Square::from_algebraic_string("c5").expect("Failed to parse 'c5' square"); assert_eq!(sq1.rank_index(), 2, "Rank doesn't match"); assert_eq!(sq1.file_index(), 4, "File doesn't match"); let sq2 = Square::from_algebraic_string("b2").expect("Failed to parse 'b2' square"); assert_eq!(sq2.rank_index(), 1, "Rank doesn't match"); assert_eq!(sq2.file_index(), 1, "File doesn't match"); } #[test] fn parse_good_input() { let sq1 = Square::from_algebraic_string("a4").expect("Failed to parse 'a4' square"); assert_eq!(sq1.rank, 0); assert_eq!(sq1.file, 3); let sq2 = Square::from_algebraic_string("B8").expect("Failed to parse 'B8' square"); assert_eq!(sq2.rank, 1); assert_eq!(sq2.file, 7); } #[test] fn from_index() { let sq1 = Square::from_index(4).expect("Unable to get Square from index"); assert_eq!(sq1.rank, 0); assert_eq!(sq1.file, 4); } }