mirror of
https://github.com/OMGeeky/hcsalmon1-Chess-Engine-Test.git
synced 2025-12-26 16:27:23 +01:00
2526 lines
116 KiB
C#
2526 lines
116 KiB
C#
using System;
|
|
|
|
|
|
namespace CEngineCopy
|
|
{
|
|
public class Program
|
|
{
|
|
|
|
const ulong MAGIC = 0x03f79d71b4cb0a89;
|
|
|
|
const int PINNED_SQUARE_INDEX = 0;
|
|
const int PINNING_PIECE_INDEX = 1;
|
|
|
|
const int MOVE_STARTING = 0;
|
|
const int MOVE_TARGET = 1;
|
|
const int MOVE_PIECE = 2;
|
|
const int MOVE_TAG = 3;
|
|
|
|
const int TAG_NONE = 0, TAG_CAPTURE = 1, TAG_WHITE_EP = 2, TAG_BLACK_EP = 3, TAG_W_CASTLE_KS = 4, TAG_W_CASTLE_QS = 5, TAG_B_CASTLE_KS = 6, TAG_B_CASTLE_QS = 7,
|
|
TAG_B_N_PROMOTION = 8, TAG_B_B_PROMOTION = 9, TAG_B_Q_PROMOTION = 10, TAG_B_R_PROMOTION = 11,
|
|
TAG_W_N_PROMOTION = 12, TAG_W_B_PROMOTION = 13, TAG_W_Q_PROMOTION = 14, TAG_W_R_PROMOTION = 15,
|
|
TAG_B_N_PROMOTION_CAP = 16, TAG_B_B_PROMOTION_CAP = 17, TAG_B_Q_PROMOTION_CAP = 18, TAG_B_R_PROMOTION_CAP = 19,
|
|
TAG_W_N_PROMOTION_CAP = 20, TAG_W_B_PROMOTION_CAP = 21, TAG_W_Q_PROMOTION_CAP = 22, TAG_W_R_PROMOTION_CAP = 23,
|
|
TAG_W_P_DOUBLE = 24, TAG_B_P_DOUBLE = 25, TAG_CHECK = 26, TAG_CHECK_CAP = 27;
|
|
|
|
const int A8 = 0, B8 = 1, C8 = 2, D8 = 3, E8 = 4, F8 = 5, G8 = 6, H8 = 7,
|
|
A7 = 8, B7 = 9, C7 = 10, D7 = 11, E7 = 12, F7 = 13, G7 = 14, H7 = 15,
|
|
A6 = 16, B6 = 17, C6 = 18, D6 = 19, E6 = 20, F6 = 21, G6 = 22, H6 = 23,
|
|
A5 = 24, B5 = 25, C5 = 26, D5 = 27, E5 = 28, F5 = 29, G5 = 30, H5 = 31,
|
|
A4 = 32, B4 = 33, C4 = 34, D4 = 35, E4 = 36, F4 = 37, G4 = 38, H4 = 39,
|
|
A3 = 40, B3 = 41, C3 = 42, D3 = 43, E3 = 44, F3 = 45, G3 = 46, H3 = 47,
|
|
A2 = 48, B2 = 49, C2 = 50, D2 = 51, E2 = 52, F2 = 53, G2 = 54, H2 = 55,
|
|
A1 = 56, B1 = 57, C1 = 58, D1 = 59, E1 = 60, F1 = 61, G1 = 62, H1 = 63, NO_SQUARE = 64;
|
|
|
|
static readonly int[] DEBRUIJN64 =
|
|
{
|
|
0, 47, 1, 56, 48, 27, 2, 60,
|
|
57, 49, 41, 37, 28, 16, 3, 61,
|
|
54, 58, 35, 52, 50, 42, 21, 44,
|
|
38, 32, 29, 23, 17, 11, 4, 62,
|
|
46, 55, 26, 59, 40, 36, 15, 53,
|
|
34, 51, 20, 43, 31, 22, 10, 45,
|
|
25, 39, 14, 33, 19, 30, 9, 24,
|
|
13, 18, 8, 12, 7, 6, 5, 63
|
|
};
|
|
|
|
static int BitScanForward(ulong tempBitboard)
|
|
{
|
|
return (DEBRUIJN64[MAGIC * (tempBitboard ^ (tempBitboard - 1)) >> 58]);
|
|
}
|
|
|
|
const ulong WKS_EMPTY_BITBOARD = 6917529027641081856UL;
|
|
const ulong WQS_EMPTY_BITBOARD = 1008806316530991104UL;
|
|
const ulong BKS_EMPTY_BITBOARD = 96UL;
|
|
const ulong BQS_EMPTY_BITBOARD = 14UL;
|
|
|
|
const int WKS_CASTLE_RIGHTS = 0, WQS_CASTLE_RIGHTS = 1, BKS_CASTLE_RIGHTS = 2, BQS_CASTLE_RIGHTS = 3;
|
|
|
|
const int WHITE_START_INDEX = WP;
|
|
const int WHITE_END_INDEX = WK;
|
|
const int BLACK_START_INDEX = BP;
|
|
const int BLACK_END_INDEX = BK;
|
|
|
|
const ulong BP_STARTING_POSITIONS = 65280;
|
|
const ulong WP_STARTING_POSITIONS = 71776119061217280;
|
|
const ulong BK_STARTING_POSITION = 16;
|
|
const ulong WK_STARTING_POSITION = 1152921504606846976;
|
|
const ulong BN_STARTING_POSITIONS = 66;
|
|
const ulong WN_STARTING_POSITIONS = 4755801206503243776;
|
|
const ulong WR_STARTING_POSITIONS = 9295429630892703744;
|
|
const ulong BR_STARTING_POSITIONS = 129;
|
|
const ulong BB_STARTING_POSITIONS = 36;
|
|
const ulong WB_STARTING_POSITIONS = 2594073385365405696;
|
|
const ulong WQ_STARTING_POSITION = 576460752303423488;
|
|
const ulong BQ_STARTING_POSITION = 8;
|
|
|
|
static readonly char[] SQ_CHAR_Y =
|
|
{
|
|
'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'
|
|
};
|
|
|
|
static readonly char[] SQ_CHAR_X =
|
|
{
|
|
'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 int WP = 0, WN = 1, WB = 2, WR = 3, WQ = 4, WK = 5,
|
|
BP = 6, BN = 7, BB = 8, BR = 9, BQ = 10, BK = 11;
|
|
|
|
|
|
static ulong[] bitboard_array_global = new ulong[12];
|
|
static int ep_global;
|
|
static bool[] castle_rights_global = new bool[4];
|
|
static bool is_white_global;
|
|
|
|
static void SetStartingPosition()
|
|
{
|
|
|
|
ep_global = Constants.NO_SQUARE;
|
|
is_white_global = true;
|
|
castle_rights_global[0] = true;
|
|
castle_rights_global[1] = true;
|
|
castle_rights_global[2] = true;
|
|
castle_rights_global[3] = true;
|
|
|
|
bitboard_array_global[WP] = WP_STARTING_POSITIONS;
|
|
bitboard_array_global[WN] = WN_STARTING_POSITIONS;
|
|
bitboard_array_global[WB] = WB_STARTING_POSITIONS;
|
|
bitboard_array_global[WR] = WR_STARTING_POSITIONS;
|
|
bitboard_array_global[WQ] = WQ_STARTING_POSITION;
|
|
bitboard_array_global[WK] = WK_STARTING_POSITION;
|
|
bitboard_array_global[BP] = BP_STARTING_POSITIONS;
|
|
bitboard_array_global[BN] = BN_STARTING_POSITIONS;
|
|
bitboard_array_global[BB] = BB_STARTING_POSITIONS;
|
|
bitboard_array_global[BR] = BR_STARTING_POSITIONS;
|
|
bitboard_array_global[BQ] = BQ_STARTING_POSITION;
|
|
bitboard_array_global[BK] = BK_STARTING_POSITION;
|
|
|
|
}
|
|
|
|
|
|
static bool Is_Square_Attacked_By_Black_Global(int square, ulong occupancy)
|
|
{
|
|
if ((bitboard_array_global[BP] & Constants.WHITE_PAWN_ATTACKS[square]) != 0)
|
|
{
|
|
return true;
|
|
}
|
|
if ((bitboard_array_global[BN] & Constants.KNIGHT_ATTACKS[square]) != 0)
|
|
{
|
|
return true;
|
|
}
|
|
if ((bitboard_array_global[BK] & Constants.KING_ATTACKS[square]) != 0)
|
|
{
|
|
return true;
|
|
}
|
|
ulong bishopAttacks = Constants.GetBishopAttacksFast(square, occupancy);
|
|
if ((bitboard_array_global[BB] & bishopAttacks) != 0)
|
|
{
|
|
return true;
|
|
}
|
|
if ((bitboard_array_global[BQ] & bishopAttacks) != 0)
|
|
{
|
|
return true;
|
|
}
|
|
ulong rookAttacks = Constants.GetRookAttacksFast(square, occupancy);
|
|
if ((bitboard_array_global[BR] & rookAttacks) != 0)
|
|
{
|
|
return true;
|
|
}
|
|
if ((bitboard_array_global[BQ] & rookAttacks) != 0)
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static bool Is_Square_Attacked_By_White_Global(int square, ulong occupancy)
|
|
{
|
|
if ((bitboard_array_global[WP] & Constants.BLACK_PAWN_ATTACKS[square]) != 0)
|
|
{
|
|
return true;
|
|
}
|
|
if ((bitboard_array_global[WN] & Constants.KNIGHT_ATTACKS[square]) != 0)
|
|
{
|
|
return true;
|
|
}
|
|
if ((bitboard_array_global[WK] & Constants.KING_ATTACKS[square]) != 0)
|
|
{
|
|
return true;
|
|
}
|
|
ulong bishopAttacks = Constants.GetBishopAttacksFast(square, occupancy);
|
|
if ((bitboard_array_global[WB] & bishopAttacks) != 0)
|
|
{
|
|
return true;
|
|
}
|
|
if ((bitboard_array_global[WQ] & bishopAttacks) != 0)
|
|
{
|
|
return true;
|
|
}
|
|
ulong rookAttacks = Constants.GetRookAttacksFast(square, occupancy);
|
|
if ((bitboard_array_global[WR] & rookAttacks) != 0)
|
|
{
|
|
return true;
|
|
}
|
|
if ((bitboard_array_global[WQ] & rookAttacks) != 0)
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static bool OutOfBounds(int move)
|
|
{
|
|
if (move < 0)
|
|
{
|
|
return true;
|
|
}
|
|
if (move > 63)
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static void PrintMoveNoNL(int[] move)
|
|
{ //starting
|
|
if (OutOfBounds(move[MOVE_STARTING]) == true)
|
|
{
|
|
Console.Write("%d", move[MOVE_STARTING]);
|
|
}
|
|
else
|
|
{
|
|
Console.Write("%c", SQ_CHAR_X[move[MOVE_STARTING]]);
|
|
Console.Write("%c", SQ_CHAR_Y[move[MOVE_STARTING]]);
|
|
}
|
|
//target
|
|
if (OutOfBounds(move[MOVE_TARGET]) == true)
|
|
{
|
|
Console.Write("%d", move[MOVE_TARGET]);
|
|
}
|
|
else
|
|
{
|
|
Console.Write("%c", SQ_CHAR_X[move[MOVE_TARGET]]);
|
|
Console.Write("%c", SQ_CHAR_Y[move[MOVE_TARGET]]);
|
|
}
|
|
int tag = move[MOVE_TAG];
|
|
if (tag == TAG_B_N_PROMOTION_CAP || tag == TAG_B_N_PROMOTION || tag == TAG_W_N_PROMOTION || tag == TAG_W_N_PROMOTION_CAP)
|
|
{
|
|
Console.Write("n");
|
|
}
|
|
else if (tag == TAG_B_R_PROMOTION_CAP || tag == TAG_B_R_PROMOTION || tag == TAG_W_R_PROMOTION || tag == TAG_W_R_PROMOTION_CAP)
|
|
{
|
|
Console.Write("r");
|
|
}
|
|
else if (tag == TAG_B_B_PROMOTION_CAP || tag == TAG_B_B_PROMOTION || tag == TAG_W_B_PROMOTION || tag == TAG_W_B_PROMOTION_CAP)
|
|
{
|
|
Console.Write("b");
|
|
}
|
|
else if (tag == TAG_B_Q_PROMOTION_CAP || tag == TAG_B_Q_PROMOTION || tag == TAG_W_Q_PROMOTION || tag == TAG_W_Q_PROMOTION_CAP)
|
|
{
|
|
Console.Write("q");
|
|
}
|
|
}
|
|
static int PerftInline(int depth, int ply)
|
|
{
|
|
//if (depth == 0)
|
|
//{
|
|
// return 1;
|
|
//}
|
|
|
|
Span<int> startingSquares = stackalloc int[50];
|
|
Span<int> targetSquares = stackalloc int[50];
|
|
Span<int> tags = stackalloc int[50];
|
|
Span<int> pieces = stackalloc int[50];
|
|
|
|
int moveCount = 0;
|
|
//Move generating variables
|
|
ulong WHITE_OCCUPANCIES_LOCAL = bitboard_array_global[0] | bitboard_array_global[1] | bitboard_array_global[2] | bitboard_array_global[3] | bitboard_array_global[4] | bitboard_array_global[5];
|
|
ulong BLACK_OCCUPANCIES_LOCAL = bitboard_array_global[6] | bitboard_array_global[7] | bitboard_array_global[8] | bitboard_array_global[9] | bitboard_array_global[10] | bitboard_array_global[11];
|
|
ulong COMBINED_OCCUPANCIES_LOCAL = WHITE_OCCUPANCIES_LOCAL | BLACK_OCCUPANCIES_LOCAL;
|
|
ulong EMPTY_OCCUPANCIES = ~COMBINED_OCCUPANCIES_LOCAL;
|
|
ulong tempBitboard, checkBitboard = 0UL, tempPinBitboard, tempAttack, tempEmpty, tempCaptures;
|
|
int startingSquare = NO_SQUARE, targetSquare = NO_SQUARE;
|
|
|
|
Span<int> pinArrayPiece = stackalloc int[8]
|
|
{
|
|
-1,-1,-1,-1,-1,-1,-1,-1
|
|
};
|
|
Span<int> pinArraySquare = stackalloc int[8]
|
|
{
|
|
-1,-1,-1,-1,-1,-1,-1,-1
|
|
};
|
|
|
|
int pinNumber = 0;
|
|
|
|
#region Generate Moves
|
|
|
|
if (is_white_global == true)
|
|
{
|
|
int whiteKingCheckCount = 0;
|
|
int whiteKingPosition = BitScanForward(bitboard_array_global[WK]);
|
|
|
|
#region pins and check
|
|
|
|
//pawns
|
|
tempBitboard = bitboard_array_global[BP] & Constants.WHITE_PAWN_ATTACKS[whiteKingPosition];
|
|
if (tempBitboard != 0)
|
|
{
|
|
int pawn_square = (DEBRUIJN64[MAGIC * (tempBitboard ^ (tempBitboard - 1)) >> 58]);
|
|
|
|
if (checkBitboard == 0)
|
|
{
|
|
checkBitboard = 1UL << pawn_square;
|
|
}
|
|
|
|
whiteKingCheckCount++;
|
|
}
|
|
|
|
//knights
|
|
tempBitboard = bitboard_array_global[BN] & Constants.KNIGHT_ATTACKS[whiteKingPosition];
|
|
if (tempBitboard != 0)
|
|
{
|
|
int knight_square = DEBRUIJN64[MAGIC * (tempBitboard ^ (tempBitboard - 1)) >> 58];
|
|
|
|
if (checkBitboard == 0)
|
|
{
|
|
checkBitboard = Constants.SQUARE_BBS[knight_square];
|
|
}
|
|
|
|
whiteKingCheckCount++;
|
|
}
|
|
|
|
//bishops
|
|
ulong bishopAttacksChecks = Constants.GetBishopAttacksFast(whiteKingPosition, BLACK_OCCUPANCIES_LOCAL);
|
|
tempBitboard = bitboard_array_global[BB] & bishopAttacksChecks;
|
|
while (tempBitboard != 0)
|
|
{
|
|
int piece_square = DEBRUIJN64[MAGIC * (tempBitboard ^ (tempBitboard - 1)) >> 58];
|
|
|
|
tempPinBitboard = Constants.INBETWEEN_BITBOARDS[whiteKingPosition, piece_square] & WHITE_OCCUPANCIES_LOCAL;
|
|
|
|
if (tempPinBitboard == 0)
|
|
{
|
|
if (checkBitboard == 0)
|
|
{
|
|
checkBitboard = Constants.INBETWEEN_BITBOARDS[whiteKingPosition, piece_square];
|
|
}
|
|
whiteKingCheckCount++;
|
|
}
|
|
else
|
|
{
|
|
int pinned_square = (DEBRUIJN64[MAGIC * (tempPinBitboard ^ (tempPinBitboard - 1)) >> 58]);
|
|
tempPinBitboard &= tempPinBitboard - 1;
|
|
|
|
if (tempPinBitboard == 0)
|
|
{
|
|
pinArraySquare[pinNumber] = pinned_square;
|
|
pinArrayPiece[pinNumber] = piece_square;
|
|
pinNumber++;
|
|
}
|
|
}
|
|
tempBitboard &= tempBitboard - 1;
|
|
}
|
|
|
|
//queen
|
|
tempBitboard = bitboard_array_global[BQ] & bishopAttacksChecks;
|
|
while (tempBitboard != 0)
|
|
{
|
|
int piece_square = DEBRUIJN64[MAGIC * (tempBitboard ^ (tempBitboard - 1)) >> 58];
|
|
|
|
tempPinBitboard = Constants.INBETWEEN_BITBOARDS[whiteKingPosition, piece_square] & WHITE_OCCUPANCIES_LOCAL;
|
|
|
|
if (tempPinBitboard == 0)
|
|
{
|
|
if (checkBitboard == 0)
|
|
{
|
|
checkBitboard = Constants.INBETWEEN_BITBOARDS[whiteKingPosition, piece_square];
|
|
}
|
|
whiteKingCheckCount++;
|
|
}
|
|
else
|
|
{
|
|
int pinned_square = (DEBRUIJN64[MAGIC * (tempPinBitboard ^ (tempPinBitboard - 1)) >> 58]);
|
|
tempPinBitboard &= tempPinBitboard - 1;
|
|
|
|
if (tempPinBitboard == 0)
|
|
{
|
|
pinArraySquare[pinNumber] = pinned_square;
|
|
pinArrayPiece[pinNumber] = piece_square;
|
|
pinNumber++;
|
|
}
|
|
}
|
|
tempBitboard &= tempBitboard - 1;
|
|
}
|
|
|
|
//rook
|
|
ulong rook_attacks = Constants.GetRookAttacksFast(whiteKingPosition, BLACK_OCCUPANCIES_LOCAL);
|
|
tempBitboard = bitboard_array_global[BR] & rook_attacks;
|
|
while (tempBitboard != 0)
|
|
{
|
|
int piece_square = DEBRUIJN64[MAGIC * (tempBitboard ^ (tempBitboard - 1)) >> 58];
|
|
|
|
tempPinBitboard = Constants.INBETWEEN_BITBOARDS[whiteKingPosition, piece_square] & WHITE_OCCUPANCIES_LOCAL;
|
|
|
|
if (tempPinBitboard == 0)
|
|
{
|
|
if (checkBitboard == 0)
|
|
{
|
|
checkBitboard = Constants.INBETWEEN_BITBOARDS[whiteKingPosition, piece_square];
|
|
}
|
|
whiteKingCheckCount++;
|
|
}
|
|
else
|
|
{
|
|
int pinned_square = (DEBRUIJN64[MAGIC * (tempPinBitboard ^ (tempPinBitboard - 1)) >> 58]);
|
|
tempPinBitboard &= tempPinBitboard - 1;
|
|
|
|
if (tempPinBitboard == 0)
|
|
{
|
|
pinArraySquare[pinNumber] = pinned_square;
|
|
pinArrayPiece[pinNumber] = piece_square;
|
|
pinNumber++;
|
|
}
|
|
}
|
|
tempBitboard &= tempBitboard - 1;
|
|
}
|
|
|
|
//queen
|
|
tempBitboard = bitboard_array_global[BQ] & rook_attacks;
|
|
while (tempBitboard != 0)
|
|
{
|
|
int piece_square = (DEBRUIJN64[MAGIC * (tempBitboard ^ (tempBitboard - 1)) >> 58]);
|
|
|
|
tempPinBitboard = Constants.INBETWEEN_BITBOARDS[whiteKingPosition, piece_square] & WHITE_OCCUPANCIES_LOCAL;
|
|
|
|
if (tempPinBitboard == 0)
|
|
{
|
|
if (checkBitboard == 0)
|
|
{
|
|
checkBitboard = Constants.INBETWEEN_BITBOARDS[whiteKingPosition, piece_square];
|
|
}
|
|
whiteKingCheckCount++;
|
|
}
|
|
else
|
|
{
|
|
int pinned_square = (DEBRUIJN64[MAGIC * (tempPinBitboard ^ (tempPinBitboard - 1)) >> 58]);
|
|
tempPinBitboard &= tempPinBitboard - 1;
|
|
|
|
if (tempPinBitboard == 0)
|
|
{
|
|
pinArraySquare[pinNumber] = pinned_square;
|
|
pinArrayPiece[pinNumber] = piece_square;
|
|
pinNumber++;
|
|
}
|
|
}
|
|
tempBitboard &= tempBitboard - 1;
|
|
}
|
|
|
|
#endregion
|
|
|
|
if (whiteKingCheckCount > 1)
|
|
{
|
|
#region White king double check
|
|
|
|
ulong occupanciesWithoutWhiteKing = COMBINED_OCCUPANCIES_LOCAL & (~bitboard_array_global[WK]);
|
|
tempAttack = Constants.KING_ATTACKS[whiteKingPosition];
|
|
tempEmpty = tempAttack & EMPTY_OCCUPANCIES;
|
|
while (tempEmpty != 0)
|
|
{
|
|
targetSquare = BitScanForward(tempEmpty);
|
|
tempEmpty &= tempEmpty - 1;
|
|
|
|
if ((bitboard_array_global[BP] & Constants.WHITE_PAWN_ATTACKS[targetSquare]) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
if ((bitboard_array_global[BN] & Constants.KNIGHT_ATTACKS[targetSquare]) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
if ((bitboard_array_global[BK] & Constants.KING_ATTACKS[targetSquare]) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
ulong bishopAttacks = Constants.GetBishopAttacksFast(targetSquare, occupanciesWithoutWhiteKing);
|
|
if ((bitboard_array_global[BB] & bishopAttacks) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
if ((bitboard_array_global[BQ] & bishopAttacks) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
ulong rookAttacks = Constants.GetRookAttacksFast(targetSquare, occupanciesWithoutWhiteKing);
|
|
if ((bitboard_array_global[BR] & rookAttacks) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
if ((bitboard_array_global[BQ] & rookAttacks) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
startingSquares[moveCount] = whiteKingPosition;
|
|
targetSquares[moveCount] = targetSquare;
|
|
tags[moveCount] = TAG_NONE;
|
|
pieces[moveCount] = WK;
|
|
moveCount++;
|
|
}
|
|
|
|
//captures
|
|
tempCaptures = tempAttack & BLACK_OCCUPANCIES_LOCAL;
|
|
while (tempCaptures != 0)
|
|
{
|
|
targetSquare = BitScanForward(tempCaptures);
|
|
tempCaptures &= tempCaptures - 1;
|
|
|
|
if ((bitboard_array_global[BP] & Constants.WHITE_PAWN_ATTACKS[targetSquare]) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
if ((bitboard_array_global[BN] & Constants.KNIGHT_ATTACKS[targetSquare]) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
if ((bitboard_array_global[BK] & Constants.KING_ATTACKS[targetSquare]) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
ulong bishopAttacks = Constants.GetBishopAttacksFast(targetSquare, occupanciesWithoutWhiteKing);
|
|
if ((bitboard_array_global[BB] & bishopAttacks) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
if ((bitboard_array_global[BQ] & bishopAttacks) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
ulong rookAttacks = Constants.GetRookAttacksFast(targetSquare, occupanciesWithoutWhiteKing);
|
|
if ((bitboard_array_global[BR] & rookAttacks) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
if ((bitboard_array_global[BQ] & rookAttacks) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
startingSquares[moveCount] = whiteKingPosition;
|
|
targetSquares[moveCount] = targetSquare;
|
|
tags[moveCount] = TAG_CAPTURE;
|
|
pieces[moveCount] = WK;
|
|
moveCount++;
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
else
|
|
{
|
|
|
|
if (whiteKingCheckCount == 0)
|
|
{
|
|
checkBitboard = ulong.MaxValue;
|
|
}
|
|
|
|
#region White king
|
|
ulong occupanciesWithoutWhiteKing = COMBINED_OCCUPANCIES_LOCAL & (~bitboard_array_global[WK]);
|
|
tempAttack = Constants.KING_ATTACKS[whiteKingPosition];
|
|
tempEmpty = tempAttack & EMPTY_OCCUPANCIES;
|
|
while (tempEmpty != 0)
|
|
{
|
|
targetSquare = BitScanForward(tempEmpty);
|
|
tempEmpty &= tempEmpty - 1;
|
|
|
|
if ((bitboard_array_global[BP] & Constants.WHITE_PAWN_ATTACKS[targetSquare]) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
if ((bitboard_array_global[BN] & Constants.KNIGHT_ATTACKS[targetSquare]) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
if ((bitboard_array_global[BK] & Constants.KING_ATTACKS[targetSquare]) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
ulong bishopAttacks = Constants.GetBishopAttacksFast(targetSquare, occupanciesWithoutWhiteKing);
|
|
if ((bitboard_array_global[BB] & bishopAttacks) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
if ((bitboard_array_global[BQ] & bishopAttacks) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
ulong rookAttacks = Constants.GetRookAttacksFast(targetSquare, occupanciesWithoutWhiteKing);
|
|
if ((bitboard_array_global[BR] & rookAttacks) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
if ((bitboard_array_global[BQ] & rookAttacks) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
startingSquares[moveCount] = whiteKingPosition;
|
|
targetSquares[moveCount] = targetSquare;
|
|
tags[moveCount] = TAG_NONE;
|
|
pieces[moveCount] = WK;
|
|
moveCount++;
|
|
}
|
|
|
|
//captures
|
|
tempCaptures = tempAttack & BLACK_OCCUPANCIES_LOCAL;
|
|
while (tempCaptures != 0)
|
|
{
|
|
targetSquare = BitScanForward(tempCaptures);
|
|
tempCaptures &= tempCaptures - 1;
|
|
|
|
if ((bitboard_array_global[BP] & Constants.WHITE_PAWN_ATTACKS[targetSquare]) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
if ((bitboard_array_global[BN] & Constants.KNIGHT_ATTACKS[targetSquare]) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
if ((bitboard_array_global[BK] & Constants.KING_ATTACKS[targetSquare]) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
ulong bishopAttacks = Constants.GetBishopAttacksFast(targetSquare, occupanciesWithoutWhiteKing);
|
|
if ((bitboard_array_global[BB] & bishopAttacks) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
if ((bitboard_array_global[BQ] & bishopAttacks) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
ulong rookAttacks = Constants.GetRookAttacksFast(targetSquare, occupanciesWithoutWhiteKing);
|
|
if ((bitboard_array_global[BR] & rookAttacks) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
if ((bitboard_array_global[BQ] & rookAttacks) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
startingSquares[moveCount] = whiteKingPosition;
|
|
targetSquares[moveCount] = targetSquare;
|
|
tags[moveCount] = TAG_CAPTURE;
|
|
pieces[moveCount] = WK;
|
|
moveCount++;
|
|
}
|
|
|
|
if (whiteKingCheckCount == 0)
|
|
{
|
|
if (castle_rights_global[WKS_CASTLE_RIGHTS] == true)
|
|
{
|
|
if (whiteKingPosition == E1) //king on e1
|
|
{
|
|
if ((WKS_EMPTY_BITBOARD & COMBINED_OCCUPANCIES_LOCAL) == 0) //f1 and g1 empty
|
|
{
|
|
if ((bitboard_array_global[WR] & Constants.SQUARE_BBS[H1]) != 0) //rook on h1
|
|
{
|
|
if (Is_Square_Attacked_By_Black_Global(F1, COMBINED_OCCUPANCIES_LOCAL) == false)
|
|
{
|
|
if (Is_Square_Attacked_By_Black_Global(G1, COMBINED_OCCUPANCIES_LOCAL) == false)
|
|
{
|
|
startingSquares[moveCount] = E1;
|
|
targetSquares[moveCount] = G1;
|
|
tags[moveCount] = TAG_W_CASTLE_KS;
|
|
pieces[moveCount] = WK;
|
|
moveCount++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (castle_rights_global[WQS_CASTLE_RIGHTS] == true)
|
|
{
|
|
if (whiteKingPosition == E1) //king on e1
|
|
{
|
|
if ((WQS_EMPTY_BITBOARD & COMBINED_OCCUPANCIES_LOCAL) == 0) //f1 and g1 empty
|
|
{
|
|
if ((bitboard_array_global[WR] & Constants.SQUARE_BBS[A1]) != 0) //rook on h1
|
|
{
|
|
if (Is_Square_Attacked_By_Black_Global(C1, COMBINED_OCCUPANCIES_LOCAL) == false)
|
|
{
|
|
if (Is_Square_Attacked_By_Black_Global(D1, COMBINED_OCCUPANCIES_LOCAL) == false)
|
|
{
|
|
startingSquares[moveCount] = E1;
|
|
targetSquares[moveCount] = C1;
|
|
tags[moveCount] = TAG_W_CASTLE_QS;
|
|
pieces[moveCount] = WK;
|
|
moveCount++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region White knight
|
|
|
|
int blackKingSquare = DEBRUIJN64[MAGIC * (bitboard_array_global[BK] ^ (bitboard_array_global[BK] - 1)) >> 58];
|
|
|
|
tempBitboard = bitboard_array_global[WN];
|
|
|
|
while (tempBitboard != 0)
|
|
{
|
|
startingSquare = DEBRUIJN64[MAGIC * (tempBitboard ^ (tempBitboard - 1)) >> 58];
|
|
tempBitboard &= tempBitboard - 1; //removes the knight from that square to not infinitely loop
|
|
|
|
tempPinBitboard = ulong.MaxValue;
|
|
if (pinNumber != 0)
|
|
{
|
|
for (int i = 0; i < pinNumber; i++)
|
|
{
|
|
if (pinArraySquare[i] == startingSquare)
|
|
{
|
|
tempPinBitboard = Constants.INBETWEEN_BITBOARDS[whiteKingPosition, pinArrayPiece[i]];
|
|
}
|
|
}
|
|
}
|
|
|
|
tempAttack = ((Constants.KNIGHT_ATTACKS[startingSquare] & BLACK_OCCUPANCIES_LOCAL) & checkBitboard) & tempPinBitboard; //gets knight captures
|
|
while (tempAttack != 0)
|
|
{
|
|
targetSquare = (DEBRUIJN64[MAGIC * (tempAttack ^ (tempAttack - 1)) >> 58]);
|
|
tempAttack &= tempAttack - 1;
|
|
|
|
|
|
startingSquares[moveCount] = startingSquare;
|
|
targetSquares[moveCount] = targetSquare;
|
|
tags[moveCount] = TAG_CAPTURE;
|
|
pieces[moveCount] = WN;
|
|
moveCount++;
|
|
|
|
}
|
|
|
|
tempAttack = ((Constants.KNIGHT_ATTACKS[startingSquare] & EMPTY_OCCUPANCIES) & checkBitboard) & tempPinBitboard;
|
|
|
|
while (tempAttack != 0)
|
|
{
|
|
targetSquare = DEBRUIJN64[MAGIC * (tempAttack ^ (tempAttack - 1)) >> 58];
|
|
tempAttack &= tempAttack - 1;
|
|
|
|
startingSquares[moveCount] = startingSquare;
|
|
targetSquares[moveCount] = targetSquare;
|
|
tags[moveCount] = TAG_NONE;
|
|
pieces[moveCount] = WN;
|
|
moveCount++;
|
|
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region White pawn
|
|
|
|
ulong whitePawnCheckBitboard = Constants.BLACK_PAWN_ATTACKS[blackKingSquare];
|
|
|
|
tempBitboard = bitboard_array_global[WP];
|
|
|
|
while (tempBitboard != 0)
|
|
{
|
|
startingSquare = DEBRUIJN64[MAGIC * (tempBitboard ^ (tempBitboard - 1)) >> 58];
|
|
tempBitboard &= tempBitboard - 1;
|
|
|
|
tempPinBitboard = ulong.MaxValue;
|
|
if (pinNumber != 0)
|
|
{
|
|
for (int i = 0; i < pinNumber; i++)
|
|
{
|
|
if (pinArraySquare[i] == startingSquare)
|
|
{
|
|
tempPinBitboard = Constants.INBETWEEN_BITBOARDS[whiteKingPosition, pinArrayPiece[i]];
|
|
}
|
|
}
|
|
}
|
|
|
|
#region Pawn forward
|
|
|
|
if ((Constants.SQUARE_BBS[startingSquare - 8] & COMBINED_OCCUPANCIES_LOCAL) == 0) //if up one square is empty
|
|
{
|
|
if (((Constants.SQUARE_BBS[startingSquare - 8] & checkBitboard) & tempPinBitboard) != 0)
|
|
{
|
|
if ((Constants.SQUARE_BBS[startingSquare] & Constants.RANK_7_BITBOARD) != 0) //if promotion
|
|
{
|
|
|
|
startingSquares[moveCount] = startingSquare;
|
|
targetSquares[moveCount] = startingSquare - 8;
|
|
tags[moveCount] = TAG_W_Q_PROMOTION;
|
|
pieces[moveCount] = WP;
|
|
moveCount++;
|
|
|
|
startingSquares[moveCount] = startingSquare;
|
|
targetSquares[moveCount] = startingSquare - 8;
|
|
tags[moveCount] = TAG_W_R_PROMOTION;
|
|
pieces[moveCount] = WP;
|
|
moveCount++;
|
|
|
|
startingSquares[moveCount] = startingSquare;
|
|
targetSquares[moveCount] = startingSquare - 8;
|
|
tags[moveCount] = TAG_W_B_PROMOTION;
|
|
pieces[moveCount] = WP;
|
|
moveCount++;
|
|
|
|
startingSquares[moveCount] = startingSquare;
|
|
targetSquares[moveCount] = startingSquare - 8;
|
|
tags[moveCount] = TAG_W_N_PROMOTION;
|
|
pieces[moveCount] = WP;
|
|
moveCount++;
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
if ((whitePawnCheckBitboard & Constants.SQUARE_BBS[startingSquare - 8]) != 0)
|
|
{
|
|
startingSquares[moveCount] = startingSquare;
|
|
targetSquares[moveCount] = startingSquare - 8;
|
|
tags[moveCount] = TAG_CHECK;
|
|
pieces[moveCount] = WP;
|
|
moveCount++;
|
|
}
|
|
else
|
|
{
|
|
startingSquares[moveCount] = startingSquare;
|
|
targetSquares[moveCount] = startingSquare - 8;
|
|
tags[moveCount] = TAG_NONE;
|
|
pieces[moveCount] = WP;
|
|
moveCount++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((Constants.SQUARE_BBS[startingSquare] & Constants.RANK_2_BITBOARD) != 0) //if on rank 2
|
|
{
|
|
if (((Constants.SQUARE_BBS[startingSquare - 16] & checkBitboard) & tempPinBitboard) != 0) //if not pinned or
|
|
{
|
|
if (((Constants.SQUARE_BBS[startingSquare - 16]) & COMBINED_OCCUPANCIES_LOCAL) == 0) //if up two squares and one square are empty
|
|
{
|
|
startingSquares[moveCount] = startingSquare;
|
|
targetSquares[moveCount] = startingSquare - 16;
|
|
tags[moveCount] = TAG_W_P_DOUBLE;
|
|
pieces[moveCount] = WP;
|
|
moveCount++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Pawn captures
|
|
|
|
tempAttack = ((Constants.WHITE_PAWN_ATTACKS[startingSquare] & BLACK_OCCUPANCIES_LOCAL) & checkBitboard) & tempPinBitboard; //if black piece diagonal to pawn
|
|
|
|
while (tempAttack != 0)
|
|
{
|
|
targetSquare = (DEBRUIJN64[MAGIC * (tempAttack ^ (tempAttack - 1)) >> 58]);
|
|
tempAttack &= tempAttack - 1;
|
|
|
|
if ((Constants.SQUARE_BBS[startingSquare] & Constants.RANK_7_BITBOARD) != 0) //if promotion
|
|
{
|
|
|
|
startingSquares[moveCount] = startingSquare;
|
|
targetSquares[moveCount] = targetSquare;
|
|
tags[moveCount] = TAG_W_Q_PROMOTION_CAP;
|
|
pieces[moveCount] = WP;
|
|
moveCount++;
|
|
|
|
startingSquares[moveCount] = startingSquare;
|
|
targetSquares[moveCount] = targetSquare;
|
|
tags[moveCount] = TAG_W_R_PROMOTION_CAP;
|
|
pieces[moveCount] = WP;
|
|
moveCount++;
|
|
|
|
startingSquares[moveCount] = startingSquare;
|
|
targetSquares[moveCount] = targetSquare;
|
|
tags[moveCount] = TAG_W_B_PROMOTION_CAP;
|
|
pieces[moveCount] = WP;
|
|
moveCount++;
|
|
|
|
startingSquares[moveCount] = startingSquare;
|
|
targetSquares[moveCount] = targetSquare;
|
|
tags[moveCount] = TAG_W_N_PROMOTION_CAP;
|
|
pieces[moveCount] = WP;
|
|
moveCount++;
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
if ((whitePawnCheckBitboard & Constants.SQUARE_BBS[targetSquare]) != 0)
|
|
{
|
|
startingSquares[moveCount] = startingSquare;
|
|
targetSquares[moveCount] = targetSquare;
|
|
tags[moveCount] = TAG_CHECK_CAP;
|
|
pieces[moveCount] = WP;
|
|
moveCount++;
|
|
}
|
|
else
|
|
{
|
|
startingSquares[moveCount] = startingSquare;
|
|
targetSquares[moveCount] = targetSquare;
|
|
tags[moveCount] = TAG_CAPTURE;
|
|
pieces[moveCount] = WP;
|
|
moveCount++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((Constants.SQUARE_BBS[startingSquare] & Constants.RANK_5_BITBOARD) != 0) //check rank for ep
|
|
{
|
|
if (ep_global != NO_SQUARE)
|
|
{
|
|
if ((((Constants.WHITE_PAWN_ATTACKS[startingSquare] & Constants.SQUARE_BBS[ep_global]) & checkBitboard) & tempPinBitboard) != 0)
|
|
{
|
|
if ((bitboard_array_global[WK] & Constants.RANK_5_BITBOARD) == 0) //if no king on rank 5
|
|
{
|
|
startingSquares[moveCount] = startingSquare;
|
|
targetSquares[moveCount] = ep_global;
|
|
tags[moveCount] = TAG_WHITE_EP;
|
|
pieces[moveCount] = WP;
|
|
moveCount++;
|
|
}
|
|
else if ((bitboard_array_global[BR] & Constants.RANK_5_BITBOARD) == 0 && (bitboard_array_global[BQ] & Constants.RANK_5_BITBOARD) == 0) // if no b rook or queen on rank 5
|
|
{
|
|
startingSquares[moveCount] = startingSquare;
|
|
targetSquares[moveCount] = ep_global;
|
|
tags[moveCount] = TAG_WHITE_EP;
|
|
pieces[moveCount] = WP;
|
|
moveCount++;
|
|
}
|
|
else //wk and br or bq on rank 5
|
|
{
|
|
ulong occupancyWithoutEPPawns = COMBINED_OCCUPANCIES_LOCAL & ~Constants.SQUARE_BBS[startingSquare];
|
|
occupancyWithoutEPPawns &= ~Constants.SQUARE_BBS[ep_global + 8];
|
|
|
|
ulong rookAttacksFromKing = Constants.GetRookAttacksFast(whiteKingPosition, occupancyWithoutEPPawns);
|
|
|
|
if ((rookAttacksFromKing & bitboard_array_global[BR]) == 0)
|
|
{
|
|
if ((rookAttacksFromKing & bitboard_array_global[BQ]) == 0)
|
|
{
|
|
startingSquares[moveCount] = startingSquare;
|
|
targetSquares[moveCount] = ep_global;
|
|
tags[moveCount] = TAG_WHITE_EP;
|
|
pieces[moveCount] = WP;
|
|
moveCount++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region White Rook
|
|
|
|
tempBitboard = bitboard_array_global[WR];
|
|
while (tempBitboard != 0)
|
|
{
|
|
startingSquare = DEBRUIJN64[MAGIC * (tempBitboard ^ (tempBitboard - 1)) >> 58];
|
|
tempBitboard &= tempBitboard - 1;
|
|
|
|
tempPinBitboard = ulong.MaxValue;
|
|
if (pinNumber != 0)
|
|
{
|
|
for (int i = 0; i < pinNumber; i++)
|
|
{
|
|
if (pinArraySquare[i] == startingSquare)
|
|
{
|
|
tempPinBitboard = Constants.INBETWEEN_BITBOARDS[whiteKingPosition, pinArrayPiece[i]];
|
|
}
|
|
}
|
|
}
|
|
|
|
ulong rookAttacks = Constants.GetRookAttacksFast(startingSquare, COMBINED_OCCUPANCIES_LOCAL);
|
|
|
|
tempAttack = ((rookAttacks & BLACK_OCCUPANCIES_LOCAL) & checkBitboard) & tempPinBitboard;
|
|
while (tempAttack != 0)
|
|
{
|
|
targetSquare = (DEBRUIJN64[MAGIC * (tempAttack ^ (tempAttack - 1)) >> 58]);
|
|
tempAttack &= tempAttack - 1;
|
|
|
|
|
|
startingSquares[moveCount] = startingSquare;
|
|
targetSquares[moveCount] = targetSquare;
|
|
tags[moveCount] = TAG_CAPTURE;
|
|
pieces[moveCount] = WR;
|
|
moveCount++;
|
|
|
|
|
|
}
|
|
|
|
tempAttack = ((rookAttacks & EMPTY_OCCUPANCIES) & checkBitboard) & tempPinBitboard;
|
|
while (tempAttack != 0)
|
|
{
|
|
targetSquare = (DEBRUIJN64[MAGIC * (tempAttack ^ (tempAttack - 1)) >> 58]);
|
|
tempAttack &= tempAttack - 1;
|
|
|
|
startingSquares[moveCount] = startingSquare;
|
|
targetSquares[moveCount] = targetSquare;
|
|
tags[moveCount] = TAG_NONE;
|
|
pieces[moveCount] = WR;
|
|
moveCount++;
|
|
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region White bishop
|
|
|
|
tempBitboard = bitboard_array_global[WB];
|
|
while (tempBitboard != 0)
|
|
{
|
|
startingSquare = DEBRUIJN64[MAGIC * (tempBitboard ^ (tempBitboard - 1)) >> 58];
|
|
tempBitboard &= tempBitboard - 1;
|
|
|
|
tempPinBitboard = ulong.MaxValue;
|
|
if (pinNumber != 0)
|
|
{
|
|
for (int i = 0; i < pinNumber; i++)
|
|
{
|
|
if (pinArraySquare[i] == startingSquare)
|
|
{
|
|
tempPinBitboard = Constants.INBETWEEN_BITBOARDS[whiteKingPosition, pinArrayPiece[i]];
|
|
}
|
|
}
|
|
}
|
|
|
|
ulong bishopAttacks = Constants.GetBishopAttacksFast(startingSquare, COMBINED_OCCUPANCIES_LOCAL);
|
|
|
|
tempAttack = ((bishopAttacks & BLACK_OCCUPANCIES_LOCAL) & checkBitboard) & tempPinBitboard;
|
|
while (tempAttack != 0)
|
|
{
|
|
targetSquare = DEBRUIJN64[MAGIC * (tempAttack ^ (tempAttack - 1)) >> 58];
|
|
tempAttack &= tempAttack - 1;
|
|
|
|
startingSquares[moveCount] = startingSquare;
|
|
targetSquares[moveCount] = targetSquare;
|
|
tags[moveCount] = TAG_CAPTURE;
|
|
pieces[moveCount] = WB;
|
|
moveCount++;
|
|
|
|
}
|
|
|
|
tempAttack = ((bishopAttacks & EMPTY_OCCUPANCIES) & checkBitboard) & tempPinBitboard;
|
|
while (tempAttack != 0)
|
|
{
|
|
targetSquare = DEBRUIJN64[MAGIC * (tempAttack ^ (tempAttack - 1)) >> 58];
|
|
tempAttack &= tempAttack - 1;
|
|
|
|
|
|
startingSquares[moveCount] = startingSquare;
|
|
targetSquares[moveCount] = targetSquare;
|
|
tags[moveCount] = TAG_NONE;
|
|
pieces[moveCount] = WB;
|
|
moveCount++;
|
|
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region White Queen
|
|
|
|
tempBitboard = bitboard_array_global[WQ];
|
|
while (tempBitboard != 0)
|
|
{
|
|
startingSquare = DEBRUIJN64[MAGIC * (tempBitboard ^ (tempBitboard - 1)) >> 58];
|
|
tempBitboard &= tempBitboard - 1;
|
|
|
|
tempPinBitboard = ulong.MaxValue;
|
|
if (pinNumber != 0)
|
|
{
|
|
for (int i = 0; i < pinNumber; i++)
|
|
{
|
|
if (pinArraySquare[i] == startingSquare)
|
|
{
|
|
tempPinBitboard = Constants.INBETWEEN_BITBOARDS[whiteKingPosition, pinArrayPiece[i]];
|
|
}
|
|
}
|
|
}
|
|
|
|
ulong queenAttacks = Constants.GetRookAttacksFast(startingSquare, COMBINED_OCCUPANCIES_LOCAL);
|
|
queenAttacks |= Constants.GetBishopAttacksFast(startingSquare, COMBINED_OCCUPANCIES_LOCAL);
|
|
|
|
tempAttack = ((queenAttacks & BLACK_OCCUPANCIES_LOCAL) & checkBitboard) & tempPinBitboard;
|
|
|
|
while (tempAttack != 0)
|
|
{
|
|
targetSquare = DEBRUIJN64[MAGIC * (tempAttack ^ (tempAttack - 1)) >> 58];
|
|
tempAttack &= tempAttack - 1;
|
|
|
|
startingSquares[moveCount] = startingSquare;
|
|
targetSquares[moveCount] = targetSquare;
|
|
tags[moveCount] = TAG_CAPTURE;
|
|
pieces[moveCount] = WQ;
|
|
moveCount++;
|
|
|
|
}
|
|
|
|
tempAttack = ((queenAttacks & EMPTY_OCCUPANCIES) & checkBitboard) & tempPinBitboard;
|
|
while (tempAttack != 0)
|
|
{
|
|
targetSquare = DEBRUIJN64[MAGIC * (tempAttack ^ (tempAttack - 1)) >> 58];
|
|
tempAttack &= tempAttack - 1;
|
|
|
|
|
|
startingSquares[moveCount] = startingSquare;
|
|
targetSquares[moveCount] = targetSquare;
|
|
tags[moveCount] = TAG_NONE;
|
|
pieces[moveCount] = WQ;
|
|
moveCount++;
|
|
|
|
}
|
|
}
|
|
#endregion
|
|
}
|
|
}
|
|
else //black move
|
|
{
|
|
int blackKingCheckCount = 0;
|
|
int blackKingPosition = BitScanForward(bitboard_array_global[BK]);
|
|
|
|
#region pins and check
|
|
|
|
//pawns
|
|
tempBitboard = bitboard_array_global[WP] & Constants.BLACK_PAWN_ATTACKS[blackKingPosition];
|
|
if (tempBitboard != 0)
|
|
{
|
|
int pawn_square = DEBRUIJN64[MAGIC * (tempBitboard ^ (tempBitboard - 1)) >> 58];
|
|
|
|
if (checkBitboard == 0)
|
|
{
|
|
checkBitboard = Constants.SQUARE_BBS[pawn_square];
|
|
}
|
|
|
|
blackKingCheckCount++;
|
|
}
|
|
|
|
//knights
|
|
tempBitboard = bitboard_array_global[WN] & Constants.KNIGHT_ATTACKS[blackKingPosition];
|
|
if (tempBitboard != 0)
|
|
{
|
|
int knight_square = DEBRUIJN64[MAGIC * (tempBitboard ^ (tempBitboard - 1)) >> 58];
|
|
|
|
if (checkBitboard == 0)
|
|
{
|
|
checkBitboard = Constants.SQUARE_BBS[knight_square];
|
|
}
|
|
|
|
blackKingCheckCount++;
|
|
}
|
|
|
|
//bishops
|
|
ulong bishopAttacksChecks = Constants.GetBishopAttacksFast(blackKingPosition, WHITE_OCCUPANCIES_LOCAL);
|
|
tempBitboard = bitboard_array_global[WB] & bishopAttacksChecks;
|
|
while (tempBitboard != 0)
|
|
{
|
|
int piece_square = DEBRUIJN64[MAGIC * (tempBitboard ^ (tempBitboard - 1)) >> 58];
|
|
|
|
tempPinBitboard = Constants.INBETWEEN_BITBOARDS[blackKingPosition, piece_square] & BLACK_OCCUPANCIES_LOCAL;
|
|
|
|
if (tempPinBitboard == 0)
|
|
{
|
|
if (checkBitboard == 0)
|
|
{
|
|
checkBitboard = Constants.INBETWEEN_BITBOARDS[blackKingPosition, piece_square];
|
|
}
|
|
blackKingCheckCount++;
|
|
}
|
|
else
|
|
{
|
|
int pinned_square = (DEBRUIJN64[MAGIC * (tempPinBitboard ^ (tempPinBitboard - 1)) >> 58]);
|
|
tempPinBitboard &= tempPinBitboard - 1;
|
|
|
|
if (tempPinBitboard == 0)
|
|
{
|
|
pinArraySquare[pinNumber] = pinned_square;
|
|
pinArrayPiece[pinNumber] = piece_square;
|
|
pinNumber++;
|
|
}
|
|
}
|
|
tempBitboard &= tempBitboard - 1;
|
|
}
|
|
|
|
//queen
|
|
tempBitboard = bitboard_array_global[WQ] & bishopAttacksChecks;
|
|
while (tempBitboard != 0)
|
|
{
|
|
int piece_square = DEBRUIJN64[MAGIC * (tempBitboard ^ (tempBitboard - 1)) >> 58];
|
|
|
|
tempPinBitboard = Constants.INBETWEEN_BITBOARDS[blackKingPosition, piece_square] & BLACK_OCCUPANCIES_LOCAL;
|
|
|
|
if (tempPinBitboard == 0)
|
|
{
|
|
if (checkBitboard == 0)
|
|
{
|
|
checkBitboard = Constants.INBETWEEN_BITBOARDS[blackKingPosition, piece_square];
|
|
}
|
|
blackKingCheckCount++;
|
|
}
|
|
else
|
|
{
|
|
int pinned_square = (DEBRUIJN64[MAGIC * (tempPinBitboard ^ (tempPinBitboard - 1)) >> 58]);
|
|
tempPinBitboard &= tempPinBitboard - 1;
|
|
|
|
if (tempPinBitboard == 0)
|
|
{
|
|
pinArraySquare[pinNumber] = pinned_square;
|
|
pinArrayPiece[pinNumber] = piece_square;
|
|
pinNumber++;
|
|
}
|
|
}
|
|
tempBitboard &= tempBitboard - 1;
|
|
}
|
|
|
|
//rook
|
|
ulong rook_attacks = Constants.GetRookAttacksFast(blackKingPosition, WHITE_OCCUPANCIES_LOCAL);
|
|
tempBitboard = bitboard_array_global[WR] & rook_attacks;
|
|
while (tempBitboard != 0)
|
|
{
|
|
int piece_square = DEBRUIJN64[MAGIC * (tempBitboard ^ (tempBitboard - 1)) >> 58];
|
|
|
|
tempPinBitboard = Constants.INBETWEEN_BITBOARDS[blackKingPosition, piece_square] & BLACK_OCCUPANCIES_LOCAL;
|
|
|
|
if (tempPinBitboard == 0)
|
|
{
|
|
if (checkBitboard == 0)
|
|
{
|
|
checkBitboard = Constants.INBETWEEN_BITBOARDS[blackKingPosition, piece_square];
|
|
}
|
|
blackKingCheckCount++;
|
|
}
|
|
else
|
|
{
|
|
int pinned_square = (DEBRUIJN64[MAGIC * (tempPinBitboard ^ (tempPinBitboard - 1)) >> 58]);
|
|
tempPinBitboard &= tempPinBitboard - 1;
|
|
|
|
if (tempPinBitboard == 0)
|
|
{
|
|
pinArraySquare[pinNumber] = pinned_square;
|
|
pinArrayPiece[pinNumber] = piece_square;
|
|
pinNumber++;
|
|
}
|
|
}
|
|
tempBitboard &= tempBitboard - 1;
|
|
}
|
|
|
|
//queen
|
|
tempBitboard = bitboard_array_global[WQ] & rook_attacks;
|
|
while (tempBitboard != 0)
|
|
{
|
|
int piece_square = DEBRUIJN64[MAGIC * (tempBitboard ^ (tempBitboard - 1)) >> 58];
|
|
|
|
tempPinBitboard = Constants.INBETWEEN_BITBOARDS[blackKingPosition, piece_square] & BLACK_OCCUPANCIES_LOCAL;
|
|
|
|
if (tempPinBitboard == 0)
|
|
{
|
|
if (checkBitboard == 0)
|
|
{
|
|
checkBitboard = Constants.INBETWEEN_BITBOARDS[blackKingPosition, piece_square];
|
|
}
|
|
blackKingCheckCount++;
|
|
}
|
|
else
|
|
{
|
|
int pinned_square = (DEBRUIJN64[MAGIC * (tempPinBitboard ^ (tempPinBitboard - 1)) >> 58]);
|
|
tempPinBitboard &= tempPinBitboard - 1;
|
|
|
|
if (tempPinBitboard == 0)
|
|
{
|
|
pinArraySquare[pinNumber] = pinned_square;
|
|
pinArrayPiece[pinNumber] = piece_square;
|
|
pinNumber++;
|
|
}
|
|
}
|
|
tempBitboard &= tempBitboard - 1;
|
|
}
|
|
|
|
#endregion
|
|
|
|
if (blackKingCheckCount > 1)
|
|
{
|
|
#region Black king
|
|
ulong occupancyWithoutBlackKing = COMBINED_OCCUPANCIES_LOCAL & (~bitboard_array_global[BK]);
|
|
|
|
tempAttack = Constants.KING_ATTACKS[blackKingPosition] & WHITE_OCCUPANCIES_LOCAL;
|
|
|
|
while (tempAttack != 0)
|
|
{
|
|
targetSquare = DEBRUIJN64[MAGIC * (tempAttack ^ (tempAttack - 1)) >> 58];
|
|
tempAttack &= tempAttack - 1;
|
|
|
|
if ((bitboard_array_global[WP] & Constants.BLACK_PAWN_ATTACKS[targetSquare]) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
if ((bitboard_array_global[WN] & Constants.KNIGHT_ATTACKS[targetSquare]) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
if ((bitboard_array_global[WK] & Constants.KING_ATTACKS[targetSquare]) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
ulong bishopAttacks = Constants.GetBishopAttacksFast(targetSquare, occupancyWithoutBlackKing);
|
|
if ((bitboard_array_global[WB] & bishopAttacks) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
if ((bitboard_array_global[WQ] & bishopAttacks) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
ulong rookAttacks = Constants.GetRookAttacksFast(targetSquare, occupancyWithoutBlackKing);
|
|
if ((bitboard_array_global[WR] & rookAttacks) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
if ((bitboard_array_global[WQ] & rookAttacks) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
startingSquares[moveCount] = blackKingPosition;
|
|
targetSquares[moveCount] = targetSquare;
|
|
tags[moveCount] = TAG_CAPTURE;
|
|
pieces[moveCount] = BK;
|
|
moveCount++;
|
|
|
|
}
|
|
|
|
tempAttack = Constants.KING_ATTACKS[blackKingPosition] & ~COMBINED_OCCUPANCIES_LOCAL;
|
|
|
|
while (tempAttack != 0)
|
|
{
|
|
targetSquare = DEBRUIJN64[MAGIC * (tempAttack ^ (tempAttack - 1)) >> 58];
|
|
tempAttack &= tempAttack - 1;
|
|
|
|
if ((bitboard_array_global[WP] & Constants.WHITE_PAWN_ATTACKS[targetSquare]) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
if ((bitboard_array_global[WN] & Constants.KNIGHT_ATTACKS[targetSquare]) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
if ((bitboard_array_global[WK] & Constants.KING_ATTACKS[targetSquare]) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
ulong bishopAttacks = Constants.GetBishopAttacksFast(targetSquare, occupancyWithoutBlackKing);
|
|
if ((bitboard_array_global[WB] & bishopAttacks) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
if ((bitboard_array_global[WQ] & bishopAttacks) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
ulong rookAttacks = Constants.GetRookAttacksFast(targetSquare, occupancyWithoutBlackKing);
|
|
if ((bitboard_array_global[WR] & rookAttacks) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
if ((bitboard_array_global[WQ] & rookAttacks) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
startingSquares[moveCount] = blackKingPosition;
|
|
targetSquares[moveCount] = targetSquare;
|
|
tags[moveCount] = TAG_NONE;
|
|
pieces[moveCount] = BK;
|
|
moveCount++;
|
|
|
|
}
|
|
#endregion
|
|
}
|
|
else
|
|
{
|
|
if (blackKingCheckCount == 0)
|
|
{
|
|
checkBitboard = ulong.MaxValue;
|
|
}
|
|
|
|
#region Black pawns
|
|
|
|
tempBitboard = bitboard_array_global[BP];
|
|
|
|
while (tempBitboard != 0)
|
|
{
|
|
startingSquare = DEBRUIJN64[MAGIC * (tempBitboard ^ (tempBitboard - 1)) >> 58];
|
|
tempBitboard &= tempBitboard - 1;
|
|
|
|
tempPinBitboard = ulong.MaxValue;
|
|
if (pinNumber != 0)
|
|
{
|
|
for (int i = 0; i < pinNumber; i++)
|
|
{
|
|
if (pinArraySquare[i] == startingSquare)
|
|
{
|
|
tempPinBitboard = Constants.INBETWEEN_BITBOARDS[blackKingPosition, pinArrayPiece[i]];
|
|
}
|
|
}
|
|
}
|
|
|
|
#region Pawn forward
|
|
|
|
if ((Constants.SQUARE_BBS[startingSquare + 8] & COMBINED_OCCUPANCIES_LOCAL) == 0) //if up one square is empty
|
|
{
|
|
if (((Constants.SQUARE_BBS[startingSquare + 8] & checkBitboard) & tempPinBitboard) != 0)
|
|
{
|
|
if ((Constants.SQUARE_BBS[startingSquare] & Constants.RANK_2_BITBOARD) != 0) //if promotion
|
|
{
|
|
startingSquares[moveCount] = startingSquare;
|
|
targetSquares[moveCount] = startingSquare + 8;
|
|
tags[moveCount] = TAG_B_B_PROMOTION;
|
|
pieces[moveCount] = BP;
|
|
moveCount++;
|
|
|
|
startingSquares[moveCount] = startingSquare;
|
|
targetSquares[moveCount] = startingSquare + 8;
|
|
tags[moveCount] = TAG_B_N_PROMOTION;
|
|
pieces[moveCount] = BP;
|
|
moveCount++;
|
|
|
|
startingSquares[moveCount] = startingSquare;
|
|
targetSquares[moveCount] = startingSquare + 8;
|
|
tags[moveCount] = TAG_B_R_PROMOTION;
|
|
pieces[moveCount] = BP;
|
|
moveCount++;
|
|
|
|
startingSquares[moveCount] = startingSquare;
|
|
targetSquares[moveCount] = startingSquare + 8;
|
|
tags[moveCount] = TAG_B_Q_PROMOTION;
|
|
pieces[moveCount] = BP;
|
|
moveCount++;
|
|
}
|
|
else
|
|
{
|
|
startingSquares[moveCount] = startingSquare;
|
|
targetSquares[moveCount] = startingSquare + 8;
|
|
tags[moveCount] = TAG_NONE;
|
|
pieces[moveCount] = BP;
|
|
moveCount++;
|
|
}
|
|
}
|
|
|
|
if ((Constants.SQUARE_BBS[startingSquare] & Constants.RANK_7_BITBOARD) != 0) //if on rank 2
|
|
{
|
|
if (((Constants.SQUARE_BBS[startingSquare + 16] & checkBitboard) & tempPinBitboard) != 0)
|
|
{
|
|
if (((Constants.SQUARE_BBS[startingSquare + 16]) & COMBINED_OCCUPANCIES_LOCAL) == 0) //if up two squares and one square are empty
|
|
{
|
|
startingSquares[moveCount] = startingSquare;
|
|
targetSquares[moveCount] = startingSquare + 16;
|
|
tags[moveCount] = TAG_B_P_DOUBLE;
|
|
pieces[moveCount] = BP;
|
|
moveCount++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region region Pawn captures
|
|
|
|
tempAttack = ((Constants.BLACK_PAWN_ATTACKS[startingSquare] & WHITE_OCCUPANCIES_LOCAL) & checkBitboard) & tempPinBitboard; //if black piece diagonal to pawn
|
|
|
|
while (tempAttack != 0)
|
|
{
|
|
targetSquare = DEBRUIJN64[MAGIC * (tempAttack ^ (tempAttack - 1)) >> 58]; //find the bit
|
|
tempAttack &= tempAttack - 1;
|
|
|
|
if ((Constants.SQUARE_BBS[startingSquare] & Constants.RANK_2_BITBOARD) != 0) //if promotion
|
|
{
|
|
startingSquares[moveCount] = startingSquare;
|
|
targetSquares[moveCount] = targetSquare;
|
|
tags[moveCount] = TAG_B_B_PROMOTION_CAP;
|
|
pieces[moveCount] = BP;
|
|
moveCount++;
|
|
|
|
startingSquares[moveCount] = startingSquare;
|
|
targetSquares[moveCount] = targetSquare;
|
|
tags[moveCount] = TAG_B_N_PROMOTION_CAP;
|
|
pieces[moveCount] = BP;
|
|
moveCount++;
|
|
|
|
startingSquares[moveCount] = startingSquare;
|
|
targetSquares[moveCount] = targetSquare;
|
|
tags[moveCount] = TAG_B_R_PROMOTION_CAP;
|
|
pieces[moveCount] = BP;
|
|
moveCount++;
|
|
|
|
startingSquares[moveCount] = startingSquare;
|
|
targetSquares[moveCount] = targetSquare;
|
|
tags[moveCount] = TAG_B_Q_PROMOTION_CAP;
|
|
pieces[moveCount] = BP;
|
|
moveCount++;
|
|
|
|
}
|
|
else
|
|
{
|
|
startingSquares[moveCount] = startingSquare;
|
|
targetSquares[moveCount] = targetSquare;
|
|
tags[moveCount] = TAG_CAPTURE;
|
|
pieces[moveCount] = BP;
|
|
moveCount++;
|
|
}
|
|
}
|
|
|
|
if ((Constants.SQUARE_BBS[startingSquare] & Constants.RANK_4_BITBOARD) != 0) //check rank for ep
|
|
{
|
|
if (ep_global != NO_SQUARE)
|
|
{
|
|
if ((((Constants.BLACK_PAWN_ATTACKS[startingSquare] & Constants.SQUARE_BBS[ep_global]) & checkBitboard) & tempPinBitboard) != 0)
|
|
{
|
|
if ((bitboard_array_global[BK] & Constants.RANK_4_BITBOARD) == 0) //if no king on rank 5
|
|
{
|
|
startingSquares[moveCount] = startingSquare;
|
|
targetSquares[moveCount] = ep_global;
|
|
tags[moveCount] = TAG_BLACK_EP;
|
|
pieces[moveCount] = BP;
|
|
moveCount++;
|
|
}
|
|
else if ((bitboard_array_global[WR] & Constants.RANK_4_BITBOARD) == 0 && (bitboard_array_global[WQ] & Constants.RANK_4_BITBOARD) == 0) // if no b rook or queen on rank 5
|
|
{
|
|
startingSquares[moveCount] = startingSquare;
|
|
targetSquares[moveCount] = ep_global;
|
|
tags[moveCount] = TAG_BLACK_EP;
|
|
pieces[moveCount] = BP;
|
|
moveCount++;
|
|
}
|
|
else //wk and br or bq on rank 5
|
|
{
|
|
ulong occupancyWithoutEPPawns = COMBINED_OCCUPANCIES_LOCAL & ~Constants.SQUARE_BBS[startingSquare];
|
|
occupancyWithoutEPPawns &= ~Constants.SQUARE_BBS[ep_global - 8];
|
|
|
|
ulong rookAttacksFromKing = Constants.GetRookAttacksFast(blackKingPosition, occupancyWithoutEPPawns);
|
|
|
|
if ((rookAttacksFromKing & bitboard_array_global[WR]) == 0)
|
|
{
|
|
if ((rookAttacksFromKing & bitboard_array_global[WQ]) == 0)
|
|
{
|
|
startingSquares[moveCount] = startingSquare;
|
|
targetSquares[moveCount] = ep_global;
|
|
tags[moveCount] = TAG_BLACK_EP;
|
|
pieces[moveCount] = BP;
|
|
moveCount++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
#endregion
|
|
|
|
#region black Knight
|
|
|
|
int whiteKingSquare = DEBRUIJN64[MAGIC * (bitboard_array_global[WK] ^ (bitboard_array_global[WK] - 1)) >> 58];
|
|
|
|
tempBitboard = bitboard_array_global[BN];
|
|
|
|
while (tempBitboard != 0)
|
|
{
|
|
startingSquare = DEBRUIJN64[MAGIC * (tempBitboard ^ (tempBitboard - 1)) >> 58]; //looks for the startingSquare
|
|
tempBitboard &= tempBitboard - 1; //removes the knight from that square to not infinitely loop
|
|
|
|
tempPinBitboard = ulong.MaxValue;
|
|
if (pinNumber != 0)
|
|
{
|
|
for (int i = 0; i < pinNumber; i++)
|
|
{
|
|
if (pinArraySquare[i] == startingSquare)
|
|
{
|
|
tempPinBitboard = Constants.INBETWEEN_BITBOARDS[blackKingPosition, pinArrayPiece[i]];
|
|
}
|
|
}
|
|
}
|
|
|
|
tempAttack = ((Constants.KNIGHT_ATTACKS[startingSquare] & WHITE_OCCUPANCIES_LOCAL) & checkBitboard) & tempPinBitboard; //gets knight captures
|
|
while (tempAttack != 0)
|
|
{
|
|
targetSquare = DEBRUIJN64[MAGIC * (tempAttack ^ (tempAttack - 1)) >> 58];
|
|
tempAttack &= tempAttack - 1;
|
|
|
|
|
|
startingSquares[moveCount] = startingSquare;
|
|
targetSquares[moveCount] = targetSquare;
|
|
tags[moveCount] = TAG_CAPTURE;
|
|
pieces[moveCount] = BN;
|
|
moveCount++;
|
|
|
|
}
|
|
|
|
tempAttack = ((Constants.KNIGHT_ATTACKS[startingSquare] & (~COMBINED_OCCUPANCIES_LOCAL)) & checkBitboard) & tempPinBitboard;
|
|
|
|
while (tempAttack != 0)
|
|
{
|
|
targetSquare = (DEBRUIJN64[MAGIC * (tempAttack ^ (tempAttack - 1)) >> 58]);
|
|
tempAttack &= tempAttack - 1;
|
|
|
|
|
|
startingSquares[moveCount] = startingSquare;
|
|
targetSquares[moveCount] = targetSquare;
|
|
tags[moveCount] = TAG_NONE;
|
|
pieces[moveCount] = BN;
|
|
moveCount++;
|
|
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Black bishop
|
|
ulong blackBishopCheckBitboard = Constants.GetBishopAttacksFast(whiteKingSquare, COMBINED_OCCUPANCIES_LOCAL);
|
|
|
|
tempBitboard = bitboard_array_global[BB];
|
|
while (tempBitboard != 0)
|
|
{
|
|
startingSquare = DEBRUIJN64[MAGIC * (tempBitboard ^ (tempBitboard - 1)) >> 58];
|
|
tempBitboard &= tempBitboard - 1;
|
|
|
|
tempPinBitboard = ulong.MaxValue;
|
|
if (pinNumber != 0)
|
|
{
|
|
for (int i = 0; i < pinNumber; i++)
|
|
{
|
|
if (pinArraySquare[i] == startingSquare)
|
|
{
|
|
tempPinBitboard = Constants.INBETWEEN_BITBOARDS[blackKingPosition, pinArrayPiece[i]];
|
|
}
|
|
}
|
|
}
|
|
|
|
ulong bishopAttacks = Constants.GetBishopAttacksFast(startingSquare, COMBINED_OCCUPANCIES_LOCAL);
|
|
|
|
tempAttack = ((bishopAttacks & WHITE_OCCUPANCIES_LOCAL) & checkBitboard) & tempPinBitboard;
|
|
while (tempAttack != 0)
|
|
{
|
|
targetSquare = DEBRUIJN64[MAGIC * (tempAttack ^ (tempAttack - 1)) >> 58];
|
|
tempAttack &= tempAttack - 1;
|
|
|
|
|
|
startingSquares[moveCount] = startingSquare;
|
|
targetSquares[moveCount] = targetSquare;
|
|
tags[moveCount] = TAG_CAPTURE;
|
|
pieces[moveCount] = BB;
|
|
moveCount++;
|
|
|
|
}
|
|
|
|
tempAttack = ((bishopAttacks & (~COMBINED_OCCUPANCIES_LOCAL)) & checkBitboard) & tempPinBitboard;
|
|
while (tempAttack != 0)
|
|
{
|
|
targetSquare = DEBRUIJN64[MAGIC * (tempAttack ^ (tempAttack - 1)) >> 58];
|
|
tempAttack &= tempAttack - 1;
|
|
|
|
|
|
startingSquares[moveCount] = startingSquare;
|
|
targetSquares[moveCount] = targetSquare;
|
|
tags[moveCount] = TAG_NONE;
|
|
pieces[moveCount] = BB;
|
|
moveCount++;
|
|
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Black Rook
|
|
tempBitboard = bitboard_array_global[BR];
|
|
while (tempBitboard != 0)
|
|
{
|
|
startingSquare = DEBRUIJN64[MAGIC * (tempBitboard ^ (tempBitboard - 1)) >> 58];
|
|
tempBitboard &= tempBitboard - 1;
|
|
|
|
tempPinBitboard = ulong.MaxValue;
|
|
if (pinNumber != 0)
|
|
{
|
|
for (int i = 0; i < pinNumber; i++)
|
|
{
|
|
if (pinArraySquare[i] == startingSquare)
|
|
{
|
|
tempPinBitboard = Constants.INBETWEEN_BITBOARDS[blackKingPosition, pinArrayPiece[i]];
|
|
}
|
|
}
|
|
}
|
|
|
|
ulong rookAttacks = Constants.GetRookAttacksFast(startingSquare, COMBINED_OCCUPANCIES_LOCAL);
|
|
|
|
tempAttack = ((rookAttacks & WHITE_OCCUPANCIES_LOCAL) & checkBitboard) & tempPinBitboard;
|
|
while (tempAttack != 0)
|
|
{
|
|
targetSquare = DEBRUIJN64[MAGIC * (tempAttack ^ (tempAttack - 1)) >> 58];
|
|
tempAttack &= tempAttack - 1;
|
|
|
|
|
|
startingSquares[moveCount] = startingSquare;
|
|
targetSquares[moveCount] = targetSquare;
|
|
tags[moveCount] = TAG_CAPTURE;
|
|
pieces[moveCount] = BR;
|
|
moveCount++;
|
|
|
|
}
|
|
|
|
tempAttack = ((rookAttacks & (~COMBINED_OCCUPANCIES_LOCAL)) & checkBitboard) & tempPinBitboard;
|
|
while (tempAttack != 0)
|
|
{
|
|
targetSquare = DEBRUIJN64[MAGIC * (tempAttack ^ (tempAttack - 1)) >> 58];
|
|
tempAttack &= tempAttack - 1;
|
|
|
|
|
|
startingSquares[moveCount] = startingSquare;
|
|
targetSquares[moveCount] = targetSquare;
|
|
tags[moveCount] = TAG_NONE;
|
|
pieces[moveCount] = BR;
|
|
moveCount++;
|
|
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Black queen
|
|
|
|
tempBitboard = bitboard_array_global[BQ];
|
|
while (tempBitboard != 0)
|
|
{
|
|
startingSquare = DEBRUIJN64[MAGIC * (tempBitboard ^ (tempBitboard - 1)) >> 58];
|
|
tempBitboard &= tempBitboard - 1;
|
|
|
|
tempPinBitboard = ulong.MaxValue;
|
|
if (pinNumber != 0)
|
|
{
|
|
for (int i = 0; i < pinNumber; i++)
|
|
{
|
|
if (pinArraySquare[i] == startingSquare)
|
|
{
|
|
tempPinBitboard = Constants.INBETWEEN_BITBOARDS[blackKingPosition, pinArrayPiece[i]];
|
|
}
|
|
}
|
|
}
|
|
|
|
ulong queenAttacks = Constants.GetRookAttacksFast(startingSquare, COMBINED_OCCUPANCIES_LOCAL);
|
|
queenAttacks |= Constants.GetBishopAttacksFast(startingSquare, COMBINED_OCCUPANCIES_LOCAL);
|
|
|
|
tempAttack = ((queenAttacks & WHITE_OCCUPANCIES_LOCAL) & checkBitboard) & tempPinBitboard;
|
|
|
|
while (tempAttack != 0)
|
|
{
|
|
targetSquare = DEBRUIJN64[MAGIC * (tempAttack ^ (tempAttack - 1)) >> 58];
|
|
tempAttack &= tempAttack - 1;
|
|
|
|
|
|
startingSquares[moveCount] = startingSquare;
|
|
targetSquares[moveCount] = targetSquare;
|
|
tags[moveCount] = TAG_CAPTURE;
|
|
pieces[moveCount] = BQ;
|
|
moveCount++;
|
|
|
|
}
|
|
|
|
tempAttack = ((queenAttacks & (~COMBINED_OCCUPANCIES_LOCAL)) & checkBitboard) & tempPinBitboard;
|
|
while (tempAttack != 0)
|
|
{
|
|
targetSquare = DEBRUIJN64[MAGIC * (tempAttack ^ (tempAttack - 1)) >> 58];
|
|
tempAttack &= tempAttack - 1;
|
|
|
|
|
|
startingSquares[moveCount] = startingSquare;
|
|
targetSquares[moveCount] = targetSquare;
|
|
tags[moveCount] = TAG_NONE;
|
|
pieces[moveCount] = BQ;
|
|
moveCount++;
|
|
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Black King
|
|
|
|
tempAttack = Constants.KING_ATTACKS[blackKingPosition] & WHITE_OCCUPANCIES_LOCAL; //gets knight captures
|
|
while (tempAttack != 0)
|
|
{
|
|
targetSquare = DEBRUIJN64[MAGIC * (tempAttack ^ (tempAttack - 1)) >> 58];
|
|
tempAttack &= tempAttack - 1;
|
|
|
|
if ((bitboard_array_global[WP] & Constants.BLACK_PAWN_ATTACKS[targetSquare]) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
if ((bitboard_array_global[WN] & Constants.KNIGHT_ATTACKS[targetSquare]) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
if ((bitboard_array_global[WK] & Constants.KING_ATTACKS[targetSquare]) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
ulong occupancyWithoutBlackKing = COMBINED_OCCUPANCIES_LOCAL & (~bitboard_array_global[BK]);
|
|
ulong bishopAttacks = Constants.GetBishopAttacksFast(targetSquare, occupancyWithoutBlackKing);
|
|
if ((bitboard_array_global[WB] & bishopAttacks) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
if ((bitboard_array_global[WQ] & bishopAttacks) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
ulong rookAttacks = Constants.GetRookAttacksFast(targetSquare, occupancyWithoutBlackKing);
|
|
if ((bitboard_array_global[WR] & rookAttacks) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
if ((bitboard_array_global[WQ] & rookAttacks) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
startingSquares[moveCount] = blackKingPosition;
|
|
targetSquares[moveCount] = targetSquare;
|
|
tags[moveCount] = TAG_CAPTURE;
|
|
pieces[moveCount] = BK;
|
|
moveCount++;
|
|
|
|
}
|
|
|
|
tempAttack = Constants.KING_ATTACKS[blackKingPosition] & (~COMBINED_OCCUPANCIES_LOCAL); //get knight moves to emtpy squares
|
|
|
|
while (tempAttack != 0)
|
|
{
|
|
targetSquare = DEBRUIJN64[MAGIC * (tempAttack ^ (tempAttack - 1)) >> 58];
|
|
tempAttack &= tempAttack - 1;
|
|
|
|
if ((bitboard_array_global[WP] & Constants.BLACK_PAWN_ATTACKS[targetSquare]) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
if ((bitboard_array_global[WN] & Constants.KNIGHT_ATTACKS[targetSquare]) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
if ((bitboard_array_global[WK] & Constants.KING_ATTACKS[targetSquare]) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
ulong occupancyWithoutBlackKing = COMBINED_OCCUPANCIES_LOCAL & (~bitboard_array_global[BK]);
|
|
ulong bishopAttacks = Constants.GetBishopAttacksFast(targetSquare, occupancyWithoutBlackKing);
|
|
if ((bitboard_array_global[WB] & bishopAttacks) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
if ((bitboard_array_global[WQ] & bishopAttacks) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
ulong rookAttacks = Constants.GetRookAttacksFast(targetSquare, occupancyWithoutBlackKing);
|
|
if ((bitboard_array_global[WR] & rookAttacks) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
if ((bitboard_array_global[WQ] & rookAttacks) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
startingSquares[moveCount] = blackKingPosition;
|
|
targetSquares[moveCount] = targetSquare;
|
|
tags[moveCount] = TAG_NONE;
|
|
pieces[moveCount] = BK;
|
|
moveCount++;
|
|
|
|
}
|
|
}
|
|
if (blackKingCheckCount == 0)
|
|
{
|
|
if (castle_rights_global[BKS_CASTLE_RIGHTS] == true)
|
|
{
|
|
if (blackKingPosition == E8) //king on e1
|
|
{
|
|
if ((BKS_EMPTY_BITBOARD & COMBINED_OCCUPANCIES_LOCAL) == 0) //f1 and g1 empty
|
|
{
|
|
if ((bitboard_array_global[BR] & Constants.SQUARE_BBS[H8]) != 0) //rook on h1
|
|
{
|
|
if (Is_Square_Attacked_By_White_Global(F8, COMBINED_OCCUPANCIES_LOCAL) == false)
|
|
{
|
|
if (Is_Square_Attacked_By_White_Global(G8, COMBINED_OCCUPANCIES_LOCAL) == false)
|
|
{
|
|
startingSquares[moveCount] = E8;
|
|
targetSquares[moveCount] = G8;
|
|
tags[moveCount] = TAG_B_CASTLE_KS;
|
|
pieces[moveCount] = BK;
|
|
moveCount++;
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (castle_rights_global[BQS_CASTLE_RIGHTS] == true)
|
|
{
|
|
if (blackKingPosition == E8) //king on e1
|
|
{
|
|
if ((BQS_EMPTY_BITBOARD & COMBINED_OCCUPANCIES_LOCAL) == 0) //f1 and g1 empty
|
|
{
|
|
if ((bitboard_array_global[BR] & Constants.SQUARE_BBS[A8]) != 0) //rook on h1
|
|
{
|
|
if (Is_Square_Attacked_By_White_Global(C8, COMBINED_OCCUPANCIES_LOCAL) == false)
|
|
{
|
|
if (Is_Square_Attacked_By_White_Global(D8, COMBINED_OCCUPANCIES_LOCAL) == false)
|
|
{
|
|
startingSquares[moveCount] = E8;
|
|
targetSquares[moveCount] = C8;
|
|
tags[moveCount] = TAG_B_CASTLE_QS;
|
|
pieces[moveCount] = BK;
|
|
moveCount++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
}
|
|
|
|
#endregion
|
|
|
|
|
|
if (depth == 1)
|
|
{
|
|
return moveCount;
|
|
}
|
|
|
|
int nodes = 0, priorNodes;
|
|
int copyEp = ep_global;
|
|
bool[] copy_castle = { castle_rights_global[0], castle_rights_global[1], castle_rights_global[2], castle_rights_global[3] };
|
|
|
|
for (int move_index = 0; move_index < moveCount; ++move_index)
|
|
{
|
|
int startingSquareCopy = startingSquares[move_index];
|
|
int targetSquareCopy = targetSquares[move_index];
|
|
int piece = pieces[move_index];
|
|
int tag = tags[move_index];
|
|
|
|
int captureIndex = -1;
|
|
|
|
#region Makemove
|
|
|
|
if (is_white_global == true)
|
|
{
|
|
is_white_global = false;
|
|
}
|
|
else
|
|
{
|
|
is_white_global = true;
|
|
}
|
|
|
|
switch (tag)
|
|
{
|
|
case 0: //none
|
|
case 26: //check
|
|
bitboard_array_global[piece] |= Constants.SQUARE_BBS[targetSquareCopy];
|
|
bitboard_array_global[piece] &= ~Constants.SQUARE_BBS[startingSquareCopy];
|
|
ep_global = NO_SQUARE;
|
|
break;
|
|
case 1: //capture
|
|
case 27: //check cap
|
|
bitboard_array_global[piece] |= Constants.SQUARE_BBS[targetSquareCopy];
|
|
bitboard_array_global[piece] &= ~Constants.SQUARE_BBS[startingSquareCopy];
|
|
if (piece >= WP && piece <= WK)
|
|
{
|
|
for (int i = BLACK_START_INDEX; i <= BLACK_END_INDEX; ++i)
|
|
{
|
|
if ((bitboard_array_global[i] & Constants.SQUARE_BBS[targetSquareCopy]) != 0)
|
|
{
|
|
captureIndex = i;
|
|
break;
|
|
}
|
|
}
|
|
bitboard_array_global[captureIndex] &= ~Constants.SQUARE_BBS[targetSquareCopy];
|
|
|
|
}
|
|
else //is black
|
|
{
|
|
for (int i = WHITE_START_INDEX; i <= WHITE_END_INDEX; ++i)
|
|
{
|
|
if ((bitboard_array_global[i] & Constants.SQUARE_BBS[targetSquareCopy]) != 0)
|
|
{
|
|
captureIndex = i;
|
|
break;
|
|
}
|
|
}
|
|
bitboard_array_global[captureIndex] &= ~Constants.SQUARE_BBS[targetSquareCopy];
|
|
}
|
|
|
|
ep_global = NO_SQUARE;
|
|
break;
|
|
case 2: //white ep
|
|
//move piece
|
|
bitboard_array_global[WP] |= Constants.SQUARE_BBS[targetSquareCopy];
|
|
bitboard_array_global[WP] &= ~Constants.SQUARE_BBS[startingSquareCopy];
|
|
//remove
|
|
bitboard_array_global[BP] &= ~Constants.SQUARE_BBS[targetSquareCopy + 8];
|
|
ep_global = NO_SQUARE;
|
|
break;
|
|
case 3: //black ep
|
|
//move piece
|
|
bitboard_array_global[BP] |= Constants.SQUARE_BBS[targetSquareCopy];
|
|
bitboard_array_global[BP] &= ~Constants.SQUARE_BBS[startingSquareCopy];
|
|
//remove white pawn square up
|
|
bitboard_array_global[WP] &= ~Constants.SQUARE_BBS[targetSquareCopy - 8];
|
|
ep_global = NO_SQUARE;
|
|
break;
|
|
|
|
#region Castling
|
|
|
|
case 4: //WKS
|
|
//white king
|
|
bitboard_array_global[WK] |= Constants.SQUARE_BBS[G1];
|
|
bitboard_array_global[WK] &= ~Constants.SQUARE_BBS[E1];
|
|
//white rook
|
|
bitboard_array_global[WR] |= Constants.SQUARE_BBS[F1];
|
|
bitboard_array_global[WR] &= ~Constants.SQUARE_BBS[H1];
|
|
castle_rights_global[WKS_CASTLE_RIGHTS] = false;
|
|
castle_rights_global[WQS_CASTLE_RIGHTS] = false;
|
|
ep_global = NO_SQUARE;
|
|
break;
|
|
case 5: //WQS
|
|
//white king
|
|
bitboard_array_global[WK] |= Constants.SQUARE_BBS[C1];
|
|
bitboard_array_global[WK] &= ~Constants.SQUARE_BBS[E1];
|
|
//white rook
|
|
bitboard_array_global[WR] |= Constants.SQUARE_BBS[D1];
|
|
bitboard_array_global[WR] &= ~Constants.SQUARE_BBS[A1];
|
|
castle_rights_global[WKS_CASTLE_RIGHTS] = false;
|
|
castle_rights_global[WQS_CASTLE_RIGHTS] = false;
|
|
ep_global = NO_SQUARE;
|
|
break;
|
|
case 6: //BKS
|
|
//white king
|
|
bitboard_array_global[BK] |= Constants.SQUARE_BBS[G8];
|
|
bitboard_array_global[BK] &= ~Constants.SQUARE_BBS[E8];
|
|
//white rook
|
|
bitboard_array_global[BR] |= Constants.SQUARE_BBS[F8];
|
|
bitboard_array_global[BR] &= ~Constants.SQUARE_BBS[H8];
|
|
|
|
castle_rights_global[BKS_CASTLE_RIGHTS] = false;
|
|
castle_rights_global[BQS_CASTLE_RIGHTS] = false;
|
|
ep_global = NO_SQUARE;
|
|
break;
|
|
case 7: //BQS
|
|
//white king
|
|
bitboard_array_global[BK] |= Constants.SQUARE_BBS[C8];
|
|
bitboard_array_global[BK] &= ~Constants.SQUARE_BBS[E8];
|
|
//white rook
|
|
bitboard_array_global[BR] |= Constants.SQUARE_BBS[D8];
|
|
bitboard_array_global[BR] &= ~Constants.SQUARE_BBS[A8];
|
|
castle_rights_global[BKS_CASTLE_RIGHTS] = false;
|
|
castle_rights_global[BQS_CASTLE_RIGHTS] = false;
|
|
ep_global = NO_SQUARE;
|
|
break;
|
|
|
|
#endregion
|
|
|
|
#region Promotion makemove
|
|
|
|
case 8: //BNPr
|
|
bitboard_array_global[BN] |= Constants.SQUARE_BBS[targetSquareCopy];
|
|
bitboard_array_global[piece] &= ~Constants.SQUARE_BBS[startingSquareCopy];
|
|
ep_global = NO_SQUARE;
|
|
break;
|
|
case 9: //BBPr
|
|
bitboard_array_global[BB] |= Constants.SQUARE_BBS[targetSquareCopy];
|
|
bitboard_array_global[piece] &= ~Constants.SQUARE_BBS[startingSquareCopy];
|
|
ep_global = NO_SQUARE;
|
|
break;
|
|
case 10: //BQPr
|
|
bitboard_array_global[BQ] |= Constants.SQUARE_BBS[targetSquareCopy];
|
|
bitboard_array_global[piece] &= ~Constants.SQUARE_BBS[startingSquareCopy];
|
|
ep_global = NO_SQUARE;
|
|
break;
|
|
case 11: //BRPr
|
|
bitboard_array_global[BR] |= Constants.SQUARE_BBS[targetSquareCopy];
|
|
bitboard_array_global[piece] &= ~Constants.SQUARE_BBS[startingSquareCopy];
|
|
ep_global = NO_SQUARE;
|
|
break;
|
|
case 12: //WNPr
|
|
bitboard_array_global[WN] |= Constants.SQUARE_BBS[targetSquareCopy];
|
|
bitboard_array_global[piece] &= ~Constants.SQUARE_BBS[startingSquareCopy];
|
|
ep_global = NO_SQUARE;
|
|
break;
|
|
case 13: //WBPr
|
|
bitboard_array_global[WB] |= Constants.SQUARE_BBS[targetSquareCopy];
|
|
bitboard_array_global[piece] &= ~Constants.SQUARE_BBS[startingSquareCopy];
|
|
ep_global = NO_SQUARE;
|
|
break;
|
|
case 14: //WQPr
|
|
bitboard_array_global[WQ] |= Constants.SQUARE_BBS[targetSquareCopy];
|
|
bitboard_array_global[piece] &= ~Constants.SQUARE_BBS[startingSquareCopy];
|
|
ep_global = NO_SQUARE;
|
|
break;
|
|
case 15: //WRPr
|
|
bitboard_array_global[WR] |= Constants.SQUARE_BBS[targetSquareCopy];
|
|
bitboard_array_global[piece] &= ~Constants.SQUARE_BBS[startingSquareCopy];
|
|
ep_global = NO_SQUARE;
|
|
break;
|
|
case 16: //BNPrCAP
|
|
bitboard_array_global[BN] |= Constants.SQUARE_BBS[targetSquareCopy];
|
|
bitboard_array_global[piece] &= ~Constants.SQUARE_BBS[startingSquareCopy];
|
|
ep_global = NO_SQUARE;
|
|
for (int i = WHITE_START_INDEX; i <= WHITE_END_INDEX; ++i)
|
|
{
|
|
if ((bitboard_array_global[i] & Constants.SQUARE_BBS[targetSquareCopy]) != 0)
|
|
{
|
|
captureIndex = i;
|
|
break;
|
|
}
|
|
}
|
|
bitboard_array_global[captureIndex] &= ~Constants.SQUARE_BBS[targetSquareCopy];
|
|
|
|
break;
|
|
case 17: //BBPrCAP
|
|
bitboard_array_global[BB] |= Constants.SQUARE_BBS[targetSquareCopy];
|
|
bitboard_array_global[piece] &= ~Constants.SQUARE_BBS[startingSquareCopy];
|
|
ep_global = NO_SQUARE;
|
|
for (int i = WHITE_START_INDEX; i <= WHITE_END_INDEX; ++i)
|
|
{
|
|
if ((bitboard_array_global[i] & Constants.SQUARE_BBS[targetSquareCopy]) != 0)
|
|
{
|
|
captureIndex = i;
|
|
break;
|
|
}
|
|
}
|
|
bitboard_array_global[captureIndex] &= ~Constants.SQUARE_BBS[targetSquareCopy];
|
|
|
|
break;
|
|
case 18: //BQPrCAP
|
|
bitboard_array_global[BQ] |= Constants.SQUARE_BBS[targetSquareCopy];
|
|
bitboard_array_global[piece] &= ~Constants.SQUARE_BBS[startingSquareCopy];
|
|
ep_global = NO_SQUARE;
|
|
for (int i = WHITE_START_INDEX; i <= WHITE_END_INDEX; ++i)
|
|
{
|
|
if ((bitboard_array_global[i] & Constants.SQUARE_BBS[targetSquareCopy]) != 0)
|
|
{
|
|
captureIndex = i;
|
|
break;
|
|
}
|
|
}
|
|
bitboard_array_global[captureIndex] &= ~Constants.SQUARE_BBS[targetSquareCopy];
|
|
|
|
break;
|
|
case 19: //BRPrCAP
|
|
bitboard_array_global[BR] |= Constants.SQUARE_BBS[targetSquareCopy];
|
|
bitboard_array_global[piece] &= ~Constants.SQUARE_BBS[startingSquareCopy];
|
|
ep_global = NO_SQUARE;
|
|
for (int i = WHITE_START_INDEX; i <= WHITE_END_INDEX; ++i)
|
|
{
|
|
if ((bitboard_array_global[i] & Constants.SQUARE_BBS[targetSquareCopy]) != 0)
|
|
{
|
|
captureIndex = i;
|
|
break;
|
|
}
|
|
}
|
|
bitboard_array_global[captureIndex] &= ~Constants.SQUARE_BBS[targetSquareCopy];
|
|
|
|
break;
|
|
case 20: //WNPrCAP
|
|
bitboard_array_global[WN] |= Constants.SQUARE_BBS[targetSquareCopy];
|
|
bitboard_array_global[piece] &= ~Constants.SQUARE_BBS[startingSquareCopy];
|
|
ep_global = NO_SQUARE;
|
|
for (int i = BLACK_START_INDEX; i <= BLACK_END_INDEX; ++i)
|
|
{
|
|
if ((bitboard_array_global[i] & Constants.SQUARE_BBS[targetSquareCopy]) != 0)
|
|
{
|
|
captureIndex = i;
|
|
break;
|
|
}
|
|
}
|
|
bitboard_array_global[captureIndex] &= ~Constants.SQUARE_BBS[targetSquareCopy];
|
|
|
|
break;
|
|
case 21: //WBPrCAP
|
|
bitboard_array_global[WB] |= Constants.SQUARE_BBS[targetSquareCopy];
|
|
bitboard_array_global[piece] &= ~Constants.SQUARE_BBS[startingSquareCopy];
|
|
ep_global = NO_SQUARE;
|
|
for (int i = BLACK_START_INDEX; i <= BLACK_END_INDEX; ++i)
|
|
{
|
|
if ((bitboard_array_global[i] & Constants.SQUARE_BBS[targetSquareCopy]) != 0)
|
|
{
|
|
captureIndex = i;
|
|
break;
|
|
}
|
|
}
|
|
bitboard_array_global[captureIndex] &= ~Constants.SQUARE_BBS[targetSquareCopy];
|
|
|
|
break;
|
|
case 22: //WQPrCAP
|
|
bitboard_array_global[WQ] |= Constants.SQUARE_BBS[targetSquareCopy];
|
|
bitboard_array_global[piece] &= ~Constants.SQUARE_BBS[startingSquareCopy];
|
|
ep_global = NO_SQUARE;
|
|
for (int i = BLACK_START_INDEX; i <= BLACK_END_INDEX; ++i)
|
|
{
|
|
if ((bitboard_array_global[i] & Constants.SQUARE_BBS[targetSquareCopy]) != 0)
|
|
{
|
|
captureIndex = i;
|
|
break;
|
|
}
|
|
}
|
|
bitboard_array_global[captureIndex] &= ~Constants.SQUARE_BBS[targetSquareCopy];
|
|
|
|
break;
|
|
case 23: //WRPrCAP
|
|
bitboard_array_global[WR] |= Constants.SQUARE_BBS[targetSquareCopy];
|
|
bitboard_array_global[piece] &= ~Constants.SQUARE_BBS[startingSquareCopy];
|
|
|
|
ep_global = NO_SQUARE;
|
|
for (int i = BLACK_START_INDEX; i <= BLACK_END_INDEX; ++i)
|
|
{
|
|
if ((bitboard_array_global[i] & Constants.SQUARE_BBS[targetSquareCopy]) != 0)
|
|
{
|
|
captureIndex = i;
|
|
break;
|
|
}
|
|
}
|
|
bitboard_array_global[captureIndex] &= ~Constants.SQUARE_BBS[targetSquareCopy];
|
|
break;
|
|
|
|
#endregion
|
|
|
|
case 24: //WDouble
|
|
bitboard_array_global[WP] |= Constants.SQUARE_BBS[targetSquareCopy];
|
|
bitboard_array_global[WP] &= ~Constants.SQUARE_BBS[startingSquareCopy];
|
|
ep_global = targetSquareCopy + 8;
|
|
break;
|
|
case 25: //BDouble
|
|
bitboard_array_global[BP] |= Constants.SQUARE_BBS[targetSquareCopy];
|
|
bitboard_array_global[BP] &= ~Constants.SQUARE_BBS[startingSquareCopy];
|
|
ep_global = targetSquareCopy - 8;
|
|
break;
|
|
}
|
|
|
|
if (piece == WK)
|
|
{
|
|
castle_rights_global[WKS_CASTLE_RIGHTS] = false;
|
|
castle_rights_global[WQS_CASTLE_RIGHTS] = false;
|
|
}
|
|
else if (piece == BK)
|
|
{
|
|
castle_rights_global[BKS_CASTLE_RIGHTS] = false;
|
|
castle_rights_global[BQS_CASTLE_RIGHTS] = false;
|
|
}
|
|
else if (piece == WR)
|
|
{
|
|
if (castle_rights_global[WKS_CASTLE_RIGHTS] == true)
|
|
{
|
|
if ((bitboard_array_global[WR] & Constants.SQUARE_BBS[H1]) == 0)
|
|
{
|
|
castle_rights_global[WKS_CASTLE_RIGHTS] = false;
|
|
}
|
|
}
|
|
if (castle_rights_global[WQS_CASTLE_RIGHTS] == true)
|
|
{
|
|
if ((bitboard_array_global[WR] & Constants.SQUARE_BBS[A1]) == 0)
|
|
{
|
|
castle_rights_global[WQS_CASTLE_RIGHTS] = false;
|
|
}
|
|
}
|
|
}
|
|
else if (piece == BR)
|
|
{
|
|
if (castle_rights_global[BKS_CASTLE_RIGHTS] == true)
|
|
{
|
|
if ((bitboard_array_global[BR] & Constants.SQUARE_BBS[H8]) == 0)
|
|
{
|
|
castle_rights_global[BKS_CASTLE_RIGHTS] = false;
|
|
}
|
|
}
|
|
if (castle_rights_global[BQS_CASTLE_RIGHTS] == true)
|
|
{
|
|
if ((bitboard_array_global[BR] & Constants.SQUARE_BBS[A8]) == 0)
|
|
{
|
|
castle_rights_global[BQS_CASTLE_RIGHTS] = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
priorNodes = nodes;
|
|
nodes += PerftInline(depth - 1, ply + 1);
|
|
|
|
#region Unmakemove
|
|
|
|
if (is_white_global == true)
|
|
{
|
|
is_white_global = false;
|
|
}
|
|
else
|
|
{
|
|
is_white_global = true;
|
|
}
|
|
|
|
switch (tag)
|
|
{
|
|
case 0: //none
|
|
case 26: //check
|
|
bitboard_array_global[piece] |= Constants.SQUARE_BBS[startingSquareCopy];
|
|
bitboard_array_global[piece] &= ~Constants.SQUARE_BBS[targetSquareCopy];
|
|
|
|
break;
|
|
case 1: //capture
|
|
case 27: //check cap
|
|
bitboard_array_global[piece] |= Constants.SQUARE_BBS[startingSquareCopy];
|
|
bitboard_array_global[piece] &= ~Constants.SQUARE_BBS[targetSquareCopy];
|
|
if (piece >= WP && piece <= WK)
|
|
{
|
|
bitboard_array_global[captureIndex] |= Constants.SQUARE_BBS[targetSquareCopy];
|
|
}
|
|
else //is black
|
|
{
|
|
bitboard_array_global[captureIndex] |= Constants.SQUARE_BBS[targetSquareCopy];
|
|
}
|
|
|
|
break;
|
|
case 2: //white ep
|
|
bitboard_array_global[WP] |= Constants.SQUARE_BBS[startingSquareCopy];
|
|
bitboard_array_global[WP] &= ~Constants.SQUARE_BBS[targetSquareCopy];
|
|
bitboard_array_global[BP] |= Constants.SQUARE_BBS[targetSquareCopy + 8];
|
|
|
|
break;
|
|
case 3: //black ep
|
|
bitboard_array_global[BP] |= Constants.SQUARE_BBS[startingSquareCopy];
|
|
bitboard_array_global[BP] &= ~Constants.SQUARE_BBS[targetSquareCopy];
|
|
bitboard_array_global[WP] |= Constants.SQUARE_BBS[targetSquareCopy - 8];
|
|
|
|
break;
|
|
case 4: //WKS
|
|
//white king
|
|
bitboard_array_global[WK] |= Constants.SQUARE_BBS[E1];
|
|
bitboard_array_global[WK] &= ~Constants.SQUARE_BBS[G1];
|
|
//white rook
|
|
bitboard_array_global[WR] |= Constants.SQUARE_BBS[H1];
|
|
bitboard_array_global[WR] &= ~Constants.SQUARE_BBS[F1];
|
|
break;
|
|
case 5: //WQS
|
|
//white king
|
|
bitboard_array_global[WK] |= Constants.SQUARE_BBS[E1];
|
|
bitboard_array_global[WK] &= ~Constants.SQUARE_BBS[C1];
|
|
//white rook
|
|
bitboard_array_global[WR] |= Constants.SQUARE_BBS[A1];
|
|
bitboard_array_global[WR] &= ~Constants.SQUARE_BBS[D1];
|
|
break;
|
|
case 6: //BKS
|
|
//white king
|
|
bitboard_array_global[BK] |= Constants.SQUARE_BBS[E8];
|
|
bitboard_array_global[BK] &= ~Constants.SQUARE_BBS[G8];
|
|
//white rook
|
|
bitboard_array_global[BR] |= Constants.SQUARE_BBS[H8];
|
|
bitboard_array_global[BR] &= ~Constants.SQUARE_BBS[F8];
|
|
break;
|
|
case 7: //BQS
|
|
//white king
|
|
bitboard_array_global[BK] |= Constants.SQUARE_BBS[E8];
|
|
bitboard_array_global[BK] &= ~Constants.SQUARE_BBS[C8];
|
|
//white rook
|
|
bitboard_array_global[BR] |= Constants.SQUARE_BBS[A8];
|
|
bitboard_array_global[BR] &= ~Constants.SQUARE_BBS[D8];
|
|
|
|
break;
|
|
|
|
#region Promotion Unmakemove
|
|
case 8: //BNPr
|
|
bitboard_array_global[BP] |= Constants.SQUARE_BBS[startingSquareCopy];
|
|
bitboard_array_global[BN] &= ~Constants.SQUARE_BBS[targetSquareCopy];
|
|
break;
|
|
case 9: //BBPr
|
|
bitboard_array_global[BP] |= Constants.SQUARE_BBS[startingSquareCopy];
|
|
bitboard_array_global[BB] &= ~Constants.SQUARE_BBS[targetSquareCopy];
|
|
break;
|
|
case 10: //BQPr
|
|
bitboard_array_global[BP] |= Constants.SQUARE_BBS[startingSquareCopy];
|
|
bitboard_array_global[BQ] &= ~Constants.SQUARE_BBS[targetSquareCopy];
|
|
break;
|
|
case 11: //BRPr
|
|
bitboard_array_global[BP] |= Constants.SQUARE_BBS[startingSquareCopy];
|
|
bitboard_array_global[BR] &= ~Constants.SQUARE_BBS[targetSquareCopy];
|
|
break;
|
|
case 12: //WNPr
|
|
bitboard_array_global[WP] |= Constants.SQUARE_BBS[startingSquareCopy];
|
|
bitboard_array_global[WN] &= ~Constants.SQUARE_BBS[targetSquareCopy];
|
|
break;
|
|
case 13: //WBPr
|
|
bitboard_array_global[WP] |= Constants.SQUARE_BBS[startingSquareCopy];
|
|
bitboard_array_global[WB] &= ~Constants.SQUARE_BBS[targetSquareCopy];
|
|
break;
|
|
case 14: //WQPr
|
|
bitboard_array_global[WP] |= Constants.SQUARE_BBS[startingSquareCopy];
|
|
bitboard_array_global[WQ] &= ~Constants.SQUARE_BBS[targetSquareCopy];
|
|
break;
|
|
case 15: //WRPr
|
|
bitboard_array_global[WP] |= Constants.SQUARE_BBS[startingSquareCopy];
|
|
bitboard_array_global[WR] &= ~Constants.SQUARE_BBS[targetSquareCopy];
|
|
break;
|
|
case 16: //BNPrCAP
|
|
bitboard_array_global[BP] |= Constants.SQUARE_BBS[startingSquareCopy];
|
|
bitboard_array_global[BN] &= ~Constants.SQUARE_BBS[targetSquareCopy];
|
|
|
|
bitboard_array_global[captureIndex] |= Constants.SQUARE_BBS[targetSquareCopy];
|
|
break;
|
|
case 17: //BBPrCAP
|
|
bitboard_array_global[BP] |= Constants.SQUARE_BBS[startingSquareCopy];
|
|
bitboard_array_global[BB] &= ~Constants.SQUARE_BBS[targetSquareCopy];
|
|
|
|
bitboard_array_global[captureIndex] |= Constants.SQUARE_BBS[targetSquareCopy];
|
|
|
|
break;
|
|
case 18: //BQPrCAP
|
|
bitboard_array_global[BP] |= Constants.SQUARE_BBS[startingSquareCopy];
|
|
bitboard_array_global[BQ] &= ~Constants.SQUARE_BBS[targetSquareCopy];
|
|
|
|
bitboard_array_global[captureIndex] |= Constants.SQUARE_BBS[targetSquareCopy];
|
|
break;
|
|
case 19: //BRPrCAP
|
|
bitboard_array_global[BP] |= Constants.SQUARE_BBS[startingSquareCopy];
|
|
bitboard_array_global[BR] &= ~Constants.SQUARE_BBS[targetSquareCopy];
|
|
|
|
bitboard_array_global[captureIndex] |= Constants.SQUARE_BBS[targetSquareCopy];
|
|
break;
|
|
case 20: //WNPrCAP
|
|
bitboard_array_global[WP] |= Constants.SQUARE_BBS[startingSquareCopy];
|
|
bitboard_array_global[WN] &= ~Constants.SQUARE_BBS[targetSquareCopy];
|
|
|
|
bitboard_array_global[captureIndex] |= Constants.SQUARE_BBS[targetSquareCopy];
|
|
break;
|
|
case 21: //WBPrCAP
|
|
bitboard_array_global[WP] |= Constants.SQUARE_BBS[startingSquareCopy];
|
|
bitboard_array_global[WB] &= ~Constants.SQUARE_BBS[targetSquareCopy];
|
|
|
|
bitboard_array_global[captureIndex] |= Constants.SQUARE_BBS[targetSquareCopy];
|
|
break;
|
|
case 22: //WQPrCAP
|
|
bitboard_array_global[WP] |= Constants.SQUARE_BBS[startingSquareCopy];
|
|
bitboard_array_global[WQ] &= ~Constants.SQUARE_BBS[targetSquareCopy];
|
|
|
|
bitboard_array_global[captureIndex] |= Constants.SQUARE_BBS[targetSquareCopy];
|
|
break;
|
|
case 23: //WRPrCAP
|
|
bitboard_array_global[WP] |= Constants.SQUARE_BBS[startingSquareCopy];
|
|
bitboard_array_global[WR] &= ~Constants.SQUARE_BBS[targetSquareCopy];
|
|
|
|
bitboard_array_global[captureIndex] |= Constants.SQUARE_BBS[targetSquareCopy];
|
|
break;
|
|
|
|
#endregion
|
|
|
|
case 24: //WDouble
|
|
bitboard_array_global[WP] |= Constants.SQUARE_BBS[startingSquareCopy];
|
|
bitboard_array_global[WP] &= ~Constants.SQUARE_BBS[targetSquareCopy];
|
|
break;
|
|
case 25: //BDouble
|
|
bitboard_array_global[BP] |= Constants.SQUARE_BBS[startingSquareCopy];
|
|
bitboard_array_global[BP] &= ~Constants.SQUARE_BBS[targetSquareCopy];
|
|
break;
|
|
}
|
|
|
|
castle_rights_global[0] = copy_castle[0];
|
|
castle_rights_global[1] = copy_castle[1];
|
|
castle_rights_global[2] = copy_castle[2];
|
|
castle_rights_global[3] = copy_castle[3];
|
|
ep_global = copyEp;
|
|
|
|
//if (epGlobal != NO_SQUARE)
|
|
//{
|
|
// std::cout << " ep: " << SQ_CHAR_X[epGlobal] << SQ_CHAR_Y[epGlobal] << '\n';
|
|
//}
|
|
|
|
#endregion
|
|
|
|
//if (ply == 0)
|
|
//{
|
|
// PrintMoveNoNL(move_list[move_index]);
|
|
// Console.Write(": %llu\n", nodes - priorNodes);
|
|
//}
|
|
}
|
|
|
|
return nodes;
|
|
}
|
|
|
|
static void RunPerftInline(int depth)
|
|
{
|
|
DateTime start = DateTime.Now;
|
|
|
|
int nodes = PerftInline(depth, 0);
|
|
|
|
DateTime end = DateTime.Now;
|
|
TimeSpan elapsed = end - start;
|
|
int elapsedTimeInMs = (int)elapsed.TotalMilliseconds; ;
|
|
Console.WriteLine($"Nodes: {nodes}");
|
|
|
|
Console.WriteLine($"Elapsed time: {elapsedTimeInMs}ms");
|
|
}
|
|
|
|
static void Main()
|
|
{
|
|
SetStartingPosition();
|
|
RunPerftInline(6);
|
|
}
|
|
|
|
|
|
}
|
|
}
|