From 433d0f380a6c395e62c05a141c38e9dcb8354c19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Macio=C5=82ek?= Date: Sun, 13 Oct 2024 20:14:09 +0200 Subject: [PATCH] New start --- src/bitboard.rs | 12 +- src/board.rs | 720 ++++++---------------------------------- src/constans.rs | 19 ++ src/lib.rs | 2 +- tests/bitboard_tests.rs | 14 +- tests/board_tests.rs | 676 ++++++++++++++++++------------------- 6 files changed, 479 insertions(+), 964 deletions(-) create mode 100644 src/constans.rs diff --git a/src/bitboard.rs b/src/bitboard.rs index af25c53..7a3d698 100644 --- a/src/bitboard.rs +++ b/src/bitboard.rs @@ -3,11 +3,21 @@ use std::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr}; #[derive(Debug, Clone, Copy, PartialEq)] pub struct Bitboard(pub u64); +impl Default for Bitboard { + fn default() -> Self { + Self::new() + } +} + impl Bitboard { pub fn new() -> Self { Bitboard(0) } + pub fn from_index(index: usize) -> Self { + Bitboard(1 << index) + } + pub fn value(&self) -> u64 { self.0 } @@ -119,4 +129,4 @@ impl Shr for Bitboard { fn shr(self, shift: u32) -> Bitboard { Bitboard(self.0 >> shift) } -} \ No newline at end of file +} diff --git a/src/board.rs b/src/board.rs index 45985ba..e492843 100644 --- a/src/board.rs +++ b/src/board.rs @@ -1,10 +1,13 @@ use crate::bitboard::Bitboard; +use crate::constans::STARTING_POSITION; pub struct Board { pub white_occupancy: Bitboard, + pub white_attacks: Bitboard, pub white_pieces: Pieces, pub black_occupancy: Bitboard, + pub black_attacks: Bitboard, pub black_pieces: Pieces, pub turn: Color, @@ -47,89 +50,68 @@ pub struct CastlingRights { pub black_queen_side: bool, } +impl Default for Board { + fn default() -> Self { + Self::new() + } +} + impl Board { - /// Creates a new chessboard with default values pub fn new() -> Self { - let white_pieces = Pieces { - pawns: Bitboard(0b0000000000000000000000000000000000000000000000001111111100000000), - knights: Bitboard(0b0000000000000000000000000000000000000000000000000000000001000010), - bishops: Bitboard(0b0000000000000000000000000000000000000000000000000000000000100100), - rooks: Bitboard(0b0000000000000000000000000000000000000000000000000000000010000001), - queens: Bitboard(0b0000000000000000000000000000000000000000000000000000000000001000), - king: Bitboard(0b0000000000000000000000000000000000000000000000000000000000010000), - }; - - let white_occupancy = Bitboard::new() - .or(&white_pieces.pawns) - .or(&white_pieces.knights) - .or(&white_pieces.bishops) - .or(&white_pieces.rooks) - .or(&white_pieces.queens) - .or(&white_pieces.king); - - let black_pieces = Pieces { - pawns: Bitboard(0b0000000011111111000000000000000000000000000000000000000000000000), - knights: Bitboard(0b0100001000000000000000000000000000000000000000000000000000000000), - bishops: Bitboard(0b0010010000000000000000000000000000000000000000000000000000000000), - rooks: Bitboard(0b1000000100000000000000000000000000000000000000000000000000000000), - queens: Bitboard(0b0000100000000000000000000000000000000000000000000000000000000000), - king: Bitboard(0b0001000000000000000000000000000000000000000000000000000000000000), - }; - - let black_occupancy = Bitboard::new() - .or(&black_pieces.pawns) - .or(&black_pieces.knights) - .or(&black_pieces.bishops) - .or(&black_pieces.rooks) - .or(&black_pieces.queens) - .or(&black_pieces.king); - - let turn = Color::White; - - let castling_rights = CastlingRights { - white_king_side: true, - white_queen_side: true, - black_king_side: true, - black_queen_side: true, - }; - - let en_passant_square = None; - let halfmove_clock = 0; - let fullmove_number = 1; - Board { - white_pieces, - white_occupancy, - black_pieces, - black_occupancy, - turn, - castling_rights, - en_passant_square, - halfmove_clock, - fullmove_number, - } - } - - /// Creates a chessboard from a FEN string - pub fn from_fen(fen: &str) -> Option { + white_occupancy: Bitboard::new(), + white_attacks: Bitboard::new(), + white_pieces: Pieces { + pawns: Bitboard::new(), + knights: Bitboard::new(), + bishops: Bitboard::new(), + rooks: Bitboard::new(), + queens: Bitboard::new(), + king: Bitboard::new(), + }, + black_occupancy: Bitboard::new(), + black_attacks: Bitboard::new(), + black_pieces: Pieces { + pawns: Bitboard::new(), + knights: Bitboard::new(), + bishops: Bitboard::new(), + rooks: Bitboard::new(), + queens: Bitboard::new(), + king: Bitboard::new(), + }, + turn: Color::White, + castling_rights: CastlingRights { + white_king_side: true, + white_queen_side: true, + black_king_side: true, + black_queen_side: true, + }, + en_passant_square: None, + halfmove_clock: 0, + fullmove_number: 1, + } + } + + pub fn init() -> Self { let mut board = Board::new(); - let mut squares = fen.split_whitespace(); + board.set_fen(STARTING_POSITION); + board + } - let piece_placement = squares.next()?; + pub fn set_fen(&mut self, fen: &str) { + let parts: Vec<&str> = fen.split_whitespace().collect(); let mut rank = 7; let mut file = 0; - for c in piece_placement.chars() { + + for c in parts[0].chars() { match c { '/' => { - if file != 8 { - return None; - } rank -= 1; file = 0; } '1'..='8' => { - let empty_squares = c.to_digit(10).unwrap() as usize; - file += empty_squares; + let offset = c.to_digit(10).unwrap() as usize; + file += offset; } _ => { let color = if c.is_uppercase() { @@ -137,6 +119,7 @@ impl Board { } else { Color::Black }; + let piece = match c.to_ascii_lowercase() { 'p' => Piece::Pawn, 'n' => Piece::Knight, @@ -144,587 +127,78 @@ impl Board { 'r' => Piece::Rook, 'q' => Piece::Queen, 'k' => Piece::King, - _ => return None, + _ => panic!("Invalid FEN"), }; - board.place_piece(color, piece, rank * 8 + file); + + self.add_piece(color, piece, rank, file); file += 1; } } } - let turn = squares.next()?; - board.turn = match turn { + self.turn = match parts[1] { "w" => Color::White, "b" => Color::Black, - _ => return None, + _ => panic!("Invalid FEN"), }; - let castling_rights = squares.next()?; - board.castling_rights = CastlingRights { - white_king_side: castling_rights.contains('K'), - white_queen_side: castling_rights.contains('Q'), - black_king_side: castling_rights.contains('k'), - black_queen_side: castling_rights.contains('q'), + self.castling_rights = CastlingRights { + white_king_side: parts[2].contains('K'), + white_queen_side: parts[2].contains('Q'), + black_king_side: parts[2].contains('k'), + black_queen_side: parts[2].contains('q'), }; - let en_passant_square = squares.next()?; - board.en_passant_square = match en_passant_square { + self.en_passant_square = match parts[3] { "-" => None, - square => Some(Board::square_to_index(square)), - }; - - let halfmove_clock = squares.next()?.parse().ok()?; - board.halfmove_clock = halfmove_clock; - - let fullmove_number = squares.next()?.parse().ok()?; - board.fullmove_number = fullmove_number; - - Some(board) - } - - /// Converts a square representation to an index - pub fn square_to_index(square: &str) -> usize { - let file = square.chars().nth(0).unwrap() as usize - 'a' as usize; - let rank = square.chars().nth(1).unwrap().to_digit(10).unwrap() as usize - 1; - - rank * 8 + file - } - - /// Gets the bitboard for a specific piece and color - fn get_piece_bitboard(&self, color: Color, piece: Piece) -> Bitboard { - match (color, piece) { - (Color::White, Piece::Pawn) => self.white_pieces.pawns, - (Color::White, Piece::Knight) => self.white_pieces.knights, - (Color::White, Piece::Bishop) => self.white_pieces.bishops, - (Color::White, Piece::Rook) => self.white_pieces.rooks, - (Color::White, Piece::Queen) => self.white_pieces.queens, - (Color::White, Piece::King) => self.white_pieces.king, - (Color::Black, Piece::Pawn) => self.black_pieces.pawns, - (Color::Black, Piece::Knight) => self.black_pieces.knights, - (Color::Black, Piece::Bishop) => self.black_pieces.bishops, - (Color::Black, Piece::Rook) => self.black_pieces.rooks, - (Color::Black, Piece::Queen) => self.black_pieces.queens, - (Color::Black, Piece::King) => self.black_pieces.king, - } - } - - /// Places a piece on the board at the specified square index - pub fn place_piece(&mut self, color: Color, piece: Piece, index: usize) { - match color { - Color::White => self.white_occupancy.set_bit(index), - Color::Black => self.black_occupancy.set_bit(index), + s => Some(Board::square_to_index(s)), }; - match (color, piece) { - (Color::White, Piece::Pawn) => self.white_pieces.pawns.set_bit(index), - (Color::White, Piece::Knight) => self.white_pieces.knights.set_bit(index), - (Color::White, Piece::Bishop) => self.white_pieces.bishops.set_bit(index), - (Color::White, Piece::Rook) => self.white_pieces.rooks.set_bit(index), - (Color::White, Piece::Queen) => self.white_pieces.queens.set_bit(index), - (Color::White, Piece::King) => self.white_pieces.king.set_bit(index), - (Color::Black, Piece::Pawn) => self.black_pieces.pawns.set_bit(index), - (Color::Black, Piece::Knight) => self.black_pieces.knights.set_bit(index), - (Color::Black, Piece::Bishop) => self.black_pieces.bishops.set_bit(index), - (Color::Black, Piece::Rook) => self.black_pieces.rooks.set_bit(index), - (Color::Black, Piece::Queen) => self.black_pieces.queens.set_bit(index), - (Color::Black, Piece::King) => self.black_pieces.king.set_bit(index), - }; - } - - /// Check if pawn position is starting position - pub fn is_pawn_starting_position(color: Color, position: usize) -> bool { - match color { - Color::White => (8..16).contains(&position), - Color::Black => (48..56).contains(&position), - } + self.halfmove_clock = parts[4].parse().unwrap(); + self.fullmove_number = parts[5].parse().unwrap(); } - /// Check is square is empty - pub fn is_square_empty(index: usize, occupancy: Bitboard) -> bool { - !occupancy.is_set(index) - } + fn add_piece(&mut self, color: Color, piece: Piece, rank: usize, file: usize) { + let index = rank * 8 + file; + let bb = Bitboard::from_index(index); - /// Chceck if enemy piece is on square - pub fn is_square_enemy(&self, color: Color, position: usize) -> bool { - match color { - Color::White => self.black_occupancy.is_set(position), - Color::Black => self.white_occupancy.is_set(position), - } - } - - pub fn is_check(&self) -> Option { - let (king_position, opponent_occupancy, opponent_pieces) = match self.turn { - Color::White => ( - self.white_pieces.king, - self.black_occupancy, - &self.black_pieces, - ), - Color::Black => ( - self.black_pieces.king, - self.white_occupancy, - &self.white_pieces, - ), - }; - - let attacks = &Board::generate_pawn_attacks(self.turn, opponent_pieces.pawns) - .or(&Board::generate_knight_attacks(opponent_pieces.knights)) - .or(&Board::generate_bishop_attacks( - opponent_pieces.bishops, - opponent_occupancy, - )) - .or(&Board::generate_rook_attacks( - opponent_pieces.rooks, - opponent_occupancy, - )) - .or(&Board::generate_queen_attacks( - opponent_pieces.queens, - opponent_occupancy, - )) - .or(&Board::generate_king_attacks(opponent_pieces.king)); - - if attacks.is_set(king_position.first_set_bit().unwrap()) { - return Some(self.turn); - } - - None - } - - pub fn generate_pawn_attacks(color: Color, pawns: Bitboard) -> Bitboard { match color { Color::White => { - let attacks_left = pawns.left_shift(7) & !Bitboard(0x8080808080808080); - let attacks_right = pawns.left_shift(9) & !Bitboard(0x0101010101010101); - attacks_left.or(&attacks_right) - } - Color::Black => { - let attacks_left = pawns.right_shift(9) & !Bitboard(0x8080808080808080); - let attacks_right = pawns.right_shift(7) & !Bitboard(0x0101010101010101); - attacks_left.or(&attacks_right) - } - } - } - - pub fn generate_knight_attacks(knights: Bitboard) -> Bitboard { - let mut attacks = Bitboard::new(); - let knight_positions = knights; - - for i in 0..64 { - if knight_positions.is_set(i) { - let rank = i / 8; - let file = i % 8; - - let knight_moves = [ - (i.wrapping_add(17), rank + 2 <= 7 && file + 1 <= 7), - (i.wrapping_add(15), rank + 2 <= 7 && file >= 1), - (i.wrapping_add(10), rank + 1 <= 7 && file + 2 <= 7), - (i.wrapping_add(6), rank + 1 <= 7 && file >= 2), - (i.wrapping_sub(17), rank >= 2 && file >= 1), - (i.wrapping_sub(15), rank >= 2 && file + 1 <= 7), - (i.wrapping_sub(10), rank >= 1 && file >= 2), - (i.wrapping_sub(6), rank >= 1 && file + 2 <= 7), - ]; - - for &(move_index, valid) in &knight_moves { - if valid && move_index < 64 { - attacks.set_bit(move_index); - } + self.white_occupancy.set_bit(index); + // self.white_attacks = self.white_attacks.or(&bb); + match piece { + Piece::Pawn => self.white_pieces.pawns = self.white_pieces.pawns.or(&bb), + Piece::Knight => self.white_pieces.knights = self.white_pieces.knights.or(&bb), + Piece::Bishop => self.white_pieces.bishops = self.white_pieces.bishops.or(&bb), + Piece::Rook => self.white_pieces.rooks = self.white_pieces.rooks.or(&bb), + Piece::Queen => self.white_pieces.queens = self.white_pieces.queens.or(&bb), + Piece::King => self.white_pieces.king = self.white_pieces.king.or(&bb), } } - } - - attacks - } - - pub fn generate_bishop_attacks(bishops: Bitboard, occupancy: Bitboard) -> Bitboard { - let mut attacks = Bitboard::new(); - let bishop_positions = bishops; - - for i in 0..64 { - if bishop_positions.is_set(i) { - attacks = attacks.or(&Board::generate_diagonal_attacks(i, occupancy)); - } - } - - attacks - } - - fn generate_diagonal_attacks(index: usize, occupancy: Bitboard) -> Bitboard { - let mut attacks = Bitboard::new(); - let directions = [9, 7, -9, -7]; - - for &direction in &directions { - let mut current_index = index as isize; - - loop { - current_index += direction; - - if current_index < 0 || current_index >= 64 { - break; - } - - if (direction == 9 || direction == -7) && current_index % 8 == 0 { - break; - } - if (direction == 7 || direction == -9) && current_index % 8 == 7 { - break; - } - - let current_index_usize = current_index as usize; - attacks.set_bit(current_index_usize); - - if occupancy.is_set(current_index_usize) { - break; - } - } - } - - attacks - } - - pub fn generate_rook_attacks(rooks: Bitboard, occupancy: Bitboard) -> Bitboard { - let mut attacks = Bitboard::new(); - let rook_positions = rooks; - - for i in 0..64 { - if rook_positions.is_set(i) { - attacks = attacks.or(&Board::generate_straight_attacks(i, occupancy)); - } - } - - attacks - } - - fn generate_straight_attacks(index: usize, occupancy: Bitboard) -> Bitboard { - let mut attacks = Bitboard::new(); - let directions = [8, -8, 1, -1]; - - for &direction in &directions { - let mut current_index = index as isize; - - loop { - current_index += direction; - - if current_index < 0 || current_index >= 64 { - break; - } - - if (direction == 1 && current_index % 8 == 0) - || (direction == -1 && current_index % 8 == 7) - { - break; - } - - let current_index_usize = current_index as usize; - attacks.set_bit(current_index_usize); - - if occupancy.is_set(current_index_usize) { - break; - } - } - } - - attacks - } - - pub fn generate_queen_attacks(queens: Bitboard, occupancy: Bitboard) -> Bitboard { - let mut attacks = Bitboard::new(); - let queen_positions = queens; - - for i in 0..64 { - if queen_positions.is_set(i) { - attacks = attacks.or(&Board::generate_diagonal_attacks(i, occupancy)); - attacks = attacks.or(&Board::generate_straight_attacks(i, occupancy)); - } - } - - attacks - } - - pub fn generate_king_attacks(king: Bitboard) -> Bitboard { - let mut attacks = Bitboard::new(); - let king_index = king.first_set_bit().unwrap(); - - let king_moves = [ - king_index.wrapping_add(8), - king_index.wrapping_sub(8), - king_index.wrapping_add(1), - king_index.wrapping_sub(1), - king_index.wrapping_add(9), - king_index.wrapping_sub(9), - king_index.wrapping_add(7), - king_index.wrapping_sub(7), - ]; - - for &move_index in &king_moves { - if move_index < 64 { - attacks.set_bit(move_index); - } - } - - attacks - } - - pub fn generate_all_moves(board: &Board) -> Vec<(usize, usize)> { - let mut moves = Vec::new(); - let (pieces, occupancy, opponent_occupancy) = match board.turn { - Color::White => ( - &board.white_pieces, - board.white_occupancy, - board.black_occupancy, - ), - Color::Black => ( - &board.black_pieces, - board.black_occupancy, - board.white_occupancy, - ), - }; - - moves.extend(Board::generate_pawn_moves( - pieces.pawns, - occupancy, - opponent_occupancy, - board.turn, - board.en_passant_square, - )); - moves.extend(Board::generate_knight_moves( - pieces.knights, - occupancy, - opponent_occupancy, - )); - moves.extend(Board::generate_bishop_moves( - pieces.bishops, - occupancy, - opponent_occupancy, - )); - moves.extend(Board::generate_rook_moves( - pieces.rooks, - occupancy, - opponent_occupancy, - )); - moves.extend(Board::generate_queen_moves( - pieces.queens, - occupancy, - opponent_occupancy, - )); - moves.extend(Board::generate_king_moves( - pieces.king, - occupancy, - opponent_occupancy, - )); - - moves - } - - pub fn generate_pawn_moves( - pawns: Bitboard, - occupancy: Bitboard, - opponent_occupancy: Bitboard, - turn: Color, - en_passant_square: Option, - ) -> Vec<(usize, usize)> { - let mut moves = Vec::new(); - let direction = match turn { - Color::White => 8, - Color::Black => -8, - }; - - for i in 0..64 { - if pawns.is_set(i) { - let forward_one = (i as isize + direction) as usize; - if forward_one < 64 && !occupancy.is_set(forward_one) { - moves.push((i, forward_one)); - - if Board::is_pawn_starting_position(turn, i) { - let forward_two = (i as isize + 2 * direction) as usize; - if forward_two < 64 && !occupancy.is_set(forward_two) { - moves.push((i, forward_two)); - } - } - } - - let capture_left = (i as isize + direction - 1) as usize; - if capture_left < 64 && opponent_occupancy.is_set(capture_left) && i % 8 != 0 { - moves.push((i, capture_left)); - } - - let capture_right = (i as isize + direction + 1) as usize; - if capture_right < 64 && opponent_occupancy.is_set(capture_right) && i % 8 != 7 { - moves.push((i, capture_right)); - } - - if let Some(en_passant_square) = en_passant_square { - if en_passant_square == capture_left || en_passant_square == capture_right { - moves.push((i, en_passant_square)); - } - } - } - } - - moves - } - - pub fn generate_knight_moves( - knights: Bitboard, - occupancy: Bitboard, - opponent_occupancy: Bitboard, - ) -> Vec<(usize, usize)> { - let mut moves = Vec::new(); - let knight_moves = [17, 15, 10, 6, -17, -15, -10, -6]; - - for i in 0..64 { - if knights.is_set(i) { - for &offset in &knight_moves { - let target = (i as isize + offset) as usize; - if target < 64 && (target as isize >= 0) && !occupancy.is_set(target) { - moves.push((i, target)); - } else if target < 64 - && (target as isize >= 0) - && opponent_occupancy.is_set(target) - { - moves.push((i, target)); - } - } - } - } - - moves - } - - pub fn generate_bishop_moves( - bishops: Bitboard, - occupancy: Bitboard, - opponent_occupancy: Bitboard, - ) -> Vec<(usize, usize)> { - let mut moves = Vec::new(); - let directions = [9, 7, -9, -7]; - - for i in 0..64 { - if bishops.is_set(i) { - for &direction in &directions { - let mut current_index = i as isize; - - loop { - current_index += direction; - - if current_index < 0 || current_index >= 64 { - break; - } - - if (direction == 9 || direction == -7) && current_index % 8 == 0 { - break; - } - if (direction == 7 || direction == -9) && current_index % 8 == 7 { - break; - } - - let current_index_usize = current_index as usize; - - if occupancy.is_set(current_index_usize) { - break; - } - - moves.push((i, current_index_usize)); - - if opponent_occupancy.is_set(current_index_usize) { - break; - } - } - } - } - } - - moves - } - - pub fn generate_rook_moves( - rooks: Bitboard, - occupancy: Bitboard, - opponent_occupancy: Bitboard, - ) -> Vec<(usize, usize)> { - let mut moves = Vec::new(); - let directions = [8, -8, 1, -1]; - - for i in 0..64 { - if rooks.is_set(i) { - for &direction in &directions { - let mut current_index = i as isize; - - loop { - current_index += direction; - - if current_index < 0 || current_index >= 64 { - break; - } - - if (direction == 1 && current_index % 8 == 0) - || (direction == -1 && current_index % 8 == 7) - { - break; - } - - let current_index_usize = current_index as usize; - - if occupancy.is_set(current_index_usize) { - break; - } - - moves.push((i, current_index_usize)); - - if opponent_occupancy.is_set(current_index_usize) { - break; - } - } + Color::Black => { + self.black_occupancy.set_bit(index); + // self.black_attacks = self.black_attacks.or(&bb); + match piece { + Piece::Pawn => self.black_pieces.pawns = self.black_pieces.pawns.or(&bb), + Piece::Knight => self.black_pieces.knights = self.black_pieces.knights.or(&bb), + Piece::Bishop => self.black_pieces.bishops = self.black_pieces.bishops.or(&bb), + Piece::Rook => self.black_pieces.rooks = self.black_pieces.rooks.or(&bb), + Piece::Queen => self.black_pieces.queens = self.black_pieces.queens.or(&bb), + Piece::King => self.black_pieces.king = self.black_pieces.king.or(&bb), } } } - - moves } - pub fn generate_queen_moves( - queens: Bitboard, - occupancy: Bitboard, - opponent_occupancy: Bitboard, - ) -> Vec<(usize, usize)> { - let mut moves = Vec::new(); - - for i in 0..64 { - if queens.is_set(i) { - moves.extend(Board::generate_bishop_moves( - Bitboard(1 << i), - occupancy, - opponent_occupancy, - )); - moves.extend(Board::generate_rook_moves( - Bitboard(1 << i), - occupancy, - opponent_occupancy, - )); - } - } - - moves + fn square_to_index(square: &str) -> usize { + let file = square.chars().nth(0).unwrap() as usize - 'a' as usize; + let rank = square.chars().nth(1).unwrap() as usize - '1' as usize; + rank * 8 + file } - pub fn generate_king_moves( - king: Bitboard, - occupancy: Bitboard, - opponent_occupancy: Bitboard, - ) -> Vec<(usize, usize)> { - let mut moves = Vec::new(); - let king_index = king.first_set_bit().unwrap(); - - let king_moves = [8, -8, 1, -1, 9, -9, 7, -7]; - - for &offset in &king_moves { - let target = (king_index as isize + offset) as usize; - if target < 64 && (target as isize >= 0) && !occupancy.is_set(target) { - moves.push((king_index, target)); - } else if target < 64 && (target as isize >= 0) && opponent_occupancy.is_set(target) { - moves.push((king_index, target)); - } - } - - moves + fn index_to_square(index: usize) -> String { + let file = (index % 8) as u8 + b'a'; + let rank = (index / 8) as u8 + b'1'; + format!("{}{}", file as char, rank as char) } } diff --git a/src/constans.rs b/src/constans.rs new file mode 100644 index 0000000..756a9b8 --- /dev/null +++ b/src/constans.rs @@ -0,0 +1,19 @@ +pub const RANK_1: u64 = 0x00000000000000FF; +pub const RANK_2: u64 = 0x000000000000FF00; +pub const RANK_3: u64 = 0x0000000000FF0000; +pub const RANK_4: u64 = 0x00000000FF000000; +pub const RANK_5: u64 = 0x000000FF00000000; +pub const RANK_6: u64 = 0x0000FF0000000000; +pub const RANK_7: u64 = 0x00FF000000000000; +pub const RANK_8: u64 = 0xFF00000000000000; + +pub const FILE_A: u64 = 0x0101010101010101; +pub const FILE_B: u64 = 0x0202020202020202; +pub const FILE_C: u64 = 0x0404040404040404; +pub const FILE_D: u64 = 0x0808080808080808; +pub const FILE_E: u64 = 0x1010101010101010; +pub const FILE_F: u64 = 0x2020202020202020; +pub const FILE_G: u64 = 0x4040404040404040; +pub const FILE_H: u64 = 0x8080808080808080; + +pub const STARTING_POSITION: &str = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"; diff --git a/src/lib.rs b/src/lib.rs index 7f821e0..b7885c0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,3 @@ pub mod bitboard; - pub mod board; +pub mod constans; diff --git a/tests/bitboard_tests.rs b/tests/bitboard_tests.rs index 66a6ce8..8b94ef6 100644 --- a/tests/bitboard_tests.rs +++ b/tests/bitboard_tests.rs @@ -96,4 +96,16 @@ mod tests { let bb = Bitboard(0b1010); assert_eq!(bb.last_set_bit(), Some(3)); } -} \ No newline at end of file + + #[test] + fn test_bitboard_from_index() { + let bb = Bitboard::from_index(3); + assert_eq!(bb.value(), 8); // 1 << 3 = 8 + } + + #[test] + fn test_bitboard_default() { + let bb: Bitboard = Default::default(); + assert_eq!(bb.value(), 0); + } +} diff --git a/tests/board_tests.rs b/tests/board_tests.rs index a8ee447..5cb76d0 100644 --- a/tests/board_tests.rs +++ b/tests/board_tests.rs @@ -6,346 +6,346 @@ mod tests { use super::*; #[test] - fn test_board_new() { - let board = Board::new(); + fn test_board_starting_position() { + let board = Board::init(); assert_eq!(board.turn, Color::White); assert!(board.white_pieces.pawns.is_set(8)); assert!(board.black_pieces.pawns.is_set(48)); } - - #[test] - fn test_square_to_index() { - assert_eq!(Board::square_to_index("a1"), 0); - assert_eq!(Board::square_to_index("h8"), 63); - } - - #[test] - fn test_place_piece() { - let mut board = Board::new(); - board.place_piece(Color::White, Piece::Knight, 18); - assert!(board.white_pieces.knights.is_set(18)); - } - - #[test] - fn test_is_pawn_starting_position() { - assert!(Board::is_pawn_starting_position(Color::White, 8)); - assert!(!Board::is_pawn_starting_position(Color::White, 16)); - } - - #[test] - fn test_is_square_empty() { - let board = Board::new(); - assert!(Board::is_square_empty(16, board.white_occupancy)); - } - - #[test] - fn test_is_square_enemy() { - let board = - Board::from_fen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1").unwrap(); - assert!(board.is_square_enemy(Color::White, 48)); // a7 should have a black pawn - assert!(!board.is_square_enemy(Color::White, 8)); // a2 should have a white pawn - } - - #[test] - fn test_is_check() { - let board = Board::new(); - assert_eq!(board.is_check(), None); - } - - #[test] - fn test_generate_pawn_attacks() { - let board = Board::new(); - let white_pawns = - Bitboard(0b0000000000000000000000000000000000000000000000000000000000100000); - let black_pawns = Bitboard(0b100000000000000000000000000000000000000000000000000000000000); - - let white_attacks = Board::generate_pawn_attacks(Color::White, white_pawns); - let black_attacks = Board::generate_pawn_attacks(Color::Black, black_pawns); - - assert_eq!(white_attacks, Bitboard(0b101000000000000)); - assert_eq!( - black_attacks, - Bitboard(0b10100000000000000000000000000000000000000000000000000) - ); - } - - #[test] - fn test_generate_knight_attacks() { - let board = Board::new(); - let knights = Bitboard(0b0000000000000000000000000000000000000000000000000000000000000010); - - let attacks = Board::generate_knight_attacks(knights); - - assert_eq!(attacks, Bitboard(0b1010000100000000000)); - } - - #[test] - fn test_generate_bishop_attacks() { - let board = Board::new(); - let bishops = Bitboard(0b0000000000000000000000000000000000000000000000000000000000001000); - let occupancy = - Bitboard(0b0000000000000000000000000000000000000000000000000000000000000000); - - let attacks = Board::generate_bishop_attacks(bishops, occupancy); - - let expected_attacks = Bitboard(0b1000000001000001001000100001010000000000); - assert_eq!(attacks, expected_attacks); - } - - #[test] - fn test_generate_rook_attacks() { - let board = Board::new(); - let rooks = Bitboard(0b0000000000000000000000000000000000000000000000000000000000000001); - let occupancy = - Bitboard(0b0000000000000000000000000000000000000000000000000000000000000000); - - let attacks = Board::generate_rook_attacks(rooks, occupancy); - - assert_eq!( - attacks, - Bitboard(0b100000001000000010000000100000001000000010000000111111110) - ); - } - - #[test] - fn test_generate_queen_attacks() { - let board = Board::new(); - let queens = Bitboard(0b0000000000000000000000000000000000000000000000000000000000001000); - let occupancy = - Bitboard(0b0000000000000000000000000000000000000000000000000000000000000000); - - let attacks = Board::generate_queen_attacks(queens, occupancy); - - assert_eq!( - attacks, - Bitboard(0b100000001000000010001000100001001001001010100001110011110111) - ); - } - - #[test] - fn test_generate_king_attacks() { - let board = Board::new(); - let king = Bitboard(0b0000000000000000000000000000000000000000000000000000000000001000); - - let attacks = Board::generate_king_attacks(king); - - assert_eq!(attacks, Bitboard(0b1110000010100)); - } - - #[test] - fn test_from_fen_starting_position() { - let fen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"; - let board = Board::from_fen(fen).unwrap(); - - assert_eq!( - board.white_pieces.pawns, - Bitboard(0b0000000000000000000000000000000000000000000000001111111100000000) - ); - assert_eq!( - board.white_pieces.knights, - Bitboard(0b0000000000000000000000000000000000000000000000000000000001000010) - ); - assert_eq!( - board.white_pieces.bishops, - Bitboard(0b0000000000000000000000000000000000000000000000000000000000100100) - ); - assert_eq!( - board.white_pieces.rooks, - Bitboard(0b0000000000000000000000000000000000000000000000000000000010000001) - ); - assert_eq!( - board.white_pieces.queens, - Bitboard(0b0000000000000000000000000000000000000000000000000000000000001000) - ); - assert_eq!( - board.white_pieces.king, - Bitboard(0b0000000000000000000000000000000000000000000000000000000000010000) - ); - - assert_eq!( - board.black_pieces.pawns, - Bitboard(0b0000000011111111000000000000000000000000000000000000000000000000) - ); - assert_eq!( - board.black_pieces.knights, - Bitboard(0b0100001000000000000000000000000000000000000000000000000000000000) - ); - assert_eq!( - board.black_pieces.bishops, - Bitboard(0b0010010000000000000000000000000000000000000000000000000000000000) - ); - assert_eq!( - board.black_pieces.rooks, - Bitboard(0b1000000100000000000000000000000000000000000000000000000000000000) - ); - assert_eq!( - board.black_pieces.queens, - Bitboard(0b0000100000000000000000000000000000000000000000000000000000000000) - ); - assert_eq!( - board.black_pieces.king, - Bitboard(0b0001000000000000000000000000000000000000000000000000000000000000) - ); - - assert_eq!(board.turn, Color::White); - - assert_eq!( - board.castling_rights, - CastlingRights { - white_king_side: true, - white_queen_side: true, - black_king_side: true, - black_queen_side: true, - } - ); - - assert_eq!(board.en_passant_square, None); - - assert_eq!(board.halfmove_clock, 0); - assert_eq!(board.fullmove_number, 1); - } - - #[test] - fn test_generate_pawn_moves() { - let white_pawns = Bitboard(0b10000000000000); - let black_pawns = Bitboard(0b1000000000000000000000000000000000000000000000000000); - - let white_moves = - Board::generate_pawn_moves(white_pawns, white_pawns, Bitboard(0), Color::White, None); - let black_moves = - Board::generate_pawn_moves(black_pawns, black_pawns, Bitboard(0), Color::Black, None); - - assert_eq!(white_moves, vec![(13, 21), (13, 29)]); - assert_eq!(black_moves, vec![(51, 43), (51, 35)]); - } - - #[test] - fn test_generate_knight_moves() { - let knights = Bitboard(0b1000000000000000000000000000); - - let moves = Board::generate_knight_moves(knights, knights, Bitboard(0)); - - assert_eq!( - moves, - vec![ - (27, 44), - (27, 42), - (27, 37), - (27, 33), - (27, 10), - (27, 12), - (27, 17), - (27, 21) - ] - ); - } - - #[test] - fn test_generate_bishop_moves() { - let bishops = Bitboard(0b1000000000000000000000000000); - let occupancy = Bitboard(0); - - let moves = Board::generate_bishop_moves(bishops, occupancy, occupancy); - - let expected_moves = vec![ - (27, 36), - (27, 45), - (27, 54), - (27, 63), - (27, 34), - (27, 41), - (27, 48), - (27, 18), - (27, 9), - (27, 0), - (27, 20), - (27, 13), - (27, 6), - ]; - assert_eq!(moves, expected_moves); - } - - #[test] - fn test_generate_rook_moves() { - let rooks = Bitboard(0b1000000000000000000000000000); - let occupancy = Bitboard(0); - - let moves = Board::generate_rook_moves(rooks, rooks, occupancy); - - let expected_moves = vec![ - (27, 35), - (27, 43), - (27, 51), - (27, 59), - (27, 19), - (27, 11), - (27, 3), - (27, 28), - (27, 29), - (27, 30), - (27, 31), - (27, 26), - (27, 25), - (27, 24), - ]; - assert_eq!(moves, expected_moves); - } - - #[test] - fn test_generate_queen_moves() { - let queens = Bitboard(0b1000000000000000000000000000); - let occupancy = Bitboard(0); - - let moves = Board::generate_queen_moves(queens, queens, occupancy); - - let expected_moves = vec![ - (27, 36), - (27, 45), - (27, 54), - (27, 63), - (27, 34), - (27, 41), - (27, 48), - (27, 18), - (27, 9), - (27, 0), - (27, 20), - (27, 13), - (27, 6), - (27, 35), - (27, 43), - (27, 51), - (27, 59), - (27, 19), - (27, 11), - (27, 3), - (27, 28), - (27, 29), - (27, 30), - (27, 31), - (27, 26), - (27, 25), - (27, 24), - ]; - assert_eq!(moves, expected_moves); - } - - #[test] - fn test_generate_king_moves() { - let king = Bitboard(0b1000000000000000000000000000); - - let moves = Board::generate_king_moves(king, king, Bitboard(0)); - - let expected_moves = vec![ - (27, 35), - (27, 19), - (27, 28), - (27, 26), - (27, 36), - (27, 18), - (27, 34), - (27, 20), - ]; - assert_eq!(moves, expected_moves); - } + // + // #[test] + // fn test_square_to_index() { + // assert_eq!(Board::square_to_index("a1"), 0); + // assert_eq!(Board::square_to_index("h8"), 63); + // } + // + // #[test] + // fn test_place_piece() { + // let mut board = Board::new(); + // board.place_piece(Color::White, Piece::Knight, 18); + // assert!(board.white_pieces.knights.is_set(18)); + // } + // + // #[test] + // fn test_is_pawn_starting_position() { + // assert!(Board::is_pawn_starting_position(Color::White, 8)); + // assert!(!Board::is_pawn_starting_position(Color::White, 16)); + // } + // + // #[test] + // fn test_is_square_empty() { + // let board = Board::new(); + // assert!(Board::is_square_empty(16, board.white_occupancy)); + // } + // + // #[test] + // fn test_is_square_enemy() { + // let board = + // Board::from_fen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1").unwrap(); + // assert!(board.is_square_enemy(Color::White, 48)); // a7 should have a black pawn + // assert!(!board.is_square_enemy(Color::White, 8)); // a2 should have a white pawn + // } + // + // #[test] + // fn test_is_check() { + // let board = Board::starting_position(); + // assert_eq!(board.is_check(), None); + // } + // + // #[test] + // fn test_generate_pawn_attacks() { + // let board = Board::new(); + // let white_pawns = + // Bitboard(0b0000000000000000000000000000000000000000000000000000000000100000); + // let black_pawns = Bitboard(0b100000000000000000000000000000000000000000000000000000000000); + // + // let white_attacks = Board::generate_pawn_attacks(Color::White, white_pawns); + // let black_attacks = Board::generate_pawn_attacks(Color::Black, black_pawns); + // + // assert_eq!(white_attacks, Bitboard(0b101000000000000)); + // assert_eq!( + // black_attacks, + // Bitboard(0b10100000000000000000000000000000000000000000000000000) + // ); + // } + // + // #[test] + // fn test_generate_knight_attacks() { + // let board = Board::new(); + // let knights = Bitboard(0b0000000000000000000000000000000000000000000000000000000000000010); + // + // let attacks = Board::generate_knight_attacks(knights); + // + // assert_eq!(attacks, Bitboard(0b1010000100000000000)); + // } + // + // #[test] + // fn test_generate_bishop_attacks() { + // let board = Board::new(); + // let bishops = Bitboard(0b0000000000000000000000000000000000000000000000000000000000001000); + // let occupancy = + // Bitboard(0b0000000000000000000000000000000000000000000000000000000000000000); + // + // let attacks = Board::generate_bishop_attacks(bishops, occupancy); + // + // let expected_attacks = Bitboard(0b1000000001000001001000100001010000000000); + // assert_eq!(attacks, expected_attacks); + // } + // + // #[test] + // fn test_generate_rook_attacks() { + // let board = Board::new(); + // let rooks = Bitboard(0b0000000000000000000000000000000000000000000000000000000000000001); + // let occupancy = + // Bitboard(0b0000000000000000000000000000000000000000000000000000000000000000); + // + // let attacks = Board::generate_rook_attacks(rooks, occupancy); + // + // assert_eq!( + // attacks, + // Bitboard(0b100000001000000010000000100000001000000010000000111111110) + // ); + // } + // + // #[test] + // fn test_generate_queen_attacks() { + // let board = Board::new(); + // let queens = Bitboard(0b0000000000000000000000000000000000000000000000000000000000001000); + // let occupancy = + // Bitboard(0b0000000000000000000000000000000000000000000000000000000000000000); + // + // let attacks = Board::generate_queen_attacks(queens, occupancy); + // + // assert_eq!( + // attacks, + // Bitboard(0b100000001000000010001000100001001001001010100001110011110111) + // ); + // } + // + // #[test] + // fn test_generate_king_attacks() { + // let board = Board::new(); + // let king = Bitboard(0b0000000000000000000000000000000000000000000000000000000000001000); + // + // let attacks = Board::generate_king_attacks(king); + // + // assert_eq!(attacks, Bitboard(0b1110000010100)); + // } + // + // #[test] + // fn test_from_fen_starting_position() { + // let fen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"; + // let board = Board::from_fen(fen).unwrap(); + // + // assert_eq!( + // board.white_pieces.pawns, + // Bitboard(0b0000000000000000000000000000000000000000000000001111111100000000) + // ); + // assert_eq!( + // board.white_pieces.knights, + // Bitboard(0b0000000000000000000000000000000000000000000000000000000001000010) + // ); + // assert_eq!( + // board.white_pieces.bishops, + // Bitboard(0b0000000000000000000000000000000000000000000000000000000000100100) + // ); + // assert_eq!( + // board.white_pieces.rooks, + // Bitboard(0b0000000000000000000000000000000000000000000000000000000010000001) + // ); + // assert_eq!( + // board.white_pieces.queens, + // Bitboard(0b0000000000000000000000000000000000000000000000000000000000001000) + // ); + // assert_eq!( + // board.white_pieces.king, + // Bitboard(0b0000000000000000000000000000000000000000000000000000000000010000) + // ); + // + // assert_eq!( + // board.black_pieces.pawns, + // Bitboard(0b0000000011111111000000000000000000000000000000000000000000000000) + // ); + // assert_eq!( + // board.black_pieces.knights, + // Bitboard(0b0100001000000000000000000000000000000000000000000000000000000000) + // ); + // assert_eq!( + // board.black_pieces.bishops, + // Bitboard(0b0010010000000000000000000000000000000000000000000000000000000000) + // ); + // assert_eq!( + // board.black_pieces.rooks, + // Bitboard(0b1000000100000000000000000000000000000000000000000000000000000000) + // ); + // assert_eq!( + // board.black_pieces.queens, + // Bitboard(0b0000100000000000000000000000000000000000000000000000000000000000) + // ); + // assert_eq!( + // board.black_pieces.king, + // Bitboard(0b0001000000000000000000000000000000000000000000000000000000000000) + // ); + // + // assert_eq!(board.turn, Color::White); + // + // assert_eq!( + // board.castling_rights, + // CastlingRights { + // white_king_side: true, + // white_queen_side: true, + // black_king_side: true, + // black_queen_side: true, + // } + // ); + // + // assert_eq!(board.en_passant_square, None); + // + // assert_eq!(board.halfmove_clock, 0); + // assert_eq!(board.fullmove_number, 1); + // } + // + // #[test] + // fn test_generate_pawn_moves() { + // let white_pawns = Bitboard(0b10000000000000); + // let black_pawns = Bitboard(0b1000000000000000000000000000000000000000000000000000); + // + // let white_moves = + // Board::generate_pawn_moves(white_pawns, white_pawns, Bitboard(0), Color::White, None); + // let black_moves = + // Board::generate_pawn_moves(black_pawns, black_pawns, Bitboard(0), Color::Black, None); + // + // assert_eq!(white_moves, vec![(13, 21), (13, 29)]); + // assert_eq!(black_moves, vec![(51, 43), (51, 35)]); + // } + // + // #[test] + // fn test_generate_knight_moves() { + // let knights = Bitboard(0b1000000000000000000000000000); + // + // let moves = Board::generate_knight_moves(knights, knights, Bitboard(0)); + // + // assert_eq!( + // moves, + // vec![ + // (27, 44), + // (27, 42), + // (27, 37), + // (27, 33), + // (27, 10), + // (27, 12), + // (27, 17), + // (27, 21) + // ] + // ); + // } + // + // #[test] + // fn test_generate_bishop_moves() { + // let bishops = Bitboard(0b1000000000000000000000000000); + // let occupancy = Bitboard(0); + // + // let moves = Board::generate_bishop_moves(bishops, occupancy, occupancy); + // + // let expected_moves = vec![ + // (27, 36), + // (27, 45), + // (27, 54), + // (27, 63), + // (27, 34), + // (27, 41), + // (27, 48), + // (27, 18), + // (27, 9), + // (27, 0), + // (27, 20), + // (27, 13), + // (27, 6), + // ]; + // assert_eq!(moves, expected_moves); + // } + // + // #[test] + // fn test_generate_rook_moves() { + // let rooks = Bitboard(0b1000000000000000000000000000); + // let occupancy = Bitboard(0); + // + // let moves = Board::generate_rook_moves(rooks, rooks, occupancy); + // + // let expected_moves = vec![ + // (27, 35), + // (27, 43), + // (27, 51), + // (27, 59), + // (27, 19), + // (27, 11), + // (27, 3), + // (27, 28), + // (27, 29), + // (27, 30), + // (27, 31), + // (27, 26), + // (27, 25), + // (27, 24), + // ]; + // assert_eq!(moves, expected_moves); + // } + // + // #[test] + // fn test_generate_queen_moves() { + // let queens = Bitboard(0b1000000000000000000000000000); + // let occupancy = Bitboard(0); + // + // let moves = Board::generate_queen_moves(queens, queens, occupancy); + // + // let expected_moves = vec![ + // (27, 36), + // (27, 45), + // (27, 54), + // (27, 63), + // (27, 34), + // (27, 41), + // (27, 48), + // (27, 18), + // (27, 9), + // (27, 0), + // (27, 20), + // (27, 13), + // (27, 6), + // (27, 35), + // (27, 43), + // (27, 51), + // (27, 59), + // (27, 19), + // (27, 11), + // (27, 3), + // (27, 28), + // (27, 29), + // (27, 30), + // (27, 31), + // (27, 26), + // (27, 25), + // (27, 24), + // ]; + // assert_eq!(moves, expected_moves); + // } + // + // #[test] + // fn test_generate_king_moves() { + // let king = Bitboard(0b1000000000000000000000000000); + // + // let moves = Board::generate_king_moves(king, king, Bitboard(0)); + // + // let expected_moves = vec![ + // (27, 35), + // (27, 19), + // (27, 28), + // (27, 26), + // (27, 36), + // (27, 18), + // (27, 34), + // (27, 20), + // ]; + // assert_eq!(moves, expected_moves); + // } }