diff --git a/helper_scripts/generate_attacking_pawns.py b/helper_scripts/generate_attacking_pawns.py new file mode 100644 index 0000000..a9fca24 --- /dev/null +++ b/helper_scripts/generate_attacking_pawns.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python3 + +def generate_pawn_attacked_by(): + """ + Generates a list of 64 u64 bitboards for each color (White, Black), + where each bitboard represents the squares FROM WHICH a pawn + can attack a given TARGET square. + Uses Little-Endian File-Rank (LEFR) mapping: A1=0, H1=7, A2=8, ..., H8=63. + + Returns: + [[u64; 64]; 2] (represented as a list of two lists) + Index 0: White attackers (squares where a White pawn attacks the target) + Index 1: Black attackers (squares where a Black pawn attacks the target) + """ + + # all_attacks[0] = White, all_attacks[1] = Black + all_attacks = [[], []] + + for sq in range(64): + rank = sq // 8 + file = sq % 8 + + white_attackers_bb = 0 + black_attackers_bb = 0 + + # --- White Attackers (Index 0) --- + # A white pawn attacks "up" the board to reach the target square 'sq'. + # This means the attacking pawn must be "below" 'sq'. + # We only check if the target is not on the 1st rank + if rank > 0: + # Attacker from Down-Left (relative to target sq) + # Not possible if target is on the A-file + if file > 0: + white_attackers_bb |= (1 << (sq - 9)) + + # Attacker from Down-Right (relative to target sq) + # Not possible if target is on the H-file + if file < 7: + white_attackers_bb |= (1 << (sq - 7)) + + # --- Black Attackers (Index 1) --- + # A black pawn attacks "down" the board to reach the target square 'sq'. + # This means the attacking pawn must be "above" 'sq'. + # We only check if the target is not on the 8th rank + if rank < 7: + # Attacker from Up-Left (relative to target sq) + # Not possible if target is on the A-file + if file > 0: + black_attackers_bb |= (1 << (sq + 7)) + + # Attacker from Up-Right (relative to target sq) + # Not possible if target is on the H-file + if file < 7: + black_attackers_bb |= (1 << (sq + 9)) + + all_attacks[0].append(white_attackers_bb) + all_attacks[1].append(black_attackers_bb) + + return all_attacks + +def print_rust_array(attacks_by_color, const_name): + """ + Prints the list of attack bitboards as a nested Rust array. + """ + print(f"pub const {const_name}: [[u64; 64]; 2] = [") + + # --- Print White Attacks --- + print(" [ // Color 0: White (Squares a White pawn attacks FROM)") + for i, attacks_bb in enumerate(attacks_by_color[0]): + raw_binary_string = f"{attacks_bb:064b}" + chunks = [raw_binary_string[i:i+8] for i in range(0, 64, 8)] + binary_string = f"0b{'_'.join(chunks)}" + print(f" {binary_string}, // Target Square {i} ({'ABCDEFGH'[i%8]}{i//8 + 1})") + print(" ],") + + # --- Print Black Attacks --- + print(" [ // Color 1: Black (Squares a Black pawn attacks FROM)") + for i, attacks_bb in enumerate(attacks_by_color[1]): + raw_binary_string = f"{attacks_bb:064b}" + chunks = [raw_binary_string[i:i+8] for i in range(0, 64, 8)] + binary_string = f"0b{'_'.join(chunks)}" + print(f" {binary_string}, // Target Square {i} ({'ABCDEFGH'[i%8]}{i//8 + 1})") + print(" ]") + + print("];") + +if __name__ == "__main__": + attacks = generate_pawn_attacked_by() + print_rust_array(attacks, "ATTACKING_PAWNS") \ No newline at end of file diff --git a/src/display.rs b/src/display.rs index 8a09861..f8a9a29 100644 --- a/src/display.rs +++ b/src/display.rs @@ -1,6 +1,7 @@ -use std::fmt; use crate::board::{Board, Color, PieceType}; -use crate::r#move::{Move, MoveList, MOVE_FLAG_BK_CASTLE, MOVE_FLAG_BQ_CASTLE, MOVE_FLAG_PROMO_B, MOVE_FLAG_PROMO_B_CAP, MOVE_FLAG_PROMO_N, MOVE_FLAG_PROMO_N_CAP, MOVE_FLAG_PROMO_Q, MOVE_FLAG_PROMO_Q_CAP, MOVE_FLAG_PROMO_R, MOVE_FLAG_PROMO_R_CAP, MOVE_FLAG_WK_CASTLE, MOVE_FLAG_WQ_CASTLE, MOVE_FROM_MASK, MOVE_TO_MASK}; +use crate::r#move::MoveList; +use crate::square::Square; +use std::fmt; impl Board { /// Prints the board as a human-readable ASCII grid. @@ -12,7 +13,7 @@ impl Board { let sq = (rank * 8 + file) as u8; let mask = 1u64 << sq; - if let Some(piece) = self.get_piece_at(mask) { + if let Some(piece) = self.get_piece_at_unicode(mask) { print!("{} ", piece); } else { print!(". "); @@ -45,7 +46,7 @@ impl Board { println!(); } - /// Helper function to find which piece (as a char) is on a given square mask. + /// Helper function to find which piece (as a FEN char) is on a given square mask. pub fn get_piece_at(&self, sq_mask: u64) -> Option { let white = Color::White as usize; let black = Color::Black as usize; @@ -90,6 +91,51 @@ impl Board { None } + /// Helper function to find which piece (as a unicode char) is on a given square mask. + pub fn get_piece_at_unicode(&self, sq_mask: u64) -> Option { + let white = Color::White as usize; + let black = Color::Black as usize; + + if (self.pieces[PieceType::Pawn as usize][white] & sq_mask) != 0 { + return Some('♙'); + } + if (self.pieces[PieceType::Pawn as usize][black] & sq_mask) != 0 { + return Some('♟'); + } + if (self.pieces[PieceType::Knight as usize][white] & sq_mask) != 0 { + return Some('♘'); + } + if (self.pieces[PieceType::Knight as usize][black] & sq_mask) != 0 { + return Some('♞'); + } + if (self.pieces[PieceType::Bishop as usize][white] & sq_mask) != 0 { + return Some('♗'); + } + if (self.pieces[PieceType::Bishop as usize][black] & sq_mask) != 0 { + return Some('♝'); + } + if (self.pieces[PieceType::Rook as usize][white] & sq_mask) != 0 { + return Some('♖'); + } + if (self.pieces[PieceType::Rook as usize][black] & sq_mask) != 0 { + return Some('♜'); + } + if (self.pieces[PieceType::Queen as usize][white] & sq_mask) != 0 { + return Some('♕'); + } + if (self.pieces[PieceType::Queen as usize][black] & sq_mask) != 0 { + return Some('♛'); + } + if (self.pieces[PieceType::King as usize][white] & sq_mask) != 0 { + return Some('♔'); + } + if (self.pieces[PieceType::King as usize][black] & sq_mask) != 0 { + return Some('♚'); + } + + None + } + /// Prints all internal bitboards for debugging purposes. pub fn pretty_print_internals(&self) { println!("\n========= BOARD INTERNAL BITBOARDS ========="); @@ -145,6 +191,85 @@ impl Board { impl fmt::Display for MoveList { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", &self.iter().map(|mv| mv.to_algebraic()).collect::>().join(" ")) + write!( + f, + "{}", + &self + .iter() + .map(|mv| mv.to_algebraic()) + .collect::>() + .join(" ") + ) } -} \ No newline at end of file +} + +impl fmt::Display for Square { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Square::A1 => write!(f, "A1"), + Square::B1 => write!(f, "B1"), + Square::C1 => write!(f, "C1"), + Square::D1 => write!(f, "D1"), + Square::E1 => write!(f, "E1"), + Square::F1 => write!(f, "F1"), + Square::G1 => write!(f, "G1"), + Square::H1 => write!(f, "H1"), + Square::A2 => write!(f, "A2"), + Square::B2 => write!(f, "B2"), + Square::C2 => write!(f, "C2"), + Square::D2 => write!(f, "D2"), + Square::E2 => write!(f, "E2"), + Square::F2 => write!(f, "F2"), + Square::G2 => write!(f, "G2"), + Square::H2 => write!(f, "H2"), + Square::A3 => write!(f, "A3"), + Square::B3 => write!(f, "B3"), + Square::C3 => write!(f, "C3"), + Square::D3 => write!(f, "D3"), + Square::E3 => write!(f, "E3"), + Square::F3 => write!(f, "F3"), + Square::G3 => write!(f, "G3"), + Square::H3 => write!(f, "H3"), + Square::A4 => write!(f, "A4"), + Square::B4 => write!(f, "B4"), + Square::C4 => write!(f, "C4"), + Square::D4 => write!(f, "D4"), + Square::E4 => write!(f, "E4"), + Square::F4 => write!(f, "F4"), + Square::G4 => write!(f, "G4"), + Square::H4 => write!(f, "H4"), + Square::A5 => write!(f, "A5"), + Square::B5 => write!(f, "B5"), + Square::C5 => write!(f, "C5"), + Square::D5 => write!(f, "D5"), + Square::E5 => write!(f, "E5"), + Square::F5 => write!(f, "F5"), + Square::G5 => write!(f, "G5"), + Square::H5 => write!(f, "H5"), + Square::A6 => write!(f, "A6"), + Square::B6 => write!(f, "B6"), + Square::C6 => write!(f, "C6"), + Square::D6 => write!(f, "D6"), + Square::E6 => write!(f, "E6"), + Square::F6 => write!(f, "F6"), + Square::G6 => write!(f, "G6"), + Square::H6 => write!(f, "H6"), + Square::A7 => write!(f, "A7"), + Square::B7 => write!(f, "B7"), + Square::C7 => write!(f, "C7"), + Square::D7 => write!(f, "D7"), + Square::E7 => write!(f, "E7"), + Square::F7 => write!(f, "F7"), + Square::G7 => write!(f, "G7"), + Square::H7 => write!(f, "H7"), + Square::A8 => write!(f, "A8"), + Square::B8 => write!(f, "B8"), + Square::C8 => write!(f, "C8"), + Square::D8 => write!(f, "D8"), + Square::E8 => write!(f, "E8"), + Square::F8 => write!(f, "F8"), + Square::G8 => write!(f, "G8"), + Square::H8 => write!(f, "H8") + } + } +} diff --git a/src/movegen/legal_check.rs b/src/movegen/legal_check.rs new file mode 100644 index 0000000..669f6d3 --- /dev/null +++ b/src/movegen/legal_check.rs @@ -0,0 +1,74 @@ +use crate::board::{Board, Color, PieceType}; +use crate::movegen::tables::{get_bishop_attacks, get_rook_attacks, ATTACKING_PAWNS, KING_ATTACKS, KNIGHT_ATTACKS, MAGICS_BISHOP, MAGICS_ROOK, PREMASKS_BISHOP, PREMASKS_ROOK, RELEVANT_BITS_BISHOP, RELEVANT_BITS_ROOK}; +use crate::square::{Square, SQUARES}; + +/// Checks if the king of the side that is NOT to move is in check +pub fn is_king_attacked(board: &Board) -> bool { + let king = board.pieces[PieceType::King as usize][!board.side_to_move as usize]; + is_square_attacked(board, SQUARES[king.trailing_zeros() as usize], board.side_to_move) +} + +// TODO check if castle is legal (squares in between) + +/// calculate if a square on the board is attacked by a color +pub fn is_square_attacked(board: &Board, square: Square, color: Color) -> bool { + // 1. Non sliding + // 1.1 Pawn + let pawns = board.pieces[PieceType::Pawn as usize][color as usize]; + if (pawns & ATTACKING_PAWNS[color as usize][square as usize]) != 0 { + return true; + } + + // 1.2 Knight + let knights = board.pieces[PieceType::Knight as usize][color as usize]; + if (knights & KNIGHT_ATTACKS[square as usize]) != 0 { + return true; + } + + // 1.3 King + let king = board.pieces[PieceType::King as usize][color as usize]; + if (king & KING_ATTACKS[square as usize]) != 0 { + return true; + } + + // 2. Sliding + let blockers = board.all_occupied; + + // 2.1 Bishop (and part of Queen) + let premask_bishop = PREMASKS_BISHOP[square as usize]; + let magic_bishop = MAGICS_BISHOP[square as usize]; + let relevant_bits_bishop = RELEVANT_BITS_BISHOP[square as usize]; + let shift_bishop = 64 - relevant_bits_bishop; + let attack_table_bishop = get_bishop_attacks(); + let magic_index_bishop = ((blockers & premask_bishop).wrapping_mul(magic_bishop)) >> shift_bishop; + let bishop_attackable_squares = attack_table_bishop[square as usize][magic_index_bishop as usize]; + + let bishops = board.pieces[PieceType::Bishop as usize][color as usize]; + if (bishop_attackable_squares & bishops) != 0 { + return true; + } + + // 2.2 Rooks (and part of Queen) + let premask_rook = PREMASKS_ROOK[square as usize]; + let magic_rook = MAGICS_ROOK[square as usize]; + let relevant_bits_rook = RELEVANT_BITS_ROOK[square as usize]; + let shift_rook = 64 - relevant_bits_rook; + let attack_table_rook = get_rook_attacks(); + let magic_index_rook = ((blockers & premask_rook).wrapping_mul(magic_rook)) >> shift_rook; + let rook_attackable_squares = attack_table_rook[square as usize][magic_index_rook as usize]; + + let rooks = board.pieces[PieceType::Rook as usize][color as usize]; + if (rook_attackable_squares & rooks) != 0 { + return true; + } + + // 2.3 Queens + let queen_attackable_squares = bishop_attackable_squares | rook_attackable_squares; + let queens = board.pieces[PieceType::Queen as usize][color as usize]; + if (queen_attackable_squares & queens) != 0 { + return true; + } + + // No attackers found + false +} \ No newline at end of file diff --git a/src/movegen/mod.rs b/src/movegen/mod.rs index f3d2061..8c77d95 100644 --- a/src/movegen/mod.rs +++ b/src/movegen/mod.rs @@ -1,13 +1,14 @@ +use crate::board::Board; +use crate::movegen::non_sliders::{generate_king_moves, generate_knight_moves}; +use crate::movegen::pawns::generate_pawn_moves; +use crate::movegen::sliders::{generate_bishop_moves, generate_queen_moves, generate_rook_moves}; +use crate::r#move::MoveList; + pub mod non_sliders; pub mod sliders; pub mod pawns; pub mod tables; - -use crate::board::Board; -use crate::r#move::*; -use non_sliders::*; -use sliders::*; -use pawns::*; +pub mod legal_check; pub fn generate_pseudo_legal_moves(board: &Board, list: &mut MoveList) { generate_pawn_moves(board, list); diff --git a/src/movegen/tables.rs b/src/movegen/tables.rs index 6c8ee31..3bb3a4c 100644 --- a/src/movegen/tables.rs +++ b/src/movegen/tables.rs @@ -1,6 +1,141 @@ use std::sync::OnceLock; +pub const ATTACKING_PAWNS: [[u64; 64]; 2] = [ + [ // Color 0: White (Squares a White pawn attacks FROM) + 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000, // Target Square 0 (A1) + 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000, // Target Square 1 (B1) + 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000, // Target Square 2 (C1) + 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000, // Target Square 3 (D1) + 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000, // Target Square 4 (E1) + 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000, // Target Square 5 (F1) + 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000, // Target Square 6 (G1) + 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000, // Target Square 7 (H1) + 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000010, // Target Square 8 (A2) + 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000101, // Target Square 9 (B2) + 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00001010, // Target Square 10 (C2) + 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00010100, // Target Square 11 (D2) + 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00101000, // Target Square 12 (E2) + 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_01010000, // Target Square 13 (F2) + 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_10100000, // Target Square 14 (G2) + 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_01000000, // Target Square 15 (H2) + 0b00000000_00000000_00000000_00000000_00000000_00000000_00000010_00000000, // Target Square 16 (A3) + 0b00000000_00000000_00000000_00000000_00000000_00000000_00000101_00000000, // Target Square 17 (B3) + 0b00000000_00000000_00000000_00000000_00000000_00000000_00001010_00000000, // Target Square 18 (C3) + 0b00000000_00000000_00000000_00000000_00000000_00000000_00010100_00000000, // Target Square 19 (D3) + 0b00000000_00000000_00000000_00000000_00000000_00000000_00101000_00000000, // Target Square 20 (E3) + 0b00000000_00000000_00000000_00000000_00000000_00000000_01010000_00000000, // Target Square 21 (F3) + 0b00000000_00000000_00000000_00000000_00000000_00000000_10100000_00000000, // Target Square 22 (G3) + 0b00000000_00000000_00000000_00000000_00000000_00000000_01000000_00000000, // Target Square 23 (H3) + 0b00000000_00000000_00000000_00000000_00000000_00000010_00000000_00000000, // Target Square 24 (A4) + 0b00000000_00000000_00000000_00000000_00000000_00000101_00000000_00000000, // Target Square 25 (B4) + 0b00000000_00000000_00000000_00000000_00000000_00001010_00000000_00000000, // Target Square 26 (C4) + 0b00000000_00000000_00000000_00000000_00000000_00010100_00000000_00000000, // Target Square 27 (D4) + 0b00000000_00000000_00000000_00000000_00000000_00101000_00000000_00000000, // Target Square 28 (E4) + 0b00000000_00000000_00000000_00000000_00000000_01010000_00000000_00000000, // Target Square 29 (F4) + 0b00000000_00000000_00000000_00000000_00000000_10100000_00000000_00000000, // Target Square 30 (G4) + 0b00000000_00000000_00000000_00000000_00000000_01000000_00000000_00000000, // Target Square 31 (H4) + 0b00000000_00000000_00000000_00000000_00000010_00000000_00000000_00000000, // Target Square 32 (A5) + 0b00000000_00000000_00000000_00000000_00000101_00000000_00000000_00000000, // Target Square 33 (B5) + 0b00000000_00000000_00000000_00000000_00001010_00000000_00000000_00000000, // Target Square 34 (C5) + 0b00000000_00000000_00000000_00000000_00010100_00000000_00000000_00000000, // Target Square 35 (D5) + 0b00000000_00000000_00000000_00000000_00101000_00000000_00000000_00000000, // Target Square 36 (E5) + 0b00000000_00000000_00000000_00000000_01010000_00000000_00000000_00000000, // Target Square 37 (F5) + 0b00000000_00000000_00000000_00000000_10100000_00000000_00000000_00000000, // Target Square 38 (G5) + 0b00000000_00000000_00000000_00000000_01000000_00000000_00000000_00000000, // Target Square 39 (H5) + 0b00000000_00000000_00000000_00000010_00000000_00000000_00000000_00000000, // Target Square 40 (A6) + 0b00000000_00000000_00000000_00000101_00000000_00000000_00000000_00000000, // Target Square 41 (B6) + 0b00000000_00000000_00000000_00001010_00000000_00000000_00000000_00000000, // Target Square 42 (C6) + 0b00000000_00000000_00000000_00010100_00000000_00000000_00000000_00000000, // Target Square 43 (D6) + 0b00000000_00000000_00000000_00101000_00000000_00000000_00000000_00000000, // Target Square 44 (E6) + 0b00000000_00000000_00000000_01010000_00000000_00000000_00000000_00000000, // Target Square 45 (F6) + 0b00000000_00000000_00000000_10100000_00000000_00000000_00000000_00000000, // Target Square 46 (G6) + 0b00000000_00000000_00000000_01000000_00000000_00000000_00000000_00000000, // Target Square 47 (H6) + 0b00000000_00000000_00000010_00000000_00000000_00000000_00000000_00000000, // Target Square 48 (A7) + 0b00000000_00000000_00000101_00000000_00000000_00000000_00000000_00000000, // Target Square 49 (B7) + 0b00000000_00000000_00001010_00000000_00000000_00000000_00000000_00000000, // Target Square 50 (C7) + 0b00000000_00000000_00010100_00000000_00000000_00000000_00000000_00000000, // Target Square 51 (D7) + 0b00000000_00000000_00101000_00000000_00000000_00000000_00000000_00000000, // Target Square 52 (E7) + 0b00000000_00000000_01010000_00000000_00000000_00000000_00000000_00000000, // Target Square 53 (F7) + 0b00000000_00000000_10100000_00000000_00000000_00000000_00000000_00000000, // Target Square 54 (G7) + 0b00000000_00000000_01000000_00000000_00000000_00000000_00000000_00000000, // Target Square 55 (H7) + 0b00000000_00000010_00000000_00000000_00000000_00000000_00000000_00000000, // Target Square 56 (A8) + 0b00000000_00000101_00000000_00000000_00000000_00000000_00000000_00000000, // Target Square 57 (B8) + 0b00000000_00001010_00000000_00000000_00000000_00000000_00000000_00000000, // Target Square 58 (C8) + 0b00000000_00010100_00000000_00000000_00000000_00000000_00000000_00000000, // Target Square 59 (D8) + 0b00000000_00101000_00000000_00000000_00000000_00000000_00000000_00000000, // Target Square 60 (E8) + 0b00000000_01010000_00000000_00000000_00000000_00000000_00000000_00000000, // Target Square 61 (F8) + 0b00000000_10100000_00000000_00000000_00000000_00000000_00000000_00000000, // Target Square 62 (G8) + 0b00000000_01000000_00000000_00000000_00000000_00000000_00000000_00000000, // Target Square 63 (H8) + ], + [ // Color 1: Black (Squares a Black pawn attacks FROM) + 0b00000000_00000000_00000000_00000000_00000000_00000000_00000010_00000000, // Target Square 0 (A1) + 0b00000000_00000000_00000000_00000000_00000000_00000000_00000101_00000000, // Target Square 1 (B1) + 0b00000000_00000000_00000000_00000000_00000000_00000000_00001010_00000000, // Target Square 2 (C1) + 0b00000000_00000000_00000000_00000000_00000000_00000000_00010100_00000000, // Target Square 3 (D1) + 0b00000000_00000000_00000000_00000000_00000000_00000000_00101000_00000000, // Target Square 4 (E1) + 0b00000000_00000000_00000000_00000000_00000000_00000000_01010000_00000000, // Target Square 5 (F1) + 0b00000000_00000000_00000000_00000000_00000000_00000000_10100000_00000000, // Target Square 6 (G1) + 0b00000000_00000000_00000000_00000000_00000000_00000000_01000000_00000000, // Target Square 7 (H1) + 0b00000000_00000000_00000000_00000000_00000000_00000010_00000000_00000000, // Target Square 8 (A2) + 0b00000000_00000000_00000000_00000000_00000000_00000101_00000000_00000000, // Target Square 9 (B2) + 0b00000000_00000000_00000000_00000000_00000000_00001010_00000000_00000000, // Target Square 10 (C2) + 0b00000000_00000000_00000000_00000000_00000000_00010100_00000000_00000000, // Target Square 11 (D2) + 0b00000000_00000000_00000000_00000000_00000000_00101000_00000000_00000000, // Target Square 12 (E2) + 0b00000000_00000000_00000000_00000000_00000000_01010000_00000000_00000000, // Target Square 13 (F2) + 0b00000000_00000000_00000000_00000000_00000000_10100000_00000000_00000000, // Target Square 14 (G2) + 0b00000000_00000000_00000000_00000000_00000000_01000000_00000000_00000000, // Target Square 15 (H2) + 0b00000000_00000000_00000000_00000000_00000010_00000000_00000000_00000000, // Target Square 16 (A3) + 0b00000000_00000000_00000000_00000000_00000101_00000000_00000000_00000000, // Target Square 17 (B3) + 0b00000000_00000000_00000000_00000000_00001010_00000000_00000000_00000000, // Target Square 18 (C3) + 0b00000000_00000000_00000000_00000000_00010100_00000000_00000000_00000000, // Target Square 19 (D3) + 0b00000000_00000000_00000000_00000000_00101000_00000000_00000000_00000000, // Target Square 20 (E3) + 0b00000000_00000000_00000000_00000000_01010000_00000000_00000000_00000000, // Target Square 21 (F3) + 0b00000000_00000000_00000000_00000000_10100000_00000000_00000000_00000000, // Target Square 22 (G3) + 0b00000000_00000000_00000000_00000000_01000000_00000000_00000000_00000000, // Target Square 23 (H3) + 0b00000000_00000000_00000000_00000010_00000000_00000000_00000000_00000000, // Target Square 24 (A4) + 0b00000000_00000000_00000000_00000101_00000000_00000000_00000000_00000000, // Target Square 25 (B4) + 0b00000000_00000000_00000000_00001010_00000000_00000000_00000000_00000000, // Target Square 26 (C4) + 0b00000000_00000000_00000000_00010100_00000000_00000000_00000000_00000000, // Target Square 27 (D4) + 0b00000000_00000000_00000000_00101000_00000000_00000000_00000000_00000000, // Target Square 28 (E4) + 0b00000000_00000000_00000000_01010000_00000000_00000000_00000000_00000000, // Target Square 29 (F4) + 0b00000000_00000000_00000000_10100000_00000000_00000000_00000000_00000000, // Target Square 30 (G4) + 0b00000000_00000000_00000000_01000000_00000000_00000000_00000000_00000000, // Target Square 31 (H4) + 0b00000000_00000000_00000010_00000000_00000000_00000000_00000000_00000000, // Target Square 32 (A5) + 0b00000000_00000000_00000101_00000000_00000000_00000000_00000000_00000000, // Target Square 33 (B5) + 0b00000000_00000000_00001010_00000000_00000000_00000000_00000000_00000000, // Target Square 34 (C5) + 0b00000000_00000000_00010100_00000000_00000000_00000000_00000000_00000000, // Target Square 35 (D5) + 0b00000000_00000000_00101000_00000000_00000000_00000000_00000000_00000000, // Target Square 36 (E5) + 0b00000000_00000000_01010000_00000000_00000000_00000000_00000000_00000000, // Target Square 37 (F5) + 0b00000000_00000000_10100000_00000000_00000000_00000000_00000000_00000000, // Target Square 38 (G5) + 0b00000000_00000000_01000000_00000000_00000000_00000000_00000000_00000000, // Target Square 39 (H5) + 0b00000000_00000010_00000000_00000000_00000000_00000000_00000000_00000000, // Target Square 40 (A6) + 0b00000000_00000101_00000000_00000000_00000000_00000000_00000000_00000000, // Target Square 41 (B6) + 0b00000000_00001010_00000000_00000000_00000000_00000000_00000000_00000000, // Target Square 42 (C6) + 0b00000000_00010100_00000000_00000000_00000000_00000000_00000000_00000000, // Target Square 43 (D6) + 0b00000000_00101000_00000000_00000000_00000000_00000000_00000000_00000000, // Target Square 44 (E6) + 0b00000000_01010000_00000000_00000000_00000000_00000000_00000000_00000000, // Target Square 45 (F6) + 0b00000000_10100000_00000000_00000000_00000000_00000000_00000000_00000000, // Target Square 46 (G6) + 0b00000000_01000000_00000000_00000000_00000000_00000000_00000000_00000000, // Target Square 47 (H6) + 0b00000010_00000000_00000000_00000000_00000000_00000000_00000000_00000000, // Target Square 48 (A7) + 0b00000101_00000000_00000000_00000000_00000000_00000000_00000000_00000000, // Target Square 49 (B7) + 0b00001010_00000000_00000000_00000000_00000000_00000000_00000000_00000000, // Target Square 50 (C7) + 0b00010100_00000000_00000000_00000000_00000000_00000000_00000000_00000000, // Target Square 51 (D7) + 0b00101000_00000000_00000000_00000000_00000000_00000000_00000000_00000000, // Target Square 52 (E7) + 0b01010000_00000000_00000000_00000000_00000000_00000000_00000000_00000000, // Target Square 53 (F7) + 0b10100000_00000000_00000000_00000000_00000000_00000000_00000000_00000000, // Target Square 54 (G7) + 0b01000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000, // Target Square 55 (H7) + 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000, // Target Square 56 (A8) + 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000, // Target Square 57 (B8) + 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000, // Target Square 58 (C8) + 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000, // Target Square 59 (D8) + 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000, // Target Square 60 (E8) + 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000, // Target Square 61 (F8) + 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000, // Target Square 62 (G8) + 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000, // Target Square 63 (H8) + ] +]; + pub const KNIGHT_ATTACKS: [u64; 64] = [ 0b00000000_00000000_00000000_00000000_00000000_00000010_00000100_00000000, // Square 0 (A1) 0b00000000_00000000_00000000_00000000_00000000_00000101_00001000_00000000, // Square 1 (B1) diff --git a/tests/is_square_attacked.rs b/tests/is_square_attacked.rs new file mode 100644 index 0000000..b56494f --- /dev/null +++ b/tests/is_square_attacked.rs @@ -0,0 +1,27 @@ +use chess_engine::board::{Board, Color}; +use chess_engine::movegen::legal_check::is_square_attacked; +use chess_engine::square::Square; + + +fn assert_square_attacked(board: &mut Board, square: Square, white: bool, black: bool) { + assert_eq!(is_square_attacked(board, square, Color::White), white, "{}", square); + assert_eq!(is_square_attacked(board, square, Color::Black), black, "{}", square); +} + +#[test] +fn test_is_attacked_kiwipete() { + let mut board = Board::from_fen("r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1"); + assert_square_attacked(&mut board, Square::B1, true, false); + assert_square_attacked(&mut board, Square::C1, true, false); + assert_square_attacked(&mut board, Square::D1, true, false); + assert_square_attacked(&mut board, Square::F1, true, false); + assert_square_attacked(&mut board, Square::G1, true, false); + + assert_square_attacked(&mut board, Square::A3, true, true); + assert_square_attacked(&mut board, Square::B3, true, false); + assert_square_attacked(&mut board, Square::D3, true, true); + assert_square_attacked(&mut board, Square::E3, true, false); + assert_square_attacked(&mut board, Square::G3, true, false); + + // TODO keep going with the rest +} \ No newline at end of file