X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fposition.cpp;h=397c87dd694c8eaba043f273d2255a883b68b69c;hp=d49c0c2d7da23a0698e4656b3bafc00b82fe8b93;hb=fd5d6c53402517cf8277641a8e37af153b7540c5;hpb=2fe4e10b0bf11e98f66185c04084e87a1341af02 diff --git a/src/position.cpp b/src/position.cpp index d49c0c2d..397c87dd 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -764,7 +764,7 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI if (is_castle(m)) { st->key = key; - do_castle_move(m); + do_castle_move(m); return; } @@ -781,11 +781,66 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI assert(color_of(piece_on(from)) == us); assert(color_of(piece_on(to)) == them || square_is_empty(to)); - assert(!(ep || pm) || piece == make_piece(us, PAWN)); - assert(!pm || relative_rank(us, to) == RANK_8); + assert(capture != KING); if (capture) - do_capture_move(key, capture, them, to, ep); + { + Square capsq = to; + + // If the captured piece was a pawn, update pawn hash key, otherwise + // update non-pawn material. + if (capture == PAWN) + { + if (ep) // En passant? + { + capsq += pawn_push(them); + + assert(pt == PAWN); + assert(to == st->epSquare); + assert(relative_rank(us, to) == RANK_6); + assert(piece_on(to) == PIECE_NONE); + assert(piece_on(capsq) == make_piece(them, PAWN)); + + board[capsq] = PIECE_NONE; + } + + st->pawnKey ^= zobrist[them][PAWN][capsq]; + } + else + st->npMaterial[them] -= PieceValueMidgame[capture]; + + // Remove captured piece + clear_bit(&byColorBB[them], capsq); + clear_bit(&byTypeBB[capture], capsq); + clear_bit(&byTypeBB[0], capsq); + + // Update hash key + key ^= zobrist[them][capture][capsq]; + + // Update incremental scores + st->value -= pst(make_piece(them, capture), capsq); + + // Update piece count + pieceCount[them][capture]--; + + // Update material hash key + st->materialKey ^= zobrist[them][capture][pieceCount[them][capture]]; + + // Update piece list, move the last piece at index[capsq] position + // + // WARNING: This is a not perfectly revresible operation. When we + // will reinsert the captured piece in undo_move() we will put it + // at the end of the list and not in its original place, it means + // index[] and pieceList[] are not guaranteed to be invariant to a + // do_move() + undo_move() sequence. + Square lastPieceSquare = pieceList[them][capture][pieceCount[them][capture]]; + index[lastPieceSquare] = index[capsq]; + pieceList[them][capture][index[lastPieceSquare]] = lastPieceSquare; + pieceList[them][capture][pieceCount[them][capture]] = SQ_NONE; + + // Reset rule 50 counter + st->rule50 = 0; + } // Update hash key key ^= zobrist[us][pt][from] ^ zobrist[us][pt][to]; @@ -930,102 +985,43 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI } -/// Position::do_capture_move() is a private method used to update captured -/// piece info. It is called from the main Position::do_move function. - -void Position::do_capture_move(Key& key, PieceType capture, Color them, Square to, bool ep) { - - assert(capture != KING); - - Square capsq = to; - - // If the captured piece was a pawn, update pawn hash key, - // otherwise update non-pawn material. - if (capture == PAWN) - { - if (ep) // en passant ? - { - capsq = to + pawn_push(them); - - assert(to == st->epSquare); - assert(relative_rank(flip(them), to) == RANK_6); - assert(piece_on(to) == PIECE_NONE); - assert(piece_on(capsq) == make_piece(them, PAWN)); - - board[capsq] = PIECE_NONE; - } - st->pawnKey ^= zobrist[them][PAWN][capsq]; - } - else - st->npMaterial[them] -= PieceValueMidgame[capture]; - - // Remove captured piece - clear_bit(&byColorBB[them], capsq); - clear_bit(&byTypeBB[capture], capsq); - clear_bit(&byTypeBB[0], capsq); - - // Update hash key - key ^= zobrist[them][capture][capsq]; - - // Update incremental scores - st->value -= pst(make_piece(them, capture), capsq); - - // Update piece count - pieceCount[them][capture]--; - - // Update material hash key - st->materialKey ^= zobrist[them][capture][pieceCount[them][capture]]; - - // Update piece list, move the last piece at index[capsq] position - // - // WARNING: This is a not perfectly revresible operation. When we - // will reinsert the captured piece in undo_move() we will put it - // at the end of the list and not in its original place, it means - // index[] and pieceList[] are not guaranteed to be invariant to a - // do_move() + undo_move() sequence. - Square lastPieceSquare = pieceList[them][capture][pieceCount[them][capture]]; - index[lastPieceSquare] = index[capsq]; - pieceList[them][capture][index[lastPieceSquare]] = lastPieceSquare; - pieceList[them][capture][pieceCount[them][capture]] = SQ_NONE; - - // Reset rule 50 counter - st->rule50 = 0; -} - - -/// Position::do_castle_move() is a private method used to make a castling -/// move. It is called from the main Position::do_move function. Note that -/// castling moves are encoded as "king captures friendly rook" moves, for -/// instance white short castling in a non-Chess960 game is encoded as e1h1. - +/// Position::do_castle_move() is a private method used to do/undo a castling +/// move. Note that castling moves are encoded as "king captures friendly rook" +/// moves, for instance white short castling in a non-Chess960 game is encoded +/// as e1h1. +template void Position::do_castle_move(Move m) { assert(is_ok(m)); assert(is_castle(m)); - Color us = side_to_move(); - Color them = flip(us); + Square kto, kfrom, rfrom, rto, kAfter, rAfter; - // Find source squares for king and rook - Square kfrom = move_from(m); - Square rfrom = move_to(m); - Square kto, rto; - - assert(piece_on(kfrom) == make_piece(us, KING)); - assert(piece_on(rfrom) == make_piece(us, ROOK)); + Color us = side_to_move(); + Square kBefore = move_from(m); + Square rBefore = move_to(m); - // Find destination squares for king and rook - if (rfrom > kfrom) // O-O + // Find after-castle squares for king and rook + if (rBefore > kBefore) // O-O { - kto = relative_square(us, SQ_G1); - rto = relative_square(us, SQ_F1); + kAfter = relative_square(us, SQ_G1); + rAfter = relative_square(us, SQ_F1); } else // O-O-O { - kto = relative_square(us, SQ_C1); - rto = relative_square(us, SQ_D1); + kAfter = relative_square(us, SQ_C1); + rAfter = relative_square(us, SQ_D1); } + kfrom = Do ? kBefore : kAfter; + rfrom = Do ? rBefore : rAfter; + + kto = Do ? kAfter : kBefore; + rto = Do ? rAfter : rBefore; + + assert(piece_on(kfrom) == make_piece(us, KING)); + assert(piece_on(rfrom) == make_piece(us, ROOK)); + // Remove pieces from source squares clear_bit(&byColorBB[us], kfrom); clear_bit(&byTypeBB[KING], kfrom); @@ -1056,38 +1052,44 @@ void Position::do_castle_move(Move m) { index[kto] = index[kfrom]; index[rto] = tmp; - // Reset capture field - st->capturedType = PIECE_TYPE_NONE; + if (Do) + { + // Reset capture field + st->capturedType = PIECE_TYPE_NONE; - // Update incremental scores - st->value += pst_delta(king, kfrom, kto); - st->value += pst_delta(rook, rfrom, rto); + // Update incremental scores + st->value += pst_delta(king, kfrom, kto); + st->value += pst_delta(rook, rfrom, rto); - // Update hash key - st->key ^= zobrist[us][KING][kfrom] ^ zobrist[us][KING][kto]; - st->key ^= zobrist[us][ROOK][rfrom] ^ zobrist[us][ROOK][rto]; + // Update hash key + st->key ^= zobrist[us][KING][kfrom] ^ zobrist[us][KING][kto]; + st->key ^= zobrist[us][ROOK][rfrom] ^ zobrist[us][ROOK][rto]; - // Clear en passant square - if (st->epSquare != SQ_NONE) - { - st->key ^= zobEp[st->epSquare]; - st->epSquare = SQ_NONE; - } + // Clear en passant square + if (st->epSquare != SQ_NONE) + { + st->key ^= zobEp[st->epSquare]; + st->epSquare = SQ_NONE; + } - // Update castling rights - st->key ^= zobCastle[st->castleRights]; - st->castleRights &= castleRightsMask[kfrom]; - st->key ^= zobCastle[st->castleRights]; + // Update castling rights + st->key ^= zobCastle[st->castleRights]; + st->castleRights &= castleRightsMask[kfrom]; + st->key ^= zobCastle[st->castleRights]; - // Reset rule 50 counter - st->rule50 = 0; + // Reset rule 50 counter + st->rule50 = 0; - // Update checkers BB - st->checkersBB = attackers_to(king_square(them)) & pieces(us); + // Update checkers BB + st->checkersBB = attackers_to(king_square(flip(us))) & pieces(us); - // Finish - sideToMove = flip(sideToMove); - st->value += (sideToMove == WHITE ? TempoValue : -TempoValue); + // Finish + sideToMove = flip(sideToMove); + st->value += (sideToMove == WHITE ? TempoValue : -TempoValue); + } + else + // Undo: point our state pointer back to the previous state + st = st->previous; assert(pos_is_ok()); } @@ -1104,7 +1106,7 @@ void Position::undo_move(Move m) { if (is_castle(m)) { - undo_castle_move(m); + do_castle_move(m); return; } @@ -1194,134 +1196,49 @@ void Position::undo_move(Move m) { } -/// Position::undo_castle_move() is a private method used to unmake a castling -/// move. It is called from the main Position::undo_move function. Note that -/// castling moves are encoded as "king captures friendly rook" moves, for -/// instance white short castling in a non-Chess960 game is encoded as e1h1. - -void Position::undo_castle_move(Move m) { - - assert(is_ok(m)); - assert(is_castle(m)); - - // When we have arrived here, some work has already been done by - // Position::undo_move. In particular, the side to move has been switched, - // so the code below is correct. - Color us = side_to_move(); - - // Find source squares for king and rook - Square kfrom = move_from(m); - Square rfrom = move_to(m); - Square kto, rto; - - // Find destination squares for king and rook - if (rfrom > kfrom) // O-O - { - kto = relative_square(us, SQ_G1); - rto = relative_square(us, SQ_F1); - } - else // O-O-O - { - kto = relative_square(us, SQ_C1); - rto = relative_square(us, SQ_D1); - } - - assert(piece_on(kto) == make_piece(us, KING)); - assert(piece_on(rto) == make_piece(us, ROOK)); - - // Remove pieces from destination squares - clear_bit(&byColorBB[us], kto); - clear_bit(&byTypeBB[KING], kto); - clear_bit(&byTypeBB[0], kto); - clear_bit(&byColorBB[us], rto); - clear_bit(&byTypeBB[ROOK], rto); - clear_bit(&byTypeBB[0], rto); - - // Put pieces on source squares - set_bit(&byColorBB[us], kfrom); - set_bit(&byTypeBB[KING], kfrom); - set_bit(&byTypeBB[0], kfrom); - set_bit(&byColorBB[us], rfrom); - set_bit(&byTypeBB[ROOK], rfrom); - set_bit(&byTypeBB[0], rfrom); - - // Update board - Piece king = make_piece(us, KING); - Piece rook = make_piece(us, ROOK); - board[kto] = board[rto] = PIECE_NONE; - board[kfrom] = king; - board[rfrom] = rook; - - // Update piece lists - pieceList[us][KING][index[kto]] = kfrom; - pieceList[us][ROOK][index[rto]] = rfrom; - int tmp = index[rto]; // In Chess960 could be rto == kfrom - index[kfrom] = index[kto]; - index[rfrom] = tmp; - - // Finally point our state pointer back to the previous state - st = st->previous; - - assert(pos_is_ok()); -} - - -/// 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. - +/// Position::do_null_move() is used to do/undo a "null move": It flips the side +/// to move and updates the hash key without executing any move on the board. +template void Position::do_null_move(StateInfo& backupSt) { assert(!in_check()); // Back up the information necessary to undo the null move to the supplied - // StateInfo object. - // Note that differently from normal case here backupSt is actually used as - // a backup storage not as a new state to be used. - backupSt.key = st->key; - backupSt.epSquare = st->epSquare; - backupSt.value = st->value; - backupSt.previous = st->previous; - backupSt.pliesFromNull = st->pliesFromNull; - st->previous = &backupSt; - - // Update the necessary information - if (st->epSquare != SQ_NONE) - st->key ^= zobEp[st->epSquare]; - - st->key ^= zobSideToMove; - prefetch((char*)TT.first_entry(st->key)); + // StateInfo object. Note that differently from normal case here backupSt + // is actually used as a backup storage not as the new state. This reduces + // the number of fields to be copied. + StateInfo* src = Do ? st : &backupSt; + StateInfo* dst = Do ? &backupSt : st; + + dst->key = src->key; + dst->epSquare = src->epSquare; + dst->value = src->value; + dst->rule50 = src->rule50; + dst->pliesFromNull = src->pliesFromNull; sideToMove = flip(sideToMove); - st->epSquare = SQ_NONE; - st->rule50++; - st->pliesFromNull = 0; - st->value += (sideToMove == WHITE) ? TempoValue : -TempoValue; - assert(pos_is_ok()); -} - - -/// Position::undo_null_move() unmakes a "null move". - -void Position::undo_null_move() { - - assert(!in_check()); + if (Do) + { + if (st->epSquare != SQ_NONE) + st->key ^= zobEp[st->epSquare]; - // Restore information from the our backup StateInfo object - StateInfo* backupSt = st->previous; - st->key = backupSt->key; - st->epSquare = backupSt->epSquare; - st->value = backupSt->value; - st->previous = backupSt->previous; - st->pliesFromNull = backupSt->pliesFromNull; + st->key ^= zobSideToMove; + prefetch((char*)TT.first_entry(st->key)); - // Update the necessary information - sideToMove = flip(sideToMove); - st->rule50--; + st->epSquare = SQ_NONE; + st->rule50++; + st->pliesFromNull = 0; + st->value += (sideToMove == WHITE) ? TempoValue : -TempoValue; + } assert(pos_is_ok()); } +// Explicit template instantiations +template void Position::do_null_move(StateInfo& backupSt); +template void Position::do_null_move(StateInfo& backupSt); + /// 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