From 556f72039febc364481dbced27e1c0ece00278c2 Mon Sep 17 00:00:00 2001 From: KrinjMaster <5opkasuka@gmail.com> Date: Wed, 20 Mar 2024 00:08:57 +0300 Subject: [PATCH] feat: changed move encoding + test.rs --- Cargo.toml | 1 - src/board.rs | 462 ++++++++++++++++++++--------------------- src/main.rs | 29 +-- src/move_generation.rs | 1 - src/test.rs | 23 ++ src/utils.rs | 6 +- 6 files changed, 253 insertions(+), 269 deletions(-) create mode 100644 src/test.rs diff --git a/Cargo.toml b/Cargo.toml index b6d49e1..e1d0be0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,5 +6,4 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -rand = "0.8.5" diff --git a/src/board.rs b/src/board.rs index 4da4be6..766a551 100644 --- a/src/board.rs +++ b/src/board.rs @@ -1,23 +1,14 @@ -use std::ops::Index; - use crate::{ - constants::{BOARD_SQUARES, FIFTH_RANK, FOURTH_RANK}, + constants::BOARD_SQUARES, move_generation::{ generate_bishop_moves, generate_king_moves, generate_knight_moves, generate_pawn_moves, generate_queen_moves, generate_rook_moves, }, piece_parsing::parse_bitboards, - utils::print_bitboard, + utils::encode_move, }; -pub fn count_ones(bb: Bitboard) -> u8 { - bb.count_ones() as u8 -} - -pub fn trailing_zeros(bb: Bitboard) -> u8 { - bb.trailing_zeros() as u8 -} - +pub type Move = u16; pub type Bitboard = u64; #[derive(Debug, Copy, Clone)] @@ -47,7 +38,7 @@ pub struct BoardState { pub bb_en_passant: Bitboard, pub halfmove: u32, pub fullmove: u32, - pub move_history: Vec<(Bitboard, Bitboard, Color, Piece, Piece)>, + pub move_history: Vec, } impl BoardState { @@ -60,211 +51,210 @@ impl BoardState { let all_attacks = self .generate_moves_by_color(&opposite_color) .iter() - .fold(0, |acc, cur| acc | cur.1); + .fold(0, |acc, cur| { + acc | BOARD_SQUARES[((cur >> 6 & !(1 << 8 | 1 << 7)) as u8) as usize] + }); all_attacks & self.get_piece_bb(self.to_move, Piece::King) != 0 } - pub fn make_move(&mut self, color: &Color, piece: &Piece, piece_move: (Bitboard, Bitboard)) { - self.bb_pieces[*color as usize][*piece as usize] ^= piece_move.0; - let mut captured_piece: Piece = Piece::None; - - // delete piece on the move square if there is one - for index in 0..6 { - // opposite color - match color { - Color::White => { - if self.bb_pieces[Color::Black as usize][index] & piece_move.1 != 0 { - self.bb_pieces[Color::Black as usize][index] &= !(piece_move.1); - match index { - 0 => captured_piece = Piece::Pawn, - 1 => captured_piece = Piece::Knight, - 2 => captured_piece = Piece::Bishop, - 3 => captured_piece = Piece::Rook, - 4 => captured_piece = Piece::Queen, - 5 => captured_piece = Piece::King, - _ => (), - }; - } - } - Color::Black => { - if self.bb_pieces[Color::White as usize][index] & piece_move.1 != 0 { - self.bb_pieces[Color::White as usize][index] &= !(piece_move.1); - match index { - 0 => captured_piece = Piece::Pawn, - 1 => captured_piece = Piece::Knight, - 2 => captured_piece = Piece::Bishop, - 3 => captured_piece = Piece::Rook, - 4 => captured_piece = Piece::Queen, - 5 => captured_piece = Piece::King, - _ => (), - }; - } - } - } - } - - // delete piece from color bitboards - match color { - Color::White => { - self.bb_colors[Color::White as usize] &= !(piece_move.0); - self.bb_colors[Color::White as usize] |= piece_move.1; - - self.bb_colors[Color::Black as usize] &= !(piece_move.0); - self.bb_colors[Color::Black as usize] &= !(piece_move.1); - } - Color::Black => { - self.bb_colors[Color::Black as usize] &= !(piece_move.0); - self.bb_colors[Color::Black as usize] |= piece_move.1; - - self.bb_colors[Color::White as usize] &= !(piece_move.0); - self.bb_colors[Color::White as usize] &= !(piece_move.1); - } - } - - // new fullboard - self.bb_fullboard = - self.bb_colors[Color::White as usize] | self.bb_colors[Color::Black as usize]; - - // check for castling and en passant - match piece { - Piece::King => { - self.bb_castling_rigths[*color as usize][1] = 0; - self.bb_castling_rigths[*color as usize][0] = 0; - } - Piece::Rook => { - self.bb_castling_rigths[*color as usize][1] &= !(piece_move.0); - self.bb_castling_rigths[*color as usize][0] &= !(piece_move.0); - } - Piece::Pawn => { - if piece_move.0 >> 16 == piece_move.1 && matches!(color, Color::White) { - self.bb_en_passant |= piece_move.0 >> 8; - } - if piece_move.0 << 16 == piece_move.1 && matches!(color, Color::Black) { - self.bb_en_passant |= piece_move.0 << 8; - } - } - _ => (), - } - - // make a move - self.bb_pieces[*color as usize][*piece as usize] |= piece_move.1; - self.bb_colors[*color as usize] |= piece_move.1; - self.bb_fullboard |= piece_move.1; - - self.move_history - .push((piece_move.0, piece_move.1, *color, *piece, captured_piece)); - - // if black to move - if self.halfmove == 1 { - self.to_move = Color::White; - self.halfmove = 0; - self.fullmove += 1; - } else { - self.to_move = Color::Black; - self.halfmove = 1; - } - } - - pub fn undo_move(&mut self) -> Result<(), &str> { - let (prev_pos, cur_pos, color, piece, captured_piece) = - self.move_history.pop().expect("No items found!"); - - let opposite_color = match color { - Color::White => Color::Black, - Color::Black => Color::White, - }; - - // check for castling and castling avaliability - match piece { - Piece::Pawn => { - match color { - Color::White => { - // if piece was previosly of fourth rank - if prev_pos & FOURTH_RANK != 0 { - self.bb_en_passant |= prev_pos << 8; - } - } - Color::Black => { - // if piece was previosly of fifth rank - if prev_pos & FIFTH_RANK != 0 { - self.bb_en_passant |= prev_pos >> 8; - } - } - } - } - Piece::Rook => { - for index in 0..2 { - if (self.bb_castling_rigths[color as usize][index] | prev_pos).count_ones() == 1 - { - self.bb_castling_rigths[color as usize][index] = prev_pos; - } - } - } - Piece::King => { - if matches!(color, Color::White) { - // white kingside - self.bb_castling_rigths[color as usize][0] = - self.bb_pieces[color as usize][Piece::Rook as usize] & BOARD_SQUARES[63]; - // white queenside - self.bb_castling_rigths[color as usize][1] = - self.bb_pieces[color as usize][Piece::Rook as usize] & BOARD_SQUARES[56]; - } else { - // black kingside - self.bb_castling_rigths[color as usize][0] = - self.bb_pieces[color as usize][Piece::Rook as usize] & BOARD_SQUARES[0]; - // black queenside - self.bb_castling_rigths[color as usize][1] = - self.bb_pieces[color as usize][Piece::Rook as usize] & BOARD_SQUARES[7]; - } - } - _ => (), - } - - // undo move - self.bb_pieces[color as usize][piece as usize] |= prev_pos; - self.bb_pieces[color as usize][piece as usize] ^= cur_pos; - - // undo move in colors bb - self.bb_colors[color as usize] |= prev_pos; - self.bb_colors[color as usize] ^= cur_pos; - - // if move captured piece - if !matches!(captured_piece, Piece::None) { - // if captured piece is not empty - self.bb_pieces[opposite_color as usize][captured_piece as usize] |= cur_pos; - self.bb_colors[opposite_color as usize] |= cur_pos; - self.bb_fullboard |= cur_pos; - } - - // undo move in fullboard - self.bb_fullboard = - self.bb_colors[color as usize] | self.bb_colors[opposite_color as usize]; - - // halfmove undo - if self.halfmove == 0 { - // undo fullmove count only if white currently to move - self.halfmove = 1; - self.fullmove -= 1; - } else { - self.halfmove = 0; - } - - self.to_move = opposite_color; - - Ok(()) - } - - pub fn generate_moves_by_color( - &self, - color: &Color, - ) -> Vec<(Bitboard, Bitboard, Color, Piece)> { + // pub fn make_move(&mut self, color: &Color, piece: &Piece, piece_move: (Bitboard, Bitboard)) { + // self.bb_pieces[*color as usize][*piece as usize] ^= piece_move.0; + // let mut captured_piece: Piece = Piece::None; + // + // // delete piece on the move square if there is one + // for index in 0..6 { + // // opposite color + // match color { + // Color::White => { + // if self.bb_pieces[Color::Black as usize][index] & piece_move.1 != 0 { + // self.bb_pieces[Color::Black as usize][index] &= !(piece_move.1); + // match index { + // 0 => captured_piece = Piece::Pawn, + // 1 => captured_piece = Piece::Knight, + // 2 => captured_piece = Piece::Bishop, + // 3 => captured_piece = Piece::Rook, + // 4 => captured_piece = Piece::Queen, + // 5 => captured_piece = Piece::King, + // _ => (), + // }; + // } + // } + // Color::Black => { + // if self.bb_pieces[Color::White as usize][index] & piece_move.1 != 0 { + // self.bb_pieces[Color::White as usize][index] &= !(piece_move.1); + // match index { + // 0 => captured_piece = Piece::Pawn, + // 1 => captured_piece = Piece::Knight, + // 2 => captured_piece = Piece::Bishop, + // 3 => captured_piece = Piece::Rook, + // 4 => captured_piece = Piece::Queen, + // 5 => captured_piece = Piece::King, + // _ => (), + // }; + // } + // } + // } + // } + // + // // delete piece from color bitboards + // match color { + // Color::White => { + // self.bb_colors[Color::White as usize] &= !(piece_move.0); + // self.bb_colors[Color::White as usize] |= piece_move.1; + // + // self.bb_colors[Color::Black as usize] &= !(piece_move.0); + // self.bb_colors[Color::Black as usize] &= !(piece_move.1); + // } + // Color::Black => { + // self.bb_colors[Color::Black as usize] &= !(piece_move.0); + // self.bb_colors[Color::Black as usize] |= piece_move.1; + // + // self.bb_colors[Color::White as usize] &= !(piece_move.0); + // self.bb_colors[Color::White as usize] &= !(piece_move.1); + // } + // } + // + // // new fullboard + // self.bb_fullboard = + // self.bb_colors[Color::White as usize] | self.bb_colors[Color::Black as usize]; + // + // // check for castling and en passant + // match piece { + // Piece::King => { + // self.bb_castling_rigths[*color as usize][1] = 0; + // self.bb_castling_rigths[*color as usize][0] = 0; + // } + // Piece::Rook => { + // self.bb_castling_rigths[*color as usize][1] &= !(piece_move.0); + // self.bb_castling_rigths[*color as usize][0] &= !(piece_move.0); + // } + // Piece::Pawn => { + // if piece_move.0 >> 16 == piece_move.1 && matches!(color, Color::White) { + // self.bb_en_passant |= piece_move.0 >> 8; + // } + // if piece_move.0 << 16 == piece_move.1 && matches!(color, Color::Black) { + // self.bb_en_passant |= piece_move.0 << 8; + // } + // } + // _ => (), + // } + // + // // make a move + // self.bb_pieces[*color as usize][*piece as usize] |= piece_move.1; + // self.bb_colors[*color as usize] |= piece_move.1; + // self.bb_fullboard |= piece_move.1; + // + // // self.move_history + // // .push((piece_move.0, piece_move.1, *color, *piece, captured_piece)); + // + // // if black to move + // if self.halfmove == 1 { + // self.to_move = Color::White; + // self.halfmove = 0; + // self.fullmove += 1; + // } else { + // self.to_move = Color::Black; + // self.halfmove = 1; + // } + // } + + // pub fn undo_move(&mut self) -> Result<(), &str> { + // let (prev_pos, cur_pos, color, piece, captured_piece) = + // self.move_history.pop().expect("No items found!"); + // + // let opposite_color = match color { + // Color::White => Color::Black, + // Color::Black => Color::White, + // }; + // + // // check for castling and castling avaliability + // match piece { + // Piece::Pawn => { + // match color { + // Color::White => { + // // if piece was previosly of fourth rank + // if prev_pos & FOURTH_RANK != 0 { + // self.bb_en_passant |= prev_pos << 8; + // } + // } + // Color::Black => { + // // if piece was previosly of fifth rank + // if prev_pos & FIFTH_RANK != 0 { + // self.bb_en_passant |= prev_pos >> 8; + // } + // } + // } + // } + // Piece::Rook => { + // for index in 0..2 { + // if (self.bb_castling_rigths[color as usize][index] | prev_pos).count_ones() == 1 + // { + // self.bb_castling_rigths[color as usize][index] = prev_pos; + // } + // } + // } + // Piece::King => { + // if matches!(color, Color::White) { + // // white kingside + // self.bb_castling_rigths[color as usize][0] = + // self.bb_pieces[color as usize][Piece::Rook as usize] & BOARD_SQUARES[63]; + // // white queenside + // self.bb_castling_rigths[color as usize][1] = + // self.bb_pieces[color as usize][Piece::Rook as usize] & BOARD_SQUARES[56]; + // } else { + // // black kingside + // self.bb_castling_rigths[color as usize][0] = + // self.bb_pieces[color as usize][Piece::Rook as usize] & BOARD_SQUARES[0]; + // // black queenside + // self.bb_castling_rigths[color as usize][1] = + // self.bb_pieces[color as usize][Piece::Rook as usize] & BOARD_SQUARES[7]; + // } + // } + // _ => (), + // } + // + // // undo move + // self.bb_pieces[color as usize][piece as usize] |= prev_pos; + // self.bb_pieces[color as usize][piece as usize] ^= cur_pos; + // + // // undo move in colors bb + // self.bb_colors[color as usize] |= prev_pos; + // self.bb_colors[color as usize] ^= cur_pos; + // + // // if move captured piece + // if !matches!(captured_piece, Piece::None) { + // // if captured piece is not empty + // self.bb_pieces[opposite_color as usize][captured_piece as usize] |= cur_pos; + // self.bb_colors[opposite_color as usize] |= cur_pos; + // self.bb_fullboard |= cur_pos; + // } + // + // // undo move in fullboard + // self.bb_fullboard = + // self.bb_colors[color as usize] | self.bb_colors[opposite_color as usize]; + // + // // halfmove undo + // if self.halfmove == 0 { + // // undo fullmove count only if white currently to move + // self.halfmove = 1; + // self.fullmove -= 1; + // } else { + // self.halfmove = 0; + // } + // + // self.to_move = opposite_color; + // + // Ok(()) + // } + + pub fn generate_moves_by_color(&self, color: &Color) -> Vec { let opposite_color: &Color = match *color { Color::White => &Color::Black, Color::Black => &Color::White, }; - let mut moves_vec: Vec<(Bitboard, Bitboard, Color, Piece)> = vec![]; + let mut moves_vec: Vec = vec![]; // generate pseudo legal moves let pawns_moves = generate_pawn_moves( @@ -280,11 +270,10 @@ impl BoardState { while move_bb != 0 { let least_sign_bit = move_bb.trailing_zeros(); - moves_vec.push(( - piece_move.0, - BOARD_SQUARES[least_sign_bit as usize], - *color, - Piece::Pawn, + moves_vec.push(encode_move( + piece_move.0.trailing_zeros() as u8, + least_sign_bit as u8, + Piece::None, )); move_bb ^= BOARD_SQUARES[least_sign_bit as usize]; @@ -302,11 +291,10 @@ impl BoardState { while move_bb != 0 { let least_sign_bit = move_bb.trailing_zeros(); - moves_vec.push(( - king.0, - BOARD_SQUARES[least_sign_bit as usize], - *color, - Piece::King, + moves_vec.push(encode_move( + king.0.trailing_zeros() as u8, + least_sign_bit as u8, + Piece::None, )); move_bb ^= BOARD_SQUARES[least_sign_bit as usize]; @@ -324,11 +312,10 @@ impl BoardState { while move_bb != 0 { let least_sign_bit = move_bb.trailing_zeros(); - moves_vec.push(( - piece_move.0, - BOARD_SQUARES[least_sign_bit as usize], - *color, - Piece::Knight, + moves_vec.push(encode_move( + piece_move.0.trailing_zeros() as u8, + least_sign_bit as u8, + Piece::None, )); move_bb ^= BOARD_SQUARES[least_sign_bit as usize]; @@ -347,11 +334,10 @@ impl BoardState { while move_bb != 0 { let least_sign_bit = move_bb.trailing_zeros(); - moves_vec.push(( - piece_move.0, - BOARD_SQUARES[least_sign_bit as usize], - *color, - Piece::Bishop, + moves_vec.push(encode_move( + piece_move.0.trailing_zeros() as u8, + least_sign_bit as u8, + Piece::None, )); move_bb ^= BOARD_SQUARES[least_sign_bit as usize]; @@ -370,11 +356,10 @@ impl BoardState { while move_bb != 0 { let least_sign_bit = move_bb.trailing_zeros(); - moves_vec.push(( - piece_move.0, - BOARD_SQUARES[least_sign_bit as usize], - *color, - Piece::Rook, + moves_vec.push(encode_move( + piece_move.0.trailing_zeros() as u8, + least_sign_bit as u8, + Piece::None, )); move_bb ^= BOARD_SQUARES[least_sign_bit as usize]; @@ -393,11 +378,10 @@ impl BoardState { while move_bb != 0 { let least_sign_bit = move_bb.trailing_zeros(); - moves_vec.push(( - piece_move.0, - BOARD_SQUARES[least_sign_bit as usize], - *color, - Piece::Queen, + moves_vec.push(encode_move( + piece_move.0.trailing_zeros() as u8, + least_sign_bit as u8, + Piece::None, )); move_bb ^= BOARD_SQUARES[least_sign_bit as usize]; diff --git a/src/main.rs b/src/main.rs index 3e64115..7d15f10 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,8 +8,7 @@ mod piece_parsing; mod utils; use board::BoardState; - -use crate::constants::DEFAULT_FEN_STRING; +use constants::DEFAULT_FEN_STRING; fn main() { let _board = BoardState::from_fen(DEFAULT_FEN_STRING).unwrap_or_else(|err| { @@ -19,28 +18,4 @@ fn main() { } #[cfg(test)] -mod tests { - use crate::{board::BoardState, constants::DEFAULT_FEN_STRING}; - - #[test] - fn from_fen_ok() { - assert_eq!(BoardState::from_fen(DEFAULT_FEN_STRING).is_ok(), true) - } - - #[test] - fn initial_moves() { - let board = BoardState::from_fen(DEFAULT_FEN_STRING).expect("Fail during board setup"); - assert_eq!( - board.generate_moves_by_color(&board.to_move).len(), - (8 * 2) + (2 * 2) - ) - } - - #[test] - fn in_check() { - let board = - BoardState::from_fen("rnbqkbnr/ppppp1pp/8/5p1Q/4P3/8/PPPP1PPP/RNB1KBNR b KQkq - 0 1") - .expect("Fail during board setup"); - assert_eq!(board.is_in_check(), true) - } -} +mod test; diff --git a/src/move_generation.rs b/src/move_generation.rs index 467a652..8ed904b 100644 --- a/src/move_generation.rs +++ b/src/move_generation.rs @@ -3,7 +3,6 @@ use crate::constants::{ BISHOP_MAGICS, BOARD_SQUARES, KING_ATTACKS, KNIGHT_ATTACKS, PAWN_ATTACKS, ROOK_MAGICS, }; use crate::magic::{get_bishop_move, get_rook_move}; -use crate::utils::print_bitboard; pub fn generate_pawn_moves( pawns: Vec<(u32, u32)>, diff --git a/src/test.rs b/src/test.rs new file mode 100644 index 0000000..36ee1d6 --- /dev/null +++ b/src/test.rs @@ -0,0 +1,23 @@ +use crate::{board::BoardState, constants::DEFAULT_FEN_STRING}; + +#[test] +fn from_fen_ok() { + assert!(BoardState::from_fen(DEFAULT_FEN_STRING).is_ok()) +} + +#[test] +fn initial_moves() { + let board = BoardState::from_fen(DEFAULT_FEN_STRING).expect("Fail during board setup"); + assert_eq!( + board.generate_moves_by_color(&board.to_move).len(), + (8 * 2) + (2 * 2) + ) +} + +#[test] +fn in_check() { + let board = + BoardState::from_fen("rnbqkbnr/ppppp1pp/8/5p1Q/4P3/8/PPPP1PPP/RNB1KBNR b KQkq - 0 1") + .expect("Fail during board setup"); + assert!(board.is_in_check()) +} diff --git a/src/utils.rs b/src/utils.rs index d8b4bf9..e32e3d5 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,4 +1,4 @@ -use crate::board::Bitboard; +use crate::board::{Bitboard, Piece}; pub fn print_bitboard(bb: Bitboard) { let formatted_bb: String = format!("{:064b}", bb); @@ -29,3 +29,7 @@ pub fn print_bitboard(bb: Bitboard) { println!("\n a b c d e f g h\n"); println!("biboard is: {}", bb); } + +pub fn encode_move(from_bb: u8, to_bb: u8, capture: Piece) -> u16 { + from_bb as u16 | ((to_bb as u16) << 6) | ((capture as u16) << 12) +}