Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor board, cleanup #17

Merged
merged 6 commits into from
Feb 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -109,11 +109,12 @@ jobs:
run: pnpm coverage:affected --nx-bail --base=$NX_BASE --head=$NX_HEAD --exclude gui

- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v3
if: matrix.platform == 'ubuntu-latest'
env:
uses: codecov/codecov-action@v4
with:
fail_ci_if_error: true
verbose: true
token: ${{ secrets.CODECOV_TOKEN }}
slug: ${{ github.repository }}

cleanup:
name: Cleanup
Expand Down
23 changes: 23 additions & 0 deletions libs/api/src/color.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Color {
White = 0,
Black = 1,
}

impl Color {
/// Returns `true` if the color is [`White`].
///
/// [`White`]: Color::White
#[must_use]
pub fn is_white(&self) -> bool {
matches!(self, Self::White)
}

/// Returns `true` if the color is [`Black`].
///
/// [`Black`]: Color::Black
#[must_use]
pub fn is_black(&self) -> bool {
matches!(self, Self::Black)
}
}
2 changes: 2 additions & 0 deletions libs/api/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#![feature(variant_count)]
mod color;
mod controller;
mod fen;
mod game;
Expand All @@ -8,6 +9,7 @@ mod square;
mod state;
mod view;

pub use color::Color;
pub use controller::Controller;
pub use fen::ForsythEdwardsNotationExt;
pub use game::GameExt;
Expand Down
27 changes: 21 additions & 6 deletions libs/board/src/fen/active_color.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
use api::Color;
use std::fmt::{Debug, Display};

pub const NUM_COLORS: usize = 2;
pub const COLORS: [u8; NUM_COLORS] = [b'w', b'b'];

