diff --git a/C#/ChessEngine.cs b/C#/ChessEngine.cs new file mode 100644 index 0000000..4ac59cd --- /dev/null +++ b/C#/ChessEngine.cs @@ -0,0 +1,4687 @@ +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 GetMoves(ref Span startingSquares, ref Span targetSquares, ref Span tags, ref Span pieces) + { + 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 pinArrayPiece = stackalloc int[8] + { + -1,-1,-1,-1,-1,-1,-1,-1 + }; + Span 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 + + return moveCount; + + } + + enum CaptureType + { + None, White, Black + } + + static int MakeMove(int startingSquare, int targetSquare, int tag, int piece) + { + + int captureIndex = -1; + + is_white_global = !is_white_global; + ep_global = NO_SQUARE; + CaptureType captureType = CaptureType.None; + + switch (tag) + { + case TAG_NONE: //none + case TAG_CHECK: //check + MovePiece(startingSquare, targetSquare, piece); + break; + case TAG_CHECK_CAP: //capture + case TAG_CAPTURE: //check cap + MovePiece(startingSquare, targetSquare, piece); + if (is_white_global == true) { + captureType = CaptureType.White; + } + else { + captureType = CaptureType.Black; + } + break; + case TAG_WHITE_EP: //white ep + MovePiece(startingSquare, targetSquare, WP); + RemovePiece(BP, targetSquare + 8); + break; + case TAG_BLACK_EP: + MovePiece(startingSquare, targetSquare, BP); + RemovePiece(WP, targetSquare - 8); + break; + + #region Castling + + case TAG_W_CASTLE_KS: + MovePiece(E1, G1, WK); + MovePiece(H1, F1, WR); + castle_rights_global[WKS_CASTLE_RIGHTS] = false; + castle_rights_global[WQS_CASTLE_RIGHTS] = false; + break; + case TAG_W_CASTLE_QS: + MovePiece(E1, C1, WK); + MovePiece(A1, D1, WR); + castle_rights_global[WKS_CASTLE_RIGHTS] = false; + castle_rights_global[WQS_CASTLE_RIGHTS] = false; + break; + case TAG_B_CASTLE_KS: + MovePiece(E8, G8, BK); + MovePiece(H8, F8, BR); + castle_rights_global[BKS_CASTLE_RIGHTS] = false; + castle_rights_global[BQS_CASTLE_RIGHTS] = false; + break; + case TAG_B_CASTLE_QS: //BQS + MovePiece(E8, C8, BK); + MovePiece(A8, D8, BR); + castle_rights_global[BKS_CASTLE_RIGHTS] = false; + castle_rights_global[BQS_CASTLE_RIGHTS] = false; + break; + + #endregion + + #region Promotion makemove + + case TAG_B_N_PROMOTION: + MovePiecePromote(startingSquare, targetSquare, piece, BN); + break; + case TAG_B_B_PROMOTION: + MovePiecePromote(startingSquare, targetSquare, piece, BB); + break; + case TAG_B_Q_PROMOTION: + MovePiecePromote(startingSquare, targetSquare, piece, BQ); + break; + case TAG_B_R_PROMOTION: + MovePiecePromote(startingSquare, targetSquare, piece, BR); + break; + case TAG_W_N_PROMOTION: + MovePiecePromote(startingSquare, targetSquare, piece, WN); + break; + case TAG_W_B_PROMOTION: + MovePiecePromote(startingSquare, targetSquare, piece, WB); + break; + case TAG_W_Q_PROMOTION: + MovePiecePromote(startingSquare, targetSquare, piece, WQ); + break; + case TAG_W_R_PROMOTION: + MovePiecePromote(startingSquare, targetSquare, piece, WR); + break; + case TAG_B_N_PROMOTION_CAP: + MovePiecePromote(startingSquare, targetSquare, piece, BN); + captureType = CaptureType.White; + break; + case TAG_B_B_PROMOTION_CAP: + MovePiecePromote(startingSquare, targetSquare, piece, BB); + captureType = CaptureType.White; + break; + case TAG_B_Q_PROMOTION_CAP: + MovePiecePromote(startingSquare, targetSquare, piece, BQ); + captureType = CaptureType.White; + break; + case TAG_B_R_PROMOTION_CAP: + MovePiecePromote(startingSquare, targetSquare, piece, BR); + captureType = CaptureType.White; + break; + case TAG_W_N_PROMOTION_CAP: + MovePiecePromote(startingSquare, targetSquare, piece, WN); + captureType = CaptureType.Black; + break; + case TAG_W_B_PROMOTION_CAP: + MovePiecePromote(startingSquare, targetSquare, piece, WB); + captureType = CaptureType.Black; + break; + case TAG_W_Q_PROMOTION_CAP: + MovePiecePromote(startingSquare, targetSquare, piece, WQ); + captureType = CaptureType.Black; + break; + case TAG_W_R_PROMOTION_CAP: + MovePiecePromote(startingSquare, targetSquare, piece, WR); + captureType = CaptureType.Black; + break; + #endregion + + case TAG_W_P_DOUBLE: + MovePiece(startingSquare, targetSquare, WP); + ep_global = targetSquare + 8; + break; + case TAG_B_P_DOUBLE: + MovePiece(startingSquare, targetSquare, BP); + ep_global = targetSquare - 8; + break; + } + + switch (captureType) + { + case CaptureType.None: + break; + case CaptureType.White: + captureIndex = FindCaptureWhite(targetSquare, captureIndex); + break; + case CaptureType.Black: + captureIndex = FindCaptureBlack(targetSquare, captureIndex); + 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; + } + } + } + + return captureIndex; + } + + private static int FindCaptureBlack(int targetSquare, int captureIndex) + { + for (int i = BLACK_START_INDEX; i <= BLACK_END_INDEX; ++i) + { + if ((bitboard_array_global[i] & Constants.SQUARE_BBS[targetSquare]) != 0) + { + captureIndex = i; + break; + } + } + bitboard_array_global[captureIndex] &= ~Constants.SQUARE_BBS[targetSquare]; + return captureIndex; + } + + private static void MovePiecePromote(int startingSquare, int targetSquare, int piece, int promotionPiece) + { + bitboard_array_global[promotionPiece] |= Constants.SQUARE_BBS[targetSquare]; + bitboard_array_global[piece] &= ~Constants.SQUARE_BBS[startingSquare]; + } + + private static void RemovePiece(int piece, int targetSquare) + { + bitboard_array_global[piece] &= ~Constants.SQUARE_BBS[targetSquare]; + } + + private static void MovePiece(int startingSquare, int targetSquare, int piece) + { + bitboard_array_global[piece] |= Constants.SQUARE_BBS[targetSquare]; + bitboard_array_global[piece] &= ~Constants.SQUARE_BBS[startingSquare]; + } + + private static int FindCaptureWhite(int targetSquareCopy, int captureIndex) + { + 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]; + return captureIndex; + } + + private static void UnmakeMove(int startingSquareCopy, int targetSquareCopy, int piece, int tag, int captureIndex) + { + 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; + } + } + + + static int PerftFunctions(int depth, int ply) + { + //Same as move list, span to avoid heap allocation + Span startingSquares = stackalloc int[50]; + Span targetSquares = stackalloc int[50]; + Span tags = stackalloc int[50]; + Span pieces = stackalloc int[50]; + + int moveCount = GetMoves(ref startingSquares, ref targetSquares, ref tags, ref pieces); + + if (depth == 1) { + return moveCount; + } + + int nodes = 0, priorNodes; + int copyEp = ep_global; + Span copy_castle = stackalloc bool[4]; + copy_castle[0] = castle_rights_global[0]; + copy_castle[1] = castle_rights_global[1]; + copy_castle[2] = castle_rights_global[2]; + copy_castle[3] = 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 = MakeMove(startingSquareCopy, targetSquareCopy, tag, piece); + + priorNodes = nodes; + nodes += PerftFunctions(depth - 1, ply + 1); + + #region Unmakemove + + UnmakeMove(startingSquareCopy, targetSquareCopy, piece, tag, captureIndex); + + 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; + + #endregion + + //if (ply == 0) + //{ + // PrintMoveNoNL(move_list[move_index]); + // Console.Write(": %llu\n", nodes - priorNodes); + //} + } + + return nodes; + } + + static void RunPerftFunctions(int depth) + { + DateTime start = DateTime.Now; + + int nodes = PerftFunctions(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 int PerftInline(int depth, int ply) + { + //if (depth == 0) + //{ + // return 1; + //} + + Span startingSquares = stackalloc int[50]; + Span targetSquares = stackalloc int[50]; + Span tags = stackalloc int[50]; + Span 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 pinArrayPiece = stackalloc int[8] + { + -1,-1,-1,-1,-1,-1,-1,-1 + }; + Span 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); + RunPerftFunctions(2); + } + + + } +}