mirror of
https://github.com/peterosterlund2/droidfish.git
synced 2025-05-06 18:54:41 +02:00
1074 lines
47 KiB
Java
1074 lines
47 KiB
Java
/*
|
|
CuckooChess - A java chess program.
|
|
Copyright (C) 2011 Peter Österlund, peterosterlund2@gmail.com
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
package chess;
|
|
|
|
import java.util.List;
|
|
|
|
/**
|
|
*
|
|
* @author petero
|
|
*/
|
|
public final class MoveGen {
|
|
static final MoveGen instance;
|
|
static {
|
|
instance = new MoveGen();
|
|
}
|
|
|
|
public final static class MoveList {
|
|
public final Move[] m;
|
|
public int size;
|
|
MoveList() {
|
|
m = new Move[MAX_MOVES];
|
|
this.size = 0;
|
|
}
|
|
public final void filter(List<Move> searchMoves) {
|
|
int used = 0;
|
|
for (int i = 0; i < size; i++)
|
|
if (searchMoves.contains(m[i]))
|
|
m[used++] = m[i];
|
|
size = used;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Generate and return a list of pseudo-legal moves.
|
|
* Pseudo-legal means that the moves doesn't necessarily defend from check threats.
|
|
*/
|
|
public final MoveList pseudoLegalMoves(Position pos) {
|
|
MoveList moveList = getMoveListObj();
|
|
final long occupied = pos.whiteBB | pos.blackBB;
|
|
if (pos.whiteMove) {
|
|
// Queen moves
|
|
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;
|
|
if (addMovesByMask(moveList, pos, sq, m)) return moveList;
|
|
squares &= squares-1;
|
|
}
|
|
|
|
// Rook moves
|
|
squares = pos.pieceTypeBB[Piece.WROOK];
|
|
while (squares != 0) {
|
|
int sq = BitBoard.numberOfTrailingZeros(squares);
|
|
long 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) {
|
|
int sq = BitBoard.numberOfTrailingZeros(squares);
|
|
long m = BitBoard.bishopAttacks(sq, occupied) & ~pos.whiteBB;
|
|
if (addMovesByMask(moveList, pos, sq, m)) return moveList;
|
|
squares &= squares-1;
|
|
}
|
|
|
|
// King moves
|
|
{
|
|
int sq = pos.getKingSq(true);
|
|
long m = BitBoard.kingAttacks[sq] & ~pos.whiteBB;
|
|
if (addMovesByMask(moveList, pos, sq, m)) return moveList;
|
|
final int k0 = 4;
|
|
if (sq == k0) {
|
|
final long OO_SQ = 0x60L;
|
|
final long 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
|
|
long knights = pos.pieceTypeBB[Piece.WKNIGHT];
|
|
while (knights != 0) {
|
|
int sq = BitBoard.numberOfTrailingZeros(knights);
|
|
long m = BitBoard.knightAttacks[sq] & ~pos.whiteBB;
|
|
if (addMovesByMask(moveList, pos, sq, m)) return moveList;
|
|
knights &= knights-1;
|
|
}
|
|
|
|
// Pawn moves
|
|
long pawns = pos.pieceTypeBB[Piece.WPAWN];
|
|
long 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();
|
|
long epMask = (epSquare >= 0) ? (1L << 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 {
|
|
// Queen moves
|
|
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;
|
|
if (addMovesByMask(moveList, pos, sq, m)) return moveList;
|
|
squares &= squares-1;
|
|
}
|
|
|
|
// Rook moves
|
|
squares = pos.pieceTypeBB[Piece.BROOK];
|
|
while (squares != 0) {
|
|
int sq = BitBoard.numberOfTrailingZeros(squares);
|
|
long 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) {
|
|
int sq = BitBoard.numberOfTrailingZeros(squares);
|
|
long m = BitBoard.bishopAttacks(sq, occupied) & ~pos.blackBB;
|
|
if (addMovesByMask(moveList, pos, sq, m)) return moveList;
|
|
squares &= squares-1;
|
|
}
|
|
|
|
// King moves
|
|
{
|
|
int sq = pos.getKingSq(false);
|
|
long m = BitBoard.kingAttacks[sq] & ~pos.blackBB;
|
|
if (addMovesByMask(moveList, pos, sq, m)) return moveList;
|
|
final int k0 = 60;
|
|
if (sq == k0) {
|
|
final long OO_SQ = 0x6000000000000000L;
|
|
final long 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
|
|
long knights = pos.pieceTypeBB[Piece.BKNIGHT];
|
|
while (knights != 0) {
|
|
int sq = BitBoard.numberOfTrailingZeros(knights);
|
|
long m = BitBoard.knightAttacks[sq] & ~pos.blackBB;
|
|
if (addMovesByMask(moveList, pos, sq, m)) return moveList;
|
|
knights &= knights-1;
|
|
}
|
|
|
|
// Pawn moves
|
|
long pawns = pos.pieceTypeBB[Piece.BPAWN];
|
|
long 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();
|
|
long epMask = (epSquare >= 0) ? (1L << 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;
|
|
}
|
|
|
|
/**
|
|
* 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 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)) { // Exactly one attacking piece
|
|
int threatSq = BitBoard.numberOfTrailingZeros(kingThreats);
|
|
validTargets = kingThreats | BitBoard.squaresBetween[pos.wKingSq][threatSq];
|
|
}
|
|
validTargets |= pos.pieceTypeBB[Piece.BKING];
|
|
// Queen moves
|
|
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;
|
|
}
|
|
|
|
// Rook moves
|
|
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;
|
|
}
|
|
|
|
// Bishop moves
|
|
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;
|
|
}
|
|
|
|
// King moves
|
|
{
|
|
int sq = pos.getKingSq(true);
|
|
long m = BitBoard.kingAttacks[sq] & ~pos.whiteBB;
|
|
if (addMovesByMask(moveList, pos, sq, m)) return moveList;
|
|
}
|
|
|
|
// Knight moves
|
|
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;
|
|
}
|
|
|
|
// Pawn moves
|
|
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)) { // Exactly one attacking piece
|
|
int threatSq = BitBoard.numberOfTrailingZeros(kingThreats);
|
|
validTargets = kingThreats | BitBoard.squaresBetween[pos.bKingSq][threatSq];
|
|
}
|
|
validTargets |= pos.pieceTypeBB[Piece.WKING];
|
|
// Queen moves
|
|
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;
|
|
}
|
|
|
|
// Rook moves
|
|
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;
|
|
}
|
|
|
|
// Bishop moves
|
|
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;
|
|
}
|
|
|
|
// King moves
|
|
{
|
|
int sq = pos.getKingSq(false);
|
|
long m = BitBoard.kingAttacks[sq] & ~pos.blackBB;
|
|
if (addMovesByMask(moveList, pos, sq, m)) return moveList;
|
|
}
|
|
|
|
// Knight moves
|
|
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;
|
|
}
|
|
|
|
// Pawn moves
|
|
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;
|
|
}
|
|
|
|
/* Extra debug checks
|
|
{
|
|
ArrayList<Move> allMoves = pseudoLegalMoves(pos);
|
|
allMoves = MoveGen.removeIllegal(pos, allMoves);
|
|
HashSet<String> evMoves = new HashSet<String>();
|
|
for (Move m : moveList)
|
|
evMoves.add(TextIO.moveToUCIString(m));
|
|
for (Move m : allMoves)
|
|
if (!evMoves.contains(TextIO.moveToUCIString(m)))
|
|
throw new RuntimeException();
|
|
}
|
|
*/
|
|
|
|
return moveList;
|
|
}
|
|
|
|
/** Generate captures, checks, and possibly some other moves that are too hard to filter out. */
|
|
public final MoveList pseudoLegalCapturesAndChecks(Position pos) {
|
|
MoveList moveList = getMoveListObj();
|
|
long occupied = pos.whiteBB | pos.blackBB;
|
|
if (pos.whiteMove) {
|
|
int bKingSq = pos.getKingSq(false);
|
|
long discovered = 0; // Squares that could generate discovered checks
|
|
long kRookAtk = BitBoard.rookAttacks(bKingSq, occupied);
|
|
if ((BitBoard.rookAttacks(bKingSq, occupied & ~kRookAtk) &
|
|
(pos.pieceTypeBB[Piece.WQUEEN] | pos.pieceTypeBB[Piece.WROOK])) != 0)
|
|
discovered |= kRookAtk;
|
|
long kBishAtk = BitBoard.bishopAttacks(bKingSq, occupied);
|
|
if ((BitBoard.bishopAttacks(bKingSq, occupied & ~kBishAtk) &
|
|
(pos.pieceTypeBB[Piece.WQUEEN] | pos.pieceTypeBB[Piece.WBISHOP])) != 0)
|
|
discovered |= kBishAtk;
|
|
|
|
// Queen moves
|
|
long squares = pos.pieceTypeBB[Piece.WQUEEN];
|
|
while (squares != 0) {
|
|
int sq = BitBoard.numberOfTrailingZeros(squares);
|
|
long m = (BitBoard.rookAttacks(sq, occupied) | BitBoard.bishopAttacks(sq, occupied));
|
|
if ((discovered & (1L<<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) {
|
|
int sq = BitBoard.numberOfTrailingZeros(squares);
|
|
long m = BitBoard.rookAttacks(sq, occupied);
|
|
if ((discovered & (1L<<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) {
|
|
int sq = BitBoard.numberOfTrailingZeros(squares);
|
|
long m = BitBoard.bishopAttacks(sq, occupied);
|
|
if ((discovered & (1L<<sq)) == 0) m &= (pos.blackBB | kBishAtk);
|
|
m &= ~pos.whiteBB;
|
|
if (addMovesByMask(moveList, pos, sq, m)) return moveList;
|
|
squares &= squares-1;
|
|
}
|
|
|
|
// King moves
|
|
{
|
|
int sq = pos.getKingSq(true);
|
|
long m = BitBoard.kingAttacks[sq];
|
|
m &= ((discovered & (1L<<sq)) == 0) ? pos.blackBB : ~pos.whiteBB;
|
|
if (addMovesByMask(moveList, pos, sq, m)) return moveList;
|
|
final int k0 = 4;
|
|
if (sq == k0) {
|
|
final long OO_SQ = 0x60L;
|
|
final long 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
|
|
long knights = pos.pieceTypeBB[Piece.WKNIGHT];
|
|
long kKnightAtk = BitBoard.knightAttacks[bKingSq];
|
|
while (knights != 0) {
|
|
int sq = BitBoard.numberOfTrailingZeros(knights);
|
|
long m = BitBoard.knightAttacks[sq] & ~pos.whiteBB;
|
|
if ((discovered & (1L<<sq)) == 0) m &= (pos.blackBB | kKnightAtk);
|
|
m &= ~pos.whiteBB;
|
|
if (addMovesByMask(moveList, pos, sq, m)) return moveList;
|
|
knights &= knights-1;
|
|
}
|
|
|
|
// Pawn moves
|
|
// Captures
|
|
long pawns = pos.pieceTypeBB[Piece.WPAWN];
|
|
int epSquare = pos.getEpSquare();
|
|
long epMask = (epSquare >= 0) ? (1L << epSquare) : 0L;
|
|
long 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
|
|
long 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 wKingSq = pos.getKingSq(true);
|
|
long discovered = 0; // Squares that could generate discovered checks
|
|
long kRookAtk = BitBoard.rookAttacks(wKingSq, occupied);
|
|
if ((BitBoard.rookAttacks(wKingSq, occupied & ~kRookAtk) &
|
|
(pos.pieceTypeBB[Piece.BQUEEN] | pos.pieceTypeBB[Piece.BROOK])) != 0)
|
|
discovered |= kRookAtk;
|
|
long kBishAtk = BitBoard.bishopAttacks(wKingSq, occupied);
|
|
if ((BitBoard.bishopAttacks(wKingSq, occupied & ~kBishAtk) &
|
|
(pos.pieceTypeBB[Piece.BQUEEN] | pos.pieceTypeBB[Piece.BBISHOP])) != 0)
|
|
discovered |= kBishAtk;
|
|
|
|
// Queen moves
|
|
long squares = pos.pieceTypeBB[Piece.BQUEEN];
|
|
while (squares != 0) {
|
|
int sq = BitBoard.numberOfTrailingZeros(squares);
|
|
long m = (BitBoard.rookAttacks(sq, occupied) | BitBoard.bishopAttacks(sq, occupied));
|
|
if ((discovered & (1L<<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) {
|
|
int sq = BitBoard.numberOfTrailingZeros(squares);
|
|
long m = BitBoard.rookAttacks(sq, occupied);
|
|
if ((discovered & (1L<<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) {
|
|
int sq = BitBoard.numberOfTrailingZeros(squares);
|
|
long m = BitBoard.bishopAttacks(sq, occupied);
|
|
if ((discovered & (1L<<sq)) == 0) m &= pos.whiteBB | kBishAtk;
|
|
m &= ~pos.blackBB;
|
|
if (addMovesByMask(moveList, pos, sq, m)) return moveList;
|
|
squares &= squares-1;
|
|
}
|
|
|
|
// King moves
|
|
{
|
|
int sq = pos.getKingSq(false);
|
|
long m = BitBoard.kingAttacks[sq];
|
|
m &= ((discovered & (1L<<sq)) == 0) ? pos.whiteBB : ~pos.blackBB;
|
|
if (addMovesByMask(moveList, pos, sq, m)) return moveList;
|
|
final int k0 = 60;
|
|
if (sq == k0) {
|
|
final long OO_SQ = 0x6000000000000000L;
|
|
final long 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
|
|
long knights = pos.pieceTypeBB[Piece.BKNIGHT];
|
|
long kKnightAtk = BitBoard.knightAttacks[wKingSq];
|
|
while (knights != 0) {
|
|
int sq = BitBoard.numberOfTrailingZeros(knights);
|
|
long m = BitBoard.knightAttacks[sq] & ~pos.blackBB;
|
|
if ((discovered & (1L<<sq)) == 0) m &= pos.whiteBB | kKnightAtk;
|
|
m &= ~pos.blackBB;
|
|
if (addMovesByMask(moveList, pos, sq, m)) return moveList;
|
|
knights &= knights-1;
|
|
}
|
|
|
|
// Pawn moves
|
|
// Captures
|
|
long pawns = pos.pieceTypeBB[Piece.BPAWN];
|
|
int epSquare = pos.getEpSquare();
|
|
long epMask = (epSquare >= 0) ? (1L << epSquare) : 0L;
|
|
long 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
|
|
long 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;
|
|
}
|
|
|
|
public final MoveList pseudoLegalCaptures(Position pos) {
|
|
MoveList moveList = getMoveListObj();
|
|
long occupied = pos.whiteBB | pos.blackBB;
|
|
if (pos.whiteMove) {
|
|
// Queen moves
|
|
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.blackBB;
|
|
if (addMovesByMask(moveList, pos, sq, m)) return moveList;
|
|
squares &= squares-1;
|
|
}
|
|
|
|
// Rook moves
|
|
squares = pos.pieceTypeBB[Piece.WROOK];
|
|
while (squares != 0) {
|
|
int sq = BitBoard.numberOfTrailingZeros(squares);
|
|
long 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) {
|
|
int sq = BitBoard.numberOfTrailingZeros(squares);
|
|
long m = BitBoard.bishopAttacks(sq, occupied) & pos.blackBB;
|
|
if (addMovesByMask(moveList, pos, sq, m)) return moveList;
|
|
squares &= squares-1;
|
|
}
|
|
|
|
// Knight moves
|
|
long knights = pos.pieceTypeBB[Piece.WKNIGHT];
|
|
while (knights != 0) {
|
|
int sq = BitBoard.numberOfTrailingZeros(knights);
|
|
long m = BitBoard.knightAttacks[sq] & pos.blackBB;
|
|
if (addMovesByMask(moveList, pos, sq, m)) return moveList;
|
|
knights &= knights-1;
|
|
}
|
|
|
|
// King moves
|
|
int sq = pos.getKingSq(true);
|
|
long m = BitBoard.kingAttacks[sq] & pos.blackBB;
|
|
if (addMovesByMask(moveList, pos, sq, m)) return moveList;
|
|
|
|
// Pawn moves
|
|
long 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();
|
|
long epMask = (epSquare >= 0) ? (1L << 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 {
|
|
// Queen moves
|
|
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.whiteBB;
|
|
if (addMovesByMask(moveList, pos, sq, m)) return moveList;
|
|
squares &= squares-1;
|
|
}
|
|
|
|
// Rook moves
|
|
squares = pos.pieceTypeBB[Piece.BROOK];
|
|
while (squares != 0) {
|
|
int sq = BitBoard.numberOfTrailingZeros(squares);
|
|
long 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) {
|
|
int sq = BitBoard.numberOfTrailingZeros(squares);
|
|
long m = BitBoard.bishopAttacks(sq, occupied) & pos.whiteBB;
|
|
if (addMovesByMask(moveList, pos, sq, m)) return moveList;
|
|
squares &= squares-1;
|
|
}
|
|
|
|
// Knight moves
|
|
long knights = pos.pieceTypeBB[Piece.BKNIGHT];
|
|
while (knights != 0) {
|
|
int sq = BitBoard.numberOfTrailingZeros(knights);
|
|
long m = BitBoard.knightAttacks[sq] & pos.whiteBB;
|
|
if (addMovesByMask(moveList, pos, sq, m)) return moveList;
|
|
knights &= knights-1;
|
|
}
|
|
|
|
// King moves
|
|
int sq = pos.getKingSq(false);
|
|
long m = BitBoard.kingAttacks[sq] & pos.whiteBB;
|
|
if (addMovesByMask(moveList, pos, sq, m)) return moveList;
|
|
|
|
// Pawn moves
|
|
long 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();
|
|
long epMask = (epSquare >= 0) ? (1L << 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;
|
|
}
|
|
|
|
/**
|
|
* Return true if the side to move is in check.
|
|
*/
|
|
public static final boolean inCheck(Position pos) {
|
|
int kingSq = pos.getKingSq(pos.whiteMove);
|
|
return sqAttacked(pos, kingSq);
|
|
}
|
|
|
|
/**
|
|
* Return the next piece in a given direction, starting from sq.
|
|
*/
|
|
private static final int nextPiece(Position pos, int sq, int delta) {
|
|
while (true) {
|
|
sq += delta;
|
|
int p = pos.getPiece(sq);
|
|
if (p != Piece.EMPTY)
|
|
return p;
|
|
}
|
|
}
|
|
|
|
/** Like nextPiece(), but handles board edges. */
|
|
private static final int nextPieceSafe(Position pos, int sq, int delta) {
|
|
int dx = 0, dy = 0;
|
|
switch (delta) {
|
|
case 1: dx=1; dy=0; break;
|
|
case 9: dx=1; dy=1; break;
|
|
case 8: dx=0; dy=1; break;
|
|
case 7: dx=-1; dy=1; break;
|
|
case -1: dx=-1; dy=0; break;
|
|
case -9: dx=-1; dy=-1; break;
|
|
case -8: dx=0; dy=-1; break;
|
|
case -7: dx=1; dy=-1; break;
|
|
}
|
|
int x = Position.getX(sq);
|
|
int y = Position.getY(sq);
|
|
while (true) {
|
|
x += dx;
|
|
y += dy;
|
|
if ((x < 0) || (x > 7) || (y < 0) || (y > 7)) {
|
|
return Piece.EMPTY;
|
|
}
|
|
int p = pos.getPiece(Position.getSquare(x, y));
|
|
if (p != Piece.EMPTY)
|
|
return p;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Return true if making a move delivers check to the opponent
|
|
*/
|
|
public static final boolean givesCheck(Position pos, Move m) {
|
|
boolean 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;
|
|
}
|
|
}
|
|
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;
|
|
}
|
|
|
|
/**
|
|
* Return true if the side to move can take the opponents king.
|
|
*/
|
|
public static final boolean canTakeKing(Position pos) {
|
|
pos.setWhiteMove(!pos.whiteMove);
|
|
boolean ret = inCheck(pos);
|
|
pos.setWhiteMove(!pos.whiteMove);
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* Return true if a square is attacked by the opposite side.
|
|
*/
|
|
public static final boolean sqAttacked(Position pos, int sq) {
|
|
if (pos.whiteMove) {
|
|
if ((BitBoard.knightAttacks[sq] & pos.pieceTypeBB[Piece.BKNIGHT]) != 0)
|
|
return true;
|
|
if ((BitBoard.kingAttacks[sq] & pos.pieceTypeBB[Piece.BKING]) != 0)
|
|
return true;
|
|
if ((BitBoard.wPawnAttacks[sq] & pos.pieceTypeBB[Piece.BPAWN]) != 0)
|
|
return true;
|
|
long occupied = pos.whiteBB | pos.blackBB;
|
|
long bbQueen = pos.pieceTypeBB[Piece.BQUEEN];
|
|
if ((BitBoard.bishopAttacks(sq, occupied) & (pos.pieceTypeBB[Piece.BBISHOP] | bbQueen)) != 0)
|
|
return true;
|
|
if ((BitBoard.rookAttacks(sq, occupied) & (pos.pieceTypeBB[Piece.BROOK] | bbQueen)) != 0)
|
|
return true;
|
|
} else {
|
|
if ((BitBoard.knightAttacks[sq] & pos.pieceTypeBB[Piece.WKNIGHT]) != 0)
|
|
return true;
|
|
if ((BitBoard.kingAttacks[sq] & pos.pieceTypeBB[Piece.WKING]) != 0)
|
|
return true;
|
|
if ((BitBoard.bPawnAttacks[sq] & pos.pieceTypeBB[Piece.WPAWN]) != 0)
|
|
return true;
|
|
long occupied = pos.whiteBB | pos.blackBB;
|
|
long bbQueen = pos.pieceTypeBB[Piece.WQUEEN];
|
|
if ((BitBoard.bishopAttacks(sq, occupied) & (pos.pieceTypeBB[Piece.WBISHOP] | bbQueen)) != 0)
|
|
return true;
|
|
if ((BitBoard.rookAttacks(sq, occupied) & (pos.pieceTypeBB[Piece.WROOK] | bbQueen)) != 0)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Remove all illegal moves from moveList.
|
|
* "moveList" is assumed to be a list of pseudo-legal moves.
|
|
* This function removes the moves that don't defend from check threats.
|
|
*/
|
|
public static final void removeIllegal(Position pos, MoveList moveList) {
|
|
int length = 0;
|
|
UndoInfo ui = new UndoInfo();
|
|
|
|
boolean isInCheck = inCheck(pos);
|
|
final long occupied = pos.whiteBB | pos.blackBB;
|
|
int kSq = pos.getKingSq(pos.whiteMove);
|
|
long kingAtks = BitBoard.rookAttacks(kSq, occupied) | BitBoard.bishopAttacks(kSq, occupied);
|
|
int epSquare = pos.getEpSquare();
|
|
if (isInCheck) {
|
|
kingAtks |= pos.pieceTypeBB[pos.whiteMove ? Piece.BKNIGHT : Piece.WKNIGHT];
|
|
for (int mi = 0; mi < moveList.size; mi++) {
|
|
Move m = moveList.m[mi];
|
|
boolean legal;
|
|
if ((m.from != kSq) && ((kingAtks & (1L<<m.to)) == 0) && (m.to != epSquare)) {
|
|
legal = false;
|
|
} else {
|
|
pos.makeMove(m, ui);
|
|
pos.setWhiteMove(!pos.whiteMove);
|
|
legal = !inCheck(pos);
|
|
pos.setWhiteMove(!pos.whiteMove);
|
|
pos.unMakeMove(m, ui);
|
|
}
|
|
if (legal)
|
|
moveList.m[length++].copyFrom(m);
|
|
}
|
|
} else {
|
|
for (int mi = 0; mi < moveList.size; mi++) {
|
|
Move m = moveList.m[mi];
|
|
boolean legal;
|
|
if ((m.from != kSq) && ((kingAtks & (1L<<m.from)) == 0) && (m.to != epSquare)) {
|
|
legal = true;
|
|
} else {
|
|
pos.makeMove(m, ui);
|
|
pos.setWhiteMove(!pos.whiteMove);
|
|
legal = !inCheck(pos);
|
|
pos.setWhiteMove(!pos.whiteMove);
|
|
pos.unMakeMove(m, ui);
|
|
}
|
|
if (legal)
|
|
moveList.m[length++].copyFrom(m);
|
|
}
|
|
}
|
|
moveList.size = length;
|
|
}
|
|
|
|
private final static boolean addPawnMovesByMask(MoveList moveList, Position pos, long mask,
|
|
int delta, boolean allPromotions) {
|
|
if (mask == 0)
|
|
return false;
|
|
long oKingMask = pos.pieceTypeBB[pos.whiteMove ? Piece.BKING : Piece.WKING];
|
|
if ((mask & oKingMask) != 0) {
|
|
int sq = BitBoard.numberOfTrailingZeros(mask & oKingMask);
|
|
moveList.size = 0;
|
|
setMove(moveList, sq + delta, sq, Piece.EMPTY);
|
|
return true;
|
|
}
|
|
long promMask = mask & BitBoard.maskRow1Row8;
|
|
mask &= ~promMask;
|
|
while (promMask != 0) {
|
|
int sq = BitBoard.numberOfTrailingZeros(promMask);
|
|
int sq0 = sq + delta;
|
|
if (sq >= 56) { // White promotion
|
|
setMove(moveList, sq0, sq, Piece.WQUEEN);
|
|
setMove(moveList, sq0, sq, Piece.WKNIGHT);
|
|
if (allPromotions) {
|
|
setMove(moveList, sq0, sq, Piece.WROOK);
|
|
setMove(moveList, sq0, sq, Piece.WBISHOP);
|
|
}
|
|
} else { // Black promotion
|
|
setMove(moveList, sq0, sq, Piece.BQUEEN);
|
|
setMove(moveList, sq0, sq, Piece.BKNIGHT);
|
|
if (allPromotions) {
|
|
setMove(moveList, sq0, sq, Piece.BROOK);
|
|
setMove(moveList, sq0, sq, Piece.BBISHOP);
|
|
}
|
|
}
|
|
promMask &= (promMask - 1);
|
|
}
|
|
while (mask != 0) {
|
|
int sq = BitBoard.numberOfTrailingZeros(mask);
|
|
setMove(moveList, sq + delta, sq, Piece.EMPTY);
|
|
mask &= (mask - 1);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private final static void addPawnDoubleMovesByMask(MoveList moveList, Position pos,
|
|
long mask, int delta) {
|
|
while (mask != 0) {
|
|
int sq = BitBoard.numberOfTrailingZeros(mask);
|
|
setMove(moveList, sq + delta, sq, Piece.EMPTY);
|
|
mask &= (mask - 1);
|
|
}
|
|
}
|
|
|
|
private final static boolean addMovesByMask(MoveList moveList, Position pos, int sq0, long mask) {
|
|
long oKingMask = pos.pieceTypeBB[pos.whiteMove ? Piece.BKING : Piece.WKING];
|
|
if ((mask & oKingMask) != 0) {
|
|
int sq = BitBoard.numberOfTrailingZeros(mask & oKingMask);
|
|
moveList.size = 0;
|
|
setMove(moveList, sq0, sq, Piece.EMPTY);
|
|
return true;
|
|
}
|
|
while (mask != 0) {
|
|
int sq = BitBoard.numberOfTrailingZeros(mask);
|
|
setMove(moveList, sq0, sq, Piece.EMPTY);
|
|
mask &= (mask - 1);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private final static void setMove(MoveList moveList, int from, int to, int promoteTo) {
|
|
Move m = moveList.m[moveList.size++];
|
|
m.from = from;
|
|
m.to = to;
|
|
m.promoteTo = promoteTo;
|
|
m.score = 0;
|
|
}
|
|
|
|
// Code to handle the Move cache.
|
|
private Object[] moveListCache = new Object[200];
|
|
private int moveListsInCache = 0;
|
|
|
|
private static final int MAX_MOVES = 256;
|
|
|
|
private final MoveList getMoveListObj() {
|
|
MoveList ml;
|
|
if (moveListsInCache > 0) {
|
|
ml = (MoveList)moveListCache[--moveListsInCache];
|
|
ml.size = 0;
|
|
} else {
|
|
ml = new MoveList();
|
|
for (int i = 0; i < MAX_MOVES; i++)
|
|
ml.m[i] = new Move(0, 0, Piece.EMPTY);
|
|
}
|
|
return ml;
|
|
}
|
|
|
|
/** Return all move objects in moveList to the move cache. */
|
|
public final void returnMoveList(MoveList moveList) {
|
|
if (moveListsInCache < moveListCache.length) {
|
|
moveListCache[moveListsInCache++] = moveList;
|
|
}
|
|
}
|
|
}
|