X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fposition.cpp;h=31176c9d42ead1a504a57c426b1b40c748a7f6c1;hp=98e79df2a82d2d661c9af66aa8d8004466da1bab;hb=088ecc242f6ef35e7785577482535ebfad56b975;hpb=dc2302b701083dade07d59b1ffbfd180d47c4383 diff --git a/src/position.cpp b/src/position.cpp index 98e79df2..31176c9d 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -60,11 +60,11 @@ static bool RequestPending = false; /// Constructors -Position::Position(const Position &pos) { +Position::Position(const Position& pos) { copy(pos); } -Position::Position(const std::string &fen) { +Position::Position(const std::string& fen) { from_fen(fen); } @@ -73,7 +73,7 @@ Position::Position(const std::string &fen) { /// string. This function is not very robust - make sure that input FENs are /// correct (this is assumed to be the responsibility of the GUI). -void Position::from_fen(const std::string &fen) { +void Position::from_fen(const std::string& fen) { static const std::string pieceLetters = "KQRBNPkqrbnp"; static const Piece pieces[] = { WK, WQ, WR, WB, WN, WP, BK, BQ, BR, BB, BN, BP }; @@ -128,8 +128,10 @@ void Position::from_fen(const std::string &fen) { i++; while(strchr("KQkqabcdefghABCDEFGH-", fen[i])) { - if(fen[i] == '-') { - i++; break; + if (fen[i] == '-') + { + i++; + break; } else if(fen[i] == 'K') allow_oo(WHITE); else if(fen[i] == 'Q') allow_ooo(WHITE); @@ -379,19 +381,6 @@ Bitboard Position::hidden_checks(Color c, Square ksq) const { } -/// Position::square_is_attacked() checks whether the given side attacks the -/// given square. - -bool Position::square_is_attacked(Square s, Color c) const { - - return (pawn_attacks(opposite_color(c), s) & pawns(c)) - || (piece_attacks(s) & knights(c)) - || (piece_attacks(s) & kings(c)) - || (piece_attacks(s) & rooks_and_queens(c)) - || (piece_attacks(s) & bishops_and_queens(c)); -} - - /// Position::attacks_to() computes a bitboard containing all pieces which /// attacks a given square. There are two versions of this function: One /// which finds attackers of both colors, and one which only finds the @@ -407,12 +396,6 @@ Bitboard Position::attacks_to(Square s) const { | (piece_attacks(s) & pieces_of_type(KING)); } -Bitboard Position::attacks_to(Square s, Color c) const { - - return attacks_to(s) & pieces_of_color(c); -} - - /// Position::piece_attacks_square() tests whether the piece on square f /// attacks square t. @@ -729,6 +712,27 @@ void Position::restore(const UndoInfo& u) { // u.capture is restored in undo_move() } + +/// Position::update_checkers() is a private method to udpate chekers info + +template +inline void Position::update_checkers(Bitboard* pCheckersBB, Square ksq, Square from, + Square to, Bitboard dcCandidates) { + + if (Piece != KING && bit_is_set(piece_attacks(ksq), to)) + set_bit(pCheckersBB, to); + + if (Piece != QUEEN && bit_is_set(dcCandidates, from)) + { + if (Piece != ROOK) + (*pCheckersBB) |= (piece_attacks(ksq) & rooks_and_queens(side_to_move())); + + if (Piece != BISHOP) + (*pCheckersBB) |= (piece_attacks(ksq) & bishops_and_queens(side_to_move())); + } +} + + /// Position::do_move() makes a move, and backs up all information necessary /// to undo the move to an UndoInfo object. The move is assumed to be legal. /// Pseudo-legal moves should be filtered out before this function is called. @@ -808,33 +812,34 @@ void Position::do_move(Move m, UndoInfo& u, Bitboard dcCandidates) { if (piece == KING) kingSquare[us] = to; - // If the move was a double pawn push, set the en passant square. - // This code is a bit ugly right now, and should be cleaned up later. - // FIXME + // Reset en passant square if (epSquare != SQ_NONE) { key ^= zobEp[epSquare]; epSquare = SQ_NONE; } + + // If the moving piece was a pawn do some special extra work if (piece == PAWN) { + // Reset rule 50 draw counter + rule50 = 0; + + // Update pawn hash key + pawnKey ^= zobrist[us][PAWN][from] ^ zobrist[us][PAWN][to]; + + // Set en passant square, only if moved pawn can be captured if (abs(int(to) - int(from)) == 16) { - if( ( us == WHITE - && (pawn_attacks(WHITE, from + DELTA_N) & pawns(BLACK))) - || ( us == BLACK - && (pawn_attacks(BLACK, from + DELTA_S) & pawns(WHITE)))) + if ( (us == WHITE && (pawn_attacks(WHITE, from + DELTA_N) & pawns(BLACK))) + || (us == BLACK && (pawn_attacks(BLACK, from + DELTA_S) & pawns(WHITE)))) { epSquare = Square((int(from) + int(to)) / 2); key ^= zobEp[epSquare]; } } - // Reset rule 50 draw counter - rule50 = 0; - - // Update pawn hash key - pawnKey ^= zobrist[us][PAWN][from] ^ zobrist[us][PAWN][to]; } + // Update piece lists pieceList[us][piece][index[from]] = to; index[to] = index[from]; @@ -845,59 +850,18 @@ void Position::do_move(Move m, UndoInfo& u, Bitboard dcCandidates) { castleRights &= castleRightsMask[to]; key ^= zobCastle[castleRights]; - // Update checkers bitboard + // Update checkers bitboard, piece must be already moved checkersBB = EmptyBoardBB; Square ksq = king_square(them); switch (piece) { - case PAWN: - if (bit_is_set(pawn_attacks(them, ksq), to)) - set_bit(&checkersBB, to); - - if (bit_is_set(dcCandidates, from)) - checkersBB |= ( (piece_attacks(ksq) & rooks_and_queens(us)) - |(piece_attacks(ksq) & bishops_and_queens(us))); - break; - - case KNIGHT: - if (bit_is_set(piece_attacks(ksq), to)) - set_bit(&checkersBB, to); - - if (bit_is_set(dcCandidates, from)) - checkersBB |= ( (piece_attacks(ksq) & rooks_and_queens(us)) - |(piece_attacks(ksq) & bishops_and_queens(us))); - break; - - case BISHOP: - if (bit_is_set(piece_attacks(ksq), to)) - set_bit(&checkersBB, to); - - if (bit_is_set(dcCandidates, from)) - checkersBB |= (piece_attacks(ksq) & rooks_and_queens(us)); - break; - - case ROOK: - if (bit_is_set(piece_attacks(ksq), to)) - set_bit(&checkersBB, to); - - if (bit_is_set(dcCandidates, from)) - checkersBB |= (piece_attacks(ksq) & bishops_and_queens(us)); - break; - - case QUEEN: - if (bit_is_set(piece_attacks(ksq), to)) - set_bit(&checkersBB, to); - break; - - case KING: - if (bit_is_set(dcCandidates, from)) - checkersBB |= ( (piece_attacks(ksq) & rooks_and_queens(us)) - |(piece_attacks(ksq) & bishops_and_queens(us))); - break; - - default: - assert(false); - break; + case PAWN: update_checkers(&checkersBB, ksq, from, to, dcCandidates); break; + case KNIGHT: update_checkers(&checkersBB, ksq, from, to, dcCandidates); break; + case BISHOP: update_checkers(&checkersBB, ksq, from, to, dcCandidates); break; + case ROOK: update_checkers(&checkersBB, ksq, from, to, dcCandidates); break; + case QUEEN: update_checkers(&checkersBB, ksq, from, to, dcCandidates); break; + case KING: update_checkers(&checkersBB, ksq, from, to, dcCandidates); break; + default: assert(false); break; } } @@ -1034,7 +998,7 @@ void Position::do_castle_move(Move m) { key ^= zobrist[us][ROOK][rfrom] ^ zobrist[us][ROOK][rto]; // Clear en passant square - if(epSquare != SQ_NONE) + if (epSquare != SQ_NONE) { key ^= zobEp[epSquare]; epSquare = SQ_NONE; @@ -1232,8 +1196,8 @@ void Position::do_ep_move(Move m) { } -/// Position::undo_move() unmakes a move. When it returns, the position should -/// be restored to exactly the same state as before the move was made. It is +/// Position::undo_move() unmakes a move. When it returns, the position should +/// be restored to exactly the same state as before the move was made. It is /// important that Position::undo_move is called with the same move and UndoInfo /// object as the earlier call to Position::do_move. @@ -1523,7 +1487,7 @@ void Position::undo_ep_move(Move m) { /// Position::do_null_move makes() a "null move": It switches the side to move /// and updates the hash key without executing any move on the board. -void Position::do_null_move(UndoInfo &u) { +void Position::do_null_move(UndoInfo& u) { assert(is_ok()); assert(!is_check()); @@ -1581,11 +1545,17 @@ void Position::undo_null_move(const UndoInfo &u) { } -/// Position::see() is a static exchange evaluator: It tries to estimate the -/// material gain or loss resulting from a move. There are two versions of -/// this function: One which takes a move as input, and one which takes a -/// 'from' and a 'to' square. The function does not yet understand promotions -/// or en passant captures. +/// Position::see() is a static exchange evaluator: It tries to estimate the +/// material gain or loss resulting from a move. There are three versions of +/// this function: One which takes a destination square as input, one takes a +/// move, and one which takes a 'from' and a 'to' square. The function does +/// not yet understand promotions captures. + +int Position::see(Square to) const { + + assert(square_is_ok(to)); + return see(SQ_NONE, to); +} int Position::see(Move m) const { @@ -1595,18 +1565,22 @@ int Position::see(Move m) const { int Position::see(Square from, Square to) const { - // Approximate material values, with pawn = 1 + // Material values static const int seeValues[18] = { - 0, 1, 3, 3, 5, 10, 100, 0, 0, 1, 3, 3, 5, 10, 100, 0, 0, 0 + 0, PawnValueMidgame, KnightValueMidgame, BishopValueMidgame, + RookValueMidgame, QueenValueMidgame, QueenValueMidgame*10, 0, + 0, PawnValueMidgame, KnightValueMidgame, BishopValueMidgame, + RookValueMidgame, QueenValueMidgame, QueenValueMidgame*10, 0, + 0, 0 }; Bitboard attackers, occ, b; - assert(square_is_ok(from)); + assert(square_is_ok(from) || from == SQ_NONE); assert(square_is_ok(to)); // Initialize colors - Color us = color_of_piece_on(from); + Color us = (from != SQ_NONE ? color_of_piece_on(from) : opposite_color(color_of_piece_on(to))); Color them = opposite_color(us); // Initialize pieces @@ -1616,15 +1590,49 @@ int Position::see(Square from, Square to) const { // Find all attackers to the destination square, with the moving piece // removed, but possibly an X-ray attacker added behind it. occ = occupied_squares(); - clear_bit(&occ, from); - attackers = (rook_attacks_bb(to, occ) & rooks_and_queens()) - | (bishop_attacks_bb(to, occ) & bishops_and_queens()) - | (piece_attacks(to) & knights()) - | (piece_attacks(to) & kings()) - | (pawn_attacks(WHITE, to) & pawns(BLACK)) - | (pawn_attacks(BLACK, to) & pawns(WHITE)); - - // If the opponent has no attackers, we are finished + + // Handle en passant moves + if (epSquare == to && type_of_piece_on(from) == PAWN) + { + assert(capture == EMPTY); + + Square capQq = (side_to_move() == WHITE)? (to - DELTA_N) : (to - DELTA_S); + capture = piece_on(capQq); + + assert(type_of_piece_on(capQq) == PAWN); + + // Remove the captured pawn + clear_bit(&occ, capQq); + } + + while (true) + { + clear_bit(&occ, from); + attackers = (rook_attacks_bb(to, occ) & rooks_and_queens()) + | (bishop_attacks_bb(to, occ) & bishops_and_queens()) + | (piece_attacks(to) & knights()) + | (piece_attacks(to) & kings()) + | (pawn_attacks(WHITE, to) & pawns(BLACK)) + | (pawn_attacks(BLACK, to) & pawns(WHITE)); + + if (from != SQ_NONE) + break; + + // If we don't have any attacker we are finished + if ((attackers & pieces_of_color(us)) == EmptyBoardBB) + return 0; + + // Locate the least valuable attacker to the destination square + // and use it to initialize from square. + PieceType pt; + for (pt = PAWN; !(attackers & pieces_of_color_and_type(us, pt)); pt++) + assert(pt < KING); + + from = first_1(attackers & pieces_of_color_and_type(us, pt)); + piece = piece_on(from); + } + + // If the opponent has no attackers we are finished if ((attackers & pieces_of_color(them)) == EmptyBoardBB) return seeValues[capture]; @@ -1724,7 +1732,7 @@ void Position::clear() { } -/// Position::reset_game_ply() simply sets gamePly to 0. It is used from the +/// Position::reset_game_ply() simply sets gamePly to 0. It is used from the /// UCI interface code, whenever a non-reversible move is made in a /// 'position fen moves m1 m2 ...' command. This makes it possible /// for the program to handle games of arbitrary length, as long as the GUI @@ -1801,7 +1809,7 @@ Key Position::compute_key() const { } -/// Position::compute_pawn_key() computes the hash key of the position. The +/// Position::compute_pawn_key() computes the hash key of the position. The /// hash key is usually updated incrementally as moves are made and unmade, /// the compute_pawn_key() function is only used when a new position is set /// up, and to verify the correctness of the pawn hash key when running in @@ -1847,7 +1855,7 @@ Key Position::compute_material_key() const { /// Position::compute_mg_value() and Position::compute_eg_value() compute the -/// incremental scores for the middle game and the endgame. These functions +/// incremental scores for the middle game and the endgame. These functions /// are used to initialize the incremental scores when a new position is set /// up, and to verify that the scores are correctly updated by do_move /// and undo_move when the program is running in debug mode. @@ -1896,7 +1904,7 @@ Value Position::compute_eg_value() const { /// Position::compute_non_pawn_material() computes the total non-pawn middle -/// game material score for the given side. Material scores are updated +/// game material score for the given side. Material scores are updated /// incrementally during the search, this function is only used while /// initializing a new Position object. @@ -1923,7 +1931,7 @@ Value Position::compute_non_pawn_material(Color c) const { /// side to move is checkmated. Note that this function is currently very /// slow, and shouldn't be used frequently inside the search. -bool Position::is_mate() { +bool Position::is_mate() const { if (is_check()) { @@ -1935,7 +1943,7 @@ bool Position::is_mate() { /// Position::is_draw() tests whether the position is drawn by material, -/// repetition, or the 50 moves rule. It does not detect stalemates, this +/// repetition, or the 50 moves rule. It does not detect stalemates, this /// must be done by the search. bool Position::is_draw() const { @@ -2061,7 +2069,7 @@ void Position::init_piece_square_tables() { /// Position::flipped_copy() makes a copy of the input position, but with -/// the white and black sides reversed. This is only useful for debugging, +/// the white and black sides reversed. This is only useful for debugging, /// especially for finding evaluation symmetry bugs. void Position::flipped_copy(const Position &pos) { @@ -2172,7 +2180,7 @@ bool Position::is_ok(int* failedStep) const { if (type_of_piece_on(s) == KING) kingCount[color_of_piece_on(s)]++; - if(kingCount[0] != 1 || kingCount[1] != 1) + if (kingCount[0] != 1 || kingCount[1] != 1) return false; } @@ -2252,10 +2260,10 @@ bool Position::is_ok(int* failedStep) const { if (failedStep) (*failedStep)++; if (debugNonPawnMaterial) { - if(npMaterial[WHITE] != compute_non_pawn_material(WHITE)) + if (npMaterial[WHITE] != compute_non_pawn_material(WHITE)) return false; - if(npMaterial[BLACK] != compute_non_pawn_material(BLACK)) + if (npMaterial[BLACK] != compute_non_pawn_material(BLACK)) return false; }