use std::num::NonZeroUsize;
use shakmaty::Color;
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct MoveNumber(pub usize);
impl MoveNumber {
pub const MIN: Self = Self(0);
pub const fn from_color_and_number(color: Color, number: NonZeroUsize) -> Self {
#[allow(clippy::arithmetic_side_effects)]
match color {
Color::White => Self((number.get() - 1) * 2),
Color::Black => Self(((number.get() - 1) * 2) + 1)
}
}
pub const fn color(self) -> Color {
if self.0 % 2 == 0 {
Color::White
} else {
Color::Black
}
}
#[allow(clippy::missing_panics_doc)] pub const fn number(self) -> NonZeroUsize {
#[allow(clippy::arithmetic_side_effects)]
#[allow(clippy::unwrap_used)]
NonZeroUsize::new(1 + (self.0 / 2)).unwrap()
}
pub const fn white_move_count(self) -> usize {
#[allow(clippy::arithmetic_side_effects)]
{
(self.0.saturating_add(1)) / 2
}
}
pub const fn black_move_count(self) -> usize {
self.0 / 2
}
}
#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod tests {
use super::*;
use pretty_assertions::assert_eq;
use test_case::test_case;
#[test_case(MoveNumber::from_color_and_number(Color::White, NonZeroUsize::new(1).unwrap()), 0)]
#[test_case(MoveNumber::from_color_and_number(Color::Black, NonZeroUsize::new(1).unwrap()), 1)]
#[test_case(MoveNumber::from_color_and_number(Color::White, NonZeroUsize::new(2).unwrap()), 2)]
#[test_case(MoveNumber::from_color_and_number(Color::Black, NonZeroUsize::new(2).unwrap()), 3)]
#[test_case(MoveNumber::from_color_and_number(Color::White, NonZeroUsize::new(3).unwrap()), 4)]
#[test_case(MoveNumber::from_color_and_number(Color::Black, NonZeroUsize::new(3).unwrap()), 5)]
fn from_color_and_number(move_number: MoveNumber, correct_index: usize) {
assert_eq!(move_number.0, correct_index);
}
#[test_case(MoveNumber::from_color_and_number(Color::White, NonZeroUsize::new(1).unwrap()), Color::White)]
#[test_case(MoveNumber::from_color_and_number(Color::Black, NonZeroUsize::new(1).unwrap()), Color::Black)]
#[test_case(MoveNumber::from_color_and_number(Color::White, NonZeroUsize::new(2).unwrap()), Color::White)]
#[test_case(MoveNumber::from_color_and_number(Color::Black, NonZeroUsize::new(2).unwrap()), Color::Black)]
fn color(move_number: MoveNumber, correct_color: Color) {
assert_eq!(move_number.color(), correct_color);
}
#[test_case(MoveNumber::from_color_and_number(Color::White, NonZeroUsize::new(1).unwrap()), NonZeroUsize::new(1).unwrap())]
#[test_case(MoveNumber::from_color_and_number(Color::Black, NonZeroUsize::new(1).unwrap()), NonZeroUsize::new(1).unwrap())]
#[test_case(MoveNumber::from_color_and_number(Color::White, NonZeroUsize::new(2).unwrap()), NonZeroUsize::new(2).unwrap())]
#[test_case(MoveNumber::from_color_and_number(Color::Black, NonZeroUsize::new(2).unwrap()), NonZeroUsize::new(2).unwrap())]
#[test_case(MoveNumber::from_color_and_number(Color::White, NonZeroUsize::new(3).unwrap()), NonZeroUsize::new(3).unwrap())]
#[test_case(MoveNumber::from_color_and_number(Color::Black, NonZeroUsize::new(3).unwrap()), NonZeroUsize::new(3).unwrap())]
#[test_case(MoveNumber::from_color_and_number(Color::White, NonZeroUsize::new(4).unwrap()), NonZeroUsize::new(4).unwrap())]
#[test_case(MoveNumber::from_color_and_number(Color::Black, NonZeroUsize::new(4).unwrap()), NonZeroUsize::new(4).unwrap())]
#[test_case(MoveNumber::from_color_and_number(Color::White, NonZeroUsize::new(5).unwrap()), NonZeroUsize::new(5).unwrap())]
#[test_case(MoveNumber::from_color_and_number(Color::Black, NonZeroUsize::new(5).unwrap()), NonZeroUsize::new(5).unwrap())]
#[test_case(MoveNumber::from_color_and_number(Color::White, NonZeroUsize::new(6).unwrap()), NonZeroUsize::new(6).unwrap())]
#[test_case(MoveNumber::from_color_and_number(Color::Black, NonZeroUsize::new(6).unwrap()), NonZeroUsize::new(6).unwrap())]
fn number(move_number: MoveNumber, correct_number: NonZeroUsize) {
assert_eq!(move_number.number(), correct_number);
}
#[test_case(MoveNumber(0), 0)]
#[test_case(MoveNumber(1), 1)]
#[test_case(MoveNumber(2), 1)]
#[test_case(MoveNumber(3), 2)]
#[test_case(MoveNumber(4), 2)]
#[test_case(MoveNumber(5), 3)]
fn white_move_count(move_number: MoveNumber, correct_white_move_count: usize) {
assert_eq!(move_number.white_move_count(), correct_white_move_count);
}
#[test_case(MoveNumber(0), 0)]
#[test_case(MoveNumber(1), 0)]
#[test_case(MoveNumber(2), 1)]
#[test_case(MoveNumber(3), 1)]
#[test_case(MoveNumber(4), 2)]
#[test_case(MoveNumber(5), 2)]
fn black_move_count(move_number: MoveNumber, correct_black_move_count: usize) {
assert_eq!(move_number.black_move_count(), correct_black_move_count);
}
}