| (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()));
+ 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. Castling moves are checked
// for legality during move generation.
}
-/// 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(in_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);
-
- 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_full(const Move m) const {
MoveStack mlist[MAX_MOVES];
MoveStack *cur, *last = generate<MV_PSEUDO_LEGAL>(*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.
-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_full(m);
// Is not a promotion, so promotion piece must be empty
if (move_promotion_piece(m) - 2 != PIECE_TYPE_NONE)
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 in_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;
}
// 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));