use std::str::FromStr;
use crate::{Error, BOARD_SIZE};
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
#[repr(u8)]
pub enum Rank {
First,
Second,
Third,
Fourth,
Fifth,
Sixth,
Seventh,
Eighth,
}
pub const NUM_RANKS: usize = BOARD_SIZE.1 as usize;
pub const ALL_RANKS: [Rank; NUM_RANKS] = [
Rank::First,
Rank::Second,
Rank::Third,
Rank::Fourth,
Rank::Fifth,
Rank::Sixth,
Rank::Seventh,
Rank::Eighth,
];
impl Rank {
#[inline]
pub fn new(index: usize) -> Self {
ALL_RANKS[index % NUM_RANKS]
}
#[inline]
pub fn to_index(&self) -> usize {
*self as usize
}
#[inline]
pub fn up(&self) -> Self {
Rank::new(self.to_index() + 1)
}
#[inline]
pub fn down(&self) -> Self {
let idx = self.to_index();
match idx {
0 => Rank::new(NUM_RANKS - 1),
_ => Rank::new(idx - 1),
}
}
#[inline]
pub fn distance(&self, other: Rank) -> u32 {
self.to_index().abs_diff(other.to_index()) as u32
}
#[inline]
pub fn between(&self, lower_bound: Rank, upper_bound: Rank) -> bool {
lower_bound <= *self && *self <= upper_bound
}
}
impl FromStr for Rank {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.is_empty() {
return Err(Error::InvalidRank);
}
match s.chars().next().unwrap() {
'1' => Ok(Rank::First),
'2' => Ok(Rank::Second),
'3' => Ok(Rank::Third),
'4' => Ok(Rank::Fourth),
'5' => Ok(Rank::Fifth),
'6' => Ok(Rank::Sixth),
'7' => Ok(Rank::Seventh),
'8' => Ok(Rank::Eighth),
_ => Err(Error::InvalidRank),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn to_index() {
assert_eq!(Rank::First.to_index(), 0);
assert_eq!(Rank::Second.to_index(), 1);
assert_eq!(Rank::Third.to_index(), 2);
assert_eq!(Rank::Fourth.to_index(), 3);
assert_eq!(Rank::Fifth.to_index(), 4);
assert_eq!(Rank::Sixth.to_index(), 5);
assert_eq!(Rank::Seventh.to_index(), 6);
assert_eq!(Rank::Eighth.to_index(), 7);
}
#[test]
fn up() {
assert_eq!(Rank::First.up(), Rank::Second);
assert_eq!(Rank::Second.up(), Rank::Third);
assert_eq!(Rank::Third.up(), Rank::Fourth);
assert_eq!(Rank::Fourth.up(), Rank::Fifth);
assert_eq!(Rank::Fifth.up(), Rank::Sixth);
assert_eq!(Rank::Sixth.up(), Rank::Seventh);
assert_eq!(Rank::Seventh.up(), Rank::Eighth);
assert_eq!(Rank::Eighth.up(), Rank::First);
}
#[test]
fn down() {
assert_eq!(Rank::First.down(), Rank::Eighth);
assert_eq!(Rank::Second.down(), Rank::First);
assert_eq!(Rank::Third.down(), Rank::Second);
assert_eq!(Rank::Fourth.down(), Rank::Third);
assert_eq!(Rank::Fifth.down(), Rank::Fourth);
assert_eq!(Rank::Sixth.down(), Rank::Fifth);
assert_eq!(Rank::Seventh.down(), Rank::Sixth);
assert_eq!(Rank::Eighth.down(), Rank::Seventh);
}
#[test]
fn distance() {
assert_eq!(Rank::First.distance(Rank::First), 0);
assert_eq!(Rank::First.distance(Rank::Fourth), 3);
assert_eq!(Rank::First.distance(Rank::Eighth), 7);
}
#[test]
fn between() {
assert!(Rank::First.between(Rank::First, Rank::Eighth));
assert!(Rank::Eighth.between(Rank::First, Rank::Eighth));
assert!(Rank::First.between(Rank::First, Rank::First));
assert!(!Rank::First.between(Rank::Second, Rank::Eighth));
assert!(!Rank::Eighth.between(Rank::First, Rank::Seventh));
assert!(!Rank::Second.between(Rank::Third, Rank::First));
}
#[test]
fn from_str() {
assert_eq!(Rank::from_str("1"), Ok(Rank::First));
assert_eq!(Rank::from_str("2"), Ok(Rank::Second));
assert_eq!(Rank::from_str("3"), Ok(Rank::Third));
assert_eq!(Rank::from_str("4"), Ok(Rank::Fourth));
assert_eq!(Rank::from_str("5"), Ok(Rank::Fifth));
assert_eq!(Rank::from_str("6"), Ok(Rank::Sixth));
assert_eq!(Rank::from_str("7"), Ok(Rank::Seventh));
assert_eq!(Rank::from_str("8"), Ok(Rank::Eighth));
}
#[test]
fn from_str_error() {
assert_eq!(Rank::from_str(""), Err(Error::InvalidRank));
assert_eq!(Rank::from_str(" 1"), Err(Error::InvalidRank));
assert_eq!(Rank::from_str("second"), Err(Error::InvalidRank));
}
}