#[derive(PartialEq, Eq, Clone, Copy)]
pub struct ActiveColor {
color: u8,
Expand All @@ -14,6 +12,9 @@ pub enum ActiveColorError {
}

impl ActiveColor {
pub const COLORS: [u8; Self::NUM_COLORS] = [b'w', b'b'];
pub const NUM_COLORS: usize = 2;

pub fn new() -> Self {
Self::default()
}
Expand All @@ -25,7 +26,7 @@ impl ActiveColor {

impl Default for ActiveColor {
fn default() -> Self {
Self { color: COLORS[0] }
Self { color: Self::COLORS[0] }
}
}

Expand Down Expand Up @@ -58,11 +59,15 @@ pub trait ActiveColorExt {

impl ActiveColorExt for ActiveColor {
fn switch(&mut self) {
self.color = if self.color == COLORS[0] { COLORS[1] } else { COLORS[0] }
self.color = if self.color == Self::COLORS[0] {
Self::COLORS[1]
} else {
Self::COLORS[0]
}
}

fn is_white(&self) -> bool {
self.color == COLORS[0]
self.color == Self::COLORS[0]
}
}

Expand All @@ -78,6 +83,16 @@ impl Debug for ActiveColor {
}
}

impl From<Color> for ActiveColor {
fn from(value: Color) -> Self {
if value.is_white() {
Self { color: b'w' }
} else {
Self { color: b'b' }
}
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
54 changes: 29 additions & 25 deletions libs/board/src/fen/castling.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
use std::fmt::{Debug, Display};

const WHITE_KING_CASTLE: u8 = 0b1000;
const WHITE_QUEEN_CASTLE: u8 = 0b0100;
const BLACK_KING_CASTLE: u8 = 0b0010;
const BLACK_QUEEN_CASTLE: u8 = 0b0001;

#[derive(PartialEq, Eq, Clone, Copy)]
pub struct Castling {
rights: u8,
Expand All @@ -17,11 +12,16 @@ pub enum CastlingError {

impl Default for Castling {
fn default() -> Self {
Self::new(WHITE_KING_CASTLE | WHITE_QUEEN_CASTLE | BLACK_KING_CASTLE | BLACK_QUEEN_CASTLE)
Self::new(Self::WHITE_KING_CASTLE | Self::WHITE_QUEEN_CASTLE | Self::BLACK_KING_CASTLE | Self::BLACK_QUEEN_CASTLE)
}
}

impl Castling {
pub const BLACK_KING_CASTLE: u8 = 0b0010;
pub const BLACK_QUEEN_CASTLE: u8 = 0b0001;
pub const WHITE_KING_CASTLE: u8 = 0b1000;
pub const WHITE_QUEEN_CASTLE: u8 = 0b0100;

pub fn new(rights: u8) -> Self {
Self { rights }
}
Expand All @@ -31,19 +31,19 @@ impl Castling {
}

pub fn has_white_king_castle(&self) -> bool {
self.rights & WHITE_KING_CASTLE != 0
self.rights & Self::WHITE_KING_CASTLE != 0
}

pub fn has_white_queen_castle(&self) -> bool {
self.rights & WHITE_QUEEN_CASTLE != 0
self.rights & Self::WHITE_QUEEN_CASTLE != 0
}

pub fn has_black_king_castle(&self) -> bool {
self.rights & BLACK_KING_CASTLE != 0
self.rights & Self::BLACK_KING_CASTLE != 0
}

pub fn has_black_queen_castle(&self) -> bool {
self.rights & BLACK_QUEEN_CASTLE != 0
self.rights & Self::BLACK_QUEEN_CASTLE != 0
}

pub fn has_no_castle_rights(&self) -> bool {
Expand All @@ -61,10 +61,10 @@ impl TryFrom<&str> for Castling {
}
for char in value.chars() {
match char {
'K' => rights |= WHITE_KING_CASTLE,
'Q' => rights |= WHITE_QUEEN_CASTLE,
'k' => rights |= BLACK_KING_CASTLE,
'q' => rights |= BLACK_QUEEN_CASTLE,
'K' => rights |= Self::WHITE_KING_CASTLE,
'Q' => rights |= Self::WHITE_QUEEN_CASTLE,
'k' => rights |= Self::BLACK_KING_CASTLE,
'q' => rights |= Self::BLACK_QUEEN_CASTLE,
'-' => return Ok(Castling::default()),
_ => return Err(Self::Error::Invalid),
}
Expand Down Expand Up @@ -117,13 +117,13 @@ mod tests {
let castling = Castling::default();
assert_eq!(
castling.rights(),
WHITE_KING_CASTLE | WHITE_QUEEN_CASTLE | BLACK_KING_CASTLE | BLACK_QUEEN_CASTLE
Castling::WHITE_KING_CASTLE | Castling::WHITE_QUEEN_CASTLE | Castling::BLACK_KING_CASTLE | Castling::BLACK_QUEEN_CASTLE
);
}

#[test]
fn test_custom_castling_rights() {
let custom_rights = WHITE_KING_CASTLE | BLACK_QUEEN_CASTLE;
let custom_rights = Castling::WHITE_KING_CASTLE | Castling::BLACK_QUEEN_CASTLE;
let castling = Castling::new(custom_rights);
assert_eq!(castling.rights(), custom_rights);
}
Expand All @@ -132,37 +132,41 @@ mod tests {
fn test_has_white_king_castle() {
let castling = Castling::default();
assert!(castling.has_white_king_castle());
let castling_without_white_king = Castling::new(WHITE_QUEEN_CASTLE | BLACK_KING_CASTLE | BLACK_QUEEN_CASTLE);
let castling_without_white_king =
Castling::new(Castling::WHITE_QUEEN_CASTLE | Castling::BLACK_KING_CASTLE | Castling::BLACK_QUEEN_CASTLE);
assert!(!castling_without_white_king.has_white_king_castle());
}

#[test]
fn test_has_white_queen_castle() {
let castling = Castling::default();
assert!(castling.has_white_queen_castle());
let castling_without_white_queen = Castling::new(WHITE_KING_CASTLE | BLACK_KING_CASTLE | BLACK_QUEEN_CASTLE);
let castling_without_white_queen =
Castling::new(Castling::WHITE_KING_CASTLE | Castling::BLACK_KING_CASTLE | Castling::BLACK_QUEEN_CASTLE);
assert!(!castling_without_white_queen.has_white_queen_castle());
}

#[test]
fn test_has_black_king_castle() {
let castling = Castling::default();
assert!(castling.has_black_king_castle());
let castling_without_black_king = Castling::new(WHITE_KING_CASTLE | WHITE_QUEEN_CASTLE | BLACK_QUEEN_CASTLE);
let castling_without_black_king =
Castling::new(Castling::WHITE_KING_CASTLE | Castling::WHITE_QUEEN_CASTLE | Castling::BLACK_QUEEN_CASTLE);
assert!(!castling_without_black_king.has_black_king_castle());
}

#[test]
fn test_has_black_queen_castle() {
let castling = Castling::default();
assert!(castling.has_black_queen_castle());
let castling_without_black_queen = Castling::new(WHITE_KING_CASTLE | WHITE_QUEEN_CASTLE | BLACK_KING_CASTLE);
let castling_without_black_queen =
Castling::new(Castling::WHITE_KING_CASTLE | Castling::WHITE_QUEEN_CASTLE | Castling::BLACK_KING_CASTLE);
assert!(!castling_without_black_queen.has_black_queen_castle());
}

#[test]
fn test_display_with_castling_rights() {
let castling = Castling::new(WHITE_KING_CASTLE | BLACK_QUEEN_CASTLE);
let castling = Castling::new(Castling::WHITE_KING_CASTLE | Castling::BLACK_QUEEN_CASTLE);
assert_eq!(format!("{castling}"), "Kq");
}

Expand All @@ -174,13 +178,13 @@ mod tests {

#[test]
fn test_individual_castling_rights() {
let castling = Castling::new(BLACK_KING_CASTLE);
let castling = Castling::new(Castling::BLACK_KING_CASTLE);
assert_eq!(format!("{castling}"), "k");
}

#[test]
fn test_combination_of_castling_rights() {
let castling = Castling::new(WHITE_KING_CASTLE | BLACK_KING_CASTLE | BLACK_QUEEN_CASTLE);
let castling = Castling::new(Castling::WHITE_KING_CASTLE | Castling::BLACK_KING_CASTLE | Castling::BLACK_QUEEN_CASTLE);
assert_eq!(format!("{castling}"), "Kkq");
}

Expand All @@ -202,7 +206,7 @@ mod tests {
assert_eq!(
result,
Ok(Castling::new(
WHITE_KING_CASTLE | WHITE_QUEEN_CASTLE | BLACK_KING_CASTLE | BLACK_QUEEN_CASTLE
Castling::WHITE_KING_CASTLE | Castling::WHITE_QUEEN_CASTLE | Castling::BLACK_KING_CASTLE | Castling::BLACK_QUEEN_CASTLE
))
);
}
Expand All @@ -225,7 +229,7 @@ mod tests {
assert_eq!(
result,
Ok(Castling::new(
WHITE_KING_CASTLE | WHITE_QUEEN_CASTLE | BLACK_KING_CASTLE | BLACK_QUEEN_CASTLE
Castling::WHITE_KING_CASTLE | Castling::WHITE_QUEEN_CASTLE | Castling::BLACK_KING_CASTLE | Castling::BLACK_QUEEN_CASTLE
))
);
}
Expand Down
22 changes: 12 additions & 10 deletions libs/board/src/fen/enpassant.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
use api::{Square, Square::*};
use bitboard::{Bitboard, BitboardExt};
use std::fmt::{Debug, Display};

use api::Square;
use api::Square::{A3, A6, H3, H6};
use bitboard::Bitboard;

#[derive(PartialEq, Eq, Clone, Copy, Default)]
pub struct EnPassant {
square: Option<Square>,
Expand All @@ -14,6 +12,11 @@ pub enum EnPassantError {
Invalid,
}

pub trait EnPassantExt {
fn set_square(&mut self, square: Option<Square>);
fn unset(&mut self);
}

impl EnPassant {
pub fn new(square: Option<Square>) -> Self {
if Self::is_valid_square(square) {
Expand All @@ -36,7 +39,11 @@ impl EnPassant {
}

pub fn mask(&self) -> Bitboard {
Bitboard::default()
if let Some(square) = self.square() {
Bitboard::get_single_bit(square.into())
} else {
Bitboard::default()
}
}
}

Expand All @@ -62,11 +69,6 @@ impl TryFrom<String> for EnPassant {
}
}

pub(crate) trait EnPassantExt {
fn set_square(&mut self, square: Option<Square>);
fn unset(&mut self);
}

impl EnPassantExt for EnPassant {
fn set_square(&mut self, square: Option<Square>) {
if Self::is_valid_square(square) {
Expand Down
10 changes: 4 additions & 6 deletions libs/board/src/fen/full_move_clock.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
use std::fmt::{Debug, Display};

pub const MIN_FULL_MOVE_CLOCK: u16 = 1;

#[derive(PartialEq, Eq, Clone, Copy)]
pub struct FullMoveClock {
clock: u16,
Expand All @@ -14,6 +12,8 @@ pub enum FullMoveClockError {
}

impl FullMoveClock {
pub const MIN: u16 = 1;

pub fn new(clock: u16) -> Self {
Self { clock }
}
Expand All @@ -25,9 +25,7 @@ impl FullMoveClock {

impl Default for FullMoveClock {
fn default() -> Self {
Self {
clock: MIN_FULL_MOVE_CLOCK,
}
Self { clock: Self::MIN }
}
}

Expand All @@ -36,7 +34,7 @@ impl TryFrom<&str> for FullMoveClock {

fn try_from(value: &str) -> Result<Self, Self::Error> {
if let Ok(parsed_value) = value.parse::<u16>() {
if parsed_value < MIN_FULL_MOVE_CLOCK {
if parsed_value < Self::MIN {
Err(Self::Error::TooLow)
} else {
Ok(Self::new(parsed_value))
Expand Down
Loading