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); } } }