X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fposition.cpp;h=13cf59944a961c75f3b30afc2e7fd7c95eb4dbf2;hp=a1823c12220ca2ba0b71b08607b17df3d49ccb24;hb=81801d395f83ff757558f640bc5d5ce44031d2b5;hpb=08abe8b4a33ab409f5b61ebcb9216ddf8a605e95 diff --git a/src/position.cpp b/src/position.cpp index a1823c12..13cf5994 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -737,9 +737,9 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI nodes++; Key key = st->key; - // Copy some fields of old state to our new StateInfo object except the - // ones which are recalculated from scratch anyway, then switch our state - // pointer to point to the new, ready to be updated, state. + // Copy some fields of old state to our new StateInfo object except the ones + // which are recalculated from scratch anyway, then switch our state pointer + // to point to the new, ready to be updated, state. struct ReducedStateInfo { Key pawnKey, materialKey; Value npMaterial[2]; @@ -772,20 +772,67 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI Color them = flip(us); Square from = move_from(m); Square to = move_to(m); - bool ep = is_enpassant(m); - bool pm = is_promotion(m); - Piece piece = piece_on(from); PieceType pt = type_of(piece); - PieceType capture = ep ? PAWN : type_of(piece_on(to)); + PieceType capture = is_enpassant(m) ? PAWN : type_of(piece_on(to)); - 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(color_of(piece) == us); + assert(color_of(piece_on(to)) != us); + assert(capture != KING); if (capture) - do_capture_move(key, capture, them, to, ep); + { + Square capsq = to; + + // If the captured piece is a pawn, update pawn hash key, otherwise + // update non-pawn material. + if (capture == PAWN) + { + if (is_enpassant(m)) + { + 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 the captured piece + clear_bit(&byColorBB[them], capsq); + clear_bit(&byTypeBB[capture], capsq); + clear_bit(&occupied, capsq); + + // Update piece list, move the last piece at index[capsq] position and + // shrink the list. + // + // WARNING: This is a not 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 lastSquare = pieceList[them][capture][--pieceCount[them][capture]]; + index[lastSquare] = index[capsq]; + pieceList[them][capture][index[lastSquare]] = lastSquare; + pieceList[them][capture][pieceCount[them][capture]] = SQ_NONE; + + // Update hash keys + key ^= zobrist[them][capture][capsq]; + st->materialKey ^= zobrist[them][capture][pieceCount[them][capture]]; + + // Update incremental scores + st->value -= pst(make_piece(them, capture), capsq); + + // Reset rule 50 counter + st->rule50 = 0; + } // Update hash key key ^= zobrist[us][pt][from] ^ zobrist[us][pt][to]; @@ -813,75 +860,67 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI Bitboard move_bb = make_move_bb(from, to); do_move_bb(&byColorBB[us], move_bb); do_move_bb(&byTypeBB[pt], move_bb); - do_move_bb(&byTypeBB[0], move_bb); // HACK: byTypeBB[0] == occupied squares + do_move_bb(&occupied, move_bb); board[to] = board[from]; board[from] = PIECE_NONE; - // Update piece lists, note that index[from] is not updated and - // becomes stale. This works as long as index[] is accessed just - // by known occupied squares. + // Update piece lists, index[from] is not updated and becomes stale. This + // works as long as index[] is accessed just by known occupied squares. index[to] = index[from]; pieceList[us][pt][index[to]] = to; - // If the moving piece was a pawn do some special extra work + // If the moving piece is a pawn do some special extra work if (pt == PAWN) { - // Reset rule 50 draw counter - st->rule50 = 0; - - // Update pawn hash key and prefetch in L1/L2 cache - st->pawnKey ^= zobrist[us][PAWN][from] ^ zobrist[us][PAWN][to]; - - // Set en passant square, only if moved pawn can be captured - if ((to ^ from) == 16) + // Set en-passant square, only if moved pawn can be captured + if ( (to ^ from) == 16 + && (attacks_from(from + pawn_push(us), us) & pieces(PAWN, them))) { - if (attacks_from(from + pawn_push(us), us) & pieces(PAWN, them)) - { - st->epSquare = Square((int(from) + int(to)) / 2); - key ^= zobEp[st->epSquare]; - } + st->epSquare = Square((from + to) / 2); + key ^= zobEp[st->epSquare]; } - if (pm) // promotion ? + if (is_promotion(m)) { PieceType promotion = promotion_piece_type(m); + assert(relative_rank(us, to) == RANK_8); assert(promotion >= KNIGHT && promotion <= QUEEN); - // Insert promoted piece instead of pawn + // Replace the pawn with the promoted piece clear_bit(&byTypeBB[PAWN], to); set_bit(&byTypeBB[promotion], to); board[to] = make_piece(us, promotion); - // Update piece counts - pieceCount[us][promotion]++; - pieceCount[us][PAWN]--; - - // Update material key - st->materialKey ^= zobrist[us][PAWN][pieceCount[us][PAWN]]; - st->materialKey ^= zobrist[us][promotion][pieceCount[us][promotion]-1]; - // Update piece lists, move the last pawn at index[to] position // and shrink the list. Add a new promotion piece to the list. - Square lastPawnSquare = pieceList[us][PAWN][pieceCount[us][PAWN]]; - index[lastPawnSquare] = index[to]; - pieceList[us][PAWN][index[lastPawnSquare]] = lastPawnSquare; + Square lastSquare = pieceList[us][PAWN][--pieceCount[us][PAWN]]; + index[lastSquare] = index[to]; + pieceList[us][PAWN][index[lastSquare]] = lastSquare; pieceList[us][PAWN][pieceCount[us][PAWN]] = SQ_NONE; - index[to] = pieceCount[us][promotion] - 1; + index[to] = pieceCount[us][promotion]; pieceList[us][promotion][index[to]] = to; - // Partially revert hash keys update + // Update hash keys key ^= zobrist[us][PAWN][to] ^ zobrist[us][promotion][to]; st->pawnKey ^= zobrist[us][PAWN][to]; + st->materialKey ^= zobrist[us][promotion][pieceCount[us][promotion]++] + ^ zobrist[us][PAWN][pieceCount[us][PAWN]]; - // Partially revert and update incremental scores - st->value -= pst(make_piece(us, PAWN), to); - st->value += pst(make_piece(us, promotion), to); + // Update incremental score + st->value += pst(make_piece(us, promotion), to) + - pst(make_piece(us, PAWN), to); // Update material st->npMaterial[us] += PieceValueMidgame[promotion]; } + + // Update pawn hash key + st->pawnKey ^= zobrist[us][PAWN][from] ^ zobrist[us][PAWN][to]; + + // Reset rule 50 draw counter + st->rule50 = 0; } // Prefetch pawn and material hash tables @@ -902,7 +941,7 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI if (moveIsCheck) { - if (ep | pm) + if (is_special(m)) st->checkersBB = attackers_to(king_square(them)) & pieces(us); else { @@ -914,10 +953,10 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI if (ci.dcCandidates && bit_is_set(ci.dcCandidates, from)) { if (pt != ROOK) - st->checkersBB |= (attacks_from(king_square(them)) & pieces(ROOK, QUEEN, us)); + st->checkersBB |= attacks_from(king_square(them)) & pieces(ROOK, QUEEN, us); if (pt != BISHOP) - st->checkersBB |= (attacks_from(king_square(them)) & pieces(BISHOP, QUEEN, us)); + st->checkersBB |= attacks_from(king_square(them)) & pieces(BISHOP, QUEEN, us); } } } @@ -930,66 +969,102 @@ 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. +/// 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. + +void Position::undo_move(Move m) { + + assert(is_ok(m)); + + sideToMove = flip(sideToMove); + + if (is_castle(m)) + { + do_castle_move(m); + return; + } -void Position::do_capture_move(Key& key, PieceType capture, Color them, Square to, bool ep) { + Color us = side_to_move(); + Color them = flip(us); + Square from = move_from(m); + Square to = move_to(m); + Piece piece = piece_on(to); + PieceType pt = type_of(piece); + PieceType capture = st->capturedType; - assert(capture != KING); + assert(square_is_empty(from)); + assert(color_of(piece) == us); + assert(capture != KING); - Square capsq = to; + if (is_promotion(m)) + { + PieceType promotion = promotion_piece_type(m); - // 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(promotion == pt); + assert(relative_rank(us, to) == RANK_8); + assert(promotion >= KNIGHT && promotion <= QUEEN); - 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)); + // Replace the promoted piece with the pawn + clear_bit(&byTypeBB[promotion], to); + set_bit(&byTypeBB[PAWN], to); + board[to] = make_piece(us, PAWN); - board[capsq] = PIECE_NONE; - } - st->pawnKey ^= zobrist[them][PAWN][capsq]; - } - else - st->npMaterial[them] -= PieceValueMidgame[capture]; + // Update piece lists, move the last promoted piece at index[to] position + // and shrink the list. Add a new pawn to the list. + Square lastSquare = pieceList[us][promotion][--pieceCount[us][promotion]]; + index[lastSquare] = index[to]; + pieceList[us][promotion][index[lastSquare]] = lastSquare; + pieceList[us][promotion][pieceCount[us][promotion]] = SQ_NONE; + index[to] = pieceCount[us][PAWN]++; + pieceList[us][PAWN][index[to]] = to; + + pt = PAWN; + } + + // Put the piece back at the source square + Bitboard move_bb = make_move_bb(to, from); + do_move_bb(&byColorBB[us], move_bb); + do_move_bb(&byTypeBB[pt], move_bb); + do_move_bb(&occupied, move_bb); + + board[from] = board[to]; + board[to] = PIECE_NONE; + + // Update piece lists, index[to] is not updated and becomes stale. This + // works as long as index[] is accessed just by known occupied squares. + index[from] = index[to]; + pieceList[us][pt][index[from]] = from; + + if (capture) + { + Square capsq = to; - // Remove captured piece - clear_bit(&byColorBB[them], capsq); - clear_bit(&byTypeBB[capture], capsq); - clear_bit(&byTypeBB[0], capsq); + if (is_enpassant(m)) + { + capsq -= pawn_push(us); - // Update hash key - key ^= zobrist[them][capture][capsq]; + assert(pt == PAWN); + assert(to == st->previous->epSquare); + assert(relative_rank(us, to) == RANK_6); + assert(piece_on(capsq) == PIECE_NONE); + } - // Update incremental scores - st->value -= pst(make_piece(them, capture), capsq); + // Restore the captured piece + set_bit(&byColorBB[them], capsq); + set_bit(&byTypeBB[capture], capsq); + set_bit(&occupied, capsq); - // Update piece count - pieceCount[them][capture]--; + board[capsq] = make_piece(them, capture); - // Update material hash key - st->materialKey ^= zobrist[them][capture][pieceCount[them][capture]]; + // Update piece list, add a new captured piece in capsq square + index[capsq] = pieceCount[them][capture]++; + pieceList[them][capture][index[capsq]] = capsq; + } - // 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; + // Finally point our state pointer back to the previous state + st = st->previous; - // Reset rule 50 counter - st->rule50 = 0; + assert(pos_is_ok()); } @@ -1033,18 +1108,18 @@ void Position::do_castle_move(Move m) { // Remove pieces from source squares clear_bit(&byColorBB[us], kfrom); clear_bit(&byTypeBB[KING], kfrom); - clear_bit(&byTypeBB[0], kfrom); + clear_bit(&occupied, kfrom); clear_bit(&byColorBB[us], rfrom); clear_bit(&byTypeBB[ROOK], rfrom); - clear_bit(&byTypeBB[0], rfrom); + clear_bit(&occupied, rfrom); // Put pieces on destination squares set_bit(&byColorBB[us], kto); set_bit(&byTypeBB[KING], kto); - set_bit(&byTypeBB[0], kto); + set_bit(&occupied, kto); set_bit(&byColorBB[us], rto); set_bit(&byTypeBB[ROOK], rto); - set_bit(&byTypeBB[0], rto); + set_bit(&occupied, rto); // Update board Piece king = make_piece(us, KING); @@ -1103,107 +1178,6 @@ void Position::do_castle_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. - -void Position::undo_move(Move m) { - - assert(is_ok(m)); - - sideToMove = flip(sideToMove); - - if (is_castle(m)) - { - do_castle_move(m); - return; - } - - Color us = side_to_move(); - Color them = flip(us); - Square from = move_from(m); - Square to = move_to(m); - bool ep = is_enpassant(m); - bool pm = is_promotion(m); - - PieceType pt = type_of(piece_on(to)); - - assert(square_is_empty(from)); - assert(color_of(piece_on(to)) == us); - assert(!pm || relative_rank(us, to) == RANK_8); - assert(!ep || to == st->previous->epSquare); - assert(!ep || relative_rank(us, to) == RANK_6); - assert(!ep || piece_on(to) == make_piece(us, PAWN)); - - if (pm) // promotion ? - { - PieceType promotion = promotion_piece_type(m); - pt = PAWN; - - assert(promotion >= KNIGHT && promotion <= QUEEN); - assert(piece_on(to) == make_piece(us, promotion)); - - // Replace promoted piece with a pawn - clear_bit(&byTypeBB[promotion], to); - set_bit(&byTypeBB[PAWN], to); - - // Update piece counts - pieceCount[us][promotion]--; - pieceCount[us][PAWN]++; - - // Update piece list replacing promotion piece with a pawn - Square lastPromotionSquare = pieceList[us][promotion][pieceCount[us][promotion]]; - index[lastPromotionSquare] = index[to]; - pieceList[us][promotion][index[lastPromotionSquare]] = lastPromotionSquare; - pieceList[us][promotion][pieceCount[us][promotion]] = SQ_NONE; - index[to] = pieceCount[us][PAWN] - 1; - pieceList[us][PAWN][index[to]] = to; - } - - // Put the piece back at the source square - Bitboard move_bb = make_move_bb(to, from); - do_move_bb(&byColorBB[us], move_bb); - do_move_bb(&byTypeBB[pt], move_bb); - do_move_bb(&byTypeBB[0], move_bb); // HACK: byTypeBB[0] == occupied squares - - board[from] = make_piece(us, pt); - board[to] = PIECE_NONE; - - // Update piece list - index[from] = index[to]; - pieceList[us][pt][index[from]] = from; - - if (st->capturedType) - { - Square capsq = to; - - if (ep) - capsq = to - pawn_push(us); - - assert(st->capturedType != KING); - assert(!ep || square_is_empty(capsq)); - - // Restore the captured piece - set_bit(&byColorBB[them], capsq); - set_bit(&byTypeBB[st->capturedType], capsq); - set_bit(&byTypeBB[0], capsq); - - board[capsq] = make_piece(them, st->capturedType); - - // Update piece count - pieceCount[them][st->capturedType]++; - - // Update piece list, add a new captured piece in capsq square - index[capsq] = pieceCount[them][st->capturedType] - 1; - pieceList[them][st->capturedType][index[capsq]] = capsq; - } - - // Finally point our state pointer back to the previous state - st = st->previous; - - assert(pos_is_ok()); -} - - /// 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 @@ -1273,7 +1247,7 @@ int Position::see_sign(Move m) const { int Position::see(Move m) const { Square from, to; - Bitboard occupied, attackers, stmAttackers, b; + Bitboard occ, attackers, stmAttackers, b; int swapList[32], slIndex = 1; PieceType capturedType, pt; Color stm; @@ -1289,10 +1263,10 @@ int Position::see(Move m) const { from = move_from(m); to = move_to(m); capturedType = type_of(piece_on(to)); - occupied = occupied_squares(); + occ = occupied_squares(); // Handle en passant moves - if (st->epSquare == to && type_of(piece_on(from)) == PAWN) + if (is_enpassant(m)) { Square capQq = to - pawn_push(side_to_move()); @@ -1300,14 +1274,14 @@ int Position::see(Move m) const { assert(type_of(piece_on(capQq)) == PAWN); // Remove the captured pawn - clear_bit(&occupied, capQq); + clear_bit(&occ, capQq); capturedType = PAWN; } // 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 = attackers_to(to, occupied); + clear_bit(&occ, from); + attackers = attackers_to(to, occ); // If the opponent has no attackers we are finished stm = flip(color_of(piece_on(from))); @@ -1334,11 +1308,11 @@ int Position::see(Move m) const { // Remove the attacker we just found from the 'occupied' bitboard, // and scan for new X-ray attacks behind the attacker. b = stmAttackers & pieces(pt); - occupied ^= (b & (~b + 1)); - attackers |= (rook_attacks_bb(to, occupied) & pieces(ROOK, QUEEN)) - | (bishop_attacks_bb(to, occupied) & pieces(BISHOP, QUEEN)); + occ ^= (b & (~b + 1)); + attackers |= (rook_attacks_bb(to, occ) & pieces(ROOK, QUEEN)) + | (bishop_attacks_bb(to, occ) & pieces(BISHOP, QUEEN)); - attackers &= occupied; // Cut out pieces we've already done + attackers &= occ; // Cut out pieces we've already done // Add the new entry to the swap list assert(slIndex < 32); @@ -1394,6 +1368,7 @@ void Position::clear() { } sideToMove = WHITE; nodes = 0; + occupied = 0; } @@ -1411,7 +1386,7 @@ void Position::put_piece(Piece p, Square s) { set_bit(&byTypeBB[pt], s); set_bit(&byColorBB[c], s); - set_bit(&byTypeBB[0], s); // HACK: byTypeBB[0] contains all occupied squares. + set_bit(&occupied, s); }