mirror of
https://github.com/OMGeeky/hcsalmon1-Chess-Engine-Test.git
synced 2025-12-26 16:27:23 +01:00
2439 lines
117 KiB
Rust
2439 lines
117 KiB
Rust
#![allow(non_snake_case)]
|
|
#![allow(unused)]
|
|
|
|
use std::time::Instant;
|
|
mod constants;
|
|
|
|
const NO_SQUARE: usize = 64;
|
|
struct Wrapper {
|
|
PIECE_ARRAY: [u64; 12], //= [0; 12];
|
|
WHITE_TO_PLAY: bool, // = true;
|
|
CASTLE_RIGHTS: [bool; 4], // = [true, true, true, true];
|
|
EP: usize, //= NO_SQUARE;
|
|
|
|
STARTING_SQUARES: [[usize; 50]; 6], // = [[0; 50]; 6];
|
|
TARGET_SQUARES: [[usize; 50]; 6], //= [[0; 50]; 6];
|
|
TAGS: [[usize; 50]; 6], //= [[0; 50]; 6];
|
|
PIECES: [[usize; 50]; 6], //= [[0; 50]; 6];
|
|
PIN_ARRAY_SQUARES: [usize; 8], //= [NO_SQUARE; 8];
|
|
PIN_ARRAY_PIECES: [usize; 8], //= [NO_SQUARE; 8];
|
|
}
|
|
|
|
impl Wrapper {
|
|
fn new() -> Self {
|
|
Wrapper {
|
|
PIECE_ARRAY: [0; 12],
|
|
WHITE_TO_PLAY: true,
|
|
CASTLE_RIGHTS: [true, true, true, true],
|
|
EP: NO_SQUARE,
|
|
STARTING_SQUARES: [[0; 50]; 6],
|
|
TARGET_SQUARES: [[0; 50]; 6],
|
|
TAGS: [[0; 50]; 6],
|
|
PIECES: [[0; 50]; 6],
|
|
PIN_ARRAY_SQUARES: [NO_SQUARE; 8],
|
|
PIN_ARRAY_PIECES: [NO_SQUARE; 8],
|
|
}
|
|
}
|
|
}
|
|
|
|
const MAGIC: u64 = 0x03f79d71b4cb0a89;
|
|
|
|
const PINNED_SQUARE_INDEX: usize = 0;
|
|
const PINNING_PIECE_INDEX: usize = 1;
|
|
|
|
const TAG_NONE: usize = 0;
|
|
const TAG_CAPTURE: usize = 1;
|
|
const TAG_WHITEEP: usize = 2;
|
|
const TAG_BLACKEP: usize = 3;
|
|
const TAG_WCASTLEKS: usize = 4;
|
|
const TAG_WCASTLEQS: usize = 5;
|
|
const TAG_BCASTLEKS: usize = 6;
|
|
const TAG_BCASTLEQS: usize = 7;
|
|
const TAG_B_KNIGHT_PROMOTION: usize = 8;
|
|
const TAG_B_BISHOP_PROMOTION: usize = 9;
|
|
const TAG_B_QUEEN_PROMOTION: usize = 10;
|
|
const TAG_B_ROOK_PROMOTION: usize = 11;
|
|
const TAG_W_KNIGHT_PROMOTION: usize = 12;
|
|
const TAG_W_BISHOP_PROMOTION: usize = 13;
|
|
const TAG_W_QUEEN_PROMOTION: usize = 14;
|
|
const TAG_W_ROOK_PROMOTION: usize = 15;
|
|
const TAG_B_CAPTURE_KNIGHT_PROMOTION: usize = 16;
|
|
const TAG_B_CAPTURE_BISHOP_PROMOTION: usize = 17;
|
|
const TAG_B_CAPTURE_QUEEN_PROMOTION: usize = 18;
|
|
const TAG_B_CAPTURE_ROOK_PROMOTION: usize = 19;
|
|
const TAG_W_CAPTURE_KNIGHT_PROMOTION: usize = 20;
|
|
const TAG_W_CAPTURE_BISHOP_PROMOTION: usize = 21;
|
|
const TAG_W_CAPTURE_QUEEN_PROMOTION: usize = 22;
|
|
const TAG_W_CAPTURE_ROOK_PROMOTION: usize = 23;
|
|
const TAG_DOUBLE_PAWN_WHITE: usize = 24;
|
|
const TAG_DOUBLE_PAWN_BLACK: usize = 25;
|
|
|
|
const MOVE_STARTING: usize = 0;
|
|
const MOVE_TARGET: usize = 1;
|
|
const MOVE_PIECE: usize = 2;
|
|
const MOVE_TAG: usize = 3;
|
|
const MAX_ULONG: u64 = 18446744073709551615;
|
|
|
|
const RANK_1_BITBOARD: u64 = 18374686479671623680;
|
|
const RANK_2_BITBOARD: u64 = 71776119061217280;
|
|
const RANK_3_BITBOARD: u64 = 280375465082880;
|
|
const RANK_4_BITBOARD: u64 = 1095216660480;
|
|
const RANK_5_BITBOARD: u64 = 4278190080;
|
|
const RANK_6_BITBOARD: u64 = 16711680;
|
|
const RANK_7_BITBOARD: u64 = 65280;
|
|
const RANK_8_BITBOARD: u64 = 255;
|
|
|
|
const WKS_CASTLE_RIGHTS: usize = 0;
|
|
const WQS_CASTLE_RIGHTS: usize = 1;
|
|
const BKS_CASTLE_RIGHTS: usize = 2;
|
|
const BQS_CASTLE_RIGHTS: usize = 3;
|
|
|
|
const WKS_EMPTY_BITBOARD: u64 = 6917529027641081856;
|
|
const WQS_EMPTY_BITBOARD: u64 = 1008806316530991104;
|
|
const BKS_EMPTY_BITBOARD: u64 = 96;
|
|
const BQS_EMPTY_BITBOARD: u64 = 14;
|
|
|
|
const EMPTY_BITBOARD: u64 = 0;
|
|
|
|
const A8: usize = 0;
|
|
const B8: usize = 1;
|
|
const C8: usize = 2;
|
|
const D8: usize = 3;
|
|
const E8: usize = 4;
|
|
const F8: usize = 5;
|
|
const G8: usize = 6;
|
|
const H8: usize = 7;
|
|
const A7: usize = 8;
|
|
const B7: usize = 9;
|
|
const C7: usize = 10;
|
|
const D7: usize = 11;
|
|
const E7: usize = 12;
|
|
const F7: usize = 13;
|
|
const G7: usize = 14;
|
|
const H7: usize = 15;
|
|
const A6: usize = 16;
|
|
const B6: usize = 17;
|
|
const C6: usize = 18;
|
|
const D6: usize = 19;
|
|
const E6: usize = 20;
|
|
const F6: usize = 21;
|
|
const G6: usize = 22;
|
|
const H6: usize = 23;
|
|
const A5: usize = 24;
|
|
const B5: usize = 25;
|
|
const C5: usize = 26;
|
|
const D5: usize = 27;
|
|
const E5: usize = 28;
|
|
const F5: usize = 29;
|
|
const G5: usize = 30;
|
|
const H5: usize = 31;
|
|
const A4: usize = 32;
|
|
const B4: usize = 33;
|
|
const C4: usize = 34;
|
|
const D4: usize = 35;
|
|
const E4: usize = 36;
|
|
const F4: usize = 37;
|
|
const G4: usize = 38;
|
|
const H4: usize = 39;
|
|
const A3: usize = 40;
|
|
const B3: usize = 41;
|
|
const C3: usize = 42;
|
|
const D3: usize = 43;
|
|
const E3: usize = 44;
|
|
const F3: usize = 45;
|
|
const G3: usize = 46;
|
|
const H3: usize = 47;
|
|
const A2: usize = 48;
|
|
const B2: usize = 49;
|
|
const C2: usize = 50;
|
|
const D2: usize = 51;
|
|
const E2: usize = 52;
|
|
const F2: usize = 53;
|
|
const G2: usize = 54;
|
|
const H2: usize = 55;
|
|
const A1: usize = 56;
|
|
const B1: usize = 57;
|
|
const C1: usize = 58;
|
|
const D1: usize = 59;
|
|
const E1: usize = 60;
|
|
const F1: usize = 61;
|
|
const G1: usize = 62;
|
|
const H1: usize = 63;
|
|
|
|
const SQ_CHAR_Y: [char; 65] = [
|
|
'8', '8', '8', '8', '8', '8', '8', '8', '7', '7', '7', '7', '7', '7', '7', '7', '6', '6', '6',
|
|
'6', '6', '6', '6', '6', '5', '5', '5', '5', '5', '5', '5', '5', '4', '4', '4', '4', '4', '4',
|
|
'4', '4', '3', '3', '3', '3', '3', '3', '3', '3', '2', '2', '2', '2', '2', '2', '2', '2', '1',
|
|
'1', '1', '1', '1', '1', '1', '1', 'A',
|
|
];
|
|
|
|
const SQ_CHAR_X: [char; 65] = [
|
|
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'a', 'b', 'c',
|
|
'd', 'e', 'f', 'g', 'h', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'a', 'b', 'c', 'd', 'e', 'f',
|
|
'g', 'h', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'a',
|
|
'b', 'c', 'd', 'e', 'f', 'g', 'h', 'N',
|
|
];
|
|
|
|
const WP: usize = 0;
|
|
const WN: usize = 1;
|
|
const WB: usize = 2;
|
|
const WR: usize = 3;
|
|
const WQ: usize = 4;
|
|
const WK: usize = 5;
|
|
const BP: usize = 6;
|
|
const BN: usize = 7;
|
|
const BB: usize = 8;
|
|
const BR: usize = 9;
|
|
const BQ: usize = 10;
|
|
const BK: usize = 11;
|
|
impl Wrapper {
|
|
fn get_rook_attacks_fast(&mut self, starting_square: usize, mut occupancy: u64) -> u64 {
|
|
occupancy &= constants::ROOK_MASKS[starting_square];
|
|
occupancy = occupancy.wrapping_mul(constants::ROOK_MAGIC_NUMBERS[starting_square]);
|
|
occupancy >>= 64 - constants::ROOK_REL_BITS[starting_square];
|
|
let converted_occupancy: usize = occupancy as usize;
|
|
return constants::ROOK_ATTACKS[starting_square][converted_occupancy];
|
|
}
|
|
|
|
fn get_bishop_attacks_fast(&mut self, starting_square: usize, mut occupancy: u64) -> u64 {
|
|
occupancy &= constants::BISHOP_MASKS[starting_square];
|
|
occupancy = occupancy.wrapping_mul(constants::BISHOP_MAGIC_NUMBERS[starting_square]);
|
|
occupancy >>= 64 - constants::BISHOP_REL_BITS[starting_square];
|
|
return constants::BISHOP_ATTACKS[starting_square][occupancy as usize];
|
|
}
|
|
|
|
fn bitscan_forward_separate(&mut self, bitboard: u64) -> usize {
|
|
let bitboard_combined: u64 = bitboard ^ (bitboard - 1);
|
|
let calculation: u128 = 0x03f79d71b4cb0a89 * bitboard_combined as u128;
|
|
let calc_truncated: u64 = calculation as u64;
|
|
let index: usize = (calc_truncated >> 58) as usize;
|
|
return constants::DEBRUIJN64[index];
|
|
}
|
|
|
|
fn Is_Square_Attacked_By_Black_Global(&mut self, square: usize, occupancy: u64) -> bool {
|
|
if (self.PIECE_ARRAY[BP] & constants::WHITE_PAWN_ATTACKS[square]) != 0 {
|
|
return true;
|
|
}
|
|
if (self.PIECE_ARRAY[BN] & constants::KNIGHT_ATTACKS[square]) != 0 {
|
|
return true;
|
|
}
|
|
if (self.PIECE_ARRAY[BK] & constants::KING_ATTACKS[square]) != 0 {
|
|
return true;
|
|
}
|
|
let bishopAttacks = self.get_bishop_attacks_fast(square, occupancy);
|
|
if (self.PIECE_ARRAY[BB] & bishopAttacks) != 0 {
|
|
return true;
|
|
}
|
|
if (self.PIECE_ARRAY[BQ] & bishopAttacks) != 0 {
|
|
return true;
|
|
}
|
|
let rookAttacks = self.get_rook_attacks_fast(square, occupancy);
|
|
if (self.PIECE_ARRAY[BR] & rookAttacks) != 0 {
|
|
return true;
|
|
}
|
|
if (self.PIECE_ARRAY[BQ] & rookAttacks) != 0 {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
fn Is_Square_Attacked_By_White_Global(&mut self, square: usize, occupancy: u64) -> bool {
|
|
if (self.PIECE_ARRAY[WP] & constants::BLACK_PAWN_ATTACKS[square]) != 0 {
|
|
return true;
|
|
}
|
|
if (self.PIECE_ARRAY[WN] & constants::KNIGHT_ATTACKS[square]) != 0 {
|
|
return true;
|
|
}
|
|
if (self.PIECE_ARRAY[WK] & constants::KING_ATTACKS[square]) != 0 {
|
|
return true;
|
|
}
|
|
let bishopAttacks = self.get_bishop_attacks_fast(square, occupancy);
|
|
if (self.PIECE_ARRAY[WB] & bishopAttacks) != 0 {
|
|
return true;
|
|
}
|
|
if (self.PIECE_ARRAY[WQ] & bishopAttacks) != 0 {
|
|
return true;
|
|
}
|
|
let rookAttacks = self.get_rook_attacks_fast(square, occupancy);
|
|
if (self.PIECE_ARRAY[WR] & rookAttacks) != 0 {
|
|
return true;
|
|
}
|
|
if (self.PIECE_ARRAY[WQ] & rookAttacks) != 0 {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
fn OutOfBounds(&mut self, input: usize) -> bool {
|
|
if input > 63 {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
fn PrMoveNoNL(&mut self, starting_square: usize, target_square: usize) {
|
|
//starting
|
|
if self.OutOfBounds(starting_square) == true {
|
|
print!("{}", starting_square);
|
|
} else {
|
|
print!(
|
|
"{}{}",
|
|
SQ_CHAR_X[starting_square], SQ_CHAR_Y[starting_square]
|
|
);
|
|
}
|
|
if self.OutOfBounds(target_square) == true {
|
|
print!("{}", target_square);
|
|
} else {
|
|
print!("{}{}", SQ_CHAR_X[target_square], SQ_CHAR_Y[target_square]);
|
|
}
|
|
}
|
|
|
|
fn set_starting_position(&mut self) {
|
|
self.EP = 65;
|
|
self.WHITE_TO_PLAY = true;
|
|
self.CASTLE_RIGHTS[0] = true;
|
|
self.CASTLE_RIGHTS[1] = true;
|
|
self.CASTLE_RIGHTS[2] = true;
|
|
self.CASTLE_RIGHTS[3] = true;
|
|
|
|
self.PIECE_ARRAY[0] = 71776119061217280;
|
|
self.PIECE_ARRAY[1] = 4755801206503243776;
|
|
self.PIECE_ARRAY[2] = 2594073385365405696;
|
|
self.PIECE_ARRAY[3] = 9295429630892703744;
|
|
self.PIECE_ARRAY[4] = 576460752303423488;
|
|
self.PIECE_ARRAY[5] = 1152921504606846976;
|
|
self.PIECE_ARRAY[6] = 65280;
|
|
self.PIECE_ARRAY[7] = 66;
|
|
self.PIECE_ARRAY[8] = 36;
|
|
self.PIECE_ARRAY[9] = 129;
|
|
self.PIECE_ARRAY[10] = 8;
|
|
self.PIECE_ARRAY[11] = 16;
|
|
}
|
|
|
|
fn is_occupied(&mut self, bitboard: u64, square: usize) -> bool {
|
|
return (bitboard & constants::SQUARE_BBS[square]) != 0;
|
|
}
|
|
|
|
fn get_occupied_index(&mut self, square: usize) -> usize {
|
|
for i in 0..12 {
|
|
if self.is_occupied(self.PIECE_ARRAY[i], square) {
|
|
return i;
|
|
}
|
|
}
|
|
return 12;
|
|
}
|
|
|
|
fn fill_board_array(&mut self) -> [usize; 64] {
|
|
let mut board_array: [usize; 64] = [0; 64];
|
|
|
|
for i in 0..64 {
|
|
board_array[i] = self.get_occupied_index(i);
|
|
}
|
|
return board_array;
|
|
}
|
|
|
|
fn print_board(&mut self) {
|
|
const PIECE_NAMES: [u8; 13] = [
|
|
b'P', b'N', b'B', b'R', b'Q', b'K', b'P', b'N', b'B', b'R', b'Q', b'K', b'_',
|
|
];
|
|
const PIECE_COLOURS: [u8; 13] = [
|
|
b'W', b'W', b'W', b'W', b'W', b'W', b'B', b'B', b'B', b'B', b'B', b'B', b'_',
|
|
];
|
|
|
|
println!("Board:");
|
|
let board_array = self.fill_board_array();
|
|
|
|
for rank in 0..8 {
|
|
print!(" ");
|
|
|
|
for file in 0..8 {
|
|
let square: usize = (rank * 8) + file;
|
|
print!(
|
|
"{}{} ",
|
|
PIECE_COLOURS[board_array[square]] as char,
|
|
PIECE_NAMES[board_array[square]] as char
|
|
);
|
|
}
|
|
|
|
println!();
|
|
}
|
|
println!();
|
|
|
|
println!("White to play: {}", self.WHITE_TO_PLAY);
|
|
|
|
println!(
|
|
"Castle: {} {} {} {}",
|
|
self.CASTLE_RIGHTS[0],
|
|
self.CASTLE_RIGHTS[1],
|
|
self.CASTLE_RIGHTS[2],
|
|
self.CASTLE_RIGHTS[3]
|
|
);
|
|
println!("ep: {}\n", self.EP);
|
|
println!();
|
|
println!();
|
|
}
|
|
|
|
fn perft_inline(&mut self, depth: i8, ply: usize) -> usize {
|
|
// println!("Perft called with depth: {}", depth);
|
|
// unsafe
|
|
{
|
|
//if (depth == 0)
|
|
//{
|
|
// return 1;
|
|
//}
|
|
|
|
let mut move_count: usize = 0;
|
|
|
|
//Move generating variables
|
|
let white_occupancies: u64 = self.PIECE_ARRAY[0]
|
|
| self.PIECE_ARRAY[1]
|
|
| self.PIECE_ARRAY[2]
|
|
| self.PIECE_ARRAY[3]
|
|
| self.PIECE_ARRAY[4]
|
|
| self.PIECE_ARRAY[5];
|
|
let black_occupancies: u64 = self.PIECE_ARRAY[6]
|
|
| self.PIECE_ARRAY[7]
|
|
| self.PIECE_ARRAY[8]
|
|
| self.PIECE_ARRAY[9]
|
|
| self.PIECE_ARRAY[10]
|
|
| self.PIECE_ARRAY[11];
|
|
let combined_occupancies: u64 = white_occupancies | black_occupancies;
|
|
let EMPTY_OCCUPANCIES: u64 = !combined_occupancies;
|
|
let mut temp_bitboard: u64;
|
|
let mut check_bitboard: u64 = 0;
|
|
let mut temp_pin_bitboard: u64;
|
|
let mut temp_attack: u64;
|
|
let mut temp_empty: u64;
|
|
let mut temp_captures: u64;
|
|
let mut starting_square: usize = NO_SQUARE;
|
|
let mut target_square: usize = NO_SQUARE;
|
|
|
|
let mut pin_number: usize = 0;
|
|
|
|
if self.WHITE_TO_PLAY == true {
|
|
let mut white_king_check_count: usize = 0;
|
|
let white_king_position: usize =
|
|
self.bitscan_forward_separate(self.PIECE_ARRAY[WK]);
|
|
|
|
//pawns
|
|
temp_bitboard =
|
|
self.PIECE_ARRAY[BP] & constants::WHITE_PAWN_ATTACKS[white_king_position];
|
|
if temp_bitboard != 0 {
|
|
let pawn_square: usize = self.bitscan_forward_separate(temp_bitboard);
|
|
check_bitboard = constants::SQUARE_BBS[pawn_square];
|
|
|
|
white_king_check_count += 1;
|
|
}
|
|
|
|
//knights
|
|
temp_bitboard =
|
|
self.PIECE_ARRAY[BN] & constants::KNIGHT_ATTACKS[white_king_position];
|
|
if temp_bitboard != 0 {
|
|
let knight_square: usize = self.bitscan_forward_separate(temp_bitboard);
|
|
|
|
check_bitboard = constants::SQUARE_BBS[knight_square];
|
|
|
|
white_king_check_count += 1;
|
|
}
|
|
|
|
//bishops
|
|
let bishop_attacks_checks: u64 =
|
|
self.get_bishop_attacks_fast(white_king_position, black_occupancies);
|
|
temp_bitboard = self.PIECE_ARRAY[BB] & bishop_attacks_checks;
|
|
while temp_bitboard != 0 {
|
|
let piece_square: usize = self.bitscan_forward_separate(temp_bitboard);
|
|
temp_pin_bitboard = constants::INBETWEEN_BITBOARDS[white_king_position]
|
|
[piece_square]
|
|
& white_occupancies;
|
|
|
|
if temp_pin_bitboard == 0 {
|
|
check_bitboard =
|
|
constants::INBETWEEN_BITBOARDS[white_king_position][piece_square];
|
|
white_king_check_count += 1;
|
|
} else {
|
|
let pinned_square: usize = self.bitscan_forward_separate(temp_pin_bitboard);
|
|
temp_pin_bitboard &= temp_pin_bitboard - 1;
|
|
|
|
if temp_pin_bitboard == 0 {
|
|
self.PIN_ARRAY_SQUARES[pin_number] = pinned_square;
|
|
self.PIN_ARRAY_PIECES[pin_number] = piece_square;
|
|
pin_number += 1;
|
|
}
|
|
}
|
|
temp_bitboard &= temp_bitboard - 1;
|
|
}
|
|
|
|
//queen
|
|
temp_bitboard = self.PIECE_ARRAY[BQ] & bishop_attacks_checks;
|
|
while temp_bitboard != 0 {
|
|
let piece_square: usize = self.bitscan_forward_separate(temp_bitboard);
|
|
|
|
temp_pin_bitboard = constants::INBETWEEN_BITBOARDS[white_king_position]
|
|
[piece_square]
|
|
& white_occupancies;
|
|
|
|
if temp_pin_bitboard == 0 {
|
|
check_bitboard =
|
|
constants::INBETWEEN_BITBOARDS[white_king_position][piece_square];
|
|
white_king_check_count += 1;
|
|
} else {
|
|
let pinned_square: usize = self.bitscan_forward_separate(temp_pin_bitboard);
|
|
temp_pin_bitboard &= temp_pin_bitboard - 1;
|
|
|
|
if temp_pin_bitboard == 0 {
|
|
self.PIN_ARRAY_SQUARES[pin_number] = pinned_square;
|
|
self.PIN_ARRAY_PIECES[pin_number] = piece_square;
|
|
pin_number += 1;
|
|
}
|
|
}
|
|
temp_bitboard &= temp_bitboard - 1;
|
|
}
|
|
|
|
//rook
|
|
let rook_attacks: u64 =
|
|
self.get_rook_attacks_fast(white_king_position, black_occupancies);
|
|
temp_bitboard = self.PIECE_ARRAY[BR] & rook_attacks;
|
|
while temp_bitboard != 0 {
|
|
let piece_square: usize = self.bitscan_forward_separate(temp_bitboard);
|
|
temp_pin_bitboard = constants::INBETWEEN_BITBOARDS[white_king_position]
|
|
[piece_square]
|
|
& white_occupancies;
|
|
|
|
if temp_pin_bitboard == 0 {
|
|
check_bitboard =
|
|
constants::INBETWEEN_BITBOARDS[white_king_position][piece_square];
|
|
white_king_check_count += 1;
|
|
} else {
|
|
let pinned_square: usize = self.bitscan_forward_separate(temp_pin_bitboard);
|
|
temp_pin_bitboard &= temp_pin_bitboard - 1;
|
|
|
|
if temp_pin_bitboard == 0 {
|
|
self.PIN_ARRAY_SQUARES[pin_number] = pinned_square;
|
|
self.PIN_ARRAY_PIECES[pin_number] = piece_square;
|
|
pin_number += 1;
|
|
}
|
|
}
|
|
temp_bitboard &= temp_bitboard - 1;
|
|
}
|
|
|
|
//queen
|
|
temp_bitboard = self.PIECE_ARRAY[BQ] & rook_attacks;
|
|
while temp_bitboard != 0 {
|
|
let piece_square: usize = self.bitscan_forward_separate(temp_bitboard);
|
|
temp_pin_bitboard = constants::INBETWEEN_BITBOARDS[white_king_position]
|
|
[piece_square]
|
|
& white_occupancies;
|
|
|
|
if temp_pin_bitboard == 0 {
|
|
check_bitboard =
|
|
constants::INBETWEEN_BITBOARDS[white_king_position][piece_square];
|
|
white_king_check_count += 1;
|
|
} else {
|
|
let pinned_square: usize = self.bitscan_forward_separate(temp_pin_bitboard);
|
|
temp_pin_bitboard &= temp_pin_bitboard - 1;
|
|
|
|
if temp_pin_bitboard == 0 {
|
|
self.PIN_ARRAY_SQUARES[pin_number] = pinned_square;
|
|
self.PIN_ARRAY_PIECES[pin_number] = piece_square;
|
|
pin_number += 1;
|
|
}
|
|
}
|
|
temp_bitboard &= temp_bitboard - 1;
|
|
}
|
|
|
|
if white_king_check_count > 1 {
|
|
let occupancies_without_white_king: u64 =
|
|
combined_occupancies & (!self.PIECE_ARRAY[WK]);
|
|
temp_attack = constants::KING_ATTACKS[white_king_position];
|
|
temp_empty = temp_attack & EMPTY_OCCUPANCIES;
|
|
while temp_empty != 0 {
|
|
target_square = self.bitscan_forward_separate(temp_empty);
|
|
temp_empty &= temp_empty - 1;
|
|
|
|
if (self.PIECE_ARRAY[BP] & constants::WHITE_PAWN_ATTACKS[target_square])
|
|
!= 0
|
|
{
|
|
continue;
|
|
}
|
|
if (self.PIECE_ARRAY[BN] & constants::KNIGHT_ATTACKS[target_square]) != 0 {
|
|
continue;
|
|
}
|
|
if (self.PIECE_ARRAY[BK] & constants::KING_ATTACKS[target_square]) != 0 {
|
|
continue;
|
|
}
|
|
let bishop_attacks: u64 = self
|
|
.get_bishop_attacks_fast(target_square, occupancies_without_white_king);
|
|
if (self.PIECE_ARRAY[BB] & bishop_attacks) != 0 {
|
|
continue;
|
|
}
|
|
if (self.PIECE_ARRAY[BQ] & bishop_attacks) != 0 {
|
|
continue;
|
|
}
|
|
let rook_attacks: u64 = self
|
|
.get_rook_attacks_fast(target_square, occupancies_without_white_king);
|
|
if (self.PIECE_ARRAY[BR] & rook_attacks) != 0 {
|
|
continue;
|
|
}
|
|
if (self.PIECE_ARRAY[BQ] & rook_attacks) != 0 {
|
|
continue;
|
|
}
|
|
|
|
self.STARTING_SQUARES[ply][move_count] = white_king_position;
|
|
self.TARGET_SQUARES[ply][move_count] = target_square;
|
|
self.TAGS[ply][move_count] = TAG_NONE;
|
|
self.PIECES[ply][move_count] = WK;
|
|
move_count += 1;
|
|
}
|
|
|
|
//captures
|
|
temp_captures = temp_attack & black_occupancies;
|
|
while temp_captures != 0 {
|
|
target_square = self.bitscan_forward_separate(temp_captures);
|
|
temp_captures &= temp_captures - 1;
|
|
|
|
if (self.PIECE_ARRAY[BP] & constants::WHITE_PAWN_ATTACKS[target_square])
|
|
!= 0
|
|
{
|
|
continue;
|
|
}
|
|
if (self.PIECE_ARRAY[BN] & constants::KNIGHT_ATTACKS[target_square]) != 0 {
|
|
continue;
|
|
}
|
|
if (self.PIECE_ARRAY[BK] & constants::KING_ATTACKS[target_square]) != 0 {
|
|
continue;
|
|
}
|
|
let bishop_attacks: u64 = self
|
|
.get_bishop_attacks_fast(target_square, occupancies_without_white_king);
|
|
if (self.PIECE_ARRAY[BB] & bishop_attacks) != 0 {
|
|
continue;
|
|
}
|
|
if (self.PIECE_ARRAY[BQ] & bishop_attacks) != 0 {
|
|
continue;
|
|
}
|
|
let rook_attacks: u64 = self
|
|
.get_rook_attacks_fast(target_square, occupancies_without_white_king);
|
|
if (self.PIECE_ARRAY[BR] & rook_attacks) != 0 {
|
|
continue;
|
|
}
|
|
if (self.PIECE_ARRAY[BQ] & rook_attacks) != 0 {
|
|
continue;
|
|
}
|
|
|
|
self.STARTING_SQUARES[ply][move_count] = white_king_position;
|
|
self.TARGET_SQUARES[ply][move_count] = target_square;
|
|
self.TAGS[ply][move_count] = TAG_CAPTURE;
|
|
self.PIECES[ply][move_count] = WK;
|
|
move_count += 1;
|
|
}
|
|
} else {
|
|
if white_king_check_count == 0 {
|
|
check_bitboard = MAX_ULONG;
|
|
}
|
|
|
|
let occupancies_without_white_king: u64 =
|
|
combined_occupancies & (!self.PIECE_ARRAY[WK]);
|
|
temp_attack = constants::KING_ATTACKS[white_king_position];
|
|
temp_empty = temp_attack & EMPTY_OCCUPANCIES;
|
|
while temp_empty != 0 {
|
|
target_square = self.bitscan_forward_separate(temp_empty);
|
|
temp_empty &= temp_empty - 1;
|
|
|
|
if (self.PIECE_ARRAY[BP] & constants::WHITE_PAWN_ATTACKS[target_square])
|
|
!= 0
|
|
{
|
|
continue;
|
|
}
|
|
if (self.PIECE_ARRAY[BN] & constants::KNIGHT_ATTACKS[target_square]) != 0 {
|
|
continue;
|
|
}
|
|
if (self.PIECE_ARRAY[BK] & constants::KING_ATTACKS[target_square]) != 0 {
|
|
continue;
|
|
}
|
|
let bishop_attacks: u64 = self
|
|
.get_bishop_attacks_fast(target_square, occupancies_without_white_king);
|
|
if (self.PIECE_ARRAY[BB] & bishop_attacks) != 0 {
|
|
continue;
|
|
}
|
|
if (self.PIECE_ARRAY[BQ] & bishop_attacks) != 0 {
|
|
continue;
|
|
}
|
|
let rook_attacks: u64 = self
|
|
.get_rook_attacks_fast(target_square, occupancies_without_white_king);
|
|
if (self.PIECE_ARRAY[BR] & rook_attacks) != 0 {
|
|
continue;
|
|
}
|
|
if (self.PIECE_ARRAY[BQ] & rook_attacks) != 0 {
|
|
continue;
|
|
}
|
|
|
|
self.STARTING_SQUARES[ply][move_count] = white_king_position;
|
|
self.TARGET_SQUARES[ply][move_count] = target_square;
|
|
self.TAGS[ply][move_count] = TAG_NONE;
|
|
self.PIECES[ply][move_count] = WK;
|
|
move_count += 1;
|
|
}
|
|
|
|
//captures
|
|
temp_captures = temp_attack & black_occupancies;
|
|
while temp_captures != 0 {
|
|
target_square = self.bitscan_forward_separate(temp_captures);
|
|
temp_captures &= temp_captures - 1;
|
|
|
|
if (self.PIECE_ARRAY[BP] & constants::WHITE_PAWN_ATTACKS[target_square])
|
|
!= 0
|
|
{
|
|
continue;
|
|
}
|
|
if (self.PIECE_ARRAY[BN] & constants::KNIGHT_ATTACKS[target_square]) != 0 {
|
|
continue;
|
|
}
|
|
if (self.PIECE_ARRAY[BK] & constants::KING_ATTACKS[target_square]) != 0 {
|
|
continue;
|
|
}
|
|
let bishop_attacks: u64 = self
|
|
.get_bishop_attacks_fast(target_square, occupancies_without_white_king);
|
|
if (self.PIECE_ARRAY[BB] & bishop_attacks) != 0 {
|
|
continue;
|
|
}
|
|
if (self.PIECE_ARRAY[BQ] & bishop_attacks) != 0 {
|
|
continue;
|
|
}
|
|
let rook_attacks: u64 = self
|
|
.get_rook_attacks_fast(target_square, occupancies_without_white_king);
|
|
if (self.PIECE_ARRAY[BR] & rook_attacks) != 0 {
|
|
continue;
|
|
}
|
|
if (self.PIECE_ARRAY[BQ] & rook_attacks) != 0 {
|
|
continue;
|
|
}
|
|
|
|
self.STARTING_SQUARES[ply][move_count] = white_king_position;
|
|
self.TARGET_SQUARES[ply][move_count] = target_square;
|
|
self.TAGS[ply][move_count] = TAG_CAPTURE;
|
|
self.PIECES[ply][move_count] = WK;
|
|
move_count += 1;
|
|
}
|
|
|
|
if white_king_check_count == 0 {
|
|
if self.CASTLE_RIGHTS[WKS_CASTLE_RIGHTS] == true {
|
|
if white_king_position == E1
|
|
//king on e1
|
|
{
|
|
if (WKS_EMPTY_BITBOARD & combined_occupancies) == 0
|
|
//f1 and g1 empty
|
|
{
|
|
if (self.PIECE_ARRAY[WR] & constants::SQUARE_BBS[H1]) != 0
|
|
//rook on h1
|
|
{
|
|
if self.Is_Square_Attacked_By_Black_Global(
|
|
F1,
|
|
combined_occupancies,
|
|
) == false
|
|
{
|
|
if self.Is_Square_Attacked_By_Black_Global(
|
|
G1,
|
|
combined_occupancies,
|
|
) == false
|
|
{
|
|
self.STARTING_SQUARES[ply][move_count] = E1;
|
|
self.TARGET_SQUARES[ply][move_count] = G1;
|
|
self.TAGS[ply][move_count] = TAG_WCASTLEKS;
|
|
self.PIECES[ply][move_count] = WK;
|
|
move_count += 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if self.CASTLE_RIGHTS[WQS_CASTLE_RIGHTS] == true {
|
|
if white_king_position == E1
|
|
//king on e1
|
|
{
|
|
if (WQS_EMPTY_BITBOARD & combined_occupancies) == 0
|
|
//f1 and g1 empty
|
|
{
|
|
if (self.PIECE_ARRAY[WR] & constants::SQUARE_BBS[A1]) != 0
|
|
//rook on h1
|
|
{
|
|
if self.Is_Square_Attacked_By_Black_Global(
|
|
C1,
|
|
combined_occupancies,
|
|
) == false
|
|
{
|
|
if self.Is_Square_Attacked_By_Black_Global(
|
|
D1,
|
|
combined_occupancies,
|
|
) == false
|
|
{
|
|
self.STARTING_SQUARES[ply][move_count] = E1;
|
|
self.TARGET_SQUARES[ply][move_count] = C1;
|
|
self.TAGS[ply][move_count] = TAG_WCASTLEQS;
|
|
self.PIECES[ply][move_count] = WK;
|
|
move_count += 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
temp_bitboard = self.PIECE_ARRAY[WN];
|
|
|
|
while temp_bitboard != 0 {
|
|
starting_square = self.bitscan_forward_separate(temp_bitboard);
|
|
temp_bitboard &= temp_bitboard - 1; //removes the knight from that square to not infinitely loop
|
|
|
|
temp_pin_bitboard = MAX_ULONG;
|
|
if pin_number != 0 {
|
|
for i in 0..pin_number {
|
|
if self.PIN_ARRAY_SQUARES[i] == starting_square {
|
|
temp_pin_bitboard = constants::INBETWEEN_BITBOARDS
|
|
[white_king_position][self.PIN_ARRAY_PIECES[i]];
|
|
}
|
|
}
|
|
}
|
|
|
|
temp_attack = ((constants::KNIGHT_ATTACKS[starting_square]
|
|
& black_occupancies)
|
|
& check_bitboard)
|
|
& temp_pin_bitboard; //gets knight captures
|
|
while temp_attack != 0 {
|
|
target_square = self.bitscan_forward_separate(temp_attack);
|
|
temp_attack &= temp_attack - 1;
|
|
|
|
self.STARTING_SQUARES[ply][move_count] = starting_square;
|
|
self.TARGET_SQUARES[ply][move_count] = target_square;
|
|
self.TAGS[ply][move_count] = TAG_CAPTURE;
|
|
self.PIECES[ply][move_count] = WN;
|
|
move_count += 1;
|
|
}
|
|
|
|
temp_attack = ((constants::KNIGHT_ATTACKS[starting_square]
|
|
& EMPTY_OCCUPANCIES)
|
|
& check_bitboard)
|
|
& temp_pin_bitboard;
|
|
|
|
while temp_attack != 0 {
|
|
target_square = self.bitscan_forward_separate(temp_attack);
|
|
temp_attack &= temp_attack - 1;
|
|
|
|
self.STARTING_SQUARES[ply][move_count] = starting_square;
|
|
self.TARGET_SQUARES[ply][move_count] = target_square;
|
|
self.TAGS[ply][move_count] = TAG_NONE;
|
|
self.PIECES[ply][move_count] = WN;
|
|
move_count += 1;
|
|
}
|
|
}
|
|
|
|
temp_bitboard = self.PIECE_ARRAY[WP];
|
|
|
|
while temp_bitboard != 0 {
|
|
starting_square = self.bitscan_forward_separate(temp_bitboard);
|
|
temp_bitboard &= temp_bitboard - 1;
|
|
|
|
temp_pin_bitboard = MAX_ULONG;
|
|
if pin_number != 0 {
|
|
for i in 0..pin_number {
|
|
if self.PIN_ARRAY_SQUARES[i] == starting_square {
|
|
temp_pin_bitboard = constants::INBETWEEN_BITBOARDS
|
|
[white_king_position][self.PIN_ARRAY_PIECES[i]];
|
|
}
|
|
}
|
|
}
|
|
|
|
if (constants::SQUARE_BBS[starting_square - 8] & combined_occupancies) == 0
|
|
{
|
|
//if up one square is empty
|
|
if ((constants::SQUARE_BBS[starting_square - 8] & check_bitboard)
|
|
& temp_pin_bitboard)
|
|
!= 0
|
|
{
|
|
if (constants::SQUARE_BBS[starting_square] & RANK_7_BITBOARD) != 0 {
|
|
//if promotion
|
|
self.STARTING_SQUARES[ply][move_count] = starting_square;
|
|
self.TARGET_SQUARES[ply][move_count] = starting_square - 8;
|
|
self.TAGS[ply][move_count] = TAG_W_QUEEN_PROMOTION;
|
|
self.PIECES[ply][move_count] = WP;
|
|
move_count += 1;
|
|
|
|
self.STARTING_SQUARES[ply][move_count] = starting_square;
|
|
self.TARGET_SQUARES[ply][move_count] = starting_square - 8;
|
|
self.TAGS[ply][move_count] = TAG_W_ROOK_PROMOTION;
|
|
self.PIECES[ply][move_count] = WP;
|
|
move_count += 1;
|
|
|
|
self.STARTING_SQUARES[ply][move_count] = starting_square;
|
|
self.TARGET_SQUARES[ply][move_count] = starting_square - 8;
|
|
self.TAGS[ply][move_count] = TAG_W_BISHOP_PROMOTION;
|
|
self.PIECES[ply][move_count] = WP;
|
|
move_count += 1;
|
|
|
|
self.STARTING_SQUARES[ply][move_count] = starting_square;
|
|
self.TARGET_SQUARES[ply][move_count] = starting_square - 8;
|
|
self.TAGS[ply][move_count] = TAG_W_KNIGHT_PROMOTION;
|
|
self.PIECES[ply][move_count] = WP;
|
|
move_count += 1;
|
|
} else {
|
|
self.STARTING_SQUARES[ply][move_count] = starting_square;
|
|
self.TARGET_SQUARES[ply][move_count] = starting_square - 8;
|
|
self.TAGS[ply][move_count] = TAG_NONE;
|
|
self.PIECES[ply][move_count] = WP;
|
|
move_count += 1;
|
|
}
|
|
}
|
|
|
|
if (constants::SQUARE_BBS[starting_square] & RANK_2_BITBOARD) != 0 {
|
|
//if on rank 2
|
|
if ((constants::SQUARE_BBS[starting_square - 16] & check_bitboard)
|
|
& temp_pin_bitboard)
|
|
!= 0
|
|
{
|
|
//if not pinned or
|
|
if ((constants::SQUARE_BBS[starting_square - 16])
|
|
& combined_occupancies)
|
|
== 0
|
|
{
|
|
//if up two squares and one square are empty
|
|
self.STARTING_SQUARES[ply][move_count] = starting_square;
|
|
self.TARGET_SQUARES[ply][move_count] = starting_square - 16;
|
|
self.TAGS[ply][move_count] = TAG_DOUBLE_PAWN_WHITE;
|
|
self.PIECES[ply][move_count] = WP;
|
|
move_count += 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
temp_attack = ((constants::WHITE_PAWN_ATTACKS[starting_square]
|
|
& black_occupancies)
|
|
& check_bitboard)
|
|
& temp_pin_bitboard; //if black piece diagonal to pawn
|
|
|
|
while temp_attack != 0 {
|
|
target_square = self.bitscan_forward_separate(temp_attack);
|
|
temp_attack &= temp_attack - 1;
|
|
|
|
if (constants::SQUARE_BBS[starting_square] & RANK_7_BITBOARD) != 0
|
|
//if promotion
|
|
{
|
|
self.STARTING_SQUARES[ply][move_count] = starting_square;
|
|
self.TARGET_SQUARES[ply][move_count] = target_square;
|
|
self.TAGS[ply][move_count] = TAG_W_CAPTURE_BISHOP_PROMOTION;
|
|
self.PIECES[ply][move_count] = WP;
|
|
move_count += 1;
|
|
|
|
self.STARTING_SQUARES[ply][move_count] = starting_square;
|
|
self.TARGET_SQUARES[ply][move_count] = target_square;
|
|
self.TAGS[ply][move_count] = TAG_W_CAPTURE_KNIGHT_PROMOTION;
|
|
self.PIECES[ply][move_count] = WP;
|
|
move_count += 1;
|
|
|
|
self.STARTING_SQUARES[ply][move_count] = starting_square;
|
|
self.TARGET_SQUARES[ply][move_count] = target_square;
|
|
self.TAGS[ply][move_count] = TAG_W_CAPTURE_QUEEN_PROMOTION;
|
|
self.PIECES[ply][move_count] = WP;
|
|
move_count += 1;
|
|
|
|
self.STARTING_SQUARES[ply][move_count] = starting_square;
|
|
self.TARGET_SQUARES[ply][move_count] = target_square;
|
|
self.TAGS[ply][move_count] = TAG_W_CAPTURE_ROOK_PROMOTION;
|
|
self.PIECES[ply][move_count] = WP;
|
|
move_count += 1;
|
|
} else {
|
|
self.STARTING_SQUARES[ply][move_count] = starting_square;
|
|
self.TARGET_SQUARES[ply][move_count] = target_square;
|
|
self.TAGS[ply][move_count] = TAG_CAPTURE;
|
|
self.PIECES[ply][move_count] = WP;
|
|
move_count += 1;
|
|
}
|
|
}
|
|
|
|
if (constants::SQUARE_BBS[starting_square] & RANK_5_BITBOARD) != 0
|
|
//check rank for ep
|
|
{
|
|
if self.EP != NO_SQUARE {
|
|
if (((constants::WHITE_PAWN_ATTACKS[starting_square]
|
|
& constants::SQUARE_BBS[self.EP])
|
|
& check_bitboard)
|
|
& temp_pin_bitboard)
|
|
!= 0
|
|
{
|
|
if (self.PIECE_ARRAY[WK] & RANK_5_BITBOARD) == 0
|
|
//if no king on rank 5
|
|
{
|
|
self.STARTING_SQUARES[ply][move_count] = starting_square;
|
|
self.TARGET_SQUARES[ply][move_count] = self.EP;
|
|
self.TAGS[ply][move_count] = TAG_WHITEEP;
|
|
self.PIECES[ply][move_count] = WP;
|
|
move_count += 1;
|
|
} else if (self.PIECE_ARRAY[BR] & RANK_5_BITBOARD) == 0
|
|
&& (self.PIECE_ARRAY[BQ] & RANK_5_BITBOARD) == 0
|
|
// if no b rook or queen on rank 5
|
|
{
|
|
self.STARTING_SQUARES[ply][move_count] = starting_square;
|
|
self.TARGET_SQUARES[ply][move_count] = self.EP;
|
|
self.TAGS[ply][move_count] = TAG_WHITEEP;
|
|
self.PIECES[ply][move_count] = WP;
|
|
move_count += 1;
|
|
} else
|
|
//wk and br or bq on rank 5
|
|
{
|
|
let mut occupancy_without_ep_pawns: u64 =
|
|
combined_occupancies
|
|
& (!constants::SQUARE_BBS[starting_square]);
|
|
occupancy_without_ep_pawns &=
|
|
!constants::SQUARE_BBS[self.EP + 8];
|
|
|
|
let rook_attacks_from_king: u64 = self
|
|
.get_rook_attacks_fast(
|
|
white_king_position,
|
|
occupancy_without_ep_pawns,
|
|
);
|
|
if (rook_attacks_from_king & self.PIECE_ARRAY[BR]) == 0 {
|
|
if (rook_attacks_from_king & self.PIECE_ARRAY[BQ]) == 0
|
|
{
|
|
self.STARTING_SQUARES[ply][move_count] =
|
|
starting_square;
|
|
self.TARGET_SQUARES[ply][move_count] = self.EP;
|
|
self.TAGS[ply][move_count] = TAG_WHITEEP;
|
|
self.PIECES[ply][move_count] = WP;
|
|
move_count += 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
temp_bitboard = self.PIECE_ARRAY[WR];
|
|
while temp_bitboard != 0 {
|
|
starting_square = self.bitscan_forward_separate(temp_bitboard);
|
|
temp_bitboard &= temp_bitboard - 1;
|
|
|
|
temp_pin_bitboard = MAX_ULONG;
|
|
if pin_number != 0 {
|
|
for i in 0..pin_number {
|
|
if self.PIN_ARRAY_SQUARES[i] == starting_square {
|
|
temp_pin_bitboard = constants::INBETWEEN_BITBOARDS
|
|
[white_king_position][self.PIN_ARRAY_PIECES[i]];
|
|
}
|
|
}
|
|
}
|
|
|
|
let rook_attacks =
|
|
self.get_rook_attacks_fast(starting_square, combined_occupancies);
|
|
|
|
temp_attack = ((rook_attacks & black_occupancies) & check_bitboard)
|
|
& temp_pin_bitboard;
|
|
while temp_attack != 0 {
|
|
target_square = self.bitscan_forward_separate(temp_attack);
|
|
temp_attack &= temp_attack - 1;
|
|
|
|
self.STARTING_SQUARES[ply][move_count] = starting_square;
|
|
self.TARGET_SQUARES[ply][move_count] = target_square;
|
|
self.TAGS[ply][move_count] = TAG_CAPTURE;
|
|
self.PIECES[ply][move_count] = WR;
|
|
move_count += 1;
|
|
}
|
|
|
|
temp_attack = ((rook_attacks & EMPTY_OCCUPANCIES) & check_bitboard)
|
|
& temp_pin_bitboard;
|
|
while temp_attack != 0 {
|
|
target_square = self.bitscan_forward_separate(temp_attack);
|
|
temp_attack &= temp_attack - 1;
|
|
|
|
self.STARTING_SQUARES[ply][move_count] = starting_square;
|
|
self.TARGET_SQUARES[ply][move_count] = target_square;
|
|
self.TAGS[ply][move_count] = TAG_NONE;
|
|
self.PIECES[ply][move_count] = WR;
|
|
move_count += 1;
|
|
}
|
|
}
|
|
|
|
temp_bitboard = self.PIECE_ARRAY[WB];
|
|
while temp_bitboard != 0 {
|
|
starting_square = self.bitscan_forward_separate(temp_bitboard);
|
|
temp_bitboard &= temp_bitboard - 1;
|
|
|
|
temp_pin_bitboard = MAX_ULONG;
|
|
if pin_number != 0 {
|
|
for i in 0..pin_number {
|
|
if self.PIN_ARRAY_SQUARES[i] == starting_square {
|
|
temp_pin_bitboard = constants::INBETWEEN_BITBOARDS
|
|
[white_king_position][self.PIN_ARRAY_PIECES[i]];
|
|
}
|
|
}
|
|
}
|
|
|
|
let bishop_attacks: u64 =
|
|
self.get_bishop_attacks_fast(starting_square, combined_occupancies);
|
|
|
|
temp_attack = ((bishop_attacks & black_occupancies) & check_bitboard)
|
|
& temp_pin_bitboard;
|
|
while temp_attack != 0 {
|
|
target_square = self.bitscan_forward_separate(temp_attack);
|
|
temp_attack &= temp_attack - 1;
|
|
|
|
self.STARTING_SQUARES[ply][move_count] = starting_square;
|
|
self.TARGET_SQUARES[ply][move_count] = target_square;
|
|
self.TAGS[ply][move_count] = TAG_CAPTURE;
|
|
self.PIECES[ply][move_count] = WB;
|
|
move_count += 1;
|
|
}
|
|
|
|
temp_attack = ((bishop_attacks & EMPTY_OCCUPANCIES) & check_bitboard)
|
|
& temp_pin_bitboard;
|
|
while temp_attack != 0 {
|
|
target_square = self.bitscan_forward_separate(temp_attack);
|
|
temp_attack &= temp_attack - 1;
|
|
|
|
self.STARTING_SQUARES[ply][move_count] = starting_square;
|
|
self.TARGET_SQUARES[ply][move_count] = target_square;
|
|
self.TAGS[ply][move_count] = TAG_NONE;
|
|
self.PIECES[ply][move_count] = WB;
|
|
move_count += 1;
|
|
}
|
|
}
|
|
|
|
temp_bitboard = self.PIECE_ARRAY[WQ];
|
|
while temp_bitboard != 0 {
|
|
starting_square = self.bitscan_forward_separate(temp_bitboard);
|
|
temp_bitboard &= temp_bitboard - 1;
|
|
|
|
temp_pin_bitboard = MAX_ULONG;
|
|
if pin_number != 0 {
|
|
for i in 0..pin_number {
|
|
if self.PIN_ARRAY_SQUARES[i] == starting_square {
|
|
temp_pin_bitboard = constants::INBETWEEN_BITBOARDS
|
|
[white_king_position][self.PIN_ARRAY_PIECES[i]];
|
|
}
|
|
}
|
|
}
|
|
|
|
let mut queen_attacks =
|
|
self.get_rook_attacks_fast(starting_square, combined_occupancies);
|
|
queen_attacks |=
|
|
self.get_bishop_attacks_fast(starting_square, combined_occupancies);
|
|
|
|
temp_attack = ((queen_attacks & black_occupancies) & check_bitboard)
|
|
& temp_pin_bitboard;
|
|
|
|
while temp_attack != 0 {
|
|
target_square = self.bitscan_forward_separate(temp_attack);
|
|
temp_attack &= temp_attack - 1;
|
|
|
|
self.STARTING_SQUARES[ply][move_count] = starting_square;
|
|
self.TARGET_SQUARES[ply][move_count] = target_square;
|
|
self.TAGS[ply][move_count] = TAG_CAPTURE;
|
|
self.PIECES[ply][move_count] = WQ;
|
|
move_count += 1;
|
|
}
|
|
|
|
temp_attack = ((queen_attacks & EMPTY_OCCUPANCIES) & check_bitboard)
|
|
& temp_pin_bitboard;
|
|
while temp_attack != 0 {
|
|
target_square = self.bitscan_forward_separate(temp_attack);
|
|
temp_attack &= temp_attack - 1;
|
|
|
|
self.STARTING_SQUARES[ply][move_count] = starting_square;
|
|
self.TARGET_SQUARES[ply][move_count] = target_square;
|
|
self.TAGS[ply][move_count] = TAG_NONE;
|
|
self.PIECES[ply][move_count] = WQ;
|
|
move_count += 1;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
//black move
|
|
let mut black_king_check_count: u8 = 0;
|
|
let black_king_position: usize =
|
|
self.bitscan_forward_separate(self.PIECE_ARRAY[BK]);
|
|
//pawns
|
|
temp_bitboard =
|
|
self.PIECE_ARRAY[WP] & constants::BLACK_PAWN_ATTACKS[black_king_position];
|
|
if temp_bitboard != 0 {
|
|
let pawn_square = self.bitscan_forward_separate(temp_bitboard);
|
|
if check_bitboard == 0 {
|
|
check_bitboard = constants::SQUARE_BBS[pawn_square];
|
|
}
|
|
|
|
black_king_check_count += 1;
|
|
}
|
|
|
|
//knights
|
|
temp_bitboard =
|
|
self.PIECE_ARRAY[WN] & constants::KNIGHT_ATTACKS[black_king_position];
|
|
if temp_bitboard != 0 {
|
|
let knight_square: usize = self.bitscan_forward_separate(temp_bitboard);
|
|
|
|
check_bitboard = constants::SQUARE_BBS[knight_square];
|
|
|
|
black_king_check_count += 1;
|
|
}
|
|
|
|
//bishops
|
|
let bishop_attacks_checks: u64 =
|
|
self.get_bishop_attacks_fast(black_king_position, white_occupancies);
|
|
temp_bitboard = self.PIECE_ARRAY[WB] & bishop_attacks_checks;
|
|
while temp_bitboard != 0 {
|
|
let piece_square: usize = self.bitscan_forward_separate(temp_bitboard);
|
|
temp_pin_bitboard = constants::INBETWEEN_BITBOARDS[black_king_position]
|
|
[piece_square]
|
|
& black_occupancies;
|
|
|
|
if temp_pin_bitboard == 0 {
|
|
if check_bitboard == 0 {
|
|
check_bitboard =
|
|
constants::INBETWEEN_BITBOARDS[black_king_position][piece_square];
|
|
}
|
|
black_king_check_count += 1;
|
|
} else {
|
|
let pinned_square: usize = self.bitscan_forward_separate(temp_pin_bitboard);
|
|
temp_pin_bitboard &= temp_pin_bitboard - 1;
|
|
|
|
if temp_pin_bitboard == 0 {
|
|
self.PIN_ARRAY_SQUARES[pin_number] = pinned_square;
|
|
self.PIN_ARRAY_PIECES[pin_number] = piece_square;
|
|
pin_number += 1;
|
|
}
|
|
}
|
|
temp_bitboard &= temp_bitboard - 1;
|
|
}
|
|
|
|
//queen
|
|
temp_bitboard = self.PIECE_ARRAY[WQ] & bishop_attacks_checks;
|
|
while temp_bitboard != 0 {
|
|
let piece_square: usize = self.bitscan_forward_separate(temp_bitboard);
|
|
temp_pin_bitboard = constants::INBETWEEN_BITBOARDS[black_king_position]
|
|
[piece_square]
|
|
& black_occupancies;
|
|
|
|
if temp_pin_bitboard == 0 {
|
|
if check_bitboard == 0 {
|
|
check_bitboard =
|
|
constants::INBETWEEN_BITBOARDS[black_king_position][piece_square];
|
|
}
|
|
black_king_check_count += 1;
|
|
} else {
|
|
let pinned_square: usize = self.bitscan_forward_separate(temp_pin_bitboard);
|
|
temp_pin_bitboard &= temp_pin_bitboard - 1;
|
|
|
|
if temp_pin_bitboard == 0 {
|
|
self.PIN_ARRAY_SQUARES[pin_number] = pinned_square;
|
|
self.PIN_ARRAY_PIECES[pin_number] = piece_square;
|
|
pin_number += 1;
|
|
}
|
|
}
|
|
temp_bitboard &= temp_bitboard - 1;
|
|
}
|
|
|
|
//rook
|
|
let rook_attacks =
|
|
self.get_rook_attacks_fast(black_king_position, white_occupancies);
|
|
temp_bitboard = self.PIECE_ARRAY[WR] & rook_attacks;
|
|
while temp_bitboard != 0 {
|
|
let piece_square: usize = self.bitscan_forward_separate(temp_bitboard);
|
|
temp_pin_bitboard = constants::INBETWEEN_BITBOARDS[black_king_position]
|
|
[piece_square]
|
|
& black_occupancies;
|
|
|
|
if temp_pin_bitboard == 0 {
|
|
if check_bitboard == 0 {
|
|
check_bitboard =
|
|
constants::INBETWEEN_BITBOARDS[black_king_position][piece_square];
|
|
}
|
|
black_king_check_count += 1;
|
|
} else {
|
|
let pinned_square: usize = self.bitscan_forward_separate(temp_pin_bitboard);
|
|
temp_pin_bitboard &= temp_pin_bitboard - 1;
|
|
|
|
if temp_pin_bitboard == 0 {
|
|
self.PIN_ARRAY_SQUARES[pin_number] = pinned_square;
|
|
self.PIN_ARRAY_PIECES[pin_number] = piece_square;
|
|
pin_number += 1;
|
|
}
|
|
}
|
|
temp_bitboard &= temp_bitboard - 1;
|
|
}
|
|
|
|
//queen
|
|
temp_bitboard = self.PIECE_ARRAY[WQ] & rook_attacks;
|
|
while temp_bitboard != 0 {
|
|
let piece_square: usize = self.bitscan_forward_separate(temp_bitboard);
|
|
|
|
temp_pin_bitboard = constants::INBETWEEN_BITBOARDS[black_king_position]
|
|
[piece_square]
|
|
& black_occupancies;
|
|
|
|
if temp_pin_bitboard == 0 {
|
|
if check_bitboard == 0 {
|
|
check_bitboard =
|
|
constants::INBETWEEN_BITBOARDS[black_king_position][piece_square];
|
|
}
|
|
black_king_check_count += 1;
|
|
} else {
|
|
let pinned_square: usize = self.bitscan_forward_separate(temp_pin_bitboard);
|
|
temp_pin_bitboard &= temp_pin_bitboard - 1;
|
|
|
|
if temp_pin_bitboard == 0 {
|
|
self.PIN_ARRAY_SQUARES[pin_number] = pinned_square;
|
|
self.PIN_ARRAY_PIECES[pin_number] = piece_square;
|
|
pin_number += 1;
|
|
}
|
|
}
|
|
temp_bitboard &= temp_bitboard - 1;
|
|
}
|
|
|
|
if black_king_check_count > 1 {
|
|
let occupancy_without_black_king =
|
|
combined_occupancies & (!self.PIECE_ARRAY[BK]);
|
|
temp_attack = constants::KING_ATTACKS[black_king_position] & white_occupancies;
|
|
|
|
temp_attack = constants::KING_ATTACKS[black_king_position] & white_occupancies;
|
|
|
|
while temp_attack != 0 {
|
|
target_square = self.bitscan_forward_separate(temp_attack);
|
|
temp_attack &= temp_attack - 1;
|
|
|
|
if (self.PIECE_ARRAY[WP] & constants::BLACK_PAWN_ATTACKS[target_square])
|
|
!= 0
|
|
{
|
|
continue;
|
|
}
|
|
if (self.PIECE_ARRAY[WN] & constants::KNIGHT_ATTACKS[target_square]) != 0 {
|
|
continue;
|
|
}
|
|
if (self.PIECE_ARRAY[WK] & constants::KING_ATTACKS[target_square]) != 0 {
|
|
continue;
|
|
}
|
|
let bishop_attacks = self
|
|
.get_bishop_attacks_fast(target_square, occupancy_without_black_king);
|
|
if (self.PIECE_ARRAY[WB] & bishop_attacks) != 0 {
|
|
continue;
|
|
}
|
|
if (self.PIECE_ARRAY[WQ] & bishop_attacks) != 0 {
|
|
continue;
|
|
}
|
|
let rook_attacks =
|
|
self.get_rook_attacks_fast(target_square, occupancy_without_black_king);
|
|
if (self.PIECE_ARRAY[WR] & rook_attacks) != 0 {
|
|
continue;
|
|
}
|
|
if (self.PIECE_ARRAY[WQ] & rook_attacks) != 0 {
|
|
continue;
|
|
}
|
|
|
|
self.STARTING_SQUARES[ply][move_count] = starting_square;
|
|
self.TARGET_SQUARES[ply][move_count] = target_square;
|
|
self.TAGS[ply][move_count] = TAG_CAPTURE;
|
|
self.PIECES[ply][move_count] = BK;
|
|
move_count += 1;
|
|
}
|
|
|
|
temp_attack =
|
|
constants::KING_ATTACKS[black_king_position] & !combined_occupancies;
|
|
|
|
while temp_attack != 0 {
|
|
target_square = self.bitscan_forward_separate(temp_attack);
|
|
temp_attack &= temp_attack - 1;
|
|
|
|
if (self.PIECE_ARRAY[WP] & constants::WHITE_PAWN_ATTACKS[target_square])
|
|
!= 0
|
|
{
|
|
continue;
|
|
}
|
|
if (self.PIECE_ARRAY[WN] & constants::KNIGHT_ATTACKS[target_square]) != 0 {
|
|
continue;
|
|
}
|
|
if (self.PIECE_ARRAY[WK] & constants::KING_ATTACKS[target_square]) != 0 {
|
|
continue;
|
|
}
|
|
let bishop_attacks = self
|
|
.get_bishop_attacks_fast(target_square, occupancy_without_black_king);
|
|
if (self.PIECE_ARRAY[WB] & bishop_attacks) != 0 {
|
|
continue;
|
|
}
|
|
if (self.PIECE_ARRAY[WQ] & bishop_attacks) != 0 {
|
|
continue;
|
|
}
|
|
let rook_attacks =
|
|
self.get_rook_attacks_fast(target_square, occupancy_without_black_king);
|
|
if (self.PIECE_ARRAY[WR] & rook_attacks) != 0 {
|
|
continue;
|
|
}
|
|
if (self.PIECE_ARRAY[WQ] & rook_attacks) != 0 {
|
|
continue;
|
|
}
|
|
|
|
self.STARTING_SQUARES[ply][move_count] = starting_square;
|
|
self.TARGET_SQUARES[ply][move_count] = target_square;
|
|
self.TAGS[ply][move_count] = TAG_NONE;
|
|
self.PIECES[ply][move_count] = BK;
|
|
move_count += 1;
|
|
}
|
|
} else {
|
|
if black_king_check_count == 0 {
|
|
check_bitboard = MAX_ULONG;
|
|
}
|
|
|
|
temp_bitboard = self.PIECE_ARRAY[BP];
|
|
|
|
while temp_bitboard != 0 {
|
|
starting_square = self.bitscan_forward_separate(temp_bitboard);
|
|
temp_bitboard &= temp_bitboard - 1;
|
|
|
|
temp_pin_bitboard = MAX_ULONG;
|
|
if pin_number != 0 {
|
|
for i in 0..pin_number {
|
|
if self.PIN_ARRAY_SQUARES[i] == starting_square {
|
|
temp_pin_bitboard = constants::INBETWEEN_BITBOARDS
|
|
[black_king_position][self.PIN_ARRAY_PIECES[i]];
|
|
}
|
|
}
|
|
}
|
|
|
|
if (constants::SQUARE_BBS[starting_square + 8] & combined_occupancies) == 0
|
|
//if up one square is empty
|
|
{
|
|
if ((constants::SQUARE_BBS[starting_square + 8] & check_bitboard)
|
|
& temp_pin_bitboard)
|
|
!= 0
|
|
{
|
|
if (constants::SQUARE_BBS[starting_square] & RANK_2_BITBOARD) != 0
|
|
//if promotion
|
|
{
|
|
self.STARTING_SQUARES[ply][move_count] = starting_square;
|
|
self.TARGET_SQUARES[ply][move_count] = starting_square + 8;
|
|
self.TAGS[ply][move_count] = TAG_B_BISHOP_PROMOTION;
|
|
self.PIECES[ply][move_count] = BP;
|
|
move_count += 1;
|
|
|
|
self.STARTING_SQUARES[ply][move_count] = starting_square;
|
|
self.TARGET_SQUARES[ply][move_count] = starting_square + 8;
|
|
self.TAGS[ply][move_count] = TAG_B_KNIGHT_PROMOTION;
|
|
self.PIECES[ply][move_count] = BP;
|
|
move_count += 1;
|
|
|
|
self.STARTING_SQUARES[ply][move_count] = starting_square;
|
|
self.TARGET_SQUARES[ply][move_count] = starting_square + 8;
|
|
self.TAGS[ply][move_count] = TAG_B_ROOK_PROMOTION;
|
|
self.PIECES[ply][move_count] = BP;
|
|
move_count += 1;
|
|
|
|
self.STARTING_SQUARES[ply][move_count] = starting_square;
|
|
self.TARGET_SQUARES[ply][move_count] = starting_square + 8;
|
|
self.TAGS[ply][move_count] = TAG_B_QUEEN_PROMOTION;
|
|
self.PIECES[ply][move_count] = BP;
|
|
move_count += 1;
|
|
} else {
|
|
self.STARTING_SQUARES[ply][move_count] = starting_square;
|
|
self.TARGET_SQUARES[ply][move_count] = starting_square + 8;
|
|
self.TAGS[ply][move_count] = TAG_NONE;
|
|
self.PIECES[ply][move_count] = BP;
|
|
move_count += 1;
|
|
}
|
|
}
|
|
|
|
if (constants::SQUARE_BBS[starting_square] & RANK_7_BITBOARD) != 0
|
|
//if on rank 2
|
|
{
|
|
if ((constants::SQUARE_BBS[starting_square + 16] & check_bitboard)
|
|
& temp_pin_bitboard)
|
|
!= 0
|
|
{
|
|
if ((constants::SQUARE_BBS[starting_square + 16])
|
|
& combined_occupancies)
|
|
== 0
|
|
//if up two squares and one square are empty
|
|
{
|
|
self.STARTING_SQUARES[ply][move_count] = starting_square;
|
|
self.TARGET_SQUARES[ply][move_count] = starting_square + 16;
|
|
self.TAGS[ply][move_count] = TAG_DOUBLE_PAWN_BLACK;
|
|
self.PIECES[ply][move_count] = BP;
|
|
move_count += 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
temp_attack = ((constants::BLACK_PAWN_ATTACKS[starting_square]
|
|
& white_occupancies)
|
|
& check_bitboard)
|
|
& temp_pin_bitboard; //if black piece diagonal to pawn
|
|
|
|
while temp_attack != 0 {
|
|
target_square = self.bitscan_forward_separate(temp_attack); //find the bit
|
|
temp_attack &= temp_attack - 1;
|
|
|
|
if (constants::SQUARE_BBS[starting_square] & RANK_2_BITBOARD) != 0
|
|
//if promotion
|
|
{
|
|
self.STARTING_SQUARES[ply][move_count] = starting_square;
|
|
self.TARGET_SQUARES[ply][move_count] = target_square;
|
|
self.TAGS[ply][move_count] = TAG_B_CAPTURE_BISHOP_PROMOTION;
|
|
self.PIECES[ply][move_count] = BP;
|
|
move_count += 1;
|
|
|
|
self.STARTING_SQUARES[ply][move_count] = starting_square;
|
|
self.TARGET_SQUARES[ply][move_count] = target_square;
|
|
self.TAGS[ply][move_count] = TAG_B_CAPTURE_ROOK_PROMOTION;
|
|
self.PIECES[ply][move_count] = BP;
|
|
move_count += 1;
|
|
|
|
self.STARTING_SQUARES[ply][move_count] = starting_square;
|
|
self.TARGET_SQUARES[ply][move_count] = target_square;
|
|
self.TAGS[ply][move_count] = TAG_B_CAPTURE_QUEEN_PROMOTION;
|
|
self.PIECES[ply][move_count] = BP;
|
|
move_count += 1;
|
|
|
|
self.STARTING_SQUARES[ply][move_count] = starting_square;
|
|
self.TARGET_SQUARES[ply][move_count] = target_square;
|
|
self.TAGS[ply][move_count] = TAG_B_CAPTURE_KNIGHT_PROMOTION;
|
|
self.PIECES[ply][move_count] = BP;
|
|
move_count += 1;
|
|
} else {
|
|
self.STARTING_SQUARES[ply][move_count] = starting_square;
|
|
self.TARGET_SQUARES[ply][move_count] = target_square;
|
|
self.TAGS[ply][move_count] = TAG_CAPTURE;
|
|
self.PIECES[ply][move_count] = BP;
|
|
move_count += 1;
|
|
}
|
|
}
|
|
|
|
if (constants::SQUARE_BBS[starting_square] & RANK_4_BITBOARD) != 0
|
|
//check rank for ep
|
|
{
|
|
if self.EP != NO_SQUARE {
|
|
if (((constants::BLACK_PAWN_ATTACKS[starting_square]
|
|
& constants::SQUARE_BBS[self.EP])
|
|
& check_bitboard)
|
|
& temp_pin_bitboard)
|
|
!= 0
|
|
{
|
|
if (self.PIECE_ARRAY[BK] & RANK_4_BITBOARD) == 0
|
|
//if no king on rank 5
|
|
{
|
|
self.STARTING_SQUARES[ply][move_count] = starting_square;
|
|
self.TARGET_SQUARES[ply][move_count] = self.EP;
|
|
self.TAGS[ply][move_count] = TAG_BLACKEP;
|
|
self.PIECES[ply][move_count] = BP;
|
|
move_count += 1;
|
|
} else if (self.PIECE_ARRAY[WR] & RANK_4_BITBOARD) == 0
|
|
&& (self.PIECE_ARRAY[WQ] & RANK_4_BITBOARD) == 0
|
|
// if no b rook or queen on rank 5
|
|
{
|
|
self.STARTING_SQUARES[ply][move_count] = starting_square;
|
|
self.TARGET_SQUARES[ply][move_count] = self.EP;
|
|
self.TAGS[ply][move_count] = TAG_BLACKEP;
|
|
self.PIECES[ply][move_count] = BP;
|
|
move_count += 1;
|
|
} else
|
|
//wk and br or bq on rank 5
|
|
{
|
|
let mut occupancy_without_ep_pawns: u64 =
|
|
combined_occupancies
|
|
& !constants::SQUARE_BBS[starting_square];
|
|
occupancy_without_ep_pawns &=
|
|
!constants::SQUARE_BBS[self.EP - 8];
|
|
|
|
let rook_attacks_from_king = self.get_rook_attacks_fast(
|
|
black_king_position,
|
|
occupancy_without_ep_pawns,
|
|
);
|
|
if (rook_attacks_from_king & self.PIECE_ARRAY[WR]) == 0 {
|
|
if (rook_attacks_from_king & self.PIECE_ARRAY[WQ]) == 0
|
|
{
|
|
self.STARTING_SQUARES[ply][move_count] =
|
|
starting_square;
|
|
self.TARGET_SQUARES[ply][move_count] = self.EP;
|
|
self.TAGS[ply][move_count] = TAG_BLACKEP;
|
|
self.PIECES[ply][move_count] = BP;
|
|
move_count += 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
temp_bitboard = self.PIECE_ARRAY[BN];
|
|
|
|
while temp_bitboard != 0 {
|
|
starting_square = self.bitscan_forward_separate(temp_bitboard); //looks for the startingSquare
|
|
temp_bitboard &= temp_bitboard - 1; //removes the knight from that square to not infinitely loop
|
|
|
|
temp_pin_bitboard = MAX_ULONG;
|
|
if pin_number != 0 {
|
|
for i in 0..pin_number {
|
|
if self.PIN_ARRAY_SQUARES[i] == starting_square {
|
|
temp_pin_bitboard = constants::INBETWEEN_BITBOARDS
|
|
[black_king_position][self.PIN_ARRAY_PIECES[i]];
|
|
}
|
|
}
|
|
}
|
|
|
|
temp_attack = ((constants::KNIGHT_ATTACKS[starting_square]
|
|
& white_occupancies)
|
|
& check_bitboard)
|
|
& temp_pin_bitboard; //gets knight captures
|
|
while temp_attack != 0 {
|
|
target_square = self.bitscan_forward_separate(temp_attack);
|
|
temp_attack &= temp_attack - 1;
|
|
|
|
self.STARTING_SQUARES[ply][move_count] = starting_square;
|
|
self.TARGET_SQUARES[ply][move_count] = target_square;
|
|
self.TAGS[ply][move_count] = TAG_CAPTURE;
|
|
self.PIECES[ply][move_count] = BN;
|
|
move_count += 1;
|
|
}
|
|
|
|
temp_attack = ((constants::KNIGHT_ATTACKS[starting_square]
|
|
& (!combined_occupancies))
|
|
& check_bitboard)
|
|
& temp_pin_bitboard;
|
|
|
|
while temp_attack != 0 {
|
|
target_square = self.bitscan_forward_separate(temp_attack);
|
|
temp_attack &= temp_attack - 1;
|
|
|
|
self.STARTING_SQUARES[ply][move_count] = starting_square;
|
|
self.TARGET_SQUARES[ply][move_count] = target_square;
|
|
self.TAGS[ply][move_count] = TAG_NONE;
|
|
self.PIECES[ply][move_count] = BN;
|
|
move_count += 1;
|
|
}
|
|
}
|
|
|
|
temp_bitboard = self.PIECE_ARRAY[BB];
|
|
while temp_bitboard != 0 {
|
|
starting_square = self.bitscan_forward_separate(temp_bitboard);
|
|
temp_bitboard &= temp_bitboard - 1;
|
|
|
|
temp_pin_bitboard = MAX_ULONG;
|
|
if pin_number != 0 {
|
|
for i in 0..pin_number {
|
|
if self.PIN_ARRAY_SQUARES[i] == starting_square {
|
|
temp_pin_bitboard = constants::INBETWEEN_BITBOARDS
|
|
[black_king_position][self.PIN_ARRAY_PIECES[i]];
|
|
}
|
|
}
|
|
}
|
|
|
|
let bishop_attacks =
|
|
self.get_bishop_attacks_fast(starting_square, combined_occupancies);
|
|
|
|
temp_attack = ((bishop_attacks & white_occupancies) & check_bitboard)
|
|
& temp_pin_bitboard;
|
|
while temp_attack != 0 {
|
|
target_square = self.bitscan_forward_separate(temp_attack);
|
|
temp_attack &= temp_attack - 1;
|
|
|
|
self.STARTING_SQUARES[ply][move_count] = starting_square;
|
|
self.TARGET_SQUARES[ply][move_count] = target_square;
|
|
self.TAGS[ply][move_count] = TAG_CAPTURE;
|
|
self.PIECES[ply][move_count] = BB;
|
|
move_count += 1;
|
|
}
|
|
|
|
temp_attack = ((bishop_attacks & (!combined_occupancies)) & check_bitboard)
|
|
& temp_pin_bitboard;
|
|
while temp_attack != 0 {
|
|
target_square = self.bitscan_forward_separate(temp_attack);
|
|
temp_attack &= temp_attack - 1;
|
|
|
|
self.STARTING_SQUARES[ply][move_count] = starting_square;
|
|
self.TARGET_SQUARES[ply][move_count] = target_square;
|
|
self.TAGS[ply][move_count] = TAG_NONE;
|
|
self.PIECES[ply][move_count] = BB;
|
|
move_count += 1;
|
|
}
|
|
}
|
|
|
|
temp_bitboard = self.PIECE_ARRAY[BR];
|
|
while temp_bitboard != 0 {
|
|
starting_square = self.bitscan_forward_separate(temp_bitboard);
|
|
temp_bitboard &= temp_bitboard - 1;
|
|
|
|
temp_pin_bitboard = MAX_ULONG;
|
|
if pin_number != 0 {
|
|
for i in 0..pin_number {
|
|
if self.PIN_ARRAY_SQUARES[i] == starting_square {
|
|
temp_pin_bitboard = constants::INBETWEEN_BITBOARDS
|
|
[black_king_position][self.PIN_ARRAY_PIECES[i]];
|
|
}
|
|
}
|
|
}
|
|
|
|
let rook_attacks =
|
|
self.get_rook_attacks_fast(starting_square, combined_occupancies);
|
|
|
|
temp_attack = ((rook_attacks & white_occupancies) & check_bitboard)
|
|
& temp_pin_bitboard;
|
|
while temp_attack != 0 {
|
|
target_square = self.bitscan_forward_separate(temp_attack);
|
|
temp_attack &= temp_attack - 1;
|
|
|
|
self.STARTING_SQUARES[ply][move_count] = starting_square;
|
|
self.TARGET_SQUARES[ply][move_count] = target_square;
|
|
self.TAGS[ply][move_count] = TAG_CAPTURE;
|
|
self.PIECES[ply][move_count] = BR;
|
|
move_count += 1;
|
|
}
|
|
|
|
temp_attack = ((rook_attacks & (!combined_occupancies)) & check_bitboard)
|
|
& temp_pin_bitboard;
|
|
while temp_attack != 0 {
|
|
target_square = self.bitscan_forward_separate(temp_attack);
|
|
temp_attack &= temp_attack - 1;
|
|
|
|
self.STARTING_SQUARES[ply][move_count] = starting_square;
|
|
self.TARGET_SQUARES[ply][move_count] = target_square;
|
|
self.TAGS[ply][move_count] = TAG_NONE;
|
|
self.PIECES[ply][move_count] = BR;
|
|
move_count += 1;
|
|
}
|
|
}
|
|
|
|
temp_bitboard = self.PIECE_ARRAY[BQ];
|
|
while temp_bitboard != 0 {
|
|
starting_square = self.bitscan_forward_separate(temp_bitboard);
|
|
temp_bitboard &= temp_bitboard - 1;
|
|
|
|
temp_pin_bitboard = MAX_ULONG;
|
|
if pin_number != 0 {
|
|
for i in 0..pin_number {
|
|
if self.PIN_ARRAY_SQUARES[i] == starting_square {
|
|
temp_pin_bitboard = constants::INBETWEEN_BITBOARDS
|
|
[black_king_position][self.PIN_ARRAY_PIECES[i]];
|
|
}
|
|
}
|
|
}
|
|
|
|
let mut queen_attacks =
|
|
self.get_rook_attacks_fast(starting_square, combined_occupancies);
|
|
queen_attacks |=
|
|
self.get_bishop_attacks_fast(starting_square, combined_occupancies);
|
|
|
|
temp_attack = ((queen_attacks & white_occupancies) & check_bitboard)
|
|
& temp_pin_bitboard;
|
|
|
|
while temp_attack != 0 {
|
|
target_square = self.bitscan_forward_separate(temp_attack);
|
|
temp_attack &= temp_attack - 1;
|
|
|
|
self.STARTING_SQUARES[ply][move_count] = starting_square;
|
|
self.TARGET_SQUARES[ply][move_count] = target_square;
|
|
self.TAGS[ply][move_count] = TAG_CAPTURE;
|
|
self.PIECES[ply][move_count] = BQ;
|
|
move_count += 1;
|
|
}
|
|
|
|
temp_attack = ((queen_attacks & (!combined_occupancies)) & check_bitboard)
|
|
& temp_pin_bitboard;
|
|
while temp_attack != 0 {
|
|
target_square = self.bitscan_forward_separate(temp_attack);
|
|
temp_attack &= temp_attack - 1;
|
|
|
|
self.STARTING_SQUARES[ply][move_count] = starting_square;
|
|
self.TARGET_SQUARES[ply][move_count] = target_square;
|
|
self.TAGS[ply][move_count] = TAG_NONE;
|
|
self.PIECES[ply][move_count] = BQ;
|
|
move_count += 1;
|
|
}
|
|
}
|
|
|
|
temp_attack = constants::KING_ATTACKS[black_king_position] & white_occupancies; //gets knight captures
|
|
while temp_attack != 0 {
|
|
target_square = self.bitscan_forward_separate(temp_attack);
|
|
temp_attack &= temp_attack - 1;
|
|
|
|
if (self.PIECE_ARRAY[WP] & constants::BLACK_PAWN_ATTACKS[target_square])
|
|
!= 0
|
|
{
|
|
continue;
|
|
}
|
|
if (self.PIECE_ARRAY[WN] & constants::KNIGHT_ATTACKS[target_square]) != 0 {
|
|
continue;
|
|
}
|
|
if (self.PIECE_ARRAY[WK] & constants::KING_ATTACKS[target_square]) != 0 {
|
|
continue;
|
|
}
|
|
let occupancy_without_black_king =
|
|
combined_occupancies & (!self.PIECE_ARRAY[BK]);
|
|
let bishop_attacks = self
|
|
.get_bishop_attacks_fast(target_square, occupancy_without_black_king);
|
|
if (self.PIECE_ARRAY[WB] & bishop_attacks) != 0 {
|
|
continue;
|
|
}
|
|
if (self.PIECE_ARRAY[WQ] & bishop_attacks) != 0 {
|
|
continue;
|
|
}
|
|
let rook_attacks =
|
|
self.get_rook_attacks_fast(target_square, occupancy_without_black_king);
|
|
if (self.PIECE_ARRAY[WR] & rook_attacks) != 0 {
|
|
continue;
|
|
}
|
|
if (self.PIECE_ARRAY[WQ] & rook_attacks) != 0 {
|
|
continue;
|
|
}
|
|
|
|
self.STARTING_SQUARES[ply][move_count] = black_king_position;
|
|
self.TARGET_SQUARES[ply][move_count] = target_square;
|
|
self.TAGS[ply][move_count] = TAG_CAPTURE;
|
|
self.PIECES[ply][move_count] = BK;
|
|
move_count += 1;
|
|
}
|
|
|
|
temp_attack = constants::KING_ATTACKS[black_king_position] & EMPTY_OCCUPANCIES; //get knight moves to emtpy squares
|
|
|
|
while temp_attack != 0 {
|
|
target_square = self.bitscan_forward_separate(temp_attack);
|
|
temp_attack &= temp_attack - 1;
|
|
|
|
if (self.PIECE_ARRAY[WP] & constants::BLACK_PAWN_ATTACKS[target_square])
|
|
!= 0
|
|
{
|
|
continue;
|
|
}
|
|
if (self.PIECE_ARRAY[WN] & constants::KNIGHT_ATTACKS[target_square]) != 0 {
|
|
continue;
|
|
}
|
|
if (self.PIECE_ARRAY[WK] & constants::KING_ATTACKS[target_square]) != 0 {
|
|
continue;
|
|
}
|
|
let occupancy_without_black_king =
|
|
combined_occupancies & (!self.PIECE_ARRAY[BK]);
|
|
let bishop_attacks = self
|
|
.get_bishop_attacks_fast(target_square, occupancy_without_black_king);
|
|
if (self.PIECE_ARRAY[WB] & bishop_attacks) != 0 {
|
|
continue;
|
|
}
|
|
if (self.PIECE_ARRAY[WQ] & bishop_attacks) != 0 {
|
|
continue;
|
|
}
|
|
let rook_attacks =
|
|
self.get_rook_attacks_fast(target_square, occupancy_without_black_king);
|
|
if (self.PIECE_ARRAY[WR] & rook_attacks) != 0 {
|
|
continue;
|
|
}
|
|
if (self.PIECE_ARRAY[WQ] & rook_attacks) != 0 {
|
|
continue;
|
|
}
|
|
|
|
self.STARTING_SQUARES[ply][move_count] = black_king_position;
|
|
self.TARGET_SQUARES[ply][move_count] = target_square;
|
|
self.TAGS[ply][move_count] = TAG_NONE;
|
|
self.PIECES[ply][move_count] = BK;
|
|
move_count += 1;
|
|
}
|
|
}
|
|
if black_king_check_count == 0 {
|
|
if self.CASTLE_RIGHTS[BKS_CASTLE_RIGHTS] == true {
|
|
if black_king_position == E8
|
|
//king on e1
|
|
{
|
|
if (BKS_EMPTY_BITBOARD & combined_occupancies) == 0
|
|
//f1 and g1 empty
|
|
{
|
|
if (self.PIECE_ARRAY[BR] & constants::SQUARE_BBS[H8]) != 0
|
|
//rook on h1
|
|
{
|
|
if self.Is_Square_Attacked_By_White_Global(
|
|
F8,
|
|
combined_occupancies,
|
|
) == false
|
|
{
|
|
if self.Is_Square_Attacked_By_White_Global(
|
|
G8,
|
|
combined_occupancies,
|
|
) == false
|
|
{
|
|
self.STARTING_SQUARES[ply][move_count] = E8;
|
|
self.TARGET_SQUARES[ply][move_count] = G8;
|
|
self.TAGS[ply][move_count] = TAG_BCASTLEKS;
|
|
self.PIECES[ply][move_count] = BK;
|
|
move_count += 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if self.CASTLE_RIGHTS[BQS_CASTLE_RIGHTS] == true {
|
|
if black_king_position == E8
|
|
//king on e1
|
|
{
|
|
if (BQS_EMPTY_BITBOARD & combined_occupancies) == 0
|
|
//f1 and g1 empty
|
|
{
|
|
if (self.PIECE_ARRAY[BR] & constants::SQUARE_BBS[A8]) != 0
|
|
//rook on h1
|
|
{
|
|
if self.Is_Square_Attacked_By_White_Global(
|
|
C8,
|
|
combined_occupancies,
|
|
) == false
|
|
{
|
|
if self.Is_Square_Attacked_By_White_Global(
|
|
D8,
|
|
combined_occupancies,
|
|
) == false
|
|
{
|
|
self.STARTING_SQUARES[ply][move_count] = E8;
|
|
self.TARGET_SQUARES[ply][move_count] = C8;
|
|
self.TAGS[ply][move_count] = TAG_BCASTLEQS;
|
|
self.PIECES[ply][move_count] = BK;
|
|
move_count += 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if depth == 1 {
|
|
return move_count;
|
|
}
|
|
|
|
let mut nodes: usize = 0;
|
|
//let mut prior_nodes: u64;
|
|
let copy_ep: usize = self.EP;
|
|
let mut copy_castle: [bool; 4] = [true, true, true, true];
|
|
copy_castle[0] = self.CASTLE_RIGHTS[0];
|
|
copy_castle[1] = self.CASTLE_RIGHTS[1];
|
|
copy_castle[2] = self.CASTLE_RIGHTS[2];
|
|
copy_castle[3] = self.CASTLE_RIGHTS[3];
|
|
|
|
for move_index in 0..move_count {
|
|
// println!("move_index: {}", move_index);
|
|
|
|
let starting_square: usize = self.STARTING_SQUARES[ply][move_index];
|
|
let target_square: usize = self.TARGET_SQUARES[ply][move_index];
|
|
let piece: usize = self.PIECES[ply][move_index];
|
|
let tag: usize = self.TAGS[ply][move_index];
|
|
|
|
let mut capture_index: usize = 0;
|
|
|
|
if self.WHITE_TO_PLAY == true {
|
|
self.WHITE_TO_PLAY = false;
|
|
} else {
|
|
self.WHITE_TO_PLAY = true;
|
|
}
|
|
|
|
match tag {
|
|
TAG_NONE => {
|
|
//none
|
|
self.PIECE_ARRAY[piece] |= constants::SQUARE_BBS[target_square];
|
|
self.PIECE_ARRAY[piece] &= !constants::SQUARE_BBS[starting_square];
|
|
self.EP = NO_SQUARE;
|
|
}
|
|
TAG_CAPTURE => {
|
|
//capture
|
|
self.PIECE_ARRAY[piece] |= constants::SQUARE_BBS[target_square];
|
|
self.PIECE_ARRAY[piece] &= !constants::SQUARE_BBS[starting_square];
|
|
if piece <= WK {
|
|
for i in BP..BK + 1 {
|
|
if (self.PIECE_ARRAY[i] & constants::SQUARE_BBS[target_square]) != 0
|
|
{
|
|
capture_index = i;
|
|
break;
|
|
}
|
|
}
|
|
self.PIECE_ARRAY[capture_index] &= !constants::SQUARE_BBS[target_square]
|
|
} else {
|
|
//is black
|
|
|
|
for i in WP..BP {
|
|
if (self.PIECE_ARRAY[i] & constants::SQUARE_BBS[target_square]) != 0
|
|
{
|
|
capture_index = i;
|
|
break;
|
|
}
|
|
}
|
|
self.PIECE_ARRAY[capture_index] &=
|
|
!constants::SQUARE_BBS[target_square];
|
|
}
|
|
self.EP = NO_SQUARE;
|
|
}
|
|
TAG_WHITEEP => {
|
|
//white ep
|
|
//move piece
|
|
self.PIECE_ARRAY[WP] |= constants::SQUARE_BBS[target_square];
|
|
self.PIECE_ARRAY[WP] &= !constants::SQUARE_BBS[starting_square];
|
|
//remove
|
|
self.PIECE_ARRAY[BP] &= !constants::SQUARE_BBS[target_square + 8];
|
|
self.EP = NO_SQUARE;
|
|
}
|
|
TAG_BLACKEP => {
|
|
//black ep
|
|
//move piece
|
|
self.PIECE_ARRAY[BP] |= constants::SQUARE_BBS[target_square];
|
|
self.PIECE_ARRAY[BP] &= !constants::SQUARE_BBS[starting_square];
|
|
//remove white pawn square up
|
|
self.PIECE_ARRAY[WP] &= !constants::SQUARE_BBS[target_square - 8];
|
|
self.EP = NO_SQUARE;
|
|
}
|
|
TAG_WCASTLEKS => {
|
|
//WKS
|
|
//white king
|
|
self.PIECE_ARRAY[WK] |= constants::SQUARE_BBS[G1];
|
|
self.PIECE_ARRAY[WK] &= !constants::SQUARE_BBS[E1];
|
|
//white rook
|
|
self.PIECE_ARRAY[WR] |= constants::SQUARE_BBS[F1];
|
|
self.PIECE_ARRAY[WR] &= !constants::SQUARE_BBS[H1];
|
|
//occupancies
|
|
self.CASTLE_RIGHTS[WKS_CASTLE_RIGHTS] = false;
|
|
self.CASTLE_RIGHTS[WQS_CASTLE_RIGHTS] = false;
|
|
self.EP = NO_SQUARE;
|
|
}
|
|
TAG_WCASTLEQS => {
|
|
//WQS
|
|
//white king
|
|
self.PIECE_ARRAY[WK] |= constants::SQUARE_BBS[C1];
|
|
self.PIECE_ARRAY[WK] &= !constants::SQUARE_BBS[E1];
|
|
//white rook
|
|
self.PIECE_ARRAY[WR] |= constants::SQUARE_BBS[D1];
|
|
self.PIECE_ARRAY[WR] &= !constants::SQUARE_BBS[A1];
|
|
|
|
self.CASTLE_RIGHTS[WKS_CASTLE_RIGHTS] = false;
|
|
self.CASTLE_RIGHTS[WQS_CASTLE_RIGHTS] = false;
|
|
self.EP = NO_SQUARE;
|
|
}
|
|
TAG_BCASTLEKS => {
|
|
//BKS
|
|
//white king
|
|
self.PIECE_ARRAY[BK] |= constants::SQUARE_BBS[G8];
|
|
self.PIECE_ARRAY[BK] &= !constants::SQUARE_BBS[E8];
|
|
//white rook
|
|
self.PIECE_ARRAY[BR] |= constants::SQUARE_BBS[F8];
|
|
self.PIECE_ARRAY[BR] &= !constants::SQUARE_BBS[H8];
|
|
self.CASTLE_RIGHTS[BKS_CASTLE_RIGHTS] = false;
|
|
self.CASTLE_RIGHTS[BQS_CASTLE_RIGHTS] = false;
|
|
self.EP = NO_SQUARE;
|
|
}
|
|
TAG_BCASTLEQS => {
|
|
//BQS
|
|
//white king
|
|
self.PIECE_ARRAY[BK] |= constants::SQUARE_BBS[C8];
|
|
self.PIECE_ARRAY[BK] &= !constants::SQUARE_BBS[E8];
|
|
//white rook
|
|
self.PIECE_ARRAY[BR] |= constants::SQUARE_BBS[D8];
|
|
self.PIECE_ARRAY[BR] &= !constants::SQUARE_BBS[A8];
|
|
self.CASTLE_RIGHTS[BKS_CASTLE_RIGHTS] = false;
|
|
self.CASTLE_RIGHTS[BQS_CASTLE_RIGHTS] = false;
|
|
self.EP = NO_SQUARE;
|
|
}
|
|
TAG_B_KNIGHT_PROMOTION => {
|
|
//BNPr
|
|
self.PIECE_ARRAY[BN] |= constants::SQUARE_BBS[target_square];
|
|
self.PIECE_ARRAY[piece] &= !constants::SQUARE_BBS[starting_square];
|
|
self.EP = NO_SQUARE;
|
|
}
|
|
TAG_B_BISHOP_PROMOTION => {
|
|
//BBPr
|
|
self.PIECE_ARRAY[BB] |= constants::SQUARE_BBS[target_square];
|
|
self.PIECE_ARRAY[piece] &= !constants::SQUARE_BBS[starting_square];
|
|
self.EP = NO_SQUARE;
|
|
}
|
|
TAG_B_QUEEN_PROMOTION => {
|
|
//BQPr
|
|
self.PIECE_ARRAY[BQ] |= constants::SQUARE_BBS[target_square];
|
|
self.PIECE_ARRAY[piece] &= !constants::SQUARE_BBS[starting_square];
|
|
self.EP = NO_SQUARE;
|
|
}
|
|
TAG_B_ROOK_PROMOTION => {
|
|
//BRPr
|
|
self.PIECE_ARRAY[BR] |= constants::SQUARE_BBS[target_square];
|
|
self.PIECE_ARRAY[piece] &= !constants::SQUARE_BBS[starting_square];
|
|
self.EP = NO_SQUARE;
|
|
}
|
|
TAG_W_KNIGHT_PROMOTION => {
|
|
//WNPr
|
|
self.PIECE_ARRAY[WN] |= constants::SQUARE_BBS[target_square];
|
|
self.PIECE_ARRAY[piece] &= !constants::SQUARE_BBS[starting_square];
|
|
self.EP = NO_SQUARE;
|
|
}
|
|
TAG_W_BISHOP_PROMOTION => {
|
|
//WBPr
|
|
self.PIECE_ARRAY[WB] |= constants::SQUARE_BBS[target_square];
|
|
self.PIECE_ARRAY[piece] &= !constants::SQUARE_BBS[starting_square];
|
|
self.EP = NO_SQUARE;
|
|
}
|
|
TAG_W_QUEEN_PROMOTION => {
|
|
//WQPr
|
|
self.PIECE_ARRAY[WQ] |= constants::SQUARE_BBS[target_square];
|
|
self.PIECE_ARRAY[piece] &= !constants::SQUARE_BBS[starting_square];
|
|
self.EP = NO_SQUARE;
|
|
}
|
|
TAG_W_ROOK_PROMOTION => {
|
|
//WRPr
|
|
self.PIECE_ARRAY[WR] |= constants::SQUARE_BBS[target_square];
|
|
self.PIECE_ARRAY[piece] &= !constants::SQUARE_BBS[starting_square];
|
|
self.EP = NO_SQUARE;
|
|
}
|
|
TAG_B_CAPTURE_KNIGHT_PROMOTION => {
|
|
//BNPrCAP
|
|
self.PIECE_ARRAY[BN] |= constants::SQUARE_BBS[target_square];
|
|
self.PIECE_ARRAY[piece] &= !constants::SQUARE_BBS[starting_square];
|
|
self.EP = NO_SQUARE;
|
|
for i in WP..BP {
|
|
if (self.PIECE_ARRAY[i] & constants::SQUARE_BBS[target_square]) != 0 {
|
|
capture_index = i;
|
|
break;
|
|
}
|
|
}
|
|
self.PIECE_ARRAY[capture_index] &= !constants::SQUARE_BBS[target_square]
|
|
}
|
|
TAG_B_CAPTURE_BISHOP_PROMOTION => {
|
|
//BBPrCAP
|
|
self.PIECE_ARRAY[BB] |= constants::SQUARE_BBS[target_square];
|
|
self.PIECE_ARRAY[piece] &= !constants::SQUARE_BBS[starting_square];
|
|
|
|
self.EP = NO_SQUARE;
|
|
for i in WP..BP {
|
|
if (self.PIECE_ARRAY[i] & constants::SQUARE_BBS[target_square]) != 0 {
|
|
capture_index = i;
|
|
break;
|
|
}
|
|
}
|
|
self.PIECE_ARRAY[capture_index] &= !constants::SQUARE_BBS[target_square];
|
|
}
|
|
TAG_B_CAPTURE_QUEEN_PROMOTION => {
|
|
//BQPrCAP
|
|
self.PIECE_ARRAY[BQ] |= constants::SQUARE_BBS[target_square];
|
|
self.PIECE_ARRAY[piece] &= !constants::SQUARE_BBS[starting_square];
|
|
self.EP = NO_SQUARE;
|
|
for i in WP..BP {
|
|
if (self.PIECE_ARRAY[i] & constants::SQUARE_BBS[target_square]) != 0 {
|
|
capture_index = i;
|
|
break;
|
|
}
|
|
}
|
|
self.PIECE_ARRAY[capture_index] &= !constants::SQUARE_BBS[target_square];
|
|
}
|
|
TAG_B_CAPTURE_ROOK_PROMOTION => {
|
|
//BRPrCAP
|
|
self.PIECE_ARRAY[BR] |= constants::SQUARE_BBS[target_square];
|
|
self.PIECE_ARRAY[piece] &= !constants::SQUARE_BBS[starting_square];
|
|
self.EP = NO_SQUARE;
|
|
for i in WP..BP {
|
|
if (self.PIECE_ARRAY[i] & constants::SQUARE_BBS[target_square]) != 0 {
|
|
capture_index = i;
|
|
break;
|
|
}
|
|
}
|
|
self.PIECE_ARRAY[capture_index] &= !constants::SQUARE_BBS[target_square];
|
|
}
|
|
TAG_W_CAPTURE_KNIGHT_PROMOTION => {
|
|
//WNPrCAP
|
|
self.PIECE_ARRAY[WN] |= constants::SQUARE_BBS[target_square];
|
|
self.PIECE_ARRAY[piece] &= !constants::SQUARE_BBS[starting_square];
|
|
self.EP = NO_SQUARE;
|
|
for i in BP..BK + 1 {
|
|
if (self.PIECE_ARRAY[i] & constants::SQUARE_BBS[target_square]) != 0 {
|
|
capture_index = i;
|
|
break;
|
|
}
|
|
}
|
|
self.PIECE_ARRAY[capture_index] &= !constants::SQUARE_BBS[target_square]
|
|
}
|
|
TAG_W_CAPTURE_BISHOP_PROMOTION => {
|
|
//WBPrCAP
|
|
self.PIECE_ARRAY[WB] |= constants::SQUARE_BBS[target_square];
|
|
self.PIECE_ARRAY[piece] &= !constants::SQUARE_BBS[starting_square];
|
|
self.EP = NO_SQUARE;
|
|
for i in BP..BK + 1 {
|
|
if (self.PIECE_ARRAY[i] & constants::SQUARE_BBS[target_square]) != 0 {
|
|
capture_index = i;
|
|
break;
|
|
}
|
|
}
|
|
self.PIECE_ARRAY[capture_index] &= !constants::SQUARE_BBS[target_square]
|
|
}
|
|
TAG_W_CAPTURE_QUEEN_PROMOTION => {
|
|
//WQPrCAP
|
|
self.PIECE_ARRAY[WQ] |= constants::SQUARE_BBS[target_square];
|
|
self.PIECE_ARRAY[piece] &= !constants::SQUARE_BBS[starting_square];
|
|
self.EP = NO_SQUARE;
|
|
for i in BP..BK + 1 {
|
|
if (self.PIECE_ARRAY[i] & constants::SQUARE_BBS[target_square]) != 0 {
|
|
capture_index = i;
|
|
break;
|
|
}
|
|
}
|
|
self.PIECE_ARRAY[capture_index] &= !constants::SQUARE_BBS[target_square];
|
|
}
|
|
TAG_W_CAPTURE_ROOK_PROMOTION => {
|
|
//WRPrCAP
|
|
self.PIECE_ARRAY[WR] |= constants::SQUARE_BBS[target_square];
|
|
self.PIECE_ARRAY[piece] &= !constants::SQUARE_BBS[starting_square];
|
|
self.EP = NO_SQUARE;
|
|
for i in BP..BK + 1 {
|
|
if (self.PIECE_ARRAY[i] & constants::SQUARE_BBS[target_square]) != 0 {
|
|
capture_index = i;
|
|
break;
|
|
}
|
|
}
|
|
self.PIECE_ARRAY[capture_index] &= !constants::SQUARE_BBS[target_square];
|
|
}
|
|
TAG_DOUBLE_PAWN_WHITE => {
|
|
//WDouble
|
|
self.PIECE_ARRAY[WP] |= constants::SQUARE_BBS[target_square];
|
|
self.PIECE_ARRAY[WP] &= !constants::SQUARE_BBS[starting_square];
|
|
self.EP = target_square + 8;
|
|
}
|
|
TAG_DOUBLE_PAWN_BLACK => {
|
|
//BDouble
|
|
self.PIECE_ARRAY[BP] |= constants::SQUARE_BBS[target_square];
|
|
self.PIECE_ARRAY[BP] &= !constants::SQUARE_BBS[starting_square];
|
|
self.EP = target_square - 8;
|
|
}
|
|
_ => {}
|
|
}
|
|
if piece == WK {
|
|
self.CASTLE_RIGHTS[WKS_CASTLE_RIGHTS] = false;
|
|
self.CASTLE_RIGHTS[WQS_CASTLE_RIGHTS] = false;
|
|
} else if piece == BK {
|
|
self.CASTLE_RIGHTS[BKS_CASTLE_RIGHTS] = false;
|
|
self.CASTLE_RIGHTS[BQS_CASTLE_RIGHTS] = false;
|
|
} else if piece == WR {
|
|
if self.CASTLE_RIGHTS[WKS_CASTLE_RIGHTS] == true {
|
|
if (self.PIECE_ARRAY[WR] & constants::SQUARE_BBS[H1]) == 0 {
|
|
self.CASTLE_RIGHTS[WKS_CASTLE_RIGHTS] = false;
|
|
}
|
|
}
|
|
if self.CASTLE_RIGHTS[WQS_CASTLE_RIGHTS] == true {
|
|
if (self.PIECE_ARRAY[WR] & constants::SQUARE_BBS[A1]) == 0 {
|
|
self.CASTLE_RIGHTS[WQS_CASTLE_RIGHTS] = false;
|
|
}
|
|
}
|
|
} else if piece == BR {
|
|
if self.CASTLE_RIGHTS[BKS_CASTLE_RIGHTS] == true {
|
|
if (self.PIECE_ARRAY[BR] & constants::SQUARE_BBS[H8]) == 0 {
|
|
self.CASTLE_RIGHTS[BKS_CASTLE_RIGHTS] = false;
|
|
}
|
|
}
|
|
if self.CASTLE_RIGHTS[BQS_CASTLE_RIGHTS] == true {
|
|
if (self.PIECE_ARRAY[BR] & constants::SQUARE_BBS[A8]) == 0 {
|
|
self.CASTLE_RIGHTS[BQS_CASTLE_RIGHTS] = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
// println!("calling perft_inline with depth: {:>3} and move_index: {:>3}", depth - 1, move_index);
|
|
nodes += self.perft_inline(depth - 1, ply + 1);
|
|
|
|
self.WHITE_TO_PLAY = !self.WHITE_TO_PLAY;
|
|
|
|
match tag {
|
|
TAG_NONE => {
|
|
//none
|
|
self.PIECE_ARRAY[piece] |= constants::SQUARE_BBS[starting_square];
|
|
self.PIECE_ARRAY[piece] &= !constants::SQUARE_BBS[target_square];
|
|
}
|
|
TAG_CAPTURE => {
|
|
//capture
|
|
self.PIECE_ARRAY[piece] |= constants::SQUARE_BBS[starting_square];
|
|
self.PIECE_ARRAY[piece] &= !constants::SQUARE_BBS[target_square];
|
|
if piece <= WK {
|
|
self.PIECE_ARRAY[capture_index] |= constants::SQUARE_BBS[target_square];
|
|
} else {
|
|
//is black
|
|
|
|
self.PIECE_ARRAY[capture_index] |= constants::SQUARE_BBS[target_square];
|
|
}
|
|
}
|
|
TAG_WHITEEP => {
|
|
//white ep
|
|
self.PIECE_ARRAY[WP] |= constants::SQUARE_BBS[starting_square];
|
|
self.PIECE_ARRAY[WP] &= !constants::SQUARE_BBS[target_square];
|
|
self.PIECE_ARRAY[BP] |= constants::SQUARE_BBS[target_square + 8];
|
|
}
|
|
TAG_BLACKEP => {
|
|
//black ep
|
|
self.PIECE_ARRAY[BP] |= constants::SQUARE_BBS[starting_square];
|
|
self.PIECE_ARRAY[BP] &= !constants::SQUARE_BBS[target_square];
|
|
self.PIECE_ARRAY[WP] |= constants::SQUARE_BBS[target_square - 8];
|
|
}
|
|
TAG_WCASTLEKS => {
|
|
//WKS
|
|
//white king
|
|
self.PIECE_ARRAY[WK] |= constants::SQUARE_BBS[E1];
|
|
self.PIECE_ARRAY[WK] &= !constants::SQUARE_BBS[G1];
|
|
//white rook
|
|
self.PIECE_ARRAY[WR] |= constants::SQUARE_BBS[H1];
|
|
self.PIECE_ARRAY[WR] &= !constants::SQUARE_BBS[F1];
|
|
}
|
|
TAG_WCASTLEQS => {
|
|
//WQS
|
|
//white king
|
|
self.PIECE_ARRAY[WK] |= constants::SQUARE_BBS[E1];
|
|
self.PIECE_ARRAY[WK] &= !constants::SQUARE_BBS[C1];
|
|
//white rook
|
|
self.PIECE_ARRAY[WR] |= constants::SQUARE_BBS[A1];
|
|
self.PIECE_ARRAY[WR] &= !constants::SQUARE_BBS[D1];
|
|
}
|
|
TAG_BCASTLEKS => {
|
|
//BKS
|
|
//white king
|
|
self.PIECE_ARRAY[BK] |= constants::SQUARE_BBS[E8];
|
|
self.PIECE_ARRAY[BK] &= !constants::SQUARE_BBS[G8];
|
|
//white rook
|
|
self.PIECE_ARRAY[BR] |= constants::SQUARE_BBS[H8];
|
|
self.PIECE_ARRAY[BR] &= !constants::SQUARE_BBS[F8];
|
|
}
|
|
TAG_BCASTLEQS => {
|
|
//BQS
|
|
//white king
|
|
self.PIECE_ARRAY[BK] |= constants::SQUARE_BBS[E8];
|
|
self.PIECE_ARRAY[BK] &= !constants::SQUARE_BBS[C8];
|
|
//white rook
|
|
self.PIECE_ARRAY[BR] |= constants::SQUARE_BBS[A8];
|
|
self.PIECE_ARRAY[BR] &= !constants::SQUARE_BBS[D8];
|
|
}
|
|
TAG_B_KNIGHT_PROMOTION => {
|
|
//BNPr
|
|
self.PIECE_ARRAY[BP] |= constants::SQUARE_BBS[starting_square];
|
|
self.PIECE_ARRAY[BN] &= !constants::SQUARE_BBS[target_square];
|
|
}
|
|
TAG_B_BISHOP_PROMOTION => {
|
|
//BBPr
|
|
self.PIECE_ARRAY[BP] |= constants::SQUARE_BBS[starting_square];
|
|
self.PIECE_ARRAY[BB] &= !constants::SQUARE_BBS[target_square];
|
|
}
|
|
TAG_B_QUEEN_PROMOTION => {
|
|
//BQPr
|
|
self.PIECE_ARRAY[BP] |= constants::SQUARE_BBS[starting_square];
|
|
self.PIECE_ARRAY[BQ] &= !constants::SQUARE_BBS[target_square];
|
|
}
|
|
TAG_B_ROOK_PROMOTION => {
|
|
//BRPr
|
|
self.PIECE_ARRAY[BP] |= constants::SQUARE_BBS[starting_square];
|
|
self.PIECE_ARRAY[BR] &= !constants::SQUARE_BBS[target_square];
|
|
}
|
|
TAG_W_KNIGHT_PROMOTION => {
|
|
//WNPr
|
|
self.PIECE_ARRAY[WP] |= constants::SQUARE_BBS[starting_square];
|
|
self.PIECE_ARRAY[WN] &= !constants::SQUARE_BBS[target_square];
|
|
}
|
|
TAG_W_BISHOP_PROMOTION => {
|
|
//WBPr
|
|
self.PIECE_ARRAY[WP] |= constants::SQUARE_BBS[starting_square];
|
|
self.PIECE_ARRAY[WB] &= !constants::SQUARE_BBS[target_square];
|
|
}
|
|
TAG_W_QUEEN_PROMOTION => {
|
|
//WQPr
|
|
self.PIECE_ARRAY[WP] |= constants::SQUARE_BBS[starting_square];
|
|
self.PIECE_ARRAY[WQ] &= !constants::SQUARE_BBS[target_square];
|
|
}
|
|
TAG_W_ROOK_PROMOTION => {
|
|
//WRPr
|
|
self.PIECE_ARRAY[WP] |= constants::SQUARE_BBS[starting_square];
|
|
self.PIECE_ARRAY[WR] &= !constants::SQUARE_BBS[target_square];
|
|
}
|
|
TAG_B_CAPTURE_KNIGHT_PROMOTION => {
|
|
//BNPrCAP
|
|
self.PIECE_ARRAY[BP] |= constants::SQUARE_BBS[starting_square];
|
|
self.PIECE_ARRAY[BN] &= !constants::SQUARE_BBS[target_square];
|
|
self.PIECE_ARRAY[capture_index] |= constants::SQUARE_BBS[target_square];
|
|
}
|
|
TAG_B_CAPTURE_BISHOP_PROMOTION => {
|
|
//BBPrCAP
|
|
self.PIECE_ARRAY[BP] |= constants::SQUARE_BBS[starting_square];
|
|
self.PIECE_ARRAY[BB] &= !constants::SQUARE_BBS[target_square];
|
|
self.PIECE_ARRAY[capture_index] |= constants::SQUARE_BBS[target_square];
|
|
}
|
|
TAG_B_CAPTURE_QUEEN_PROMOTION => {
|
|
//BQPrCAP
|
|
self.PIECE_ARRAY[BP] |= constants::SQUARE_BBS[starting_square];
|
|
self.PIECE_ARRAY[BQ] &= !constants::SQUARE_BBS[target_square];
|
|
self.PIECE_ARRAY[capture_index] |= constants::SQUARE_BBS[target_square];
|
|
}
|
|
TAG_B_CAPTURE_ROOK_PROMOTION => {
|
|
//BRPrCAP
|
|
self.PIECE_ARRAY[BP] |= constants::SQUARE_BBS[starting_square];
|
|
self.PIECE_ARRAY[BR] &= !constants::SQUARE_BBS[target_square];
|
|
self.PIECE_ARRAY[capture_index] |= constants::SQUARE_BBS[target_square];
|
|
}
|
|
TAG_W_CAPTURE_KNIGHT_PROMOTION => {
|
|
//WNPrCAP
|
|
self.PIECE_ARRAY[WP] |= constants::SQUARE_BBS[starting_square];
|
|
self.PIECE_ARRAY[WN] &= !constants::SQUARE_BBS[target_square];
|
|
self.PIECE_ARRAY[capture_index] |= constants::SQUARE_BBS[target_square];
|
|
}
|
|
TAG_W_CAPTURE_BISHOP_PROMOTION => {
|
|
//WBPrCAP
|
|
self.PIECE_ARRAY[WP] |= constants::SQUARE_BBS[starting_square];
|
|
self.PIECE_ARRAY[WB] &= !constants::SQUARE_BBS[target_square];
|
|
self.PIECE_ARRAY[capture_index] |= constants::SQUARE_BBS[target_square];
|
|
}
|
|
TAG_W_CAPTURE_QUEEN_PROMOTION => {
|
|
//WQPrCAP
|
|
self.PIECE_ARRAY[WP] |= constants::SQUARE_BBS[starting_square];
|
|
self.PIECE_ARRAY[WQ] &= !constants::SQUARE_BBS[target_square];
|
|
self.PIECE_ARRAY[capture_index] |= constants::SQUARE_BBS[target_square];
|
|
}
|
|
TAG_W_CAPTURE_ROOK_PROMOTION => {
|
|
//WRPrCAP
|
|
self.PIECE_ARRAY[WP] |= constants::SQUARE_BBS[starting_square];
|
|
self.PIECE_ARRAY[WR] &= !constants::SQUARE_BBS[target_square];
|
|
self.PIECE_ARRAY[capture_index] |= constants::SQUARE_BBS[target_square];
|
|
}
|
|
TAG_DOUBLE_PAWN_WHITE => {
|
|
//WDouble
|
|
self.PIECE_ARRAY[WP] |= constants::SQUARE_BBS[starting_square];
|
|
self.PIECE_ARRAY[WP] &= !constants::SQUARE_BBS[target_square];
|
|
}
|
|
TAG_DOUBLE_PAWN_BLACK => {
|
|
//BDouble
|
|
self.PIECE_ARRAY[BP] |= constants::SQUARE_BBS[starting_square];
|
|
self.PIECE_ARRAY[BP] &= !constants::SQUARE_BBS[target_square];
|
|
}
|
|
_ => {}
|
|
}
|
|
|
|
self.CASTLE_RIGHTS[0] = copy_castle[0];
|
|
self.CASTLE_RIGHTS[1] = copy_castle[1];
|
|
self.CASTLE_RIGHTS[2] = copy_castle[2];
|
|
self.CASTLE_RIGHTS[3] = copy_castle[3];
|
|
self.EP = copy_ep;
|
|
|
|
//if (epGlobal != NO_SQUARE)
|
|
//{
|
|
// std::cout << " ep: " << SQ_CHAR_X[epGlobal] << SQ_CHAR_Y[epGlobal] << '\n';
|
|
//}
|
|
|
|
//if (ply == 0)
|
|
//{
|
|
//PrMoveNoNL(startingSquare, targetSquare);
|
|
//print!(": {}\n", .{nodes - priorNodes});
|
|
//}
|
|
}
|
|
|
|
return nodes;
|
|
}
|
|
}
|
|
fn run_perft(&mut self, depth: i8) {
|
|
let timestamp_start = Instant::now();
|
|
|
|
let nodes = self.perft_inline(depth, 0);
|
|
|
|
let elapsed = timestamp_start.elapsed();
|
|
|
|
println!("Nodes: {}", nodes);
|
|
println!("Elapsed time: {:?}", elapsed);
|
|
}
|
|
}
|
|
fn main() {
|
|
let mut wrapper = Wrapper::new();
|
|
wrapper.set_starting_position();
|
|
wrapper.print_board();
|
|
wrapper.run_perft(6);
|
|
}
|