2023-12-20 11:45:12 -08:00
|
|
|
// Eryn Wells <eryn@erynwells.me>
|
|
|
|
|
|
|
|
use std::str::FromStr;
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
2023-12-21 08:15:51 -08:00
|
|
|
pub struct ParseSquareError;
|
2023-12-20 11:45:12 -08:00
|
|
|
|
|
|
|
#[derive(Debug)]
|
2023-12-21 08:15:51 -08:00
|
|
|
pub struct SquareIndexOutOfBoundsError;
|
2023-12-20 11:45:12 -08:00
|
|
|
|
|
|
|
#[derive(Debug, Eq, PartialEq)]
|
2023-12-21 08:15:51 -08:00
|
|
|
pub struct Square {
|
|
|
|
pub rank: u8,
|
|
|
|
pub file: u8,
|
|
|
|
pub index: u8,
|
2023-12-20 11:45:12 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Square {
|
2023-12-21 08:15:51 -08:00
|
|
|
pub fn from_index(index: u8) -> Result<Square, SquareIndexOutOfBoundsError> {
|
2023-12-20 11:45:12 -08:00
|
|
|
if index >= 64 {
|
|
|
|
return Err(SquareIndexOutOfBoundsError);
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(Square {
|
|
|
|
rank: index / 8,
|
|
|
|
file: index % 8,
|
2023-12-21 08:15:51 -08:00
|
|
|
index: index,
|
2023-12-20 11:45:12 -08:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2023-12-21 08:15:51 -08:00
|
|
|
pub fn from_algebraic_string(s: &str) -> Result<Square, ParseSquareError> {
|
2023-12-20 11:45:12 -08:00
|
|
|
s.parse()
|
|
|
|
}
|
|
|
|
|
2023-12-21 08:15:51 -08:00
|
|
|
pub fn rank_index(&self) -> usize {
|
2023-12-20 11:45:12 -08:00
|
|
|
self.rank.into()
|
|
|
|
}
|
|
|
|
|
2023-12-21 08:15:51 -08:00
|
|
|
pub fn file_index(&self) -> usize {
|
2023-12-20 11:45:12 -08:00
|
|
|
self.file.into()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl FromStr for Square {
|
|
|
|
type Err = ParseSquareError;
|
|
|
|
|
|
|
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
|
|
if !s.is_ascii() || s.len() != 2 {
|
|
|
|
return Err(ParseSquareError);
|
|
|
|
}
|
|
|
|
|
|
|
|
let chars: Vec<char> = s.chars().collect();
|
|
|
|
let rank_char = chars[0].to_ascii_lowercase();
|
|
|
|
if !rank_char.is_ascii_lowercase() {
|
|
|
|
return Err(ParseSquareError);
|
|
|
|
}
|
|
|
|
|
2023-12-21 08:15:51 -08:00
|
|
|
let rank = (rank_char as u8) - ('a' as u8);
|
|
|
|
if rank >= 8 {
|
2023-12-20 11:45:12 -08:00
|
|
|
return Err(ParseSquareError);
|
|
|
|
}
|
|
|
|
|
2023-12-21 08:15:51 -08:00
|
|
|
let converted_file_digit = chars[1]
|
|
|
|
.to_digit(10)
|
|
|
|
.and_then(|x| if x != 0 { Some(x) } else { None })
|
|
|
|
.ok_or(ParseSquareError)?;
|
|
|
|
let file = u8::try_from(converted_file_digit).map_err(|_| ParseSquareError)? - 1;
|
2023-12-20 11:45:12 -08:00
|
|
|
|
|
|
|
Ok(Square {
|
2023-12-21 08:15:51 -08:00
|
|
|
rank: rank,
|
|
|
|
file: file,
|
|
|
|
index: rank * 8 + file,
|
2023-12-20 11:45:12 -08:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[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]
|
2023-12-21 08:15:51 -08:00
|
|
|
fn good_algebraic_input() {
|
2023-12-20 11:45:12 -08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2023-12-21 08:15:51 -08:00
|
|
|
#[test]
|
|
|
|
fn bad_algebraic_input() {
|
|
|
|
Square::from_algebraic_string("a0").expect_err("Got valid Square for 'a0'");
|
|
|
|
Square::from_algebraic_string("j3").expect_err("Got valid Square for 'j3'");
|
|
|
|
Square::from_algebraic_string("a11").expect_err("Got valid Square for 'a11'");
|
|
|
|
Square::from_algebraic_string("b-1").expect_err("Got valid Square for 'b-1'");
|
|
|
|
Square::from_algebraic_string("a 1").expect_err("Got valid Square for 'a 1'");
|
|
|
|
Square::from_algebraic_string("").expect_err("Got valid Square for ''");
|
|
|
|
}
|
|
|
|
|
2023-12-20 11:45:12 -08:00
|
|
|
#[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);
|
|
|
|
}
|
|
|
|
}
|