/** Implements special knowledge for some endgame situations. */ private int endGameEval(Position pos, int oldScore) { int score = oldScore; if (pos.wMtrl + pos.bMtrl > 6 * rV) return score; int wMtrlPawns = pos.wMtrlPawns; int bMtrlPawns = pos.bMtrlPawns; int wMtrlNoPawns = pos.wMtrl - wMtrlPawns; int bMtrlNoPawns = pos.bMtrl - bMtrlPawns; bool handled = false; if ((wMtrlPawns + bMtrlPawns == 0) && (wMtrlNoPawns < rV) && (bMtrlNoPawns < rV)) { // King + minor piece vs king + minor piece is a draw return 0; } if (!handled && (pos.wMtrl == qV) && (pos.bMtrl == pV) && (BITS.bitCount(pos.pieceTypeBB[Piece.WQUEEN]) == 1)) { int wk = BitBoard.numberOfTrailingZeros(pos.pieceTypeBB[Piece.WKING]); int wq = BitBoard.numberOfTrailingZeros(pos.pieceTypeBB[Piece.WQUEEN]); int bk = BitBoard.numberOfTrailingZeros(pos.pieceTypeBB[Piece.BKING]); int bp = BitBoard.numberOfTrailingZeros(pos.pieceTypeBB[Piece.BPAWN]); score = evalKQKP(wk, wq, bk, bp); handled = true; } if (!handled && (pos.bMtrl == qV) && (pos.wMtrl == pV) && (BITS.bitCount(pos.pieceTypeBB[Piece.BQUEEN]) == 1)) { int bk = BitBoard.numberOfTrailingZeros(pos.pieceTypeBB[Piece.BKING]); int bq = BitBoard.numberOfTrailingZeros(pos.pieceTypeBB[Piece.BQUEEN]); int wk = BitBoard.numberOfTrailingZeros(pos.pieceTypeBB[Piece.WKING]); int wp = BitBoard.numberOfTrailingZeros(pos.pieceTypeBB[Piece.WPAWN]); score = -evalKQKP(63-bk, 63-bq, 63-wk, 63-wp); handled = true; } if (!handled && (score > 0)) { if ((wMtrlPawns == 0) && (wMtrlNoPawns <= bMtrlNoPawns + bV)) { if (wMtrlNoPawns < rV) { return -pos.bMtrl / 50; } else { score /= 8; // Too little excess material, probably draw handled = true; } } else if ((pos.pieceTypeBB[Piece.WROOK] | pos.pieceTypeBB[Piece.WKNIGHT] | pos.pieceTypeBB[Piece.WQUEEN]) == 0) { // Check for rook pawn + wrong color bishop if (((pos.pieceTypeBB[Piece.WPAWN] & BitBoard.maskBToHFiles) == 0) && ((pos.pieceTypeBB[Piece.WBISHOP] & BitBoard.maskLightSq) == 0) && ((pos.pieceTypeBB[Piece.BKING] & 0x0303000000000000L) != 0)) { return 0; } else if (((pos.pieceTypeBB[Piece.WPAWN] & BitBoard.maskAToGFiles) == 0) && ((pos.pieceTypeBB[Piece.WBISHOP] & BitBoard.maskDarkSq) == 0) && ((pos.pieceTypeBB[Piece.BKING] & 0xC0C0000000000000L) != 0)) { return 0; } } } if (!handled) { if (bMtrlPawns == 0) { if (wMtrlNoPawns - bMtrlNoPawns > bV) { int wKnights = BITS.bitCount(pos.pieceTypeBB[Piece.WKNIGHT]); int wBishops = BITS.bitCount(pos.pieceTypeBB[Piece.WBISHOP]); if ((wKnights == 2) && (wMtrlNoPawns == 2 * nV) && (bMtrlNoPawns == 0)) { score /= 50; // KNNK is a draw } else if ((wKnights == 1) && (wBishops == 1) && (wMtrlNoPawns == nV + bV) && (bMtrlNoPawns == 0)) { score /= 10; score += nV + bV + 300; int kSq = pos.getKingSq(false); int x = Position.getX(kSq); int y = Position.getY(kSq); if ((pos.pieceTypeBB[Piece.WBISHOP] & BitBoard.maskDarkSq) != 0) { score += (7 - distToH1A8[7-y][7-x]) * 10; } else { score += (7 - distToH1A8[7-y][x]) * 10; } } else { score += 300; // Enough excess material, should win } handled = true; } else if ((wMtrlNoPawns + bMtrlNoPawns == 0) && (wMtrlPawns == pV)) { // KPK int wp = BitBoard.numberOfTrailingZeros(pos.pieceTypeBB[Piece.WPAWN]); score = kpkEval(pos.getKingSq(true), pos.getKingSq(false), wp, pos.whiteMove); handled = true; } } } if (!handled && (score < 0)) { if ((bMtrlPawns == 0) && (bMtrlNoPawns <= wMtrlNoPawns + bV)) { if (bMtrlNoPawns < rV) { return pos.wMtrl / 50; } else { score /= 8; // Too little excess material, probably draw handled = true; } } else if ((pos.pieceTypeBB[Piece.BROOK] | pos.pieceTypeBB[Piece.BKNIGHT] | pos.pieceTypeBB[Piece.BQUEEN]) == 0) { // Check for rook pawn + wrong color bishop if (((pos.pieceTypeBB[Piece.BPAWN] & BitBoard.maskBToHFiles) == 0) && ((pos.pieceTypeBB[Piece.BBISHOP] & BitBoard.maskDarkSq) == 0) && ((pos.pieceTypeBB[Piece.WKING] & 0x0303L) != 0)) { return 0; } else if (((pos.pieceTypeBB[Piece.BPAWN] & BitBoard.maskAToGFiles) == 0) && ((pos.pieceTypeBB[Piece.BBISHOP] & BitBoard.maskLightSq) == 0) && ((pos.pieceTypeBB[Piece.WKING] & 0xC0C0L) != 0)) { return 0; } } } if (!handled) { if (wMtrlPawns == 0) { if (bMtrlNoPawns - wMtrlNoPawns > bV) { int bKnights = BITS.bitCount(pos.pieceTypeBB[Piece.BKNIGHT]); int bBishops = BITS.bitCount(pos.pieceTypeBB[Piece.BBISHOP]); if ((bKnights == 2) && (bMtrlNoPawns == 2 * nV) && (wMtrlNoPawns == 0)) { score /= 50; // KNNK is a draw } else if ((bKnights == 1) && (bBishops == 1) && (bMtrlNoPawns == nV + bV) && (wMtrlNoPawns == 0)) { score /= 10; score -= nV + bV + 300; int kSq = pos.getKingSq(true); int x = Position.getX(kSq); int y = Position.getY(kSq); if ((pos.pieceTypeBB[Piece.BBISHOP] & BitBoard.maskDarkSq) != 0) { score -= (7 - distToH1A8[7-y][7-x]) * 10; } else { score -= (7 - distToH1A8[7-y][x]) * 10; } } else { score -= 300; // Enough excess material, should win } handled = true; } else if ((wMtrlNoPawns + bMtrlNoPawns == 0) && (bMtrlPawns == pV)) { // KPK int bp = BitBoard.numberOfTrailingZeros(pos.pieceTypeBB[Piece.BPAWN]); score = -kpkEval(63-pos.getKingSq(false), 63-pos.getKingSq(true), 63-bp, !pos.whiteMove); handled = true; } } } return score; // FIXME! Add evaluation of KRKP // FIXME! Add evaluation of KRPKR : eg 8/8/8/5pk1/1r6/R7/8/4K3 w - - 0 74 // FIXME! KRBKR is very hard to draw }
private int pawnBonus(Position pos) { ulong key = pos.pawnZobristHash(); PawnHashData phd = pawnHash[(int)key & (pawnHash.Length - 1)]; if (phd.key != key) computePawnHashData(pos, phd); int score = phd.score; int hiMtrl = qV + rV; score += interpolate(pos.bMtrl - pos.bMtrlPawns, 0, 2 * phd.passedBonusW, hiMtrl, phd.passedBonusW); score -= interpolate(pos.wMtrl - pos.wMtrlPawns, 0, 2 * phd.passedBonusB, hiMtrl, phd.passedBonusB); // Passed pawns are more dangerous if enemy king is far away int mtrlNoPawns; int highMtrl = qV + rV; ulong m = phd.passedPawnsW; if (m != 0) { mtrlNoPawns = pos.bMtrl - pos.bMtrlPawns; if (mtrlNoPawns < highMtrl) { int kingPos = pos.getKingSq(false); int kingX = Position.getX(kingPos); int kingY = Position.getY(kingPos); while (m != 0) { int sq = BitBoard.numberOfTrailingZeros(m); int x = Position.getX(sq); int y = Position.getY(sq); int pawnDist = Math.Min(5, 7 - y); int kingDistX = Math.Abs(kingX - x); int kingDistY = Math.Abs(kingY - 7); int kingDist = Math.Max(kingDistX, kingDistY); int kScore = kingDist * 4; if (kingDist > pawnDist) kScore += (kingDist - pawnDist) * (kingDist - pawnDist); score += interpolate(mtrlNoPawns, 0, kScore, highMtrl, 0); if (!pos.whiteMove) kingDist--; if ((pawnDist < kingDist) && (mtrlNoPawns == 0)) score += 500; // King can't stop pawn m &= m-1; } } } m = phd.passedPawnsB; if (m != 0) { mtrlNoPawns = pos.wMtrl - pos.wMtrlPawns; if (mtrlNoPawns < highMtrl) { int kingPos = pos.getKingSq(true); int kingX = Position.getX(kingPos); int kingY = Position.getY(kingPos); while (m != 0) { int sq = BitBoard.numberOfTrailingZeros(m); int x = Position.getX(sq); int y = Position.getY(sq); int pawnDist = Math.Min(5, y); int kingDistX = Math.Abs(kingX - x); int kingDistY = Math.Abs(kingY - 0); int kingDist = Math.Max(kingDistX, kingDistY); int kScore = kingDist * 4; if (kingDist > pawnDist) kScore += (kingDist - pawnDist) * (kingDist - pawnDist); score -= interpolate(mtrlNoPawns, 0, kScore, highMtrl, 0); if (pos.whiteMove) kingDist--; if ((pawnDist < kingDist) && (mtrlNoPawns == 0)) score -= 500; // King can't stop pawn m &= m-1; } } } return score; }
/** * 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; }
/** * Static evaluation of a position. * @param pos The position to evaluate. * @return The evaluation score, measured in centipawns. * Positive values are good for the side to make the next move. */ public int evalPos(Position pos) { int score = pos.wMtrl - pos.bMtrl; wKingAttacks = bKingAttacks = 0; wKingZone = BitBoard.kingAttacks[pos.getKingSq(true)]; wKingZone |= wKingZone << 8; bKingZone = BitBoard.kingAttacks[pos.getKingSq(false)]; bKingZone |= bKingZone >> 8; wAttacksBB = bAttacksBB = 0L; score += pieceSquareEval(pos); score += pawnBonus(pos); score += tradeBonus(pos); score += castleBonus(pos); score += rookBonus(pos); score += bishopEval(pos, score); score += threatBonus(pos); score += kingSafety(pos); score = endGameEval(pos, score); if (!pos.whiteMove) score = -score; return score; // FIXME! Test penalty if side to move has >1 hanging piece // FIXME! Test "tempo value" }
/** 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; }
/** * Return true if making a move delivers check to the opponent */ public static bool givesCheck(Position pos, Move m) { bool wtm = pos.whiteMove; int oKingSq = pos.getKingSq(!wtm); int oKing = wtm ? Piece.BKING : Piece.WKING; int p = Piece.makeWhite(m.promoteTo == Piece.EMPTY ? pos.getPiece(m.from) : m.promoteTo); int d1 = BitBoard.getDirection(m.to, oKingSq); switch (d1) { case 8: case -8: case 1: case -1: // Rook direction if ((p == Piece.WQUEEN) || (p == Piece.WROOK)) if ((d1 != 0) && (/*MoveGen.*/ nextPiece(pos, m.to, d1) == oKing)) return true; break; case 9: case 7: case -9: case -7: // Bishop direction if ((p == Piece.WQUEEN) || (p == Piece.WBISHOP)) { if ((d1 != 0) && (/*MoveGen.*/ nextPiece(pos, m.to, d1) == oKing)) return true; } else if (p == Piece.WPAWN) { if (((d1 > 0) == wtm) && (pos.getPiece(m.to + d1) == oKing)) return true; } break; default: if (d1 != 0) { // Knight direction if (p == Piece.WKNIGHT) return true; } break; } int d2 = BitBoard.getDirection(m.from, oKingSq); if ((d2 != 0) && (d2 != d1) && (/*MoveGen.*/ nextPiece(pos, m.from, d2) == oKing)) { int p2 = /*MoveGen.*/ nextPieceSafe(pos, m.from, -d2); switch (d2) { case 8: case -8: case 1: case -1: // Rook direction if ((p2 == (wtm ? Piece.WQUEEN : Piece.BQUEEN)) || (p2 == (wtm ? Piece.WROOK : Piece.BROOK))) return true; break; case 9: case 7: case -9: case -7: // Bishop direction if ((p2 == (wtm ? Piece.WQUEEN : Piece.BQUEEN)) || (p2 == (wtm ? Piece.WBISHOP : Piece.BBISHOP))) return true; break; } } if ((m.promoteTo != Piece.EMPTY) && (d1 != 0) && (d1 == d2)) { switch (d1) { case 8: case -8: case 1: case -1: // Rook direction if ((p == Piece.WQUEEN) || (p == Piece.WROOK)) if ((d1 != 0) && (/*MoveGen.*/ nextPiece(pos, m.from, d1) == oKing)) return true; break; case 9: case 7: case -9: case -7: // Bishop direction if ((p == Piece.WQUEEN) || (p == Piece.WBISHOP)) { if ((d1 != 0) && (/*MoveGen.*/ nextPiece(pos, m.from, d1) == oKing)) return true; } break; } } if (p == Piece.WKING) { if (m.to - m.from == 2) { // O-O if (/*MoveGen.*/ nextPieceSafe(pos, m.from, -1) == oKing) return true; if (/*MoveGen.*/ nextPieceSafe(pos, m.from + 1, wtm ? 8 : -8) == oKing) return true; } else if (m.to - m.from == -2) { // O-O-O if (/*MoveGen.*/ nextPieceSafe(pos, m.from, 1) == oKing) return true; if (/*MoveGen.*/ nextPieceSafe(pos, m.from - 1, wtm ? 8 : -8) == oKing) return true; } } else if (p == Piece.WPAWN) { if (pos.getPiece(m.to) == Piece.EMPTY) { int dx = Position.getX(m.to) - Position.getX(m.from); if (dx != 0) { // en passant int epSq = m.from + dx; int d3 = BitBoard.getDirection(epSq, oKingSq); switch (d3) { case 9: case 7: case -9: case -7: if (/*MoveGen.*/ nextPiece(pos, epSq, d3) == oKing) { int p2 = /*MoveGen.*/ nextPieceSafe(pos, epSq, -d3); if ((p2 == (wtm ? Piece.WQUEEN : Piece.BQUEEN)) || (p2 == (wtm ? Piece.WBISHOP : Piece.BBISHOP))) return true; } break; case 1: if (/*MoveGen.*/ nextPiece(pos, Math.Max(epSq, m.from), d3) == oKing) { int p2 = /*MoveGen.*/ nextPieceSafe(pos, Math.Min(epSq, m.from), -d3); if ((p2 == (wtm ? Piece.WQUEEN : Piece.BQUEEN)) || (p2 == (wtm ? Piece.WROOK : Piece.BROOK))) return true; } break; case -1: if (/*MoveGen.*/ nextPiece(pos, Math.Min(epSq, m.from), d3) == oKing) { int p2 = /*MoveGen.*/ nextPieceSafe(pos, Math.Max(epSq, m.from), -d3); if ((p2 == (wtm ? Piece.WQUEEN : Piece.BQUEEN)) || (p2 == (wtm ? Piece.WROOK : Piece.BROOK))) return true; } break; } } } } return false; }
public MoveList pseudoLegalCaptures(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.blackBB; 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.blackBB; 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.blackBB; if (addMovesByMask(moveList, pos, sq, m)) return moveList; squares &= squares-1; } // Knight moves ulong knights = pos.pieceTypeBB[Piece.WKNIGHT]; while (knights != 0) { sq = BitBoard.numberOfTrailingZeros(knights); m = BitBoard.knightAttacks[sq] & pos.blackBB; if (addMovesByMask(moveList, pos, sq, m)) return moveList; knights &= knights-1; } // King moves sq = pos.getKingSq(true); m = BitBoard.kingAttacks[sq] & pos.blackBB; if (addMovesByMask(moveList, pos, sq, m)) return moveList; // Pawn moves ulong pawns = pos.pieceTypeBB[Piece.WPAWN]; m = (pawns << 8) & ~(pos.whiteBB | pos.blackBB); m &= BitBoard.maskRow8; if (addPawnMovesByMask(moveList, pos, m, -8, false)) return moveList; 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; } 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.whiteBB; 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.whiteBB; 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.whiteBB; if (addMovesByMask(moveList, pos, sq, m)) return moveList; squares &= squares-1; } // Knight moves ulong knights = pos.pieceTypeBB[Piece.BKNIGHT]; while (knights != 0) { sq = BitBoard.numberOfTrailingZeros(knights); m = BitBoard.knightAttacks[sq] & pos.whiteBB; if (addMovesByMask(moveList, pos, sq, m)) return moveList; knights &= knights-1; } // King moves sq = pos.getKingSq(false); m = BitBoard.kingAttacks[sq] & pos.whiteBB; if (addMovesByMask(moveList, pos, sq, m)) return moveList; // Pawn moves ulong pawns = pos.pieceTypeBB[Piece.BPAWN]; m = (pawns >> 8) & ~(pos.whiteBB | pos.blackBB); m &= BitBoard.maskRow1; if (addPawnMovesByMask(moveList, pos, m, 8, false)) return moveList; 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; } return moveList; }
/** * Generate and return a list of pseudo-legal check evasion moves. * Pseudo-legal means that the moves doesn't necessarily defend from check threats. */ public MoveList checkEvasions(Position pos) { MoveList moveList = getMoveListObj(); ulong occupied = pos.whiteBB | pos.blackBB; if (pos.whiteMove) { int sq = 0; ulong m = 0; ulong kingThreats = pos.pieceTypeBB[Piece.BKNIGHT] & BitBoard.knightAttacks[pos.wKingSq]; ulong rookPieces = pos.pieceTypeBB[Piece.BROOK] | pos.pieceTypeBB[Piece.BQUEEN]; if (rookPieces != 0) kingThreats |= rookPieces & BitBoard.rookAttacks(pos.wKingSq, occupied); ulong bishPieces = pos.pieceTypeBB[Piece.BBISHOP] | pos.pieceTypeBB[Piece.BQUEEN]; if (bishPieces != 0) kingThreats |= bishPieces & BitBoard.bishopAttacks(pos.wKingSq, occupied); kingThreats |= pos.pieceTypeBB[Piece.BPAWN] & BitBoard.wPawnAttacks[pos.wKingSq]; ulong validTargets = 0; if ((kingThreats != 0) && ((kingThreats & (kingThreats-1)) == 0)) { // Exactly one attacking piece int threatSq = BitBoard.numberOfTrailingZeros(kingThreats); validTargets = kingThreats | BitBoard.squaresBetween[pos.wKingSq][threatSq]; } validTargets |= pos.pieceTypeBB[Piece.BKING]; // 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 & validTargets; 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 & validTargets; 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 & validTargets; 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; } // Knight moves ulong knights = pos.pieceTypeBB[Piece.WKNIGHT]; while (knights != 0) { sq = BitBoard.numberOfTrailingZeros(knights); m = BitBoard.knightAttacks[sq] & ~pos.whiteBB & validTargets; 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 & validTargets, -8, true)) return moveList; m = ((m & BitBoard.maskRow3) << 8) & ~occupied; addPawnDoubleMovesByMask(moveList, pos, m & validTargets, -16); int epSquare = pos.getEpSquare(); ulong epMask = (epSquare >= 0) ? (1UL << epSquare) : 0L; m = (pawns << 7) & BitBoard.maskAToGFiles & ((pos.blackBB & validTargets) | epMask); if (addPawnMovesByMask(moveList, pos, m, -7, true)) return moveList; m = (pawns << 9) & BitBoard.maskBToHFiles & ((pos.blackBB & validTargets) | epMask); if (addPawnMovesByMask(moveList, pos, m, -9, true)) return moveList; } else { int sq = 0; ulong m = 0; ulong kingThreats = pos.pieceTypeBB[Piece.WKNIGHT] & BitBoard.knightAttacks[pos.bKingSq]; ulong rookPieces = pos.pieceTypeBB[Piece.WROOK] | pos.pieceTypeBB[Piece.WQUEEN]; if (rookPieces != 0) kingThreats |= rookPieces & BitBoard.rookAttacks(pos.bKingSq, occupied); ulong bishPieces = pos.pieceTypeBB[Piece.WBISHOP] | pos.pieceTypeBB[Piece.WQUEEN]; if (bishPieces != 0) kingThreats |= bishPieces & BitBoard.bishopAttacks(pos.bKingSq, occupied); kingThreats |= pos.pieceTypeBB[Piece.WPAWN] & BitBoard.bPawnAttacks[pos.bKingSq]; ulong validTargets = 0; if ((kingThreats != 0) && ((kingThreats & (kingThreats-1)) == 0)) { // Exactly one attacking piece int threatSq = BitBoard.numberOfTrailingZeros(kingThreats); validTargets = kingThreats | BitBoard.squaresBetween[pos.bKingSq][threatSq]; } validTargets |= pos.pieceTypeBB[Piece.WKING]; // 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 & validTargets; 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 & validTargets; 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 & validTargets; 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; } // Knight moves ulong knights = pos.pieceTypeBB[Piece.BKNIGHT]; while (knights != 0) { sq = BitBoard.numberOfTrailingZeros(knights); m = BitBoard.knightAttacks[sq] & ~pos.blackBB & validTargets; 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 & validTargets, 8, true)) return moveList; m = ((m & BitBoard.maskRow6) >> 8) & ~occupied; addPawnDoubleMovesByMask(moveList, pos, m & validTargets, 16); int epSquare = pos.getEpSquare(); ulong epMask = (epSquare >= 0) ? (1UL << epSquare) : 0L; m = (pawns >> 9) & BitBoard.maskAToGFiles & ((pos.whiteBB & validTargets) | epMask); if (addPawnMovesByMask(moveList, pos, m, 9, true)) return moveList; m = (pawns >> 7) & BitBoard.maskBToHFiles & ((pos.whiteBB & validTargets) | epMask); if (addPawnMovesByMask(moveList, pos, m, 7, true)) return moveList; } return moveList; }
/** * Return true if the side to move is in check. */ public static bool inCheck(Position pos) { int kingSq = pos.getKingSq(pos.whiteMove); return sqAttacked(pos, kingSq); }