Add utility functions for readability and refactor make_move
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user