diff --git a/src/position.cpp b/src/position.cpp index 1b82b6c0..6a393ebb 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -1079,25 +1079,30 @@ bool Position::see_ge(Move m, Value v) const { /// Position::is_draw() tests whether the position is drawn by 50-move rule /// or by repetition. It does not detect stalemates. -bool Position::is_draw() const { +bool Position::is_draw(int ply) const { if (st->rule50 > 99 && (!checkers() || MoveList(*this).size())) return true; - int e = std::min(st->rule50, st->pliesFromNull); + int end = std::min(st->rule50, st->pliesFromNull); - if (e < 4) + if (end < 4) return false; StateInfo* stp = st->previous->previous; + int cnt = 0; - do { + for (int i = 4; i <= end; i += 2) + { stp = stp->previous->previous; - if (stp->key == st->key) - return true; // Draw at first repetition - - } while ((e -= 2) >= 4); + // At root position ply is 1, so return a draw score if a position + // repeats once earlier but after or at the root, or repeats twice + // strictly before the root. + if ( stp->key == st->key + && ++cnt + (ply - i > 0) == 2) + return true; + } return false; } diff --git a/src/position.h b/src/position.h index 69bf40b1..1ee247e9 100644 --- a/src/position.h +++ b/src/position.h @@ -150,7 +150,7 @@ public: bool is_chess960() const; Thread* this_thread() const; uint64_t nodes_searched() const; - bool is_draw() const; + bool is_draw(int ply) const; int rule50_count() const; Score psq_score() const; Value non_pawn_material(Color c) const; diff --git a/src/search.cpp b/src/search.cpp index 8089130e..75d388b9 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -597,7 +597,7 @@ namespace { if (!rootNode) { // Step 2. Check for aborted search and immediate draw - if (Signals.stop.load(std::memory_order_relaxed) || pos.is_draw() || ss->ply >= MAX_PLY) + if (Signals.stop.load(std::memory_order_relaxed) || pos.is_draw(ss->ply) || ss->ply >= MAX_PLY) return ss->ply >= MAX_PLY && !inCheck ? evaluate(pos) : DrawValue[pos.side_to_move()]; @@ -1180,7 +1180,7 @@ moves_loop: // When in check search starts from here ss->ply = (ss-1)->ply + 1; // Check for an instant draw or if the maximum ply has been reached - if (pos.is_draw() || ss->ply >= MAX_PLY) + if (pos.is_draw(ss->ply) || ss->ply >= MAX_PLY) return ss->ply >= MAX_PLY && !InCheck ? evaluate(pos) : DrawValue[pos.side_to_move()];