diff --git a/src/movepick.cpp b/src/movepick.cpp index 11317f113..cc6d47901 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -19,6 +19,7 @@ #include "movepick.h" #include +#include #include #include "bitboard.h" @@ -316,4 +317,30 @@ top: void MovePicker::skip_quiet_moves() { skipQuiets = true; } +bool MovePicker::otherPieceTypesMobile(PieceType pt, ValueList& capturesSearched) { + if (stage != GOOD_QUIET && stage != BAD_QUIET) + return true; + + // verify good captures + for (std::size_t i = 0; i < capturesSearched.size(); i++) + if (type_of(pos.moved_piece(capturesSearched[i])) != pt) + { + if (type_of(pos.moved_piece(capturesSearched[i])) != KING) + return true; + if (pos.legal(capturesSearched[i])) + return true; + } + + // now verify bad captures and quiets + for (ExtMove* c = moves; c < endBadQuiets; ++c) + if (type_of(pos.moved_piece(*c)) != pt) + { + if (type_of(pos.moved_piece(*c)) != KING) + return true; + if (pos.legal(*c)) + return true; + } + return false; +} + } // namespace Stockfish diff --git a/src/movepick.h b/src/movepick.h index 71078bdcf..dfafe69a5 100644 --- a/src/movepick.h +++ b/src/movepick.h @@ -19,6 +19,8 @@ #ifndef MOVEPICK_H_INCLUDED #define MOVEPICK_H_INCLUDED +#include + #include "history.h" #include "movegen.h" #include "types.h" @@ -27,6 +29,9 @@ namespace Stockfish { class Position; +template +class ValueList; + // The MovePicker class is used to pick one pseudo-legal move at a time from the // current position. The most important method is next_move(), which emits one // new pseudo-legal move on every call, until there are no moves left, when @@ -50,6 +55,7 @@ class MovePicker { MovePicker(const Position&, Move, int, const CapturePieceToHistory*); Move next_move(); void skip_quiet_moves(); + bool otherPieceTypesMobile(PieceType pt, ValueList& capturesSearched); private: template diff --git a/src/search.cpp b/src/search.cpp index 7efd8499f..3f24f86c5 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -34,6 +34,7 @@ #include #include +#include "bitboard.h" #include "evaluate.h" #include "history.h" #include "misc.h" @@ -1070,7 +1071,19 @@ moves_loop: // When in check, search starts here // SEE based pruning for captures and checks int seeHist = std::clamp(captHist / 32, -138 * depth, 135 * depth); if (!pos.see_ge(move, -154 * depth - seeHist)) - continue; + { + 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())) + skip = mp.otherPieceTypesMobile( + type_of(movedPiece), + capturesSearched); // if the opponent captures last mobile piece it might be stalemate + + if (skip) + continue; + } } else { @@ -1490,7 +1503,8 @@ moves_loop: // When in check, search starts here bestValue >= beta ? BOUND_LOWER : PvNode && bestMove ? BOUND_EXACT : BOUND_UPPER, - depth, bestMove, unadjustedStaticEval, tt.generation()); + moveCount != 0 ? depth : std::min(MAX_PLY - 1, depth + 6), bestMove, + unadjustedStaticEval, tt.generation()); // Adjust correction history if (!ss->inCheck && !(bestMove && pos.capture(bestMove)) @@ -1743,6 +1757,22 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta) if (!is_decisive(bestValue) && bestValue > beta) bestValue = (bestValue + beta) / 2; + + Color us = pos.side_to_move(); + if (!ss->inCheck && !moveCount && !pos.non_pawn_material(us) + && type_of(pos.captured_piece()) >= ROOK) + { + if (!((us == WHITE ? shift(pos.pieces(us, PAWN)) + : shift(pos.pieces(us, PAWN))) + & ~pos.pieces())) // no pawn pushes available + { + pos.state()->checkersBB = Rank1BB; // search for legal king-moves only + if (!MoveList(pos).size()) // stalemate + bestValue = VALUE_DRAW; + pos.state()->checkersBB = 0; + } + } + // Save gathered info in transposition table. The static evaluation // is saved as it was before adjustment by correction history. ttWriter.write(posKey, value_to_tt(bestValue, ss->ply), pvHit,