| (attacks_from<KING>(s) & pieces(KING));
}
+Bitboard Position::attackers_to(Square s, Bitboard occ) const {
+
+ return (attacks_from<PAWN>(s, BLACK) & pieces(PAWN, WHITE))
+ | (attacks_from<PAWN>(s, WHITE) & pieces(PAWN, BLACK))
+ | (attacks_from<KNIGHT>(s) & pieces(KNIGHT))
+ | (rook_attacks_bb(s, occ) & pieces(ROOK, QUEEN))
+ | (bishop_attacks_bb(s, occ) & pieces(BISHOP, QUEEN))
+ | (attacks_from<KING>(s) & pieces(KING));
+}
+
/// Position::attacks_from() computes a bitboard of all attacks
/// of a given piece put in a given square.
assert(move_is_ok(m));
assert(pinned == pinned_pieces(side_to_move()));
- // Castling moves are checked for legality during move generation.
- if (move_is_castle(m))
- return true;
+ Color us = side_to_move();
+ Square from = move_from(m);
+
+ assert(color_of_piece_on(from) == us);
+ assert(piece_on(king_square(us)) == make_piece(us, KING));
// En passant captures are a tricky special case. Because they are
// rather uncommon, we do it simply by testing whether the king is attacked
// after the move is made
if (move_is_ep(m))
{
- Color us = side_to_move();
Color them = opposite_color(us);
- Square from = move_from(m);
Square to = move_to(m);
Square capsq = make_square(square_file(to), square_rank(from));
Square ksq = king_square(us);
&& !(bishop_attacks_bb(ksq, b) & pieces(BISHOP, QUEEN, them));
}
- Color us = side_to_move();
- Square from = move_from(m);
-
- assert(color_of_piece_on(from) == us);
- assert(piece_on(king_square(us)) == make_piece(us, KING));
-
// If the moving piece is a king, check whether the destination
- // square is attacked by the opponent.
+ // square is attacked by the opponent. Castling moves are checked
+ // for legality during move generation.
if (type_of_piece_on(from) == KING)
- return !(attackers_to(move_to(m)) & pieces_of_color(opposite_color(us)));
+ return move_is_castle(m) || !(attackers_to(move_to(m)) & pieces_of_color(opposite_color(us)));
// A non-king move is legal if and only if it is not pinned or it
// is moving along the ray towards or away from the king.
}
-/// Position::pl_move_is_evasion() tests whether a pseudo-legal move is a legal evasion
-
-bool Position::pl_move_is_evasion(Move m, Bitboard pinned) const
-{
- assert(is_check());
-
- Color us = side_to_move();
- Square from = move_from(m);
- Square to = move_to(m);
-
- // King moves and en-passant captures are verified in pl_move_is_legal()
- if (type_of_piece_on(from) == KING || move_is_ep(m))
- return pl_move_is_legal(m, pinned);
-
- Bitboard target = checkers();
- Square checksq = pop_1st_bit(&target);
+/// Position::move_is_pl_slow() takes a position and a move and tests whether
+/// the move is pseudo legal. This version is not very fast and should be used
+/// only in non time-critical paths.
- if (target) // double check ?
- return false;
-
- // Our move must be a blocking evasion or a capture of the checking piece
- target = squares_between(checksq, king_square(us)) | checkers();
- return bit_is_set(target, to) && pl_move_is_legal(m, pinned);
-}
-
-/// Position::move_is_legal() takes a position and a (not necessarily pseudo-legal)
-/// move and tests whether the move is legal. This version is not very fast and
-/// should be used only in non time-critical paths.
-
-bool Position::move_is_legal(const Move m) const {
+bool Position::move_is_pl_slow(const Move m) const {
MoveStack mlist[MAX_MOVES];
- MoveStack *cur, *last = generate<MV_PSEUDO_LEGAL>(*this, mlist);
+ MoveStack *cur, *last;
- for (cur = mlist; cur != last; cur++)
+ last = in_check() ? generate<MV_EVASION>(*this, mlist)
+ : generate<MV_NON_EVASION>(*this, mlist);
+
+ for (cur = mlist; cur != last; cur++)
if (cur->move == m)
- return pl_move_is_legal(m, pinned_pieces(sideToMove));
+ return true;
return false;
}
-/// Fast version of Position::move_is_legal() that takes a position a move and
-/// a bitboard of pinned pieces as input, and tests whether the move is legal.
+/// Fast version of Position::move_is_pl() that takes a position a move and a
+/// bitboard of pinned pieces as input, and tests whether the move is pseudo legal.
-bool Position::move_is_legal(const Move m, Bitboard pinned) const {
+bool Position::move_is_pl(const Move m) const {
assert(is_ok());
- assert(pinned == pinned_pieces(sideToMove));
Color us = sideToMove;
Color them = opposite_color(sideToMove);
// Use a slower but simpler function for uncommon cases
if (move_is_special(m))
- return move_is_legal(m);
+ return move_is_pl_slow(m);
+
+ // Is not a promotion, so promotion piece must be empty
+ if (move_promotion_piece(m) - 2 != PIECE_TYPE_NONE)
+ return false;
// If the from square is not occupied by a piece belonging to the side to
// move, the move is obviously not legal.
- if (color_of_piece(pc) != us)
+ if (pc == PIECE_NONE || color_of_piece(pc) != us)
return false;
// The destination square cannot be occupied by a friendly piece
case DELTA_SE:
// Capture. The destination square must be occupied by an enemy
// piece (en passant captures was handled earlier).
- if (color_of_piece_on(to) != them)
- return false;
- break;
+ if (color_of_piece_on(to) != them)
+ return false;
+
+ // From and to files must be one file apart, avoids a7h5
+ if (abs(square_file(from) - square_file(to)) != 1)
+ return false;
+ break;
case DELTA_N:
case DELTA_S:
// Pawn push. The destination square must be empty.
- if (!square_is_empty(to))
- return false;
- break;
+ if (!square_is_empty(to))
+ return false;
+ break;
case DELTA_NN:
// Double white pawn push. The destination square must be on the fourth
|| !square_is_empty(to)
|| !square_is_empty(from + DELTA_N))
return false;
- break;
+ break;
case DELTA_SS:
// Double black pawn push. The destination square must be on the fifth
// rank, and both the destination square and the square between the
// source and destination squares must be empty.
- if ( square_rank(to) != RANK_5
- || !square_is_empty(to)
- || !square_is_empty(from + DELTA_S))
- return false;
- break;
+ if ( square_rank(to) != RANK_5
+ || !square_is_empty(to)
+ || !square_is_empty(from + DELTA_S))
+ return false;
+ break;
default:
return false;
else if (!bit_is_set(attacks_from(pc, from), to))
return false;
- // The move is pseudo-legal, check if it is also legal
- return is_check() ? pl_move_is_evasion(m, pinned) : pl_move_is_legal(m, pinned);
+ if (in_check())
+ {
+ // In case of king moves under check we have to remove king so to catch
+ // as invalid moves like b1a1 when opposite queen is on c1.
+ if (type_of_piece_on(from) == KING)
+ {
+ Bitboard b = occupied_squares();
+ clear_bit(&b, from);
+ if (attackers_to(move_to(m), b) & pieces_of_color(opposite_color(us)))
+ return false;
+ }
+ else
+ {
+ Bitboard target = checkers();
+ Square checksq = pop_1st_bit(&target);
+
+ if (target) // double check ? In this case a king move is required
+ return false;
+
+ // Our move must be a blocking evasion or a capture of the checking piece
+ target = squares_between(checksq, king_square(us)) | checkers();
+ if (!bit_is_set(target, move_to(m)))
+ return false;
+ }
+ }
+
+ return true;
}
-/// Position::move_is_check() tests whether a pseudo-legal move is a check
+/// Position::move_gives_check() tests whether a pseudo-legal move is a check
-bool Position::move_is_check(Move m) const {
+bool Position::move_gives_check(Move m) const {
- return move_is_check(m, CheckInfo(*this));
+ return move_gives_check(m, CheckInfo(*this));
}
-bool Position::move_is_check(Move m, const CheckInfo& ci) const {
+bool Position::move_gives_check(Move m, const CheckInfo& ci) const {
assert(is_ok());
assert(move_is_ok(m));
void Position::do_move(Move m, StateInfo& newSt) {
CheckInfo ci(*this);
- do_move(m, newSt, ci, move_is_check(m, ci));
+ do_move(m, newSt, ci, move_gives_check(m, ci));
}
void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveIsCheck) {
void Position::do_null_move(StateInfo& backupSt) {
assert(is_ok());
- assert(!is_check());
+ assert(!in_check());
// Back up the information necessary to undo the null move to the supplied
// StateInfo object.
void Position::undo_null_move() {
assert(is_ok());
- assert(!is_check());
+ assert(!in_check());
// Restore information from the our backup StateInfo object
StateInfo* backupSt = st->previous;
/// move, and one which takes a 'from' and a 'to' square. The function does
/// not yet understand promotions captures.
-int Position::see(Move m) const {
-
- assert(move_is_ok(m));
- return see(move_from(m), move_to(m));
-}
-
int Position::see_sign(Move m) const {
assert(move_is_ok(m));
if (midgame_value_of_piece_on(to) >= midgame_value_of_piece_on(from))
return 1;
- return see(from, to);
+ return see(m);
}
-int Position::see(Square from, Square to) const {
+int Position::see(Move m) const {
+ Square from, to;
Bitboard occupied, attackers, stmAttackers, b;
int swapList[32], slIndex = 1;
PieceType capturedType, pt;
Color stm;
- assert(square_is_ok(from));
- assert(square_is_ok(to));
-
- capturedType = type_of_piece_on(to);
+ assert(move_is_ok(m));
- // King cannot be recaptured
- if (capturedType == KING)
- return seeValues[capturedType];
+ // As castle moves are implemented as capturing the rook, they have
+ // SEE == RookValueMidgame most of the times (unless the rook is under
+ // attack).
+ if (move_is_castle(m))
+ return 0;
+ from = move_from(m);
+ to = move_to(m);
+ capturedType = type_of_piece_on(to);
occupied = occupied_squares();
// Handle en passant moves
// Find all attackers to the destination square, with the moving piece
// removed, but possibly an X-ray attacker added behind it.
clear_bit(&occupied, from);
- attackers = (rook_attacks_bb(to, occupied) & pieces(ROOK, QUEEN))
- | (bishop_attacks_bb(to, occupied)& pieces(BISHOP, QUEEN))
- | (attacks_from<KNIGHT>(to) & pieces(KNIGHT))
- | (attacks_from<KING>(to) & pieces(KING))
- | (attacks_from<PAWN>(to, WHITE) & pieces(PAWN, BLACK))
- | (attacks_from<PAWN>(to, BLACK) & pieces(PAWN, WHITE));
+ attackers = attackers_to(to, occupied);
// If the opponent has no attackers we are finished
stm = opposite_color(color_of_piece_on(from));
bool Position::is_mate() const {
MoveStack moves[MAX_MOVES];
- return is_check() && generate<MV_LEGAL>(*this, moves) == moves;
+ return in_check() && generate<MV_LEGAL>(*this, moves) == moves;
}