X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fposition.cpp;h=52aa93ebddc918493fd720a58dace0b1ab1d8d17;hp=59caa88e47e4b0bcc8220b4c9d8617b23f799946;hb=13fe7ee4df30f5bc15189870ebf5d166e26d9906;hpb=89a06f6651882248e185bb597135af3249ec8f6a diff --git a/src/position.cpp b/src/position.cpp index 59caa88e..52aa93eb 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -490,6 +490,16 @@ Bitboard Position::attackers_to(Square s) const { | (attacks_from(s) & pieces(KING)); } +Bitboard Position::attackers_to(Square s, Bitboard occ) const { + + return (attacks_from(s, BLACK) & pieces(PAWN, WHITE)) + | (attacks_from(s, WHITE) & pieces(PAWN, BLACK)) + | (attacks_from(s) & pieces(KNIGHT)) + | (rook_attacks_bb(s, occ) & pieces(ROOK, QUEEN)) + | (bishop_attacks_bb(s, occ) & pieces(BISHOP, QUEEN)) + | (attacks_from(s) & pieces(KING)); +} + /// Position::attacks_from() computes a bitboard of all attacks /// of a given piece put in a given square. @@ -570,6 +580,12 @@ bool Position::pl_move_is_legal(Move m, Bitboard pinned) const { 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 @@ -596,16 +612,11 @@ bool Position::pl_move_is_legal(Move m, Bitboard pinned) const { && !(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. @@ -615,31 +626,6 @@ bool Position::pl_move_is_legal(Move m, Bitboard pinned) const { } -/// 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. @@ -675,9 +661,13 @@ bool Position::move_is_legal(const Move m, Bitboard pinned) const { if (move_is_special(m)) return move_is_legal(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 @@ -707,16 +697,20 @@ bool Position::move_is_legal(const Move m, Bitboard pinned) const { 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 @@ -726,17 +720,17 @@ bool Position::move_is_legal(const Move m, Bitboard pinned) const { || !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; @@ -745,8 +739,34 @@ bool Position::move_is_legal(const Move m, Bitboard pinned) const { else if (!bit_is_set(attacks_from(pc, from), to)) return false; + 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; + } + } + // 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); + return pl_move_is_legal(m, pinned); } @@ -1512,6 +1532,12 @@ int Position::see(Move m) const { assert(move_is_ok(m)); + // 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); @@ -1533,12 +1559,7 @@ int Position::see(Move m) const { // 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(to) & pieces(KNIGHT)) - | (attacks_from(to) & pieces(KING)) - | (attacks_from(to, WHITE) & pieces(PAWN, BLACK)) - | (attacks_from(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));