Files
hcsalmon1-Chess-Engine-Test/Java/Perft.java
2025-01-19 14:45:46 +00:00

2379 lines
99 KiB
Java

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