2022-07-18 17:27:09 +02:00
|
|
|
use super::{Direction, Rank};
|
2022-07-18 13:22:04 +02:00
|
|
|
|
|
|
|
/// An enum representing the color of a player.
|
|
|
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
|
|
pub enum Color {
|
|
|
|
White,
|
|
|
|
Black,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Color {
|
2022-07-20 19:19:38 +02:00
|
|
|
/// The number of [Color] variants.
|
|
|
|
pub const NUM_VARIANTS: usize = 2;
|
|
|
|
|
2022-07-23 15:32:56 +02:00
|
|
|
const ALL: [Self; Self::NUM_VARIANTS] = [Self::White, Self::Black];
|
|
|
|
|
|
|
|
/// Iterate over all colors in order.
|
|
|
|
pub fn iter() -> impl Iterator<Item = Self> {
|
|
|
|
Self::ALL.iter().cloned()
|
|
|
|
}
|
|
|
|
|
2022-07-20 19:07:37 +02:00
|
|
|
/// Convert from a color index into a [Color] type.
|
2024-04-03 21:32:59 +02:00
|
|
|
///
|
|
|
|
/// # Panics
|
|
|
|
///
|
|
|
|
/// Panics if the index is out of bounds.
|
2022-07-18 13:22:04 +02:00
|
|
|
#[inline(always)]
|
|
|
|
pub fn from_index(index: usize) -> Self {
|
2024-04-03 21:44:15 +02:00
|
|
|
Self::try_from_index(index).expect("index out of bouds")
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Convert from a color index into a [Color] type. Returns [None] if the index is out of
|
|
|
|
/// bounds.
|
|
|
|
pub fn try_from_index(index: usize) -> Option<Self> {
|
|
|
|
if index < Self::NUM_VARIANTS {
|
|
|
|
// SAFETY: we know the value is in-bounds
|
|
|
|
Some(unsafe { Self::from_index_unchecked(index) })
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
2022-07-18 13:22:04 +02:00
|
|
|
}
|
|
|
|
|
2022-07-20 19:07:37 +02:00
|
|
|
/// Convert from a color index into a [Color] type, no bounds checking.
|
2022-07-18 13:22:04 +02:00
|
|
|
///
|
|
|
|
/// # Safety
|
|
|
|
///
|
|
|
|
/// Should only be called with values that can be output by [Color::index()].
|
|
|
|
#[inline(always)]
|
|
|
|
pub unsafe fn from_index_unchecked(index: usize) -> Self {
|
|
|
|
std::mem::transmute(index as u8)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Return the index of a given [Color].
|
|
|
|
#[inline(always)]
|
|
|
|
pub fn index(self) -> usize {
|
|
|
|
self as usize
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Return the first [Rank] for pieces of the given [Color], where its pieces start.
|
|
|
|
#[inline(always)]
|
|
|
|
pub fn first_rank(self) -> Rank {
|
|
|
|
match self {
|
|
|
|
Self::White => Rank::First,
|
|
|
|
Self::Black => Rank::Eighth,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Return the second [Rank] for pieces of the given [Color], where its pawns start.
|
|
|
|
#[inline(always)]
|
|
|
|
pub fn second_rank(self) -> Rank {
|
|
|
|
match self {
|
|
|
|
Self::White => Rank::Second,
|
|
|
|
Self::Black => Rank::Seventh,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-27 23:38:51 +02:00
|
|
|
/// Return the third [Rank] for pieces of the given [Color], where its pawns move to after a
|
|
|
|
/// one-square move on the start position.
|
|
|
|
#[inline(always)]
|
|
|
|
pub fn third_rank(self) -> Rank {
|
|
|
|
match self {
|
|
|
|
Self::White => Rank::Third,
|
|
|
|
Self::Black => Rank::Sixth,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-18 13:22:04 +02:00
|
|
|
/// Return the fourth [Rank] for pieces of the given [Color], where its pawns move to after a
|
|
|
|
/// two-square move.
|
|
|
|
#[inline(always)]
|
|
|
|
pub fn fourth_rank(self) -> Rank {
|
|
|
|
match self {
|
|
|
|
Self::White => Rank::Fourth,
|
|
|
|
Self::Black => Rank::Fifth,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Return the seventh [Rank] for pieces of the given [Color], which is the rank before a pawn
|
|
|
|
/// gets promoted.
|
|
|
|
#[inline(always)]
|
|
|
|
pub fn seventh_rank(self) -> Rank {
|
|
|
|
match self {
|
|
|
|
Self::White => Rank::Seventh,
|
|
|
|
Self::Black => Rank::Second,
|
|
|
|
}
|
|
|
|
}
|
2022-07-18 17:27:09 +02:00
|
|
|
|
|
|
|
/// Which way do pawns advance for this color.
|
|
|
|
#[inline(always)]
|
|
|
|
pub fn forward_direction(self) -> Direction {
|
|
|
|
match self {
|
|
|
|
Self::White => Direction::North,
|
|
|
|
Self::Black => Direction::South,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Which way do the opponent's pawns advance for this color.
|
|
|
|
#[inline(always)]
|
|
|
|
pub fn backward_direction(self) -> Direction {
|
|
|
|
(!self).forward_direction()
|
|
|
|
}
|
2022-07-18 13:22:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
impl std::ops::Not for Color {
|
|
|
|
type Output = Color;
|
|
|
|
|
|
|
|
fn not(self) -> Self::Output {
|
|
|
|
match self {
|
|
|
|
Self::White => Self::Black,
|
|
|
|
Self::Black => Self::White,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn from_index() {
|
|
|
|
assert_eq!(Color::from_index(0), Color::White);
|
|
|
|
assert_eq!(Color::from_index(1), Color::Black);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn index() {
|
|
|
|
assert_eq!(Color::White.index(), 0);
|
|
|
|
assert_eq!(Color::Black.index(), 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn not() {
|
|
|
|
assert_eq!(!Color::White, Color::Black);
|
|
|
|
assert_eq!(!Color::Black, Color::White);
|
|
|
|
}
|
|
|
|
}
|