diff --git a/src/search.cpp b/src/search.cpp index f0d24314..d922986b 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -306,6 +306,7 @@ namespace { void update_history(const Position& pos, Move m, Depth depth, Move movesSearched[], int moveCount); void update_killers(Move m, SearchStack& ss); void slowdown(const Position& pos); + void build_pv(const Position& pos, Move pv[]); bool fail_high_ply_1(); int current_search_time(); @@ -975,6 +976,7 @@ namespace { // Update PV rml.set_move_score(i, value); update_pv(ss, 0); + build_pv(pos, ss[0].pv); rml.set_move_pv(i, ss[0].pv); if (MultiPV == 1) @@ -2430,7 +2432,7 @@ namespace { } - // slowdown() simply wastes CPU cycles doing nothing useful. It's used + // slowdown() simply wastes CPU cycles doing nothing useful. It's used // in strength handicap mode. void slowdown(const Position &pos) { @@ -2444,6 +2446,37 @@ namespace { } + // build_pv() extends a PV by adding moves from the transposition table at + // the end. This should ensure that the PV is almost always at least two + // plies long, which is important, because otherwise we will often get + // single-move PVs when the search stops while failing high, and a + // single-move PV means that we don't have a ponder move. + + void build_pv(const Position& pos, Move pv[]) { + int ply; + Position p(pos); + StateInfo st[100]; + + for (ply = 0; pv[ply] != MOVE_NONE; ply++) + p.do_move(pv[ply], st[ply]); + + bool stop; + const TTEntry* tte; + for (stop = false, tte = TT.retrieve(p.get_key()); + tte && tte->move() != MOVE_NONE && !stop; + tte = TT.retrieve(p.get_key()), ply++) + { + if (!move_is_legal(p, tte->move(), p.pinned_pieces(p.side_to_move()))) + break; + pv[ply] = tte->move(); + p.do_move(pv[ply], st[ply]); + for (int j = 0; j < ply; j++) + if (st[j].key == p.get_key()) stop = true; + } + pv[ply] = MOVE_NONE; + } + + // fail_high_ply_1() checks if some thread is currently resolving a fail // high at ply 1 at the node below the first root node. This information // is used for time managment.