Add utility functions for readability and refactor make_move

This commit is contained in:
stefiosif
2024-08-28 21:07:22 +03:00
parent 6c8f445fa9
commit 21076da68c
10 changed files with 91 additions and 61 deletions

View File

@@ -21,6 +21,13 @@ pub const fn square_to_bitboard_wrapping(square: usize) -> Bitboard {
1_u64.wrapping_shl(square as u32)
}
pub const fn bitboard_to_coords(bitboard: Bitboard) -> (usize, usize) {
match bitboard {
0 => (0, 0),
_ => (lsb(bitboard) / 8, lsb(bitboard) % 8),
}
}
pub const fn lsb(bitboard: Bitboard) -> usize {
bitboard.trailing_zeros() as usize
}

View File

@@ -167,6 +167,18 @@ impl Board {
pub fn set_state(&mut self, state: State) {
self.state = state;
}
pub fn piece_type_at(&self, square: usize, color: Color) -> Option<PieceType> {
let pieces = match color {
Color::White => &self.white_pieces,
Color::Black => &self.black_pieces,
};
pieces
.iter()
.find(|p| have_common_bit(p.bitboard, square_to_bitboard(square)))
.map(|p| p.piece_type)
}
}
impl Default for Board {
@@ -216,6 +228,8 @@ impl PieceType {
}
use std::ops::{Index, IndexMut};
use super::bitboard::square_to_bitboard;
impl Index<PieceType> for [Piece] {
type Output = Piece;

View File

@@ -1,7 +1,7 @@
use crate::board::fen::from_fen;
use String as FenError;
use super::board::Board;
use super::board::{Board, Color};
#[derive(Debug, PartialEq, Eq)]
pub struct Game {
@@ -22,6 +22,10 @@ impl Game {
pub const fn run(&self) {
Board::new();
}
pub const fn current_player(&self) -> Color {
self.board.state.current_player()
}
}
impl Default for Game {

View File

@@ -1,7 +1,3 @@
use u64 as Bitboard;
use crate::board::bitboard::lsb;
pub struct Square {}
impl Square {
@@ -82,13 +78,6 @@ pub const fn coords_to_square(rank: usize, file: usize) -> usize {
rank * 8 + file
}
pub const fn bitboard_to_coords(bitboard: Bitboard) -> (usize, usize) {
match bitboard {
0 => (0, 0),
_ => (lsb(bitboard) / 8, lsb(bitboard) % 8),
}
}
pub fn square_to_algebraic(square: usize) -> String {
let file = (square % 8) as u8;
let rank = (square / 8) as u8;

View File

@@ -3,10 +3,10 @@ use crate::{board::board::Color, movegen::r#move::MoveType};
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct State {
side_to_move: Color,
castling_ability: [Castle; 2],
en_passant_target_square: Option<usize>,
halfmove_clock: u8,
fullmove_counter: u8,
pub castling_ability: [Castle; 2],
pub en_passant_target_square: Option<usize>,
pub halfmove_clock: u8,
pub fullmove_counter: u8,
}
impl State {
@@ -40,6 +40,17 @@ impl State {
self.en_passant_target_square
}
pub fn set_en_passant_target_square(&mut self, square: Option<usize>) {
self.en_passant_target_square = square;
}
pub const fn castling_ability(&self, color: Color) -> Castle {
match color {
Color::White => self.castling_ability[0],
Color::Black => self.castling_ability[1],
}
}
pub fn set_castling_ability(&mut self, color: Color, castle: Castle) {
match color {
Color::White => self.castling_ability[0] = castle,
@@ -95,26 +106,23 @@ impl State {
}
}
pub fn change_side(&mut self) {
pub fn revert_full_move(&mut self, color: Color) {
match color {
Color::White => (),
Color::Black => self.fullmove_counter -= 1,
}
}
pub fn change_side(&mut self) -> Color {
self.side_to_move = match self.side_to_move {
Color::White => Color::Black,
Color::Black => Color::White,
}
}
pub const fn next_turn(&self) -> Color {
};
self.side_to_move
}
pub fn set_en_passant_target_square(&mut self, square: Option<usize>) {
self.en_passant_target_square = square;
}
pub const fn castling_ability(&self, color: Color) -> Castle {
match color {
Color::White => self.castling_ability[0],
Color::Black => self.castling_ability[1],
}
pub const fn current_player(&self) -> Color {
self.side_to_move
}
}

View File

@@ -101,7 +101,7 @@ pub fn uci_position(position: &mut SplitWhitespace) -> Result<Game, String> {
for mv_str in position {
let mv = Move::parse_from_str(mv_str)?;
game.board.make_move(&mv, game.board.state.next_turn());
game.board.make_move(&mv);
}
Ok(game)

View File

@@ -1,10 +1,10 @@
use crate::board::{
bitboard::{
have_common_bit, lsb, square_to_bitboard, square_to_bitboard_wrapping, EMPTY, NOT_FILE_A,
NOT_FILE_AB, NOT_FILE_GH, NOT_FILE_H,
NOT_FILE_AB, NOT_FILE_GH, NOT_FILE_H, bitboard_to_coords
},
board::Color,
square::{bitboard_to_coords, coords_to_square},
square::coords_to_square,
};
use u64 as Bitboard;

View File

@@ -15,6 +15,17 @@ pub enum Promote {
Queen,
}
impl Promote {
pub fn into_piece_type(&self) -> PieceType {
match self {
Promote::Knight => PieceType::Knight,
Promote::Rook => PieceType::Rook,
Promote::Bishop => PieceType::Bishop,
Promote::Queen => PieceType::Queen,
}
}
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
pub enum MoveType {
Quiet,
@@ -108,11 +119,8 @@ impl Move {
}
impl Board {
pub fn make_move(&mut self, mv: &Move, color: Color) {
self.update_board_state(mv, color);
}
pub fn update_board_state(&mut self, mv: &Move, color: Color) {
pub fn make_move(&mut self, mv: &Move) {
let color = self.state.current_player();
let (own_pieces, opponent_pieces, en_passant_square) = match color {
Color::White => (
&mut self.white_pieces,
@@ -172,13 +180,13 @@ impl Board {
}
fn move_piece(src: usize, dst: usize, pieces: &mut [Piece; 6]) {
for p in pieces.iter_mut() {
if have_common_bit(p.bitboard, square_to_bitboard(src)) {
pieces
.iter_mut()
.filter(|p| have_common_bit(p.bitboard, square_to_bitboard(src)))
.for_each(|p| {
p.bitboard &= !square_to_bitboard(src);
p.bitboard |= square_to_bitboard(dst);
break;
}
}
});
}
fn move_rook_castle(king_dst: usize, pieces: &mut [Piece; 6]) {
@@ -201,12 +209,12 @@ impl Board {
}
fn remove_piece(square: usize, pieces: &mut [Piece; 6]) {
for p in pieces.iter_mut() {
if have_common_bit(p.bitboard, square_to_bitboard(square)) {
p.bitboard &= !(square_to_bitboard(square));
break;
}
}
pieces
.iter_mut()
.filter(|p| have_common_bit(p.bitboard, square_to_bitboard(square)))
.for_each(|p| {
p.bitboard &= !square_to_bitboard(square);
});
}
fn remove_pawn_enpassant(square: usize, pieces: &mut [Piece; 6], color: Color) {
@@ -225,7 +233,7 @@ impl Board {
#[cfg(test)]
mod tests {
use crate::board::{board::Color, fen::from_fen, square::Square};
use crate::board::{fen::from_fen, square::Square};
use crate::movegen::r#move::{Move, MoveType, Promote};
const FEN_QUIET: [&str; 2] = [
@@ -237,7 +245,7 @@ mod tests {
fn test_make_move_quiet() -> Result<(), String> {
let mut game = from_fen(FEN_QUIET[0])?;
let mv = Move::new_with_type(9, 25, MoveType::DoublePush);
game.board.make_move(&mv, Color::White);
game.board.make_move(&mv);
assert_eq!(game, from_fen(FEN_QUIET[1])?);
Ok(())
@@ -252,7 +260,7 @@ mod tests {
fn test_make_move_capture() -> Result<(), String> {
let mut game = from_fen(FEN_CAPTURE[0])?;
let mv = Move::new_with_type(21, 37, MoveType::Capture);
game.board.make_move(&mv, Color::White);
game.board.make_move(&mv);
assert_eq!(game, from_fen(FEN_CAPTURE[1])?);
Ok(())
@@ -267,7 +275,7 @@ mod tests {
fn test_make_move_en_passant() -> Result<(), String> {
let mut game = from_fen(FEN_EN_PASSANT[0])?;
let mv = Move::new_with_type(30, 23, MoveType::EnPassant);
game.board.make_move(&mv, Color::Black);
game.board.make_move(&mv);
assert_eq!(game, from_fen(FEN_EN_PASSANT[1])?);
Ok(())
@@ -282,7 +290,7 @@ mod tests {
fn test_make_move_double_push() -> Result<(), String> {
let mut game = from_fen(FEN_DOUBLE_PUSH[0])?;
let mv = Move::new_with_type(10, 26, MoveType::DoublePush);
game.board.make_move(&mv, Color::White);
game.board.make_move(&mv);
assert_eq!(game, from_fen(FEN_DOUBLE_PUSH[1])?);
Ok(())
}
@@ -296,7 +304,7 @@ mod tests {
fn test_make_move_promotion() -> Result<(), String> {
let mut game = from_fen(FEN_PROMOTION[0])?;
let mv = Move::new_with_type(54, 62, MoveType::Promotion(Promote::Queen));
game.board.make_move(&mv, Color::White);
game.board.make_move(&mv);
assert_eq!(game, from_fen(FEN_PROMOTION[1])?);
Ok(())
@@ -311,7 +319,7 @@ mod tests {
fn test_make_move_promotion_capture() -> Result<(), String> {
let mut game = from_fen(FEN_PROMOTION_CAPTURE[0])?;
let mv = Move::new_with_type(54, 61, MoveType::PromotionCapture(Promote::Queen));
game.board.make_move(&mv, Color::White);
game.board.make_move(&mv);
assert_eq!(game, from_fen(FEN_PROMOTION_CAPTURE[1])?);
Ok(())
@@ -326,7 +334,7 @@ mod tests {
fn test_make_move_castle() -> Result<(), String> {
let mut game = from_fen(FEN_CASTLE[0])?;
let mv = Move::new_with_type(4, 6, MoveType::Castle);
game.board.make_move(&mv, Color::White);
game.board.make_move(&mv);
assert_eq!(game, from_fen(FEN_CASTLE[1])?);
Ok(())
}

View File

@@ -6,12 +6,12 @@ pub fn driver(game: &mut Game, nodes: &mut u64, depth: u8) {
return;
}
let color = game.board.state.next_turn();
let color = game.current_player();
let pseudo_moves = game.board.pseudo_moves_all(color);
for mv in pseudo_moves {
let original_board = game.board.clone();
game.board.make_move(&mv, color);
game.board.make_move(&mv);
if game.board.king_under_check(color) {
game.board = original_board;

View File

@@ -5,12 +5,12 @@ pub fn search(game: &mut Game, depth: u8) {
return;
}
let color = game.board.state.next_turn();
let color = game.current_player();
let pseudo_moves = game.board.pseudo_moves_all(color);
for mv in pseudo_moves {
let original_board = game.board.clone();
game.board.make_move(&mv, color);
game.board.make_move(&mv);
if game.board.king_under_check(color) {
game.board = original_board;