import java.math.BigInteger; class ErrorInt { private Error error; private int value; // No-argument constructor public ErrorInt(Error _error, int _value) { this.error = _error; // or any default Error value this.value = _value; // default value } public static void printError(Error error) { System.out.println(error); } // Getters for error and value public Error getError() { return error; } public int getValue() { return value; } // Setter for value public void setValue(int value) { this.value = value; } } class DebugInfo { public int CallCount; public int LastStarting; public int LastTarget; public int LastTag; public int lastPiece; public boolean PromotionExpected; } enum Error { White_King_Captured, Black_King_Captured, Too_Many_Moves, White_King_In_Check_On_BlackMove, Black_King_In_Check_On_White_Move, Copy_Boards_Not_Same, Invalid_Starting_Square, Invalid_Target_Square, Invalid_Tag, Invalid_Piece, Capture_Index_Invalid, Capture_Piece_Not_Found, Starting_Depth_Too_High, Starting_Depth_Zero, Depth_Less_Than_Zero, Starting_Square_And_Target_Square_The_Same, Ep_Not_Target_Square, Promotion_When_Not_Expected, Side_Not_Changed, Side_Not_Changed_Back, } public class Perft { static Boolean OutOfBounds(int move) { if (move < 0) { return true; } if (move > 63) { return true; } return false; } static void PrintMoveNoNL(int starting, int target_square, int tag) { //starting // Print starting if (OutOfBounds(starting)) { System.out.printf("%d", starting); } else { System.out.printf("%c%c", GenConst.SQ_CHAR_X[starting], GenConst.SQ_CHAR_Y[starting]); } // Print target if (OutOfBounds(target_square)) { System.out.printf("%d", target_square); } else { System.out.printf("%c%c", GenConst.SQ_CHAR_X[target_square], GenConst.SQ_CHAR_Y[target_square]); } // Print promotion tag switch (tag) { case GenConst.TAG_B_N_PROMOTION: case GenConst.TAG_B_N_PROMOTION_CAP: case GenConst.TAG_W_N_PROMOTION: case GenConst.TAG_W_N_PROMOTION_CAP: System.out.printf("n"); break; case GenConst.TAG_B_R_PROMOTION: case GenConst.TAG_B_R_PROMOTION_CAP: case GenConst.TAG_W_R_PROMOTION: case GenConst.TAG_W_R_PROMOTION_CAP: System.out.printf("r"); break; case GenConst.TAG_B_B_PROMOTION: case GenConst.TAG_B_B_PROMOTION_CAP: case GenConst.TAG_W_B_PROMOTION: case GenConst.TAG_W_B_PROMOTION_CAP: System.out.printf("b"); break; case GenConst.TAG_B_Q_PROMOTION: case GenConst.TAG_B_Q_PROMOTION_CAP: case GenConst.TAG_W_Q_PROMOTION: case GenConst.TAG_W_Q_PROMOTION_CAP: System.out.printf("q"); break; default: break; } } static final int MOVE_STARTING = 0; static final int MOVE_TARGET = 1; static final int MOVE_PIECE = 2; static final int MOVE_TAG = 3; static final int NO_SQUARE = 64; static final int WKS_CASTLE_RIGHTS = 0; static final int WQS_CASTLE_RIGHTS = 1; static final int BKS_CASTLE_RIGHTS = 2; static final int BQS_CASTLE_RIGHTS = 3; static final int PINNED_SQUARE_INDEX = 0; static final int PINNING_PIECE_INDEX = 1; static final BigInteger WKS_EMPTY_BITBOARD = new BigInteger("6917529027641081856"); static final BigInteger WQS_EMPTY_BITBOARD = new BigInteger("1008806316530991104"); static final BigInteger BKS_EMPTY_BITBOARD = new BigInteger("96"); static final BigInteger BQS_EMPTY_BITBOARD = new BigInteger("14"); static final BigInteger RANK_1_BITBOARD = new BigInteger( "18374686479671623680"); static final BigInteger RANK_2_BITBOARD =new BigInteger( "71776119061217280"); static final BigInteger RANK_3_BITBOARD =new BigInteger( "280375465082880"); static final BigInteger RANK_4_BITBOARD =new BigInteger( "1095216660480"); static final BigInteger RANK_5_BITBOARD =new BigInteger( "4278190080"); static final BigInteger RANK_6_BITBOARD =new BigInteger( "16711680"); static final BigInteger RANK_7_BITBOARD =new BigInteger( "65280"); static final BigInteger RANK_8_BITBOARD =new BigInteger( "255"); static final BigInteger MAX_long = new BigInteger("18446744073709551615"); static boolean Is_Square_Attacked_By_Black_Global(int square, long occupancy) { if ((Board.bitboard_array_global[GenConst.BP] & MoveConstants.WHITE_PAWN_ATTACKS[square]) != 0) { return true; } if ((Board.bitboard_array_global[GenConst.BN] & MoveConstants.KNIGHT_ATTACKS[square]) != 0) { return true; } if ((Board.bitboard_array_global[GenConst.BK] & MoveConstants.KING_ATTACKS[square]) != 0) { return true; } long bishopAttacks = MoveUtils.getBishopMovesSeparate(occupancy, square); if ((Board.bitboard_array_global[GenConst.BB] & bishopAttacks) != 0) { return true; } if ((Board.bitboard_array_global[GenConst.BQ] & bishopAttacks) != 0) { return true; } long rookAttacks = MoveUtils.getRookMovesSeparate(occupancy, square); if ((Board.bitboard_array_global[GenConst.BR] & rookAttacks) != 0) { return true; } if ((Board.bitboard_array_global[GenConst.BQ] & rookAttacks) != 0) { return true; } return false; } static boolean Is_Square_Attacked_By_White_Global(int square, long occupancy) { if ((Board.bitboard_array_global[GenConst.WP] & MoveConstants.BLACK_PAWN_ATTACKS[square]) != 0) { return true; } if ((Board.bitboard_array_global[GenConst.WN] & MoveConstants.KNIGHT_ATTACKS[square]) != 0) { return true; } if ((Board.bitboard_array_global[GenConst.WK] & MoveConstants.KING_ATTACKS[square]) != 0) { return true; } long bishopAttacks = MoveUtils.getBishopMovesSeparate(occupancy, square); if ((Board.bitboard_array_global[GenConst.WB] & bishopAttacks) != 0) { return true; } if ((Board.bitboard_array_global[GenConst.WQ] & bishopAttacks) != 0) { return true; } long rookAttacks = MoveUtils.getRookMovesSeparate(occupancy, square); if ((Board.bitboard_array_global[GenConst.WR] & rookAttacks) != 0) { return true; } if ((Board.bitboard_array_global[GenConst.WQ] & rookAttacks) != 0) { return true; } return false; } static final long MAGIC = 285870213051386505L; static final 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(long tempBitboard) { long debruijnIndex = ((MAGIC * (tempBitboard ^ (tempBitboard - 1))) >>> 58); //PrintBitboard(debruijnIndex); int indexAsInteger = (int)debruijnIndex; return (DEBRUIJN64[indexAsInteger]); } static boolean isNotZero(BigInteger bitboard) { return bitboard.signum() != 0; } static boolean isZero(BigInteger bitboard) { return bitboard.signum() == 0; } static BigInteger removeBit(BigInteger bitboard) { return bitboard.and(bitboard.subtract(BigInteger.ONE)); } static void printMoveInfo(int startingSquare, int targetSquare, int tag, int piece) { Pr.println("\n Move Info:"); Pr.print(" Starting Square: "); Pr.printInt(startingSquare); Pr.print(" "); Pr.printSquareLn(startingSquare); Pr.print(" Target Square: "); Pr.printInt(targetSquare); Pr.print(" "); Pr.printSquareLn(targetSquare); Pr.print(" Tag: "); Pr.printIntLn(tag); Pr.print(" Piece: "); Pr.printIntLn(piece); } static ErrorInt errorIntFromValue(int value) { return new ErrorInt(null, value); } static ErrorInt errorIntFromError(Error error) { return new ErrorInt(error, 0); } static long CombineBitboardsGlobal() { return Board.bitboard_array_global[0] | Board.bitboard_array_global[1] | Board.bitboard_array_global[2] | Board.bitboard_array_global[3] | Board.bitboard_array_global[4] | Board.bitboard_array_global[5] | Board.bitboard_array_global[6] | Board.bitboard_array_global[7] | Board.bitboard_array_global[8] | Board.bitboard_array_global[9] | Board.bitboard_array_global[10] | Board.bitboard_array_global[11]; } static void PrintAllDebug(int startingSquare, int targetSquare, int piece, int tag) { PrintPiece(piece); PrintMoveNoNL(startingSquare, targetSquare, tag); System.out.println(); PrintBoardGlobal(); } static final 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 final 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' }; static void PrintBoardGlobal() { char[] yCoordinates = { '8', '7', '6', '5', '4', '3', '2', '1' }; char[] castleChars = { 'K', 'Q', 'k', 'q' }; for (int y = 0; y < 8; y++) { System.out.print(String.format(" %c ", yCoordinates[y])); for (int x = 0; x < 8; x++) { int square = (y * 8) + x; boolean pieceFound = false; for (int pieceIndex = 0; pieceIndex < 12; pieceIndex++) { //Pr.print("piece index: "); Pr.printIntLn(pieceIndex); if ((Board.bitboard_array_global[pieceIndex] & MoveConstants.SQUARE_BBS[square]) != 0) { // Pr.print("not zero, anded together:"); //PrintBitboard(Board.bitboard_array_global[pieceIndex] & MoveConstants.SQUARE_BBS[square]); System.out.print(PIECE_COLOURS[pieceIndex]); System.out.print(PIECE_CHARS[pieceIndex]); System.out.print(' '); pieceFound = true; break; } } if (pieceFound == false) { System.out.print("-- "); } } System.out.print('\n'); } System.out.println(" A B C D E F G H\n\n"); if (Board.is_white_global == true) { System.out.println("Side: White To Play\n"); } else { System.out.println("Side: Black To Play\n"); } System.out.print("castle: "); for (int i = 0; i < 4; i++) { if (Board.castle_rights_global[i] == true) { System.out.print(castleChars[i]); } else { System.out.print("-"); } } System.out.print("\nEP: "); if (Board.ep_global > 63 || Board.ep_global < 0) { System.out.println(Board.ep_global); } else { System.out.println(SQ_CHAR_X[Board.ep_global]); System.out.println(SQ_CHAR_Y[Board.ep_global]); } System.out.print("\n\n"); } static final char[] PIECE_COLOURS = { 'W','W','W','W','W','W','b','b','b','b','b','b' }; static final char[] PIECE_CHARS = { 'P','N','B','R','Q','K','p','n','b','r','q','k' }; static void PrintPiece(int piece) { System.out.print(PIECE_COLOURS[piece]); System.out.print(PIECE_CHARS[piece]); } static void PrintPieceLn(int piece) { System.out.print(PIECE_COLOURS[piece]); System.out.println(PIECE_CHARS[piece]); } enum CaptureType { None, White, Black } private static int FindCaptureBlack(int targetSquare, int captureIndex) { for (int i = GenConst.BP; i <= GenConst.BK; ++i) { if ((Board.bitboard_array_global[i] & MoveConstants.SQUARE_BBS[targetSquare]) != 0) { captureIndex = i; break; } } Board.bitboard_array_global[captureIndex] &= ~MoveConstants.SQUARE_BBS[targetSquare]; return captureIndex; } private static void MovePiecePromote(int startingSquare, int targetSquare, int piece, int promotionPiece) { Board.bitboard_array_global[promotionPiece] |= MoveConstants.SQUARE_BBS[targetSquare]; Board.bitboard_array_global[piece] &= ~MoveConstants.SQUARE_BBS[startingSquare]; } private static void RemovePiece(int piece, int targetSquare) { Board.bitboard_array_global[piece] &= ~MoveConstants.SQUARE_BBS[targetSquare]; } private static void MovePiece(int startingSquare, int targetSquare, int piece) { Board.bitboard_array_global[piece] |= MoveConstants.SQUARE_BBS[targetSquare]; Board.bitboard_array_global[piece] &= ~MoveConstants.SQUARE_BBS[startingSquare]; } private static int FindCaptureWhite(int targetSquareCopy, int captureIndex) { for (int i = GenConst.WP; i <= GenConst.WK; ++i) { if ((Board.bitboard_array_global[i] & MoveConstants.SQUARE_BBS[targetSquareCopy]) != 0) { captureIndex = i; break; } } Board.bitboard_array_global[captureIndex] &= ~MoveConstants.SQUARE_BBS[targetSquareCopy]; return captureIndex; } private static void UnmakeMove(int startingSquareCopy, int targetSquareCopy, int piece, int tag, int captureIndex) { Board.is_white_global = !Board.is_white_global; switch (tag) { case 0: //none case 26: //check Board.bitboard_array_global[piece] |= MoveConstants.SQUARE_BBS[startingSquareCopy]; Board.bitboard_array_global[piece] &= ~MoveConstants.SQUARE_BBS[targetSquareCopy]; break; case 1: //capture case 27: //check cap Board.bitboard_array_global[piece] |= MoveConstants.SQUARE_BBS[startingSquareCopy]; Board.bitboard_array_global[piece] &= ~MoveConstants.SQUARE_BBS[targetSquareCopy]; if (piece >= GenConst.WP && piece <= GenConst.WK) { Board.bitboard_array_global[captureIndex] |= MoveConstants.SQUARE_BBS[targetSquareCopy]; } else //is black { Board.bitboard_array_global[captureIndex] |= MoveConstants.SQUARE_BBS[targetSquareCopy]; } break; case 2: //white ep Board.bitboard_array_global[GenConst.WP] |= MoveConstants.SQUARE_BBS[startingSquareCopy]; Board.bitboard_array_global[GenConst.WP] &= ~MoveConstants.SQUARE_BBS[targetSquareCopy]; Board.bitboard_array_global[GenConst.BP] |= MoveConstants.SQUARE_BBS[targetSquareCopy + 8]; break; case 3: //black ep Board.bitboard_array_global[GenConst.BP] |= MoveConstants.SQUARE_BBS[startingSquareCopy]; Board.bitboard_array_global[GenConst.BP] &= ~MoveConstants.SQUARE_BBS[targetSquareCopy]; Board.bitboard_array_global[GenConst.WP] |= MoveConstants.SQUARE_BBS[targetSquareCopy - 8]; break; case 4: //WKS //white king Board.bitboard_array_global[GenConst.WK] |= MoveConstants.SQUARE_BBS[GenConst.E1]; Board.bitboard_array_global[GenConst.WK] &= ~MoveConstants.SQUARE_BBS[GenConst.G1]; //white rook Board.bitboard_array_global[GenConst.WR] |= MoveConstants.SQUARE_BBS[GenConst.H1]; Board.bitboard_array_global[GenConst.WR] &= ~MoveConstants.SQUARE_BBS[GenConst.F1]; break; case 5: //WQS //white king Board.bitboard_array_global[GenConst.WK] |= MoveConstants.SQUARE_BBS[GenConst.E1]; Board.bitboard_array_global[GenConst.WK] &= ~MoveConstants.SQUARE_BBS[GenConst.C1]; //white rook Board.bitboard_array_global[GenConst.WR] |= MoveConstants.SQUARE_BBS[GenConst.A1]; Board.bitboard_array_global[GenConst.WR] &= ~MoveConstants.SQUARE_BBS[GenConst.D1]; break; case 6: //BKS //white king Board.bitboard_array_global[GenConst.BK] |= MoveConstants.SQUARE_BBS[GenConst.E8]; Board.bitboard_array_global[GenConst.BK] &= ~MoveConstants.SQUARE_BBS[GenConst.G8]; //white rook Board.bitboard_array_global[GenConst.BR] |= MoveConstants.SQUARE_BBS[GenConst.H8]; Board.bitboard_array_global[GenConst.BR] &= ~MoveConstants.SQUARE_BBS[GenConst.F8]; break; case 7: //BQS //white king Board.bitboard_array_global[GenConst.BK] |= MoveConstants.SQUARE_BBS[GenConst.E8]; Board.bitboard_array_global[GenConst.BK] &= ~MoveConstants.SQUARE_BBS[GenConst.C8]; //white rook Board.bitboard_array_global[GenConst.BR] |= MoveConstants.SQUARE_BBS[GenConst.A8]; Board.bitboard_array_global[GenConst.BR] &= ~MoveConstants.SQUARE_BBS[GenConst.D8]; break; //#region Promotion Unmakemove case 8: //BNPr Board.bitboard_array_global[GenConst.BP] |= MoveConstants.SQUARE_BBS[startingSquareCopy]; Board.bitboard_array_global[GenConst.BN] &= ~MoveConstants.SQUARE_BBS[targetSquareCopy]; break; case 9: //BBPr Board.bitboard_array_global[GenConst.BP] |= MoveConstants.SQUARE_BBS[startingSquareCopy]; Board.bitboard_array_global[GenConst.BB] &= ~MoveConstants.SQUARE_BBS[targetSquareCopy]; break; case 10: //BQPr Board.bitboard_array_global[GenConst.BP] |= MoveConstants.SQUARE_BBS[startingSquareCopy]; Board.bitboard_array_global[GenConst.BQ] &= ~MoveConstants.SQUARE_BBS[targetSquareCopy]; break; case 11: //BRPr Board.bitboard_array_global[GenConst.BP] |= MoveConstants.SQUARE_BBS[startingSquareCopy]; Board.bitboard_array_global[GenConst.BR] &= ~MoveConstants.SQUARE_BBS[targetSquareCopy]; break; case 12: //WNPr Board.bitboard_array_global[GenConst.WP] |= MoveConstants.SQUARE_BBS[startingSquareCopy]; Board.bitboard_array_global[GenConst.WN] &= ~MoveConstants.SQUARE_BBS[targetSquareCopy]; break; case 13: //WBPr Board.bitboard_array_global[GenConst.WP] |= MoveConstants.SQUARE_BBS[startingSquareCopy]; Board.bitboard_array_global[GenConst.WB] &= ~MoveConstants.SQUARE_BBS[targetSquareCopy]; break; case 14: //WQPr Board.bitboard_array_global[GenConst.WP] |= MoveConstants.SQUARE_BBS[startingSquareCopy]; Board.bitboard_array_global[GenConst.WQ] &= ~MoveConstants.SQUARE_BBS[targetSquareCopy]; break; case 15: //WRPr Board.bitboard_array_global[GenConst.WP] |= MoveConstants.SQUARE_BBS[startingSquareCopy]; Board.bitboard_array_global[GenConst.WR] &= ~MoveConstants.SQUARE_BBS[targetSquareCopy]; break; case 16: //BNPrCAP Board.bitboard_array_global[GenConst.BP] |= MoveConstants.SQUARE_BBS[startingSquareCopy]; Board.bitboard_array_global[GenConst.BN] &= ~MoveConstants.SQUARE_BBS[targetSquareCopy]; Board.bitboard_array_global[captureIndex] |= MoveConstants.SQUARE_BBS[targetSquareCopy]; break; case 17: //BBPrCAP Board.bitboard_array_global[GenConst.BP] |= MoveConstants.SQUARE_BBS[startingSquareCopy]; Board.bitboard_array_global[GenConst.BB] &= ~MoveConstants.SQUARE_BBS[targetSquareCopy]; Board.bitboard_array_global[captureIndex] |= MoveConstants.SQUARE_BBS[targetSquareCopy]; break; case 18: //BQPrCAP Board.bitboard_array_global[GenConst.BP] |= MoveConstants.SQUARE_BBS[startingSquareCopy]; Board.bitboard_array_global[GenConst.BQ] &= ~MoveConstants.SQUARE_BBS[targetSquareCopy]; Board.bitboard_array_global[captureIndex] |= MoveConstants.SQUARE_BBS[targetSquareCopy]; break; case 19: //BRPrCAP Board.bitboard_array_global[GenConst.BP] |= MoveConstants.SQUARE_BBS[startingSquareCopy]; Board.bitboard_array_global[GenConst.BR] &= ~MoveConstants.SQUARE_BBS[targetSquareCopy]; Board.bitboard_array_global[captureIndex] |= MoveConstants.SQUARE_BBS[targetSquareCopy]; break; case 20: //WNPrCAP Board.bitboard_array_global[GenConst.WP] |= MoveConstants.SQUARE_BBS[startingSquareCopy]; Board.bitboard_array_global[GenConst.WN] &= ~MoveConstants.SQUARE_BBS[targetSquareCopy]; Board.bitboard_array_global[captureIndex] |= MoveConstants.SQUARE_BBS[targetSquareCopy]; break; case 21: //WBPrCAP Board.bitboard_array_global[GenConst.WP] |= MoveConstants.SQUARE_BBS[startingSquareCopy]; Board.bitboard_array_global[GenConst.WB] &= ~MoveConstants.SQUARE_BBS[targetSquareCopy]; Board.bitboard_array_global[captureIndex] |= MoveConstants.SQUARE_BBS[targetSquareCopy]; break; case 22: //WQPrCAP Board.bitboard_array_global[GenConst.WP] |= MoveConstants.SQUARE_BBS[startingSquareCopy]; Board.bitboard_array_global[GenConst.WQ] &= ~MoveConstants.SQUARE_BBS[targetSquareCopy]; Board.bitboard_array_global[captureIndex] |= MoveConstants.SQUARE_BBS[targetSquareCopy]; break; case 23: //WRPrCAP Board.bitboard_array_global[GenConst.WP] |= MoveConstants.SQUARE_BBS[startingSquareCopy]; Board.bitboard_array_global[GenConst.WR] &= ~MoveConstants.SQUARE_BBS[targetSquareCopy]; Board.bitboard_array_global[captureIndex] |= MoveConstants.SQUARE_BBS[targetSquareCopy]; break; //#endregion case 24: //WDouble Board.bitboard_array_global[GenConst.WP] |= MoveConstants.SQUARE_BBS[startingSquareCopy]; Board.bitboard_array_global[GenConst.WP] &= ~MoveConstants.SQUARE_BBS[targetSquareCopy]; break; case 25: //BDouble Board.bitboard_array_global[GenConst.BP] |= MoveConstants.SQUARE_BBS[startingSquareCopy]; Board.bitboard_array_global[GenConst.BP] &= ~MoveConstants.SQUARE_BBS[targetSquareCopy]; break; } } public static void PrintBitboard(long input) { if (input == 0) { System.out.print(String.format(" bitboard: %d", input)); return; } for (int y = 0; y < 8; y++) { System.out.print(" "); for (int x = 0; x < 8; x++) { int square = (y * 8) + x; if ((input & MoveConstants.SQUARE_BBS[square]) != 0) { System.out.print("X "); } else { System.out.print("- "); } } System.out.println(); } System.out.println(String.format("\nbitboard: %d", input)); } public static void PrintAllBitboards() { for (int i = 0; i < 12; i++) { PrintBitboard(Board.bitboard_array_global[i]); } } static int MakeMove(int startingSquare, int targetSquare, int tag, int piece) { int captureIndex = -1; Board.is_white_global = !Board.is_white_global; Board.ep_global = NO_SQUARE; CaptureType captureType = CaptureType.None; switch (tag) { case GenConst.TAG_NONE: //none case GenConst.TAG_CHECK: //check MovePiece(startingSquare, targetSquare, piece); break; case GenConst.TAG_CHECK_CAP: //capture case GenConst.TAG_CAPTURE: //check cap MovePiece(startingSquare, targetSquare, piece); if (Board.is_white_global == true) { captureType = CaptureType.White; } else { captureType = CaptureType.Black; } break; case GenConst.TAG_WHITE_EP: //white ep MovePiece(startingSquare, targetSquare, GenConst.WP); RemovePiece(GenConst.BP, targetSquare + 8); break; case GenConst.TAG_BLACK_EP: MovePiece(startingSquare, targetSquare, GenConst.BP); RemovePiece(GenConst.WP, targetSquare - 8); break; //#region Castling case GenConst.TAG_W_CASTLE_KS: MovePiece(GenConst.E1, GenConst.G1, GenConst.WK); MovePiece(GenConst.H1, GenConst.F1, GenConst.WR); Board.castle_rights_global[WKS_CASTLE_RIGHTS] = false; Board.castle_rights_global[WQS_CASTLE_RIGHTS] = false; break; case GenConst.TAG_W_CASTLE_QS: MovePiece(GenConst.E1, GenConst.C1, GenConst.WK); MovePiece(GenConst.A1, GenConst.D1, GenConst.WR); Board.castle_rights_global[WKS_CASTLE_RIGHTS] = false; Board.castle_rights_global[WQS_CASTLE_RIGHTS] = false; break; case GenConst.TAG_B_CASTLE_KS: MovePiece(GenConst.E8, GenConst.G8, GenConst.BK); MovePiece(GenConst.H8, GenConst.F8, GenConst.BR); Board.castle_rights_global[BKS_CASTLE_RIGHTS] = false; Board.castle_rights_global[BQS_CASTLE_RIGHTS] = false; break; case GenConst.TAG_B_CASTLE_QS: //BQS MovePiece(GenConst.E8, GenConst.C8, GenConst.BK); MovePiece(GenConst.A8, GenConst.D8, GenConst.BR); Board.castle_rights_global[BKS_CASTLE_RIGHTS] = false; Board.castle_rights_global[BQS_CASTLE_RIGHTS] = false; break; //#endregion //#region Promotion makemove case GenConst.TAG_B_N_PROMOTION: MovePiecePromote(startingSquare, targetSquare, piece, GenConst.BN); break; case GenConst.TAG_B_B_PROMOTION: MovePiecePromote(startingSquare, targetSquare, piece, GenConst.BB); break; case GenConst.TAG_B_Q_PROMOTION: MovePiecePromote(startingSquare, targetSquare, piece, GenConst.BQ); break; case GenConst.TAG_B_R_PROMOTION: MovePiecePromote(startingSquare, targetSquare, piece, GenConst.BR); break; case GenConst.TAG_W_N_PROMOTION: MovePiecePromote(startingSquare, targetSquare, piece, GenConst.WN); break; case GenConst.TAG_W_B_PROMOTION: MovePiecePromote(startingSquare, targetSquare, piece, GenConst.WB); break; case GenConst.TAG_W_Q_PROMOTION: MovePiecePromote(startingSquare, targetSquare, piece, GenConst.WQ); break; case GenConst.TAG_W_R_PROMOTION: MovePiecePromote(startingSquare, targetSquare, piece, GenConst.WR); break; case GenConst.TAG_B_N_PROMOTION_CAP: MovePiecePromote(startingSquare, targetSquare, piece, GenConst.BN); captureType = CaptureType.White; break; case GenConst.TAG_B_B_PROMOTION_CAP: MovePiecePromote(startingSquare, targetSquare, piece, GenConst.BB); captureType = CaptureType.White; break; case GenConst.TAG_B_Q_PROMOTION_CAP: MovePiecePromote(startingSquare, targetSquare, piece, GenConst.BQ); captureType = CaptureType.White; break; case GenConst.TAG_B_R_PROMOTION_CAP: MovePiecePromote(startingSquare, targetSquare, piece, GenConst.BR); captureType = CaptureType.White; break; case GenConst.TAG_W_N_PROMOTION_CAP: MovePiecePromote(startingSquare, targetSquare, piece, GenConst.WN); captureType = CaptureType.Black; break; case GenConst.TAG_W_B_PROMOTION_CAP: MovePiecePromote(startingSquare, targetSquare, piece, GenConst.WB); captureType = CaptureType.Black; break; case GenConst.TAG_W_Q_PROMOTION_CAP: MovePiecePromote(startingSquare, targetSquare, piece, GenConst.WQ); captureType = CaptureType.Black; break; case GenConst.TAG_W_R_PROMOTION_CAP: MovePiecePromote(startingSquare, targetSquare, piece, GenConst.WR); captureType = CaptureType.Black; break; //#endregion case GenConst.TAG_W_P_DOUBLE: MovePiece(startingSquare, targetSquare, GenConst.WP); Board.ep_global = targetSquare + 8; break; case GenConst.TAG_B_P_DOUBLE: MovePiece(startingSquare, targetSquare, GenConst.BP); Board.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 == GenConst.WK) { Board.castle_rights_global[WKS_CASTLE_RIGHTS] = false; Board.castle_rights_global[WQS_CASTLE_RIGHTS] = false; } else if (piece == GenConst.BK) { Board.castle_rights_global[BKS_CASTLE_RIGHTS] = false; Board.castle_rights_global[BQS_CASTLE_RIGHTS] = false; } else if (piece == GenConst.WR) { if (Board.castle_rights_global[WKS_CASTLE_RIGHTS] == true) { if ((Board.bitboard_array_global[GenConst.WR] & MoveConstants.SQUARE_BBS[GenConst.H1]) == 0) { Board.castle_rights_global[WKS_CASTLE_RIGHTS] = false; } } if (Board.castle_rights_global[WQS_CASTLE_RIGHTS] == true) { if ((Board.bitboard_array_global[GenConst.WR] & MoveConstants.SQUARE_BBS[GenConst.A1]) == 0) { Board.castle_rights_global[WQS_CASTLE_RIGHTS] = false; } } } else if (piece == GenConst.BR) { if (Board.castle_rights_global[BKS_CASTLE_RIGHTS] == true) { if ((Board.bitboard_array_global[GenConst.BR] & MoveConstants.SQUARE_BBS[GenConst.H8]) == 0) { Board.castle_rights_global[BKS_CASTLE_RIGHTS] = false; } } if (Board.castle_rights_global[BQS_CASTLE_RIGHTS] == true) { if ((Board.bitboard_array_global[GenConst.BR] & MoveConstants.SQUARE_BBS[GenConst.A8]) == 0) { Board.castle_rights_global[BQS_CASTLE_RIGHTS] = false; } } } return captureIndex; } static int getMoves(int[] startingSquares, int[] targetSquares, int[] tags, int[] pieces) { int moveCount = 0; //Move generating variables long WHITE_OCCUPANCIES_LOCAL = Board.bitboard_array_global[0] | Board.bitboard_array_global[1] | Board.bitboard_array_global[2] | Board.bitboard_array_global[3] | Board.bitboard_array_global[4] | Board.bitboard_array_global[5]; long BLACK_OCCUPANCIES_LOCAL = Board.bitboard_array_global[6] | Board.bitboard_array_global[7] | Board.bitboard_array_global[8] | Board.bitboard_array_global[9] | Board.bitboard_array_global[10] | Board.bitboard_array_global[11]; long COMBINED_OCCUPANCIES_LOCAL = WHITE_OCCUPANCIES_LOCAL | BLACK_OCCUPANCIES_LOCAL; long EMPTY_OCCUPANCIES = ~COMBINED_OCCUPANCIES_LOCAL; long tempBitboard; long checkBitboard = 0L; long tempPinBitboard, tempAttack, tempEmpty, tempCaptures; int startingSquare = NO_SQUARE, targetSquare = NO_SQUARE; int kingPosition; int checkCount; long enemy_occupancies; int bishop_index; int rook_index; int queen_index; int knight_index; int[] pinArrayPiece = { -1,-1,-1,-1,-1,-1,-1,-1 }; int[] pinArraySquare = { -1,-1,-1,-1,-1,-1,-1,-1 }; int pinNumber = 0; if (Board.is_white_global == true) { checkCount = 0; kingPosition = bitScanForward(Board.bitboard_array_global[GenConst.WK]); rook_index = GenConst.WR; queen_index = GenConst.WQ; knight_index = GenConst.WN; bishop_index = GenConst.WB; enemy_occupancies = BLACK_OCCUPANCIES_LOCAL; //#region white pins and check //pawns tempBitboard = Board.bitboard_array_global[GenConst.BP] & MoveConstants.WHITE_PAWN_ATTACKS[kingPosition]; if (tempBitboard != 0) { int pawn_square = (DEBRUIJN64[(int)((MAGIC * (tempBitboard ^ (tempBitboard - 1))) >>> 58)]); checkBitboard |= MoveConstants.SQUARE_BBS[pawn_square]; checkCount++; } //knights tempBitboard = Board.bitboard_array_global[GenConst.BN] & MoveConstants.KNIGHT_ATTACKS[kingPosition]; if (tempBitboard != 0) { int knight_square = DEBRUIJN64[(int)((MAGIC * (tempBitboard ^ (tempBitboard - 1))) >>> 58)]; checkBitboard |= MoveConstants.SQUARE_BBS[knight_square]; checkCount++; } //bishops long bishopAttacksChecks = MoveUtils.getBishopMovesSeparate(BLACK_OCCUPANCIES_LOCAL, kingPosition); tempBitboard = Board.bitboard_array_global[GenConst.BB] & bishopAttacksChecks; while (tempBitboard != 0) { int piece_square = DEBRUIJN64[(int)((MAGIC * (tempBitboard ^ (tempBitboard - 1))) >>> 58)]; tempPinBitboard = Inb.INBETWEEN_BITBOARDS[kingPosition][piece_square] & WHITE_OCCUPANCIES_LOCAL; if (tempPinBitboard == 0) { checkBitboard |= Inb.INBETWEEN_BITBOARDS[kingPosition][piece_square]; checkCount++; } else { int pinned_square = (DEBRUIJN64[(int)((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 = Board.bitboard_array_global[GenConst.BQ] & bishopAttacksChecks; while (tempBitboard != 0) { int piece_square = DEBRUIJN64[(int)((MAGIC * (tempBitboard ^ (tempBitboard - 1))) >>> 58)]; tempPinBitboard = Inb.INBETWEEN_BITBOARDS[kingPosition][piece_square] & WHITE_OCCUPANCIES_LOCAL; if (tempPinBitboard == 0) { checkBitboard |= Inb.INBETWEEN_BITBOARDS[kingPosition][piece_square]; checkCount++; } else { int pinned_square = (DEBRUIJN64[(int)((MAGIC * (tempPinBitboard ^ (tempPinBitboard - 1))) >>> 58)]); tempPinBitboard &= tempPinBitboard - 1; if (tempPinBitboard == 0) { pinArraySquare[pinNumber] = pinned_square; pinArrayPiece[pinNumber] = piece_square; pinNumber++; } } tempBitboard &= tempBitboard - 1; } //rook long rook_attacks = MoveUtils.getRookMovesSeparate(BLACK_OCCUPANCIES_LOCAL, kingPosition); tempBitboard = Board.bitboard_array_global[GenConst.BR] & rook_attacks; while (tempBitboard != 0) { int piece_square = DEBRUIJN64[(int)((MAGIC * (tempBitboard ^ (tempBitboard - 1))) >>> 58)]; tempPinBitboard = Inb.INBETWEEN_BITBOARDS[kingPosition][piece_square] & WHITE_OCCUPANCIES_LOCAL; if (tempPinBitboard == 0) { checkBitboard |= Inb.INBETWEEN_BITBOARDS[kingPosition][piece_square]; checkCount++; } else { int pinned_square = (DEBRUIJN64[(int)((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 = Board.bitboard_array_global[GenConst.BQ] & rook_attacks; while (tempBitboard != 0) { int piece_square = (DEBRUIJN64[(int)((MAGIC * (tempBitboard ^ (tempBitboard - 1))) >>> 58)]); tempPinBitboard = Inb.INBETWEEN_BITBOARDS[kingPosition][piece_square] & WHITE_OCCUPANCIES_LOCAL; if (tempPinBitboard == 0) { checkBitboard |= Inb.INBETWEEN_BITBOARDS[kingPosition][piece_square]; checkCount++; } else { int pinned_square = (DEBRUIJN64[(int)((MAGIC * (tempPinBitboard ^ (tempPinBitboard - 1))) >>> 58)]); tempPinBitboard &= tempPinBitboard - 1; if (tempPinBitboard == 0) { pinArraySquare[pinNumber] = pinned_square; pinArrayPiece[pinNumber] = piece_square; pinNumber++; } } tempBitboard &= tempBitboard - 1; } //#endregion //#region White king long occupanciesWithoutWhiteKing = COMBINED_OCCUPANCIES_LOCAL & (~Board.bitboard_array_global[GenConst.WK]); tempAttack = MoveConstants.KING_ATTACKS[kingPosition]; tempEmpty = tempAttack & EMPTY_OCCUPANCIES; while (tempEmpty != 0) { targetSquare = bitScanForward(tempEmpty); tempEmpty &= tempEmpty - 1; if ((Board.bitboard_array_global[GenConst.BP] & MoveConstants.WHITE_PAWN_ATTACKS[targetSquare]) != 0) { continue; } if ((Board.bitboard_array_global[GenConst.BN] & MoveConstants.KNIGHT_ATTACKS[targetSquare]) != 0) { continue; } if ((Board.bitboard_array_global[GenConst.BK] & MoveConstants.KING_ATTACKS[targetSquare]) != 0) { continue; } long bishopAttacks = MoveUtils.getBishopMovesSeparate(occupanciesWithoutWhiteKing, targetSquare); if ((Board.bitboard_array_global[GenConst.BB] & bishopAttacks) != 0) { continue; } if ((Board.bitboard_array_global[GenConst.BQ] & bishopAttacks) != 0) { continue; } long rookAttacks = MoveUtils.getRookMovesSeparate(occupanciesWithoutWhiteKing, targetSquare); if ((Board.bitboard_array_global[GenConst.BR] & rookAttacks) != 0) { continue; } if ((Board.bitboard_array_global[GenConst.BQ] & rookAttacks) != 0) { continue; } startingSquares[moveCount] = kingPosition; targetSquares[moveCount] = targetSquare; tags[moveCount] = GenConst.TAG_NONE; pieces[moveCount] = GenConst.WK; moveCount++; } //captures tempCaptures = tempAttack & BLACK_OCCUPANCIES_LOCAL; while (tempCaptures != 0) { targetSquare = bitScanForward(tempCaptures); tempCaptures &= tempCaptures - 1; if ((Board.bitboard_array_global[GenConst.BP] & MoveConstants.WHITE_PAWN_ATTACKS[targetSquare]) != 0) { continue; } if ((Board.bitboard_array_global[GenConst.BN] & MoveConstants.KNIGHT_ATTACKS[targetSquare]) != 0) { continue; } if ((Board.bitboard_array_global[GenConst.BK] & MoveConstants.KING_ATTACKS[targetSquare]) != 0) { continue; } long bishopAttacks = MoveUtils.getBishopMovesSeparate(occupanciesWithoutWhiteKing, targetSquare); if ((Board.bitboard_array_global[GenConst.BB] & bishopAttacks) != 0) { continue; } if ((Board.bitboard_array_global[GenConst.BQ] & bishopAttacks) != 0) { continue; } long rookAttacks = MoveUtils.getRookMovesSeparate(occupanciesWithoutWhiteKing, targetSquare); if ((Board.bitboard_array_global[GenConst.BR] & rookAttacks) != 0) { continue; } if ((Board.bitboard_array_global[GenConst.BQ] & rookAttacks) != 0) { continue; } startingSquares[moveCount] = kingPosition; targetSquares[moveCount] = targetSquare; tags[moveCount] = GenConst.TAG_CAPTURE; pieces[moveCount] = GenConst.WK; moveCount++; } //#endregion if (checkCount < 2) { if (checkCount == 0) { checkBitboard = GenConst.MAX_ULONG; if (Board.castle_rights_global[WKS_CASTLE_RIGHTS] == true) { if (kingPosition == GenConst.E1) //king on e1 { if ((GenConst.WKS_EMPTY_BITBOARD & COMBINED_OCCUPANCIES_LOCAL) == 0) //f1 and g1 empty { if ((Board.bitboard_array_global[GenConst.WR] & MoveConstants.SQUARE_BBS[GenConst.H1]) != 0) //rook on h1 { if (Is_Square_Attacked_By_Black_Global(GenConst.F1, COMBINED_OCCUPANCIES_LOCAL) == false) { if (Is_Square_Attacked_By_Black_Global(GenConst.G1, COMBINED_OCCUPANCIES_LOCAL) == false) { startingSquares[moveCount] = GenConst.E1; targetSquares[moveCount] = GenConst.G1; tags[moveCount] = GenConst.TAG_W_CASTLE_KS; pieces[moveCount] = GenConst.WK; moveCount++; } } } } } } if (Board.castle_rights_global[WQS_CASTLE_RIGHTS] == true) { if (kingPosition == GenConst.E1) //king on e1 { if ((GenConst.WQS_EMPTY_BITBOARD & COMBINED_OCCUPANCIES_LOCAL) == 0) //f1 and g1 empty { if ((Board.bitboard_array_global[GenConst.WR] & MoveConstants.SQUARE_BBS[GenConst.A1]) != 0) //rook on h1 { if (Is_Square_Attacked_By_Black_Global(GenConst.C1, COMBINED_OCCUPANCIES_LOCAL) == false) { if (Is_Square_Attacked_By_Black_Global(GenConst.D1, COMBINED_OCCUPANCIES_LOCAL) == false) { startingSquares[moveCount] = GenConst.E1; targetSquares[moveCount] = GenConst.C1; tags[moveCount] = GenConst.TAG_W_CASTLE_QS; pieces[moveCount] = GenConst.WK; moveCount++; } } } } } } } //#region White pawn tempBitboard = Board.bitboard_array_global[GenConst.WP]; while (tempBitboard != 0) { startingSquare = DEBRUIJN64[(int)((MAGIC * (tempBitboard ^ (tempBitboard - 1))) >>> 58)]; tempBitboard &= tempBitboard - 1; tempPinBitboard = GenConst.MAX_ULONG; if (pinNumber != 0) { for (int i = 0; i < pinNumber; i++) { if (pinArraySquare[i] == startingSquare) { tempPinBitboard = Inb.INBETWEEN_BITBOARDS[kingPosition][pinArrayPiece[i]]; } } } //#region Pawn forward if ((MoveConstants.SQUARE_BBS[startingSquare - 8] & COMBINED_OCCUPANCIES_LOCAL) == 0) //if up one square is empty { if (((MoveConstants.SQUARE_BBS[startingSquare - 8] & checkBitboard) & tempPinBitboard) != 0) { if ((MoveConstants.SQUARE_BBS[startingSquare] & GenConst.RANK_7_BITBOARD) != 0) //if promotion { startingSquares[moveCount] = startingSquare; targetSquares[moveCount] = startingSquare - 8; tags[moveCount] = GenConst.TAG_W_Q_PROMOTION; pieces[moveCount] = GenConst.WP; moveCount++; startingSquares[moveCount] = startingSquare; targetSquares[moveCount] = startingSquare - 8; tags[moveCount] = GenConst.TAG_W_R_PROMOTION; pieces[moveCount] = GenConst.WP; moveCount++; startingSquares[moveCount] = startingSquare; targetSquares[moveCount] = startingSquare - 8; tags[moveCount] = GenConst.TAG_W_B_PROMOTION; pieces[moveCount] = GenConst.WP; moveCount++; startingSquares[moveCount] = startingSquare; targetSquares[moveCount] = startingSquare - 8; tags[moveCount] = GenConst.TAG_W_N_PROMOTION; pieces[moveCount] = GenConst.WP; moveCount++; } else { startingSquares[moveCount] = startingSquare; targetSquares[moveCount] = startingSquare - 8; tags[moveCount] = GenConst.TAG_NONE; pieces[moveCount] = GenConst.WP; moveCount++; } } if ((MoveConstants.SQUARE_BBS[startingSquare] & GenConst.RANK_2_BITBOARD) != 0) //if on rank 2 { if (((MoveConstants.SQUARE_BBS[startingSquare - 16] & checkBitboard) & tempPinBitboard) != 0) //if not pinned or { if (((MoveConstants.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] = GenConst.TAG_W_P_DOUBLE; pieces[moveCount] = GenConst.WP; moveCount++; } } } } //#endregion //#region Pawn captures tempAttack = ((MoveConstants.WHITE_PAWN_ATTACKS[startingSquare] & BLACK_OCCUPANCIES_LOCAL) & checkBitboard) & tempPinBitboard; //if black piece diagonal to pawn while (tempAttack != 0) { targetSquare = (DEBRUIJN64[(int)((MAGIC * (tempAttack ^ (tempAttack - 1))) >>> 58)]); tempAttack &= tempAttack - 1; if ((MoveConstants.SQUARE_BBS[startingSquare] & GenConst.RANK_7_BITBOARD) != 0) //if promotion { startingSquares[moveCount] = startingSquare; targetSquares[moveCount] = targetSquare; tags[moveCount] = GenConst.TAG_W_Q_PROMOTION_CAP; pieces[moveCount] = GenConst.WP; moveCount++; startingSquares[moveCount] = startingSquare; targetSquares[moveCount] = targetSquare; tags[moveCount] = GenConst.TAG_W_R_PROMOTION_CAP; pieces[moveCount] = GenConst.WP; moveCount++; startingSquares[moveCount] = startingSquare; targetSquares[moveCount] = targetSquare; tags[moveCount] = GenConst.TAG_W_B_PROMOTION_CAP; pieces[moveCount] = GenConst.WP; moveCount++; startingSquares[moveCount] = startingSquare; targetSquares[moveCount] = targetSquare; tags[moveCount] = GenConst.TAG_W_N_PROMOTION_CAP; pieces[moveCount] = GenConst.WP; moveCount++; } else { startingSquares[moveCount] = startingSquare; targetSquares[moveCount] = targetSquare; tags[moveCount] = GenConst.TAG_CAPTURE; pieces[moveCount] = GenConst.WP; moveCount++; } } if ((MoveConstants.SQUARE_BBS[startingSquare] & GenConst.RANK_5_BITBOARD) != 0) //check rank for ep { if (Board.ep_global != NO_SQUARE) { if ((((MoveConstants.WHITE_PAWN_ATTACKS[startingSquare] & MoveConstants.SQUARE_BBS[Board.ep_global]) & checkBitboard) & tempPinBitboard) != 0) { if ((Board.bitboard_array_global[GenConst.WK] & GenConst.RANK_5_BITBOARD) == 0) //if no king on rank 5 { startingSquares[moveCount] = startingSquare; targetSquares[moveCount] = Board.ep_global; tags[moveCount] = GenConst.TAG_WHITE_EP; pieces[moveCount] = GenConst.WP; moveCount++; } else if ((Board.bitboard_array_global[GenConst.BR] & GenConst.RANK_5_BITBOARD) == 0 && (Board.bitboard_array_global[GenConst.BQ] & GenConst.RANK_5_BITBOARD) == 0) // if no b rook or queen on rank 5 { startingSquares[moveCount] = startingSquare; targetSquares[moveCount] = Board.ep_global; tags[moveCount] = GenConst.TAG_WHITE_EP; pieces[moveCount] = GenConst.WP; moveCount++; } else //wk and br or bq on rank 5 { long occupancyWithoutEPPawns = COMBINED_OCCUPANCIES_LOCAL & ~MoveConstants.SQUARE_BBS[startingSquare]; occupancyWithoutEPPawns &= ~MoveConstants.SQUARE_BBS[Board.ep_global + 8]; long rookAttacksFromKing = MoveUtils.getRookMovesSeparate(occupancyWithoutEPPawns, kingPosition); if ((rookAttacksFromKing & Board.bitboard_array_global[GenConst.BR]) == 0) { if ((rookAttacksFromKing & Board.bitboard_array_global[GenConst.BQ]) == 0) { startingSquares[moveCount] = startingSquare; targetSquares[moveCount] = Board.ep_global; tags[moveCount] = GenConst.TAG_WHITE_EP; pieces[moveCount] = GenConst.WP; moveCount++; } } } } } } //#endregion } //#endregion } } else //black move { checkCount = 0; kingPosition = bitScanForward(Board.bitboard_array_global[GenConst.BK]); rook_index = GenConst.BR; queen_index = GenConst.BQ; knight_index = GenConst.BN; bishop_index = GenConst.BB; enemy_occupancies = WHITE_OCCUPANCIES_LOCAL; //#region pins and check //pawns tempBitboard = Board.bitboard_array_global[GenConst.WP] & MoveConstants.BLACK_PAWN_ATTACKS[kingPosition]; if (tempBitboard != 0) { int pawn_square = DEBRUIJN64[(int)((MAGIC * (tempBitboard ^ (tempBitboard - 1))) >>> 58)]; checkBitboard |= MoveConstants.SQUARE_BBS[pawn_square]; checkCount++; } //knights tempBitboard = Board.bitboard_array_global[GenConst.WN] & MoveConstants.KNIGHT_ATTACKS[kingPosition]; if (tempBitboard != 0) { int knight_square = DEBRUIJN64[(int)((MAGIC * (tempBitboard ^ (tempBitboard - 1))) >>> 58)]; checkBitboard |= MoveConstants.SQUARE_BBS[knight_square]; checkCount++; } //bishops long bishopAttacksChecks = MoveUtils.getBishopMovesSeparate(WHITE_OCCUPANCIES_LOCAL, kingPosition); tempBitboard = Board.bitboard_array_global[GenConst.WB] & bishopAttacksChecks; while (tempBitboard != 0) { int piece_square = DEBRUIJN64[(int)((MAGIC * (tempBitboard ^ (tempBitboard - 1))) >>> 58)]; tempPinBitboard = Inb.INBETWEEN_BITBOARDS[kingPosition][piece_square] & BLACK_OCCUPANCIES_LOCAL; if (tempPinBitboard == 0) { checkBitboard |= Inb.INBETWEEN_BITBOARDS[kingPosition][piece_square]; checkCount++; } else { int pinned_square = (DEBRUIJN64[(int)((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 = Board.bitboard_array_global[GenConst.WQ] & bishopAttacksChecks; while (tempBitboard != 0) { int piece_square = DEBRUIJN64[(int)((MAGIC * (tempBitboard ^ (tempBitboard - 1))) >>> 58)]; tempPinBitboard = Inb.INBETWEEN_BITBOARDS[kingPosition][piece_square] & BLACK_OCCUPANCIES_LOCAL; if (tempPinBitboard == 0) { checkBitboard |= Inb.INBETWEEN_BITBOARDS[kingPosition][piece_square]; checkCount++; } else { int pinned_square = (DEBRUIJN64[(int)((MAGIC * (tempPinBitboard ^ (tempPinBitboard - 1))) >>> 58)]); tempPinBitboard &= tempPinBitboard - 1; if (tempPinBitboard == 0) { pinArraySquare[pinNumber] = pinned_square; pinArrayPiece[pinNumber] = piece_square; pinNumber++; } } tempBitboard &= tempBitboard - 1; } //rook long rook_attacks = MoveUtils.getRookMovesSeparate(WHITE_OCCUPANCIES_LOCAL, kingPosition); tempBitboard = Board.bitboard_array_global[GenConst.WR] & rook_attacks; while (tempBitboard != 0) { int piece_square = DEBRUIJN64[(int)((MAGIC * (tempBitboard ^ (tempBitboard - 1))) >>> 58)]; tempPinBitboard = Inb.INBETWEEN_BITBOARDS[kingPosition][piece_square] & BLACK_OCCUPANCIES_LOCAL; if (tempPinBitboard == 0) { checkBitboard |= Inb.INBETWEEN_BITBOARDS[kingPosition][piece_square]; checkCount++; } else { int pinned_square = (DEBRUIJN64[(int)((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 = Board.bitboard_array_global[GenConst.WQ] & rook_attacks; while (tempBitboard != 0) { int piece_square = DEBRUIJN64[(int)((MAGIC * (tempBitboard ^ (tempBitboard - 1))) >>> 58)]; tempPinBitboard = Inb.INBETWEEN_BITBOARDS[kingPosition][piece_square] & BLACK_OCCUPANCIES_LOCAL; if (tempPinBitboard == 0) { checkBitboard |= Inb.INBETWEEN_BITBOARDS[kingPosition][piece_square]; checkCount++; } else { int pinned_square = (DEBRUIJN64[(int)((MAGIC * (tempPinBitboard ^ (tempPinBitboard - 1))) >>> 58)]); tempPinBitboard &= tempPinBitboard - 1; if (tempPinBitboard == 0) { pinArraySquare[pinNumber] = pinned_square; pinArrayPiece[pinNumber] = piece_square; pinNumber++; } } tempBitboard &= tempBitboard - 1; } //#endregion //#region Black king long occupancyWithoutBlackKing = COMBINED_OCCUPANCIES_LOCAL & (~Board.bitboard_array_global[GenConst.BK]); tempAttack = MoveConstants.KING_ATTACKS[kingPosition] & WHITE_OCCUPANCIES_LOCAL; while (tempAttack != 0) { targetSquare = DEBRUIJN64[(int)((MAGIC * (tempAttack ^ (tempAttack - 1))) >>> 58)]; tempAttack &= tempAttack - 1; if ((Board.bitboard_array_global[GenConst.WP] & MoveConstants.BLACK_PAWN_ATTACKS[targetSquare]) != 0) { continue; } if ((Board.bitboard_array_global[GenConst.WN] & MoveConstants.KNIGHT_ATTACKS[targetSquare]) != 0) { continue; } if ((Board.bitboard_array_global[GenConst.WK] & MoveConstants.KING_ATTACKS[targetSquare]) != 0) { continue; } long bishopAttacks = MoveUtils.getBishopMovesSeparate(occupancyWithoutBlackKing, targetSquare); if ((Board.bitboard_array_global[GenConst.WB] & bishopAttacks) != 0) { continue; } if ((Board.bitboard_array_global[GenConst.WQ] & bishopAttacks) != 0) { continue; } long rookAttacks = MoveUtils.getRookMovesSeparate(occupancyWithoutBlackKing, targetSquare); if ((Board.bitboard_array_global[GenConst.WR] & rookAttacks) != 0) { continue; } if ((Board.bitboard_array_global[GenConst.WQ] & rookAttacks) != 0) { continue; } startingSquares[moveCount] = kingPosition; targetSquares[moveCount] = targetSquare; tags[moveCount] = GenConst.TAG_CAPTURE; pieces[moveCount] = GenConst.BK; moveCount++; } tempAttack = MoveConstants.KING_ATTACKS[kingPosition] & EMPTY_OCCUPANCIES; while (tempAttack != 0) { targetSquare = DEBRUIJN64[(int)((MAGIC * (tempAttack ^ (tempAttack - 1))) >>> 58)]; tempAttack &= tempAttack - 1; if ((Board.bitboard_array_global[GenConst.WP] & MoveConstants.BLACK_PAWN_ATTACKS[targetSquare]) != 0) { continue; } if ((Board.bitboard_array_global[GenConst.WN] & MoveConstants.KNIGHT_ATTACKS[targetSquare]) != 0) { continue; } if ((Board.bitboard_array_global[GenConst.WK] & MoveConstants.KING_ATTACKS[targetSquare]) != 0) { continue; } long bishopAttacks = MoveUtils.getBishopMovesSeparate(occupancyWithoutBlackKing, targetSquare); if ((Board.bitboard_array_global[GenConst.WB] & bishopAttacks) != 0) { continue; } if ((Board.bitboard_array_global[GenConst.WQ] & bishopAttacks) != 0) { continue; } long rookAttacks = MoveUtils.getRookMovesSeparate(occupancyWithoutBlackKing, targetSquare); if ((Board.bitboard_array_global[GenConst.WR] & rookAttacks) != 0) { continue; } if ((Board.bitboard_array_global[GenConst.WQ] & rookAttacks) != 0) { continue; } startingSquares[moveCount] = kingPosition; targetSquares[moveCount] = targetSquare; tags[moveCount] = GenConst.TAG_NONE; pieces[moveCount] = GenConst.BK; moveCount++; } //#endregion if (checkCount < 2) { if (checkCount == 0) { checkBitboard = GenConst.MAX_ULONG; if (Board.castle_rights_global[BKS_CASTLE_RIGHTS] == true) { if (kingPosition == GenConst.E8) //king on e1 { if ((GenConst.BKS_EMPTY_BITBOARD & COMBINED_OCCUPANCIES_LOCAL) == 0) //f1 and g1 empty { if ((Board.bitboard_array_global[GenConst.BR] & MoveConstants.SQUARE_BBS[GenConst.H8]) != 0) //rook on h1 { if (Is_Square_Attacked_By_White_Global(GenConst.F8, COMBINED_OCCUPANCIES_LOCAL) == false) { if (Is_Square_Attacked_By_White_Global(GenConst.G8, COMBINED_OCCUPANCIES_LOCAL) == false) { startingSquares[moveCount] = GenConst.E8; targetSquares[moveCount] = GenConst.G8; tags[moveCount] = GenConst.TAG_B_CASTLE_KS; pieces[moveCount] = GenConst.BK; moveCount++; } } } } } } if (Board.castle_rights_global[BQS_CASTLE_RIGHTS] == true) { if (kingPosition == GenConst.E8) //king on e1 { if ((GenConst.BQS_EMPTY_BITBOARD & COMBINED_OCCUPANCIES_LOCAL) == 0) //f1 and g1 empty { if ((Board.bitboard_array_global[GenConst.BR] & MoveConstants.SQUARE_BBS[GenConst.A8]) != 0) //rook on h1 { if (Is_Square_Attacked_By_White_Global(GenConst.C8, COMBINED_OCCUPANCIES_LOCAL) == false) { if (Is_Square_Attacked_By_White_Global(GenConst.D8, COMBINED_OCCUPANCIES_LOCAL) == false) { startingSquares[moveCount] = GenConst.E8; targetSquares[moveCount] = GenConst.C8; tags[moveCount] = GenConst.TAG_B_CASTLE_QS; pieces[moveCount] = GenConst.BK; moveCount++; } } } } } } } //#region Black pawns tempBitboard = Board.bitboard_array_global[GenConst.BP]; while (tempBitboard != 0) { startingSquare = DEBRUIJN64[(int)((MAGIC * (tempBitboard ^ (tempBitboard - 1))) >>> 58)]; tempBitboard &= tempBitboard - 1; tempPinBitboard = GenConst.MAX_ULONG; if (pinNumber != 0) { for (int i = 0; i < pinNumber; i++) { if (pinArraySquare[i] == startingSquare) { tempPinBitboard = Inb.INBETWEEN_BITBOARDS[kingPosition][pinArrayPiece[i]]; } } } //#region Pawn forward if ((MoveConstants.SQUARE_BBS[startingSquare + 8] & COMBINED_OCCUPANCIES_LOCAL) == 0) //if up one square is empty { if (((MoveConstants.SQUARE_BBS[startingSquare + 8] & checkBitboard) & tempPinBitboard) != 0) { if ((MoveConstants.SQUARE_BBS[startingSquare] & GenConst.RANK_2_BITBOARD) != 0) //if promotion { startingSquares[moveCount] = startingSquare; targetSquares[moveCount] = startingSquare + 8; tags[moveCount] = GenConst.TAG_B_B_PROMOTION; pieces[moveCount] = GenConst.BP; moveCount++; startingSquares[moveCount] = startingSquare; targetSquares[moveCount] = startingSquare + 8; tags[moveCount] = GenConst.TAG_B_N_PROMOTION; pieces[moveCount] = GenConst.BP; moveCount++; startingSquares[moveCount] = startingSquare; targetSquares[moveCount] = startingSquare + 8; tags[moveCount] = GenConst.TAG_B_R_PROMOTION; pieces[moveCount] = GenConst.BP; moveCount++; startingSquares[moveCount] = startingSquare; targetSquares[moveCount] = startingSquare + 8; tags[moveCount] = GenConst.TAG_B_Q_PROMOTION; pieces[moveCount] = GenConst.BP; moveCount++; } else { startingSquares[moveCount] = startingSquare; targetSquares[moveCount] = startingSquare + 8; tags[moveCount] = GenConst.TAG_NONE; pieces[moveCount] = GenConst.BP; moveCount++; } } if ((MoveConstants.SQUARE_BBS[startingSquare] & GenConst.RANK_7_BITBOARD) != 0) //if on rank 2 { if (((MoveConstants.SQUARE_BBS[startingSquare + 16] & checkBitboard) & tempPinBitboard) != 0) { if (((MoveConstants.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] = GenConst.TAG_B_P_DOUBLE; pieces[moveCount] = GenConst.BP; moveCount++; } } } } //#endregion //#region region Pawn captures tempAttack = ((MoveConstants.BLACK_PAWN_ATTACKS[startingSquare] & WHITE_OCCUPANCIES_LOCAL) & checkBitboard) & tempPinBitboard; //if black piece diagonal to pawn while (tempAttack != 0) { targetSquare = DEBRUIJN64[(int)((MAGIC * (tempAttack ^ (tempAttack - 1))) >>> 58)]; //find the bit tempAttack &= tempAttack - 1; if ((MoveConstants.SQUARE_BBS[startingSquare] & GenConst.RANK_2_BITBOARD) != 0) //if promotion { startingSquares[moveCount] = startingSquare; targetSquares[moveCount] = targetSquare; tags[moveCount] = GenConst.TAG_B_B_PROMOTION_CAP; pieces[moveCount] = GenConst.BP; moveCount++; startingSquares[moveCount] = startingSquare; targetSquares[moveCount] = targetSquare; tags[moveCount] = GenConst.TAG_B_N_PROMOTION_CAP; pieces[moveCount] = GenConst.BP; moveCount++; startingSquares[moveCount] = startingSquare; targetSquares[moveCount] = targetSquare; tags[moveCount] = GenConst.TAG_B_R_PROMOTION_CAP; pieces[moveCount] = GenConst.BP; moveCount++; startingSquares[moveCount] = startingSquare; targetSquares[moveCount] = targetSquare; tags[moveCount] = GenConst.TAG_B_Q_PROMOTION_CAP; pieces[moveCount] = GenConst.BP; moveCount++; } else { startingSquares[moveCount] = startingSquare; targetSquares[moveCount] = targetSquare; tags[moveCount] = GenConst.TAG_CAPTURE; pieces[moveCount] = GenConst.BP; moveCount++; } } if ((MoveConstants.SQUARE_BBS[startingSquare] & GenConst.RANK_4_BITBOARD) != 0) //check rank for ep { if (Board.ep_global != NO_SQUARE) { if ((((MoveConstants.BLACK_PAWN_ATTACKS[startingSquare] & MoveConstants.SQUARE_BBS[Board.ep_global]) & checkBitboard) & tempPinBitboard) != 0) { if ((Board.bitboard_array_global[GenConst.BK] & GenConst.RANK_4_BITBOARD) == 0) //if no king on rank 5 { startingSquares[moveCount] = startingSquare; targetSquares[moveCount] = Board.ep_global; tags[moveCount] = GenConst.TAG_BLACK_EP; pieces[moveCount] = GenConst.BP; moveCount++; } else if ((Board.bitboard_array_global[GenConst.WR] & GenConst.RANK_4_BITBOARD) == 0 && (Board.bitboard_array_global[GenConst.WQ] & GenConst.RANK_4_BITBOARD) == 0) // if no b rook or queen on rank 5 { startingSquares[moveCount] = startingSquare; targetSquares[moveCount] = Board.ep_global; tags[moveCount] = GenConst.TAG_BLACK_EP; pieces[moveCount] = GenConst.BP; moveCount++; } else //wk and br or bq on rank 5 { long occupancyWithoutEPPawns = COMBINED_OCCUPANCIES_LOCAL & ~MoveConstants.SQUARE_BBS[startingSquare]; occupancyWithoutEPPawns &= ~MoveConstants.SQUARE_BBS[Board.ep_global - 8]; long rookAttacksFromKing = MoveUtils.getRookMovesSeparate(occupancyWithoutEPPawns, kingPosition); if ((rookAttacksFromKing & Board.bitboard_array_global[GenConst.WR]) == 0) { if ((rookAttacksFromKing & Board.bitboard_array_global[GenConst.WQ]) == 0) { startingSquares[moveCount] = startingSquare; targetSquares[moveCount] = Board.ep_global; tags[moveCount] = GenConst.TAG_BLACK_EP; pieces[moveCount] = GenConst.BP; moveCount++; } } } } } } //#endregion } //#endregion } } if (checkCount > 1) { return moveCount; } //#region knight tempBitboard = Board.bitboard_array_global[knight_index]; while (tempBitboard != 0) { startingSquare = DEBRUIJN64[(int)((MAGIC * (tempBitboard ^ (tempBitboard - 1))) >>> 58)]; tempBitboard &= tempBitboard - 1; //removes the knight from that square to not infinitely loop tempPinBitboard = GenConst.MAX_ULONG; if (pinNumber != 0) { for (int i = 0; i < pinNumber; i++) { if (pinArraySquare[i] == startingSquare) { tempPinBitboard = Inb.INBETWEEN_BITBOARDS[kingPosition][pinArrayPiece[i]]; } } } tempAttack = ((MoveConstants.KNIGHT_ATTACKS[startingSquare] & enemy_occupancies) & checkBitboard) & tempPinBitboard; //gets knight captures while (tempAttack != 0) { targetSquare = (DEBRUIJN64[(int)((MAGIC * (tempAttack ^ (tempAttack - 1))) >>> 58)]); tempAttack &= tempAttack - 1; startingSquares[moveCount] = startingSquare; targetSquares[moveCount] = targetSquare; tags[moveCount] = GenConst.TAG_CAPTURE; pieces[moveCount] = knight_index; moveCount++; } tempAttack = ((MoveConstants.KNIGHT_ATTACKS[startingSquare] & EMPTY_OCCUPANCIES) & checkBitboard) & tempPinBitboard; while (tempAttack != 0) { targetSquare = DEBRUIJN64[(int)((MAGIC * (tempAttack ^ (tempAttack - 1))) >>> 58)]; tempAttack &= tempAttack - 1; startingSquares[moveCount] = startingSquare; targetSquares[moveCount] = targetSquare; tags[moveCount] = GenConst.TAG_NONE; pieces[moveCount] = knight_index; moveCount++; } } //#endregion //#region Rook tempBitboard = Board.bitboard_array_global[rook_index]; while (tempBitboard != 0) { startingSquare = DEBRUIJN64[(int)((MAGIC * (tempBitboard ^ (tempBitboard - 1))) >>> 58)]; tempBitboard &= tempBitboard - 1; tempPinBitboard = GenConst.MAX_ULONG; if (pinNumber != 0) { for (int i = 0; i < pinNumber; i++) { if (pinArraySquare[i] == startingSquare) { tempPinBitboard = Inb.INBETWEEN_BITBOARDS[kingPosition][pinArrayPiece[i]]; } } } long rookAttacks = MoveUtils.getRookMovesSeparate(COMBINED_OCCUPANCIES_LOCAL, startingSquare); tempAttack = ((rookAttacks & enemy_occupancies) & checkBitboard) & tempPinBitboard; while (tempAttack != 0) { targetSquare = (DEBRUIJN64[(int)((MAGIC * (tempAttack ^ (tempAttack - 1))) >>> 58)]); tempAttack &= tempAttack - 1; startingSquares[moveCount] = startingSquare; targetSquares[moveCount] = targetSquare; tags[moveCount] = GenConst.TAG_CAPTURE; pieces[moveCount] = rook_index; moveCount++; } tempAttack = ((rookAttacks & EMPTY_OCCUPANCIES) & checkBitboard) & tempPinBitboard; while (tempAttack != 0) { targetSquare = (DEBRUIJN64[(int)((MAGIC * (tempAttack ^ (tempAttack - 1))) >>> 58)]); tempAttack &= tempAttack - 1; startingSquares[moveCount] = startingSquare; targetSquares[moveCount] = targetSquare; tags[moveCount] = GenConst.TAG_NONE; pieces[moveCount] = rook_index; moveCount++; } } //#endregion //#region bishop tempBitboard = Board.bitboard_array_global[bishop_index]; while (tempBitboard != 0) { startingSquare = DEBRUIJN64[(int)((MAGIC * (tempBitboard ^ (tempBitboard - 1))) >>> 58)]; tempBitboard &= tempBitboard - 1; tempPinBitboard = GenConst.MAX_ULONG; if (pinNumber != 0) { for (int i = 0; i < pinNumber; i++) { if (pinArraySquare[i] == startingSquare) { tempPinBitboard = Inb.INBETWEEN_BITBOARDS[kingPosition][pinArrayPiece[i]]; } } } long bishopAttacks = MoveUtils.getBishopMovesSeparate(COMBINED_OCCUPANCIES_LOCAL, startingSquare); tempAttack = ((bishopAttacks & enemy_occupancies) & checkBitboard) & tempPinBitboard; while (tempAttack != 0) { targetSquare = DEBRUIJN64[(int)((MAGIC * (tempAttack ^ (tempAttack - 1))) >>> 58)]; tempAttack &= tempAttack - 1; startingSquares[moveCount] = startingSquare; targetSquares[moveCount] = targetSquare; tags[moveCount] = GenConst.TAG_CAPTURE; pieces[moveCount] = bishop_index; moveCount++; } tempAttack = ((bishopAttacks & EMPTY_OCCUPANCIES) & checkBitboard) & tempPinBitboard; while (tempAttack != 0) { targetSquare = DEBRUIJN64[(int)((MAGIC * (tempAttack ^ (tempAttack - 1))) >>> 58)]; tempAttack &= tempAttack - 1; startingSquares[moveCount] = startingSquare; targetSquares[moveCount] = targetSquare; tags[moveCount] = GenConst.TAG_NONE; pieces[moveCount] = bishop_index; moveCount++; } } //#endregion //#region Queen tempBitboard = Board.bitboard_array_global[queen_index]; while (tempBitboard != 0) { startingSquare = DEBRUIJN64[(int)((MAGIC * (tempBitboard ^ (tempBitboard - 1))) >>> 58)]; tempBitboard &= tempBitboard - 1; tempPinBitboard = GenConst.MAX_ULONG; if (pinNumber != 0) { for (int i = 0; i < pinNumber; i++) { if (pinArraySquare[i] == startingSquare) { tempPinBitboard = Inb.INBETWEEN_BITBOARDS[kingPosition][pinArrayPiece[i]]; } } } long queenAttacks = MoveUtils.getRookMovesSeparate(COMBINED_OCCUPANCIES_LOCAL, startingSquare); queenAttacks |= MoveUtils.getBishopMovesSeparate(COMBINED_OCCUPANCIES_LOCAL, startingSquare); tempAttack = ((queenAttacks & enemy_occupancies) & checkBitboard) & tempPinBitboard; while (tempAttack != 0) { targetSquare = DEBRUIJN64[(int)((MAGIC * (tempAttack ^ (tempAttack - 1))) >>> 58)]; tempAttack &= tempAttack - 1; startingSquares[moveCount] = startingSquare; targetSquares[moveCount] = targetSquare; tags[moveCount] = GenConst.TAG_CAPTURE; pieces[moveCount] = queen_index; moveCount++; } tempAttack = ((queenAttacks & EMPTY_OCCUPANCIES) & checkBitboard) & tempPinBitboard; while (tempAttack != 0) { targetSquare = DEBRUIJN64[(int)((MAGIC * (tempAttack ^ (tempAttack - 1))) >>> 58)]; tempAttack &= tempAttack - 1; startingSquares[moveCount] = startingSquare; targetSquares[moveCount] = targetSquare; tags[moveCount] = GenConst.TAG_NONE; pieces[moveCount] = queen_index; moveCount++; } } //#endregion return moveCount; } static ErrorInt PerftFunctionsDebug(int depth, int ply, DebugInfo debugInfo) { if (depth < 0) { return errorIntFromError(Error.Depth_Less_Than_Zero); } if (Board.bitboard_array_global[GenConst.WK] == 0) { return errorIntFromError(Error.White_King_Captured); } if (Board.bitboard_array_global[GenConst.BK] == 0) { return errorIntFromError(Error.Black_King_Captured); } long COMBINED_OCCUPANCIES = CombineBitboardsGlobal(); if (Board.is_white_global == true) { int kingPosition = bitScanForward(Board.bitboard_array_global[GenConst.BK]); if (Is_Square_Attacked_By_White_Global(kingPosition, COMBINED_OCCUPANCIES) == true) { PrintAllBitboards(); PrintAllDebug(debugInfo.LastStarting, debugInfo.LastTarget, debugInfo.lastPiece, debugInfo.LastTag); return errorIntFromError(Error.Black_King_In_Check_On_White_Move); } } else { int kingPosition = bitScanForward(Board.bitboard_array_global[GenConst.WK]); if (Is_Square_Attacked_By_Black_Global(kingPosition, COMBINED_OCCUPANCIES) == true) { return errorIntFromError(Error.White_King_In_Check_On_BlackMove); } } debugInfo.CallCount += 1; if (depth == 0) { return errorIntFromValue(1); } //Same as move list, span to avoid heap allocation int[] startingSquares = new int[50]; int[] targetSquares = new int[50]; int[] tags = new int[50]; int[] pieces = new int[50]; int moveCount = getMoves(startingSquares, targetSquares, tags, pieces); ErrorInt nodes = errorIntFromValue(0); int copyEp = Board.ep_global; boolean[] copy_castle = { Board.castle_rights_global[0], Board.castle_rights_global[1], Board.castle_rights_global[2], Board.castle_rights_global[3], }; long[] bitboardCopy = { Board.bitboard_array_global[0], Board.bitboard_array_global[1], Board.bitboard_array_global[2], Board.bitboard_array_global[3], Board.bitboard_array_global[4], Board.bitboard_array_global[5], Board.bitboard_array_global[6], Board.bitboard_array_global[7], Board.bitboard_array_global[8], Board.bitboard_array_global[9], Board.bitboard_array_global[10], Board.bitboard_array_global[11], }; 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]; if (startingSquareCopy < 0 || startingSquareCopy > 63) { return errorIntFromError(Error.Invalid_Starting_Square); } if (targetSquareCopy < 0 || targetSquareCopy > 63) { return errorIntFromError(Error.Invalid_Target_Square); } if (piece < 0 || piece > 11) { return errorIntFromError(Error.Invalid_Piece); } if (tag < 0 || tag > 27) { return errorIntFromError(Error.Invalid_Tag); } if (startingSquareCopy == targetSquareCopy) { return errorIntFromError(Error.Starting_Square_And_Target_Square_The_Same); } if (tag == GenConst.TAG_WHITE_EP || tag == GenConst.TAG_BLACK_EP) { if (Board.ep_global != targetSquareCopy) { return errorIntFromError(Error.Ep_Not_Target_Square); } } if (debugInfo.PromotionExpected == false) { if (tag >= GenConst.TAG_B_N_PROMOTION && tag <= GenConst.TAG_W_R_PROMOTION_CAP) { PrintAllDebug(startingSquareCopy, targetSquareCopy, piece, tag); return errorIntFromError(Error.Promotion_When_Not_Expected); } } boolean sideBefore = Board.is_white_global; int captureIndex = MakeMove(startingSquareCopy, targetSquareCopy, tag, piece); if (Board.is_white_global == sideBefore) { return errorIntFromError(Error.Side_Not_Changed); } debugInfo.lastPiece = piece; debugInfo.LastStarting = startingSquareCopy; debugInfo.LastTarget = targetSquareCopy; debugInfo.LastTag = tag; ErrorInt priorNodes = errorIntFromValue(nodes.getValue()); ErrorInt nodesToAdd = PerftFunctionsDebug(depth - 1, ply + 1, debugInfo); if (nodesToAdd.getError() != null) { return nodesToAdd; } nodes.setValue(nodes.getValue() + nodesToAdd.getValue()); boolean newSide = Board.is_white_global; UnmakeMove(startingSquareCopy, targetSquareCopy, piece, tag, captureIndex); if (Board.is_white_global == newSide) { return errorIntFromError(Error.Side_Not_Changed_Back); } Board.castle_rights_global[0] = copy_castle[0]; Board.castle_rights_global[1] = copy_castle[1]; Board.castle_rights_global[2] = copy_castle[2]; Board.castle_rights_global[3] = copy_castle[3]; Board.ep_global = copyEp; for (int i = 0; i < 12; i++) { if (Board.bitboard_array_global[i] != bitboardCopy[i]) { PrintAllBitboards(); System.out.println(String.format("global %d", i)); PrintBitboard(Board.bitboard_array_global[i]); System.out.println(String.format("copy %d", i)); PrintBitboard(bitboardCopy[i]); PrintAllDebug(startingSquareCopy, targetSquareCopy, piece, tag); return errorIntFromError(Error.Copy_Boards_Not_Same); } } if (ply == 0) { PrintMoveNoNL(startingSquareCopy, targetSquareCopy, tag); System.out.println(String.format(": %d", nodes.getValue() - priorNodes.getValue())); } } return nodes; } static void runPerftFunctionsDebug(int depth) { long startTime = System.currentTimeMillis(); DebugInfo debugInfo = new DebugInfo(); debugInfo.CallCount = 0; debugInfo.LastStarting = 0; ErrorInt nodes = PerftFunctionsDebug(depth, 0, debugInfo); if (nodes.getError() != null) { ErrorInt.printError(nodes.getError()); } long endTime = System.currentTimeMillis(); long elapsedTime = endTime - startTime; String nodeString = String.format("Nodes: %d\n", nodes.getValue()); String timeString = String.format("Time taken: %d ms\n", elapsedTime); Pr.print(nodeString); Pr.print(timeString); } //int[] startingSquares = new int[50]; static int PerftFunctions(int depth, int ply) { int[] startingSquares = new int[50]; int[] targetSquares = new int[50]; int[] tags = new int[50]; int[] pieces = new int[50]; int moveCount = getMoves(startingSquares, targetSquares, tags, pieces); if (depth == 1){ return moveCount; } int nodes = 0; int copyEp = Board.ep_global; boolean[] copy_castle = { Board.castle_rights_global[0], Board.castle_rights_global[1], Board.castle_rights_global[2], Board.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); int priorNodes = nodes; nodes += PerftFunctions(depth - 1, ply + 1); UnmakeMove(startingSquareCopy, targetSquareCopy, piece, tag, captureIndex); Board.castle_rights_global[0] = copy_castle[0]; Board.castle_rights_global[1] = copy_castle[1]; Board.castle_rights_global[2] = copy_castle[2]; Board.castle_rights_global[3] = copy_castle[3]; Board.ep_global = copyEp; //if (ply == 0) //{ //PrintMoveNoNL(startingSquareCopy, targetSquareCopy, tag); //System.out.println(String.format(": %d", nodes - priorNodes)); //} } return nodes; } static void runPerftFunctions(int depth) { long startTime = System.currentTimeMillis(); int nodes = PerftFunctions(depth, 0); long endTime = System.currentTimeMillis(); long elapsedTime = endTime - startTime; String nodeString = String.format("Nodes: %d\n", nodes); String timeString = String.format("Time taken: %d ms\n", elapsedTime); Pr.print(nodeString); Pr.print(timeString); } static void callPerft() { long startTime = System.currentTimeMillis(); //int nodes = PerftInlineDebug(0, 0); long endTime = System.currentTimeMillis(); long elapsedTime = endTime - startTime; //String nodeString = String.format("Nodes: %d\n", nodes); String timeString = String.format("Time taken: %d ms\n", elapsedTime); //Pr.print(nodeString); Pr.print(timeString); } }