/** * Generate and return a list of pseudo-legal moves. * Pseudo-legal means that the moves doesn't necessarily defend from check threats. */ public MoveList pseudoLegalMoves(Position pos) { MoveList moveList = getMoveListObj(); ulong occupied = pos.whiteBB | pos.blackBB; if (pos.whiteMove) { int sq = 0; ulong m = 0; // Queen moves ulong squares = pos.pieceTypeBB[Piece.WQUEEN]; while (squares != 0) { sq = BitBoard.numberOfTrailingZeros(squares); m = (BitBoard.rookAttacks(sq, occupied) | BitBoard.bishopAttacks(sq, occupied)) & ~pos.whiteBB; if (addMovesByMask(moveList, pos, sq, m)) return moveList; squares &= squares-1; } // Rook moves squares = pos.pieceTypeBB[Piece.WROOK]; while (squares != 0) { sq = BitBoard.numberOfTrailingZeros(squares); m = BitBoard.rookAttacks(sq, occupied) & ~pos.whiteBB; if (addMovesByMask(moveList, pos, sq, m)) return moveList; squares &= squares-1; } // Bishop moves squares = pos.pieceTypeBB[Piece.WBISHOP]; while (squares != 0) { sq = BitBoard.numberOfTrailingZeros(squares); m = BitBoard.bishopAttacks(sq, occupied) & ~pos.whiteBB; if (addMovesByMask(moveList, pos, sq, m)) return moveList; squares &= squares-1; } // King moves { sq = pos.getKingSq(true); m = BitBoard.kingAttacks[sq] & ~pos.whiteBB; if (addMovesByMask(moveList, pos, sq, m)) return moveList; int k0 = 4; if (sq == k0) { ulong OO_SQ = 0x60L; ulong OOO_SQ = 0xEL; if (((pos.getCastleMask() & (1 << Position.H1_CASTLE)) != 0) && ((OO_SQ & (pos.whiteBB | pos.blackBB)) == 0) && (pos.getPiece(k0 + 3) == Piece.WROOK) && !sqAttacked(pos, k0) && !sqAttacked(pos, k0 + 1)) { setMove(moveList, k0, k0 + 2, Piece.EMPTY); } if (((pos.getCastleMask() & (1 << Position.A1_CASTLE)) != 0) && ((OOO_SQ & (pos.whiteBB | pos.blackBB)) == 0) && (pos.getPiece(k0 - 4) == Piece.WROOK) && !sqAttacked(pos, k0) && !sqAttacked(pos, k0 - 1)) { setMove(moveList, k0, k0 - 2, Piece.EMPTY); } } } // Knight moves ulong knights = pos.pieceTypeBB[Piece.WKNIGHT]; while (knights != 0) { sq = BitBoard.numberOfTrailingZeros(knights); m = BitBoard.knightAttacks[sq] & ~pos.whiteBB; if (addMovesByMask(moveList, pos, sq, m)) return moveList; knights &= knights-1; } // Pawn moves ulong pawns = pos.pieceTypeBB[Piece.WPAWN]; m = (pawns << 8) & ~occupied; if (addPawnMovesByMask(moveList, pos, m, -8, true)) return moveList; m = ((m & BitBoard.maskRow3) << 8) & ~occupied; addPawnDoubleMovesByMask(moveList, pos, m, -16); int epSquare = pos.getEpSquare(); ulong epMask = (epSquare >= 0) ? (1UL << epSquare) : 0L; m = (pawns << 7) & BitBoard.maskAToGFiles & (pos.blackBB | epMask); if (addPawnMovesByMask(moveList, pos, m, -7, true)) return moveList; m = (pawns << 9) & BitBoard.maskBToHFiles & (pos.blackBB | epMask); if (addPawnMovesByMask(moveList, pos, m, -9, true)) return moveList; } else { int sq = 0; ulong m = 0; // Queen moves ulong squares = pos.pieceTypeBB[Piece.BQUEEN]; while (squares != 0) { sq = BitBoard.numberOfTrailingZeros(squares); m = (BitBoard.rookAttacks(sq, occupied) | BitBoard.bishopAttacks(sq, occupied)) & ~pos.blackBB; if (addMovesByMask(moveList, pos, sq, m)) return moveList; squares &= squares-1; } // Rook moves squares = pos.pieceTypeBB[Piece.BROOK]; while (squares != 0) { sq = BitBoard.numberOfTrailingZeros(squares); m = BitBoard.rookAttacks(sq, occupied) & ~pos.blackBB; if (addMovesByMask(moveList, pos, sq, m)) return moveList; squares &= squares-1; } // Bishop moves squares = pos.pieceTypeBB[Piece.BBISHOP]; while (squares != 0) { sq = BitBoard.numberOfTrailingZeros(squares); m = BitBoard.bishopAttacks(sq, occupied) & ~pos.blackBB; if (addMovesByMask(moveList, pos, sq, m)) return moveList; squares &= squares-1; } // King moves { sq = pos.getKingSq(false); m = BitBoard.kingAttacks[sq] & ~pos.blackBB; if (addMovesByMask(moveList, pos, sq, m)) return moveList; int k0 = 60; if (sq == k0) { ulong OO_SQ = 0x6000000000000000L; ulong OOO_SQ = 0xE00000000000000L; if (((pos.getCastleMask() & (1 << Position.H8_CASTLE)) != 0) && ((OO_SQ & (pos.whiteBB | pos.blackBB)) == 0) && (pos.getPiece(k0 + 3) == Piece.BROOK) && !sqAttacked(pos, k0) && !sqAttacked(pos, k0 + 1)) { setMove(moveList, k0, k0 + 2, Piece.EMPTY); } if (((pos.getCastleMask() & (1 << Position.A8_CASTLE)) != 0) && ((OOO_SQ & (pos.whiteBB | pos.blackBB)) == 0) && (pos.getPiece(k0 - 4) == Piece.BROOK) && !sqAttacked(pos, k0) && !sqAttacked(pos, k0 - 1)) { setMove(moveList, k0, k0 - 2, Piece.EMPTY); } } } // Knight moves ulong knights = pos.pieceTypeBB[Piece.BKNIGHT]; while (knights != 0) { sq = BitBoard.numberOfTrailingZeros(knights); m = BitBoard.knightAttacks[sq] & ~pos.blackBB; if (addMovesByMask(moveList, pos, sq, m)) return moveList; knights &= knights-1; } // Pawn moves ulong pawns = pos.pieceTypeBB[Piece.BPAWN]; m = (pawns >> 8) & ~occupied; if (addPawnMovesByMask(moveList, pos, m, 8, true)) return moveList; m = ((m & BitBoard.maskRow6) >> 8) & ~occupied; addPawnDoubleMovesByMask(moveList, pos, m, 16); int epSquare = pos.getEpSquare(); ulong epMask = (epSquare >= 0) ? (1UL << epSquare) : 0L; m = (pawns >> 9) & BitBoard.maskAToGFiles & (pos.whiteBB | epMask); if (addPawnMovesByMask(moveList, pos, m, 9, true)) return moveList; m = (pawns >> 7) & BitBoard.maskBToHFiles & (pos.whiteBB | epMask); if (addPawnMovesByMask(moveList, pos, m, 7, true)) return moveList; } return moveList; }
/** Score castling ability. */ private int castleBonus(Position pos) { if (pos.getCastleMask() == 0) return 0; int k1 = kt1b[7*8+6] - kt1b[7*8+4]; int k2 = kt2b[7*8+6] - kt2b[7*8+4]; int t1 = qV + 2 * rV + 2 * bV; int t2 = rV; int t = pos.bMtrl - pos.bMtrlPawns; int ks = interpolate(t, t2, k2, t1, k1); int castleValue = ks + rt1b[7*8+5] - rt1b[7*8+7]; if (castleValue <= 0) return 0; ulong occupied = pos.whiteBB | pos.blackBB; int tmp = (int) (occupied & 0x6E); if (pos.a1Castle()) tmp |= 1; if (pos.h1Castle()) tmp |= (1 << 7); int wBonus = (castleValue * castleFactor[tmp]) >> 10; tmp = (int) ((occupied >> 56) & 0x6E); if (pos.a8Castle()) tmp |= 1; if (pos.h8Castle()) tmp |= (1 << 7); int bBonus = (castleValue * castleFactor[tmp]) >> 10; return wBonus - bBonus; }
/** Generate captures, checks, and possibly some other moves that are too hard to filter out. */ public MoveList pseudoLegalCapturesAndChecks(Position pos) { MoveList moveList = getMoveListObj(); ulong occupied = pos.whiteBB | pos.blackBB; if (pos.whiteMove) { int sq = 0; ulong m = 0; int bKingSq = pos.getKingSq(false); ulong discovered = 0; // Squares that could generate discovered checks ulong kRookAtk = BitBoard.rookAttacks(bKingSq, occupied); if ((BitBoard.rookAttacks(bKingSq, occupied & ~kRookAtk) & (pos.pieceTypeBB[Piece.WQUEEN] | pos.pieceTypeBB[Piece.WROOK])) != 0) discovered |= kRookAtk; ulong kBishAtk = BitBoard.bishopAttacks(bKingSq, occupied); if ((BitBoard.bishopAttacks(bKingSq, occupied & ~kBishAtk) & (pos.pieceTypeBB[Piece.WQUEEN] | pos.pieceTypeBB[Piece.WBISHOP])) != 0) discovered |= kBishAtk; // Queen moves ulong squares = pos.pieceTypeBB[Piece.WQUEEN]; while (squares != 0) { sq = BitBoard.numberOfTrailingZeros(squares); m = (BitBoard.rookAttacks(sq, occupied) | BitBoard.bishopAttacks(sq, occupied)); if ((discovered & (1UL<<sq)) == 0) m &= (pos.blackBB | kRookAtk | kBishAtk); m &= ~pos.whiteBB; if (addMovesByMask(moveList, pos, sq, m)) return moveList; squares &= squares-1; } // Rook moves squares = pos.pieceTypeBB[Piece.WROOK]; while (squares != 0) { sq = BitBoard.numberOfTrailingZeros(squares); m = BitBoard.rookAttacks(sq, occupied); if ((discovered & (1UL<<sq)) == 0) m &= (pos.blackBB | kRookAtk); m &= ~pos.whiteBB; if (addMovesByMask(moveList, pos, sq, m)) return moveList; squares &= squares-1; } // Bishop moves squares = pos.pieceTypeBB[Piece.WBISHOP]; while (squares != 0) { sq = BitBoard.numberOfTrailingZeros(squares); m = BitBoard.bishopAttacks(sq, occupied); if ((discovered & (1UL<<sq)) == 0) m &= (pos.blackBB | kBishAtk); m &= ~pos.whiteBB; if (addMovesByMask(moveList, pos, sq, m)) return moveList; squares &= squares-1; } // King moves { sq = pos.getKingSq(true); m = BitBoard.kingAttacks[sq]; m &= ((discovered & (1UL<<sq)) == 0) ? pos.blackBB : ~pos.whiteBB; if (addMovesByMask(moveList, pos, sq, m)) return moveList; int k0 = 4; if (sq == k0) { ulong OO_SQ = 0x60L; ulong OOO_SQ = 0xEL; if (((pos.getCastleMask() & (1 << Position.H1_CASTLE)) != 0) && ((OO_SQ & (pos.whiteBB | pos.blackBB)) == 0) && (pos.getPiece(k0 + 3) == Piece.WROOK) && !sqAttacked(pos, k0) && !sqAttacked(pos, k0 + 1)) { setMove(moveList, k0, k0 + 2, Piece.EMPTY); } if (((pos.getCastleMask() & (1 << Position.A1_CASTLE)) != 0) && ((OOO_SQ & (pos.whiteBB | pos.blackBB)) == 0) && (pos.getPiece(k0 - 4) == Piece.WROOK) && !sqAttacked(pos, k0) && !sqAttacked(pos, k0 - 1)) { setMove(moveList, k0, k0 - 2, Piece.EMPTY); } } } // Knight moves ulong knights = pos.pieceTypeBB[Piece.WKNIGHT]; ulong kKnightAtk = BitBoard.knightAttacks[bKingSq]; while (knights != 0) { sq = BitBoard.numberOfTrailingZeros(knights); m = BitBoard.knightAttacks[sq] & ~pos.whiteBB; if ((discovered & (1UL<<sq)) == 0) m &= (pos.blackBB | kKnightAtk); m &= ~pos.whiteBB; if (addMovesByMask(moveList, pos, sq, m)) return moveList; knights &= knights-1; } // Pawn moves // Captures ulong pawns = pos.pieceTypeBB[Piece.WPAWN]; int epSquare = pos.getEpSquare(); ulong epMask = (epSquare >= 0) ? (1UL << epSquare) : 0L; m = (pawns << 7) & BitBoard.maskAToGFiles & (pos.blackBB | epMask); if (addPawnMovesByMask(moveList, pos, m, -7, false)) return moveList; m = (pawns << 9) & BitBoard.maskBToHFiles & (pos.blackBB | epMask); if (addPawnMovesByMask(moveList, pos, m, -9, false)) return moveList; // Discovered checks and promotions ulong pawnAll = discovered | BitBoard.maskRow7; m = ((pawns & pawnAll) << 8) & ~(pos.whiteBB | pos.blackBB); if (addPawnMovesByMask(moveList, pos, m, -8, false)) return moveList; m = ((m & BitBoard.maskRow3) << 8) & ~(pos.whiteBB | pos.blackBB); addPawnDoubleMovesByMask(moveList, pos, m, -16); // Normal checks m = ((pawns & ~pawnAll) << 8) & ~(pos.whiteBB | pos.blackBB); if (addPawnMovesByMask(moveList, pos, m & BitBoard.bPawnAttacks[bKingSq], -8, false)) return moveList; m = ((m & BitBoard.maskRow3) << 8) & ~(pos.whiteBB | pos.blackBB); addPawnDoubleMovesByMask(moveList, pos, m & BitBoard.bPawnAttacks[bKingSq], -16); } else { int sq = 0; ulong m = 0; int wKingSq = pos.getKingSq(true); ulong discovered = 0; // Squares that could generate discovered checks ulong kRookAtk = BitBoard.rookAttacks(wKingSq, occupied); if ((BitBoard.rookAttacks(wKingSq, occupied & ~kRookAtk) & (pos.pieceTypeBB[Piece.BQUEEN] | pos.pieceTypeBB[Piece.BROOK])) != 0) discovered |= kRookAtk; ulong kBishAtk = BitBoard.bishopAttacks(wKingSq, occupied); if ((BitBoard.bishopAttacks(wKingSq, occupied & ~kBishAtk) & (pos.pieceTypeBB[Piece.BQUEEN] | pos.pieceTypeBB[Piece.BBISHOP])) != 0) discovered |= kBishAtk; // Queen moves ulong squares = pos.pieceTypeBB[Piece.BQUEEN]; while (squares != 0) { sq = BitBoard.numberOfTrailingZeros(squares); m = (BitBoard.rookAttacks(sq, occupied) | BitBoard.bishopAttacks(sq, occupied)); if ((discovered & (1UL<<sq)) == 0) m &= pos.whiteBB | kRookAtk | kBishAtk; m &= ~pos.blackBB; if (addMovesByMask(moveList, pos, sq, m)) return moveList; squares &= squares-1; } // Rook moves squares = pos.pieceTypeBB[Piece.BROOK]; while (squares != 0) { sq = BitBoard.numberOfTrailingZeros(squares); m = BitBoard.rookAttacks(sq, occupied); if ((discovered & (1UL<<sq)) == 0) m &= pos.whiteBB | kRookAtk; m &= ~pos.blackBB; if (addMovesByMask(moveList, pos, sq, m)) return moveList; squares &= squares-1; } // Bishop moves squares = pos.pieceTypeBB[Piece.BBISHOP]; while (squares != 0) { sq = BitBoard.numberOfTrailingZeros(squares); m = BitBoard.bishopAttacks(sq, occupied); if ((discovered & (1UL<<sq)) == 0) m &= pos.whiteBB | kBishAtk; m &= ~pos.blackBB; if (addMovesByMask(moveList, pos, sq, m)) return moveList; squares &= squares-1; } // King moves { sq = pos.getKingSq(false); m = BitBoard.kingAttacks[sq]; m &= ((discovered & (1UL<<sq)) == 0) ? pos.whiteBB : ~pos.blackBB; if (addMovesByMask(moveList, pos, sq, m)) return moveList; int k0 = 60; if (sq == k0) { ulong OO_SQ = 0x6000000000000000L; ulong OOO_SQ = 0xE00000000000000L; if (((pos.getCastleMask() & (1 << Position.H8_CASTLE)) != 0) && ((OO_SQ & (pos.whiteBB | pos.blackBB)) == 0) && (pos.getPiece(k0 + 3) == Piece.BROOK) && !sqAttacked(pos, k0) && !sqAttacked(pos, k0 + 1)) { setMove(moveList, k0, k0 + 2, Piece.EMPTY); } if (((pos.getCastleMask() & (1 << Position.A8_CASTLE)) != 0) && ((OOO_SQ & (pos.whiteBB | pos.blackBB)) == 0) && (pos.getPiece(k0 - 4) == Piece.BROOK) && !sqAttacked(pos, k0) && !sqAttacked(pos, k0 - 1)) { setMove(moveList, k0, k0 - 2, Piece.EMPTY); } } } // Knight moves ulong knights = pos.pieceTypeBB[Piece.BKNIGHT]; ulong kKnightAtk = BitBoard.knightAttacks[wKingSq]; while (knights != 0) { sq = BitBoard.numberOfTrailingZeros(knights); m = BitBoard.knightAttacks[sq] & ~pos.blackBB; if ((discovered & (1UL<<sq)) == 0) m &= pos.whiteBB | kKnightAtk; m &= ~pos.blackBB; if (addMovesByMask(moveList, pos, sq, m)) return moveList; knights &= knights-1; } // Pawn moves // Captures ulong pawns = pos.pieceTypeBB[Piece.BPAWN]; int epSquare = pos.getEpSquare(); ulong epMask = (epSquare >= 0) ? (1UL << epSquare) : 0L; m = (pawns >> 9) & BitBoard.maskAToGFiles & (pos.whiteBB | epMask); if (addPawnMovesByMask(moveList, pos, m, 9, false)) return moveList; m = (pawns >> 7) & BitBoard.maskBToHFiles & (pos.whiteBB | epMask); if (addPawnMovesByMask(moveList, pos, m, 7, false)) return moveList; // Discovered checks and promotions ulong pawnAll = discovered | BitBoard.maskRow2; m = ((pawns & pawnAll) >> 8) & ~(pos.whiteBB | pos.blackBB); if (addPawnMovesByMask(moveList, pos, m, 8, false)) return moveList; m = ((m & BitBoard.maskRow6) >> 8) & ~(pos.whiteBB | pos.blackBB); addPawnDoubleMovesByMask(moveList, pos, m, 16); // Normal checks m = ((pawns & ~pawnAll) >> 8) & ~(pos.whiteBB | pos.blackBB); if (addPawnMovesByMask(moveList, pos, m & BitBoard.wPawnAttacks[wKingSq], 8, false)) return moveList; m = ((m & BitBoard.maskRow6) >> 8) & ~(pos.whiteBB | pos.blackBB); addPawnDoubleMovesByMask(moveList, pos, m & BitBoard.wPawnAttacks[wKingSq], 16); } return moveList; }