MoveGen { public final MoveList checkEvasions(Position pos) { MoveList moveList = getMoveListObj(); final long occupied = pos.whiteBB | pos.blackBB; if (pos.whiteMove) { long kingThreats = pos.pieceTypeBB[Piece.BKNIGHT] & BitBoard.knightAttacks[pos.wKingSq]; long rookPieces = pos.pieceTypeBB[Piece.BROOK] | pos.pieceTypeBB[Piece.BQUEEN]; if (rookPieces != 0) kingThreats |= rookPieces & BitBoard.rookAttacks(pos.wKingSq, occupied); long 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]; long validTargets = 0; if ((kingThreats != 0) && ((kingThreats & (kingThreats-1)) == 0)) { int threatSq = BitBoard.numberOfTrailingZeros(kingThreats); validTargets = kingThreats | BitBoard.squaresBetween[pos.wKingSq][threatSq]; } validTargets |= pos.pieceTypeBB[Piece.BKING]; long squares = pos.pieceTypeBB[Piece.WQUEEN]; while (squares != 0) { int sq = BitBoard.numberOfTrailingZeros(squares); long m = (BitBoard.rookAttacks(sq, occupied) | BitBoard.bishopAttacks(sq, occupied)) & ~pos.whiteBB & validTargets; if (addMovesByMask(moveList, pos, sq, m)) return moveList; squares &= squares-1; } squares = pos.pieceTypeBB[Piece.WROOK]; while (squares != 0) { int sq = BitBoard.numberOfTrailingZeros(squares); long m = BitBoard.rookAttacks(sq, occupied) & ~pos.whiteBB & validTargets; if (addMovesByMask(moveList, pos, sq, m)) return moveList; squares &= squares-1; } squares = pos.pieceTypeBB[Piece.WBISHOP]; while (squares != 0) { int sq = BitBoard.numberOfTrailingZeros(squares); long m = BitBoard.bishopAttacks(sq, occupied) & ~pos.whiteBB & validTargets; if (addMovesByMask(moveList, pos, sq, m)) return moveList; squares &= squares-1; } { int sq = pos.getKingSq(true); long m = BitBoard.kingAttacks[sq] & ~pos.whiteBB; if (addMovesByMask(moveList, pos, sq, m)) return moveList; } long knights = pos.pieceTypeBB[Piece.WKNIGHT]; while (knights != 0) { int sq = BitBoard.numberOfTrailingZeros(knights); long m = BitBoard.knightAttacks[sq] & ~pos.whiteBB & validTargets; if (addMovesByMask(moveList, pos, sq, m)) return moveList; knights &= knights-1; } long pawns = pos.pieceTypeBB[Piece.WPAWN]; long 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(); long epMask = (epSquare >= 0) ? (1L << 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 { long kingThreats = pos.pieceTypeBB[Piece.WKNIGHT] & BitBoard.knightAttacks[pos.bKingSq]; long rookPieces = pos.pieceTypeBB[Piece.WROOK] | pos.pieceTypeBB[Piece.WQUEEN]; if (rookPieces != 0) kingThreats |= rookPieces & BitBoard.rookAttacks(pos.bKingSq, occupied); long 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]; long validTargets = 0; if ((kingThreats != 0) && ((kingThreats & (kingThreats-1)) == 0)) { int threatSq = BitBoard.numberOfTrailingZeros(kingThreats); validTargets = kingThreats | BitBoard.squaresBetween[pos.bKingSq][threatSq]; } validTargets |= pos.pieceTypeBB[Piece.WKING]; long squares = pos.pieceTypeBB[Piece.BQUEEN]; while (squares != 0) { int sq = BitBoard.numberOfTrailingZeros(squares); long m = (BitBoard.rookAttacks(sq, occupied) | BitBoard.bishopAttacks(sq, occupied)) & ~pos.blackBB & validTargets; if (addMovesByMask(moveList, pos, sq, m)) return moveList; squares &= squares-1; } squares = pos.pieceTypeBB[Piece.BROOK]; while (squares != 0) { int sq = BitBoard.numberOfTrailingZeros(squares); long m = BitBoard.rookAttacks(sq, occupied) & ~pos.blackBB & validTargets; if (addMovesByMask(moveList, pos, sq, m)) return moveList; squares &= squares-1; } squares = pos.pieceTypeBB[Piece.BBISHOP]; while (squares != 0) { int sq = BitBoard.numberOfTrailingZeros(squares); long m = BitBoard.bishopAttacks(sq, occupied) & ~pos.blackBB & validTargets; if (addMovesByMask(moveList, pos, sq, m)) return moveList; squares &= squares-1; } { int sq = pos.getKingSq(false); long m = BitBoard.kingAttacks[sq] & ~pos.blackBB; if (addMovesByMask(moveList, pos, sq, m)) return moveList; } long knights = pos.pieceTypeBB[Piece.BKNIGHT]; while (knights != 0) { int sq = BitBoard.numberOfTrailingZeros(knights); long m = BitBoard.knightAttacks[sq] & ~pos.blackBB & validTargets; if (addMovesByMask(moveList, pos, sq, m)) return moveList; knights &= knights-1; } long pawns = pos.pieceTypeBB[Piece.BPAWN]; long 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(); long epMask = (epSquare >= 0) ? (1L << 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; }  final MoveList pseudoLegalMoves(Position pos); final MoveList checkEvasions(Position pos); final MoveList pseudoLegalCapturesAndChecks(Position pos); final MoveList pseudoLegalCaptures(Position pos); static boolean inCheck(Position pos); static boolean givesCheck(Position pos, Move m); static boolean canTakeKing(Position pos); static boolean sqAttacked(Position pos, int sq); static void removeIllegal(Position pos, MoveList moveList); final void returnMoveList(MoveList moveList);  }
@Test public void testCheckEvasions() throws ChessParseError { System.out.println("checkEvasions"); Position pos = TextIO.readFEN("n7/8/8/7k/5pP1/5K2/8/8 b - g3 0 1"); getMoveList(pos, false); pos = TextIO.readFEN("rn1qkbnr/pppB1ppp/3p4/4p3/4P3/5N2/PPPP1PPP/RNBQK2R b KQkq - 0 1"); getMoveList(pos, false); pos = TextIO.readFEN("r1bq2r1/pp3pbk/2p1p1P1/8/3P4/2PB1N2/PP3PPR/2KR4 b - - 0 1"); UndoInfo ui = new UndoInfo(); pos.makeMove(TextIO.uciStringToMove("g7h6"), ui); getMoveList(pos, false); List<String> evList = getCheckEvasions(pos, false); assertTrue(evList.contains("g6h7")); pos = TextIO.readFEN("1R6/1brk2p1/2P1p2p/p3Pp2/P7/6P1/1P4P1/2R3K1 b - - 0 1"); getMoveList(pos, false); evList = getCheckEvasions(pos, false); assertTrue(evList.contains("b7c6")); }