chessfriend/board/src/square.rs

122 lines
3.3 KiB
Rust
Raw Normal View History

// Eryn Wells <eryn@erynwells.me>
use std::str::FromStr;
#[derive(Debug)]
pub struct ParseSquareError;
#[derive(Debug)]
pub struct SquareIndexOutOfBoundsError;
#[derive(Debug, Eq, PartialEq)]
pub struct Square {
pub rank: u8,
pub file: u8,
pub index: u8,
}
impl Square {
pub fn from_index(index: u8) -> Result<Square, SquareIndexOutOfBoundsError> {
if index >= 64 {
return Err(SquareIndexOutOfBoundsError);
}
Ok(Square {
rank: index / 8,
file: index % 8,
index: index,
})
}
pub fn from_algebraic_string(s: &str) -> Result<Square, ParseSquareError> {
s.parse()
}
pub fn rank_index(&self) -> usize {
self.rank.into()
}
pub fn file_index(&self) -> usize {
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 mut chars = s.chars();
let file_char = chars.next().unwrap().to_ascii_lowercase();
if !file_char.is_ascii_lowercase() {
return Err(ParseSquareError);
}
let file = (file_char as u8) - ('a' as u8);
if file >= 8 {
return Err(ParseSquareError);
}
let converted_rank_digit = chars
.next()
.unwrap()
.to_digit(10)
.and_then(|x| if x >= 1 && x <= 8 { Some(x) } else { None })
.ok_or(ParseSquareError)?;
let rank = u8::try_from(converted_rank_digit).map_err(|_| ParseSquareError)? - 1;
Ok(Square {
rank,
file,
index: rank * 8 + file,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn good_algebraic_input() {
let sq1 = Square::from_algebraic_string("a4").expect("Failed to parse 'a4' square");
assert_eq!(sq1.file, 0);
assert_eq!(sq1.rank, 3);
let sq2 = Square::from_algebraic_string("B8").expect("Failed to parse 'B8' square");
assert_eq!(sq2.file, 1);
assert_eq!(sq2.rank, 7);
let sq3 = Square::from_algebraic_string("e4").expect("Failed to parse 'B8' square");
assert_eq!(sq3.rank, 3, "Expected rank of e4 to be 3");
assert_eq!(sq3.file, 4, "Expected file of e4 to be 4");
}
#[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 ''");
}
#[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);
let sq1 = Square::from_index(28).expect("Unable to get Square from index");
assert_eq!(sq1.rank, 3);
assert_eq!(sq1.file, 4);
}
}
}