]> git.sesse.net Git - stockfish/commitdiff
Sync with master
authorMarco Costalba <mcostalba@gmail.com>
Fri, 30 Jan 2015 16:58:18 +0000 (17:58 +0100)
committerMarco Costalba <mcostalba@gmail.com>
Fri, 30 Jan 2015 16:58:18 +0000 (17:58 +0100)
bench: 7374604

1  2 
src/search.cpp
src/search.h

diff --combined src/search.cpp
index 4515bba0f2b9aaa605a9c18fe7fd9c85823ffe7d,3c32c4bb762a45ee1ae35f14a02aa119ff654418..e773a36a72af9b40915dfede7c9a79ed45a9c5b1
@@@ -105,14 -105,22 +105,14 @@@ namespace 
    string uci_pv(const Position& pos, Depth depth, Value alpha, Value beta);
  
    struct Skill {
 -    Skill(int l, size_t rootSize) : level(l),
 -                                    candidates(l < 20 ? std::min(4, (int)rootSize) : 0),
 -                                    best(MOVE_NONE) {}
 -   ~Skill() {
 -      if (candidates) // Swap best PV line with the sub-optimal one
 -          std::swap(RootMoves[0], *std::find(RootMoves.begin(),
 -                    RootMoves.end(), best ? best : pick_move()));
 -    }
 -
 -    size_t candidates_size() const { return candidates; }
 +    Skill(int l) : level(l) {}
 +    bool enabled() const { return level < 20; }
      bool time_to_pick(Depth depth) const { return depth / ONE_PLY == 1 + level; }
 -    Move pick_move();
 +    Move best_move(size_t multiPV) { return best ? best : pick_best(multiPV); }
 +    Move pick_best(size_t multiPV);
  
      int level;
 -    size_t candidates;
 -    Move best;
 +    Move best = MOVE_NONE;
    };
  
  } // namespace
@@@ -159,19 -167,19 +159,19 @@@ uint64_t Search::perft(Position& pos, D
    CheckInfo ci(pos);
    const bool leaf = (depth == 2 * ONE_PLY);
  
 -  for (MoveList<LEGAL> it(pos); *it; ++it)
 +  for (const ExtMove& ms : MoveList<LEGAL>(pos))
    {
        if (Root && depth <= ONE_PLY)
            cnt = 1, nodes++;
        else
        {
 -          pos.do_move(*it, st, ci, pos.gives_check(*it, ci));
 +          pos.do_move(ms.move, st, ci, pos.gives_check(ms.move, ci));
            cnt = leaf ? MoveList<LEGAL>(pos).size() : perft<false>(pos, depth - ONE_PLY);
            nodes += cnt;
 -          pos.undo_move(*it);
 +          pos.undo_move(ms.move);
        }
        if (Root)
 -          sync_cout << UCI::move(*it, pos.is_chess960()) << ": " << cnt << sync_endl;
 +          sync_cout << UCI::move(ms.move, pos.is_chess960()) << ": " << cnt << sync_endl;
    }
    return nodes;
  }
@@@ -244,8 -252,8 +244,8 @@@ void Search::think() 
            }
        }
  
 -      for (size_t i = 0; i < Threads.size(); ++i)
 -          Threads[i]->maxPly = 0;
 +      for (Thread* th : Threads)
 +          th->maxPly = 0;
  
        Threads.timer->run = true;
        Threads.timer->notify_one(); // Wake up the recurring timer
  
    sync_cout << "bestmove " << UCI::move(RootMoves[0].pv[0], RootPos.is_chess960());
  
-   if (RootMoves[0].pv.size() > 1)
+   if (RootMoves[0].pv.size() > 1 || RootMoves[0].extract_ponder_from_tt(RootPos))
        std::cout << " ponder " << UCI::move(RootMoves[0].pv[1], RootPos.is_chess960());
  
    std::cout << sync_endl;
@@@ -301,14 -309,11 +301,14 @@@ namespace 
      Followupmoves.clear();
  
      size_t multiPV = Options["MultiPV"];
 -    Skill skill(Options["Skill Level"], RootMoves.size());
 +    Skill skill(Options["Skill Level"]);
 +
 +    // When playing with strength handicap enable MultiPV search that we will
 +    // use behind the scenes to retrieve a set of possible moves.
 +    if (skill.enabled())
 +        multiPV = std::max(multiPV, (size_t)4);
  
 -    // Do we have to play with skill handicap? In this case enable MultiPV search
 -    // that we will use behind the scenes to retrieve a set of possible moves.
 -    multiPV = std::max(multiPV, skill.candidates_size());
 +    multiPV = std::min(multiPV, RootMoves.size());
  
      // Iterative deepening loop until requested to stop or target depth reached
      while (++depth < DEPTH_MAX && !Signals.stop && (!Limits.depth || depth <= Limits.depth))
  
          // Save the last iteration's scores before first PV line is searched and
          // all the move scores except the (new) PV are set to -VALUE_INFINITE.
 -        for (size_t i = 0; i < RootMoves.size(); ++i)
 -            RootMoves[i].previousScore = RootMoves[i].score;
 +        for (RootMove& rm : RootMoves)
 +            rm.previousScore = rm.score;
  
          // MultiPV loop. We perform a full root search for each PV line
 -        for (PVIdx = 0; PVIdx < std::min(multiPV, RootMoves.size()) && !Signals.stop; ++PVIdx)
 +        for (PVIdx = 0; PVIdx < multiPV && !Signals.stop; ++PVIdx)
          {
              // Reset aspiration window starting size
              if (depth >= 5 * ONE_PLY)
  
                  // When failing high/low give some update (without cluttering
                  // the UI) before a re-search.
-                 if (  (bestValue <= alpha || bestValue >= beta)
+                 if (   multiPV == 1
+                     && (bestValue <= alpha || bestValue >= beta)
                      && Time::now() - SearchTime > 3000)
                      sync_cout << uci_pv(pos, depth, alpha, beta) << sync_endl;
  
                  sync_cout << "info nodes " << RootPos.nodes_searched()
                            << " time " << Time::now() - SearchTime << sync_endl;
  
 -            else if (   PVIdx + 1 == std::min(multiPV, RootMoves.size())
 -                     || Time::now() - SearchTime > 3000)
 +            else if (PVIdx + 1 == multiPV || Time::now() - SearchTime > 3000)
                  sync_cout << uci_pv(pos, depth, alpha, beta) << sync_endl;
          }
  
 -        // If skill levels are enabled and time is up, pick a sub-optimal best move
 -        if (skill.candidates_size() && skill.time_to_pick(depth))
 -            skill.pick_move();
 +        // If skill level is enabled and time is up, pick a sub-optimal best move
 +        if (skill.enabled() && skill.time_to_pick(depth))
 +            skill.pick_best(multiPV);
  
          // Have we found a "mate in x"?
          if (   Limits.mate
              }
          }
      }
 +
 +    // If skill level is enabled, swap best PV line with the sub-optimal one
 +    if (skill.enabled())
 +        std::swap(RootMoves[0], *std::find(RootMoves.begin(),
 +                  RootMoves.end(), skill.best_move(multiPV)));
    }
  
  
          splitPoint = ss->splitPoint;
          bestMove   = splitPoint->bestMove;
          bestValue  = splitPoint->bestValue;
 -        tte = NULL;
 +        tte = nullptr;
          ttHit = false;
          ttMove = excludedMove = MOVE_NONE;
          ttValue = VALUE_NONE;
  
          // If ttMove is quiet, update killers, history, counter move and followup move on TT hit
          if (ttValue >= beta && ttMove && !pos.capture_or_promotion(ttMove) && !inCheck)
 -            update_stats(pos, ss, ttMove, depth, NULL, 0);
 +            update_stats(pos, ss, ttMove, depth, nullptr, 0);
  
          return ttValue;
      }
@@@ -787,7 -789,7 +788,7 @@@ moves_loop: // When in check and at SpN
        }
  
        if (PvNode)
 -          (ss+1)->pv = NULL;
 +          (ss+1)->pv = nullptr;
  
        extension = DEPTH_ZERO;
        captureOrPromotion = pos.capture_or_promotion(move);
        newDepth = depth - ONE_PLY + extension;
  
        // Step 13. Pruning at shallow depth
-       if (   !captureOrPromotion
+       if (   !RootNode
+           && !captureOrPromotion
            && !inCheck
            && !dangerous
            &&  bestValue > VALUE_MATED_IN_MAX_PLY)
    }
  
  
 -  // When playing with a strength handicap, choose best move among the first 'candidates'
 -  // RootMoves using a statistical rule dependent on 'level'. Idea by Heinz van Saanen.
 +  // When playing with strength handicap, choose best move among a set of RootMoves
 +  // using a statistical rule dependent on 'level'. Idea by Heinz van Saanen.
  
 -  Move Skill::pick_move() {
 +  Move Skill::pick_best(size_t multiPV) {
  
      // PRNG sequence should be non-deterministic, so we seed it with the time at init
      static PRNG rng(Time::now());
  
      // RootMoves are already sorted by score in descending order
 -    int variance = std::min(RootMoves[0].score - RootMoves[candidates - 1].score, PawnValueMg);
 +    int variance = std::min(RootMoves[0].score - RootMoves[multiPV - 1].score, PawnValueMg);
      int weakness = 120 - 2 * level;
      int maxScore = -VALUE_INFINITE;
 -    best = MOVE_NONE;
  
      // Choose best move. For each move score we add two terms both dependent on
 -    // weakness. One deterministic and bigger for weaker moves, and one random,
 +    // weakness. One deterministic and bigger for weaker levels, and one random,
      // then we choose the move with the resulting highest score.
 -    for (size_t i = 0; i < candidates; ++i)
 +    for (size_t i = 0; i < multiPV; ++i)
      {
          int score = RootMoves[i].score;
  
-         // Don't allow crazy blunders even at very low skills
-         if (i > 0 && RootMoves[i - 1].score > score + 2 * PawnValueMg)
-             break;
          // This is our magic formula
          score += (  weakness * int(RootMoves[0].score - score)
                    + variance * (rng.rand<unsigned>() % weakness)) / 128;
      size_t uciPVSize = std::min((size_t)Options["MultiPV"], RootMoves.size());
      int selDepth = 0;
  
 -    for (size_t i = 0; i < Threads.size(); ++i)
 -        if (Threads[i]->maxPly > selDepth)
 -            selDepth = Threads[i]->maxPly;
 +    for (Thread* th : Threads)
 +        if (th->maxPly > selDepth)
 +            selDepth = th->maxPly;
  
      for (size_t i = 0; i < uciPVSize; ++i)
      {
@@@ -1488,13 -1488,37 +1486,37 @@@ void RootMove::insert_pv_in_tt(Position
  }
  
  
+ /// RootMove::extract_ponder_from_tt() is called in case we have no ponder move before
+ /// exiting the search, for instance in case we stop the search during a fail high at
+ /// root. We try hard to have a ponder move to return to the GUI, otherwise in case of
+ /// 'ponder on' we have nothing to think on.
+ Move RootMove::extract_ponder_from_tt(Position& pos)
+ {
+     StateInfo st;
+     bool found;
+     assert(pv.size() == 1);
+     pos.do_move(pv[0], st);
+     TTEntry* tte = TT.probe(pos.key(), found);
+     Move m = found ? tte->move() : MOVE_NONE;
+     if (!MoveList<LEGAL>(pos).contains(m))
+         m = MOVE_NONE;
+     pos.undo_move(pv[0]);
+     pv.push_back(m);
+     return m;
+ }
  /// Thread::idle_loop() is where the thread is parked when it has no work to do
  
  void Thread::idle_loop() {
  
    // Pointer 'this_sp' is not null only if we are called from split(), and not
    // at the thread creation. This means we are the split point's master.
 -  SplitPoint* this_sp = splitPointsSize ? activeSplitPoint : NULL;
 +  SplitPoint* this_sp = splitPointsSize ? activeSplitPoint : nullptr;
  
    assert(!this_sp || (this_sp->masterThread == this && searching));
  
  
            sp->mutex.lock();
  
 -          assert(activePosition == NULL);
 +          assert(activePosition == nullptr);
  
            activePosition = &pos;
  
            assert(searching);
  
            searching = false;
 -          activePosition = NULL;
 +          activePosition = nullptr;
            sp->slavesMask.reset(idx);
            sp->allSlavesSearching = false;
            sp->nodes += pos.nodes_searched();
                for (size_t i = 0; i < Threads.size(); ++i)
                {
                    const int size = Threads[i]->splitPointsSize; // Local copy
 -                  sp = size ? &Threads[i]->splitPoints[size - 1] : NULL;
 +                  sp = size ? &Threads[i]->splitPoints[size - 1] : nullptr;
  
                    if (   sp
                        && sp->allSlavesSearching
        }
  
        // Grab the lock to avoid races with Thread::notify_one()
 -      mutex.lock();
 +      std::unique_lock<std::mutex> lk(mutex);
  
        // If we are master and all slaves have finished then exit idle_loop
        if (this_sp && this_sp->slavesMask.none())
        {
            assert(!searching);
 -          mutex.unlock();
            break;
        }
  
        // If we are not searching, wait for a condition to be signaled instead of
        // wasting CPU time polling for work.
        if (!searching && !exit)
 -          sleepCondition.wait(mutex);
 -
 -      mutex.unlock();
 +          sleepCondition.wait(lk);
    }
  }
  
@@@ -1646,10 -1673,10 +1668,10 @@@ void check_time() 
  
        // Loop across all split points and sum accumulated SplitPoint nodes plus
        // all the currently active positions nodes.
 -      for (size_t i = 0; i < Threads.size(); ++i)
 -          for (int j = 0; j < Threads[i]->splitPointsSize; ++j)
 +      for (Thread* th : Threads)
 +          for (int i = 0; i < th->splitPointsSize; ++i)
            {
 -              SplitPoint& sp = Threads[i]->splitPoints[j];
 +              SplitPoint& sp = th->splitPoints[i];
  
                sp.mutex.lock();
  
diff --combined src/search.h
index a31b189c010f2c00fe3c3fe5b3252a52f5a8c96a,5a0ad5df5790708e3a0e1d8d37f2926fcb3b668a..3d348de94b2b860d5d461b5b287c05f2496e1b6a
@@@ -60,6 -60,7 +60,7 @@@ struct RootMove 
    bool operator<(const RootMove& m) const { return score > m.score; } // Ascending sort
    bool operator==(const Move& m) const { return pv[0] == m; }
    void insert_pv_in_tt(Position& pos);
+   Move extract_ponder_from_tt(Position& pos);
  
    Value score;
    Value previousScore;
@@@ -95,7 -96,7 +96,7 @@@ struct SignalsType 
    bool stop, stopOnPonderhit, firstRootMove, failedLowAtRoot;
  };
  
 -typedef std::auto_ptr<std::stack<StateInfo> > StateStackPtr;
 +typedef std::unique_ptr<std::stack<StateInfo>> StateStackPtr;
  
  extern volatile SignalsType Signals;
  extern LimitsType Limits;