use super::Color;
#[repr(u8)]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum GameResult {
BlackWin = 0,
WhiteWin = 1,
DrawByRepetition = 2,
Error = 3,
BlackWinByDeclaration = 4,
WhiteWinByDeclaration = 5,
DrawByMaxPlies = 6,
Invalid = 7,
BlackWinByForfeit = 8,
WhiteWinByForfeit = 9,
DrawByImpasse = 10,
Paused = 11,
BlackWinByIllegalMove = 12,
WhiteWinByIllegalMove = 13,
BlackWinByTimeout = 16,
WhiteWinByTimeout = 17,
BlackWinByTryRule = 20,
WhiteWinByTryRule = 21,
}
const _: () = {
assert!(core::mem::size_of::<GameResult>() == 1);
assert!(core::mem::align_of::<GameResult>() == 1);
};
impl GameResult {
#[must_use]
pub const fn is_black_win(self) -> bool {
matches!(
self,
Self::BlackWin
| Self::BlackWinByDeclaration
| Self::BlackWinByForfeit
| Self::BlackWinByIllegalMove
| Self::BlackWinByTryRule
| Self::BlackWinByTimeout
)
}
#[must_use]
pub const fn is_white_win(self) -> bool {
matches!(
self,
Self::WhiteWin
| Self::WhiteWinByDeclaration
| Self::WhiteWinByForfeit
| Self::WhiteWinByIllegalMove
| Self::WhiteWinByTryRule
| Self::WhiteWinByTimeout
)
}
#[must_use]
pub const fn is_draw(self) -> bool {
matches!(self, Self::DrawByRepetition | Self::DrawByMaxPlies | Self::DrawByImpasse)
}
#[must_use]
pub const fn is_win(self) -> bool {
self.is_black_win() || self.is_white_win()
}
#[must_use]
pub const fn is_win_by_declaration(self) -> bool {
matches!(self, Self::BlackWinByDeclaration | Self::WhiteWinByDeclaration)
}
#[must_use]
pub const fn is_win_by_try_rule(self) -> bool {
matches!(self, Self::BlackWinByTryRule | Self::WhiteWinByTryRule)
}
#[must_use]
pub const fn winner_color(self) -> Option<Color> {
if self.is_black_win() {
Some(Color::BLACK)
} else if self.is_white_win() {
Some(Color::WHITE)
} else {
None
}
}
#[must_use]
pub fn to_score(self, color: Color) -> f32 {
if color == Color::BLACK {
if self.is_black_win() {
return 1.0;
}
if self.is_white_win() {
return 0.0;
}
} else if color == Color::WHITE {
if self.is_white_win() {
return 1.0;
}
if self.is_black_win() {
return 0.0;
}
}
if self.is_draw() {
return 0.5;
}
-1.0
}
#[must_use]
pub const fn win_from_color(color: Color) -> Self {
if color.raw() == Color::BLACK.raw() { Self::BlackWin } else { Self::WhiteWin }
}
#[must_use]
pub const fn win_by_declaration_from_color(color: Color) -> Self {
if color.raw() == Color::BLACK.raw() {
Self::BlackWinByDeclaration
} else {
Self::WhiteWinByDeclaration
}
}
#[must_use]
pub const fn win_by_forfeit_from_color(color: Color) -> Self {
if color.raw() == Color::BLACK.raw() {
Self::BlackWinByForfeit
} else {
Self::WhiteWinByForfeit
}
}
#[must_use]
pub const fn win_by_illegal_move_from_color(color: Color) -> Self {
if color.raw() == Color::BLACK.raw() {
Self::BlackWinByIllegalMove
} else {
Self::WhiteWinByIllegalMove
}
}
#[must_use]
pub const fn win_by_timeout_from_color(color: Color) -> Self {
if color.raw() == Color::BLACK.raw() {
Self::BlackWinByTimeout
} else {
Self::WhiteWinByTimeout
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_game_result_winner() {
assert_eq!(GameResult::BlackWin.winner_color(), Some(Color::BLACK));
assert_eq!(GameResult::WhiteWinByTimeout.winner_color(), Some(Color::WHITE));
assert_eq!(GameResult::DrawByRepetition.winner_color(), None);
}
#[test]
fn test_game_result_flags() {
assert!(GameResult::BlackWin.is_black_win());
assert!(GameResult::WhiteWin.is_white_win());
assert!(GameResult::DrawByMaxPlies.is_draw());
assert!(!GameResult::Paused.is_draw());
assert!(GameResult::BlackWinByDeclaration.is_win_by_declaration());
assert!(!GameResult::Paused.is_win());
}
#[test]
fn test_game_result_score() {
assert_eq!(GameResult::BlackWin.to_score(Color::BLACK), 1.0);
assert_eq!(GameResult::BlackWin.to_score(Color::WHITE), 0.0);
assert_eq!(GameResult::DrawByRepetition.to_score(Color::BLACK), 0.5);
assert_eq!(GameResult::Paused.to_score(Color::BLACK), -1.0);
}
#[test]
fn test_game_result_numeric_values() {
assert_eq!(GameResult::DrawByImpasse as u8, 10);
assert_eq!(GameResult::Paused as u8, 11);
assert_eq!(GameResult::BlackWinByTryRule as u8, 20);
assert_eq!(GameResult::WhiteWinByTryRule as u8, 21);
}
}