diff --git a/src/movepick.cpp b/src/movepick.cpp index 45bb8afe..6d00dd94 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -126,11 +126,11 @@ void MovePicker::score() { static_assert(Type == CAPTURES || Type == QUIETS || Type == EVASIONS, "Wrong type"); + Color us = pos.side_to_move(); + [[maybe_unused]] Bitboard threatenedPieces, threatByLesser[QUEEN + 1]; if constexpr (Type == QUIETS) { - Color us = pos.side_to_move(); - threatByLesser[KNIGHT] = threatByLesser[BISHOP] = pos.attacks_by(~us); threatByLesser[ROOK] = pos.attacks_by(~us) | pos.attacks_by(~us) | threatByLesser[KNIGHT]; @@ -143,21 +143,21 @@ void MovePicker::score() { } for (auto& m : *this) + { + const Square from = m.from_sq(); + const Square to = m.to_sq(); + const Piece pc = pos.moved_piece(m); + const PieceType pt = type_of(pc); + const Piece capturedPiece = pos.piece_on(to); + if constexpr (Type == CAPTURES) - m.value = - 7 * int(PieceValue[pos.piece_on(m.to_sq())]) - + 1024 * bool(pos.check_squares(type_of(pos.moved_piece(m))) & m.to_sq()) - + (*captureHistory)[pos.moved_piece(m)][m.to_sq()][type_of(pos.piece_on(m.to_sq()))]; + m.value = (*captureHistory)[pc][to][type_of(capturedPiece)] + + 7 * int(PieceValue[capturedPiece]) + 1024 * bool(pos.check_squares(pt) & to); else if constexpr (Type == QUIETS) { - Piece pc = pos.moved_piece(m); - PieceType pt = type_of(pc); - Square from = m.from_sq(); - Square to = m.to_sq(); - // histories - m.value = 2 * (*mainHistory)[pos.side_to_move()][m.from_to()]; + m.value = 2 * (*mainHistory)[us][m.from_to()]; m.value += 2 * (*pawnHistory)[pawn_structure_index(pos)][pc][to]; m.value += (*continuationHistory[0])[pc][to]; m.value += (*continuationHistory[1])[pc][to]; @@ -184,15 +184,15 @@ void MovePicker::score() { else // Type == EVASIONS { if (pos.capture_stage(m)) - m.value = PieceValue[pos.piece_on(m.to_sq())] + (1 << 28); + m.value = PieceValue[capturedPiece] + (1 << 28); else { - m.value = (*mainHistory)[pos.side_to_move()][m.from_to()] - + (*continuationHistory[0])[pos.moved_piece(m)][m.to_sq()]; + m.value = (*mainHistory)[us][m.from_to()] + (*continuationHistory[0])[pc][to]; if (ply < LOW_PLY_HISTORY_SIZE) m.value += 2 * (*lowPlyHistory)[ply][m.from_to()] / (1 + ply); } } + } } // Returns the next move satisfying a predicate function. @@ -221,7 +221,6 @@ top: case QSEARCH_TT : case PROBCUT_TT : ++stage; - cur = moves + 1; return ttMove; case CAPTURE_INIT : @@ -237,12 +236,10 @@ top: case GOOD_CAPTURE : if (select([&]() { - if (!pos.see_ge(*cur, -cur->value / 18)) - { - std::swap(*endBadCaptures++, *cur); - return false; - } - return true; + if (pos.see_ge(*cur, -cur->value / 18)) + return true; + std::swap(*endBadCaptures++, *cur); + return false; })) return *(cur - 1); @@ -315,23 +312,17 @@ top: void MovePicker::skip_quiet_moves() { skipQuiets = true; } -bool MovePicker::other_piece_types_mobile(PieceType pt) { +// this function must be called after all quiet moves and captures have been generated +bool MovePicker::can_move_king_or_pawn() { assert(stage == GOOD_QUIET || stage == BAD_QUIET || stage == EVASION); - // verify all generated captures and quiets for (ExtMove* m = moves; m < endMoves; ++m) { - if (*m && type_of(pos.moved_piece(*m)) != pt) - { - if (type_of(pos.moved_piece(*m)) != KING) - return true; - if (pos.legal(*m)) - return true; - } + PieceType movedPieceType = type_of(pos.moved_piece(*m)); + if ((movedPieceType == PAWN || movedPieceType == KING) && pos.legal(*m)) + return true; } return false; } -void MovePicker::mark_current_illegal() { *(cur - 1) = Move::none(); } - } // namespace Stockfish diff --git a/src/movepick.h b/src/movepick.h index 7da7c3a7..4218ab5a 100644 --- a/src/movepick.h +++ b/src/movepick.h @@ -50,8 +50,7 @@ class MovePicker { MovePicker(const Position&, Move, int, const CapturePieceToHistory*); Move next_move(); void skip_quiet_moves(); - bool other_piece_types_mobile(PieceType pt); - void mark_current_illegal(); + bool can_move_king_or_pawn(); private: template diff --git a/src/search.cpp b/src/search.cpp index cce01867..f5935818 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -910,7 +910,7 @@ Value Search::Worker::search( // Step 10. Internal iterative reductions // For PV nodes without a ttMove as well as for deep enough cutNodes, we decrease depth. // (*Scaler) Especially if they make IIR less aggressive. - if ((!allNode && depth >= (PvNode ? 5 : 7)) && !ttData.move) + if (!allNode && depth >= (PvNode ? 5 : 7) && !ttData.move) depth--; // Step 11. ProbCut @@ -1002,10 +1002,8 @@ moves_loop: // When in check, search starts here // Check for legality if (!pos.legal(move)) - { - mp.mark_current_illegal(); continue; - } + // At root obey the "searchmoves" option and skip moves not listed in Root // Move List. In MultiPV mode we also skip PV moves that have been already // searched and those of lower "TB rank" if we are in a TB root position. @@ -1074,15 +1072,17 @@ moves_loop: // When in check, search starts here int seeHist = std::clamp(captHist / 31, -137 * depth, 125 * depth); if (!pos.see_ge(move, -158 * depth - seeHist)) { - bool skip = true; - if (depth > 2 && !capture && givesCheck && alpha < 0 - && pos.non_pawn_material(us) == PieceValue[movedPiece] - && PieceValue[movedPiece] >= RookValue - && !(PseudoAttacks[KING][pos.square(us)] & move.from_sq())) - // if the opponent captures last mobile piece it might be stalemate - skip = mp.other_piece_types_mobile(type_of(movedPiece)); + bool mayStalemateTrap = + depth > 2 && givesCheck && alpha < 0 + && !capture // we consider that captures will likely destroy the stalemate configuration + && pos.non_pawn_material(us) == PieceValue[movedPiece] + && PieceValue[movedPiece] >= RookValue + // it can't be stalemate if we moved a piece adjacent to the king + && !(attacks_bb(pos.square(us)) & move.from_sq()) + && !mp.can_move_king_or_pawn(); - if (skip) + // avoid pruning sacrifices of our last piece for stalemate + if (!mayStalemateTrap) continue; } } @@ -1873,8 +1873,8 @@ void update_all_stats(const Position& pos, int moveCount) { CapturePieceToHistory& captureHistory = workerThread.captureHistory; - Piece moved_piece = pos.moved_piece(bestMove); - PieceType captured; + Piece movedPiece = pos.moved_piece(bestMove); + PieceType capturedPiece; int bonus = std::min(143 * depth - 89, 1496) + 302 * (bestMove == ttMove); int malus = std::min(737 * depth - 179, 3141) - 30 * moveCount; @@ -1890,8 +1890,8 @@ void update_all_stats(const Position& pos, else { // Increase stats for the best move in case it was a capture move - captured = type_of(pos.piece_on(bestMove.to_sq())); - captureHistory[moved_piece][bestMove.to_sq()][captured] << bonus * 1213 / 1024; + capturedPiece = type_of(pos.piece_on(bestMove.to_sq())); + captureHistory[movedPiece][bestMove.to_sq()][capturedPiece] << bonus * 1213 / 1024; } // Extra penalty for a quiet early move that was not a TT move in @@ -1902,9 +1902,9 @@ void update_all_stats(const Position& pos, // Decrease stats for all non-best capture moves for (Move move : capturesSearched) { - moved_piece = pos.moved_piece(move); - captured = type_of(pos.piece_on(move.to_sq())); - captureHistory[moved_piece][move.to_sq()][captured] << -malus * 1388 / 1024; + movedPiece = pos.moved_piece(move); + capturedPiece = type_of(pos.piece_on(move.to_sq())); + captureHistory[movedPiece][move.to_sq()][capturedPiece] << -malus * 1388 / 1024; } }