void ThreadPool::startThinking( const Position& pos, const LimitsType& limits, const std::vector<Move>& searchMoves, const std::chrono::time_point<std::chrono::system_clock>& goReceivedTime) { waitForThinkFinished(); pos.searcher()->searchTimer.set(goReceivedTime); pos.searcher()->signals.stopOnPonderHit = pos.searcher()->signals.firstRootMove = false; pos.searcher()->signals.stop = pos.searcher()->signals.failedLowAtRoot = false; pos.searcher()->rootPosition = pos; pos.searcher()->limits.set(limits); pos.searcher()->rootMoves.clear(); #if defined LEARN const MoveType MT = LegalAll; #else const MoveType MT = Legal; #endif for (MoveList<MT> ml(pos); !ml.end(); ++ml) { if (searchMoves.empty() || std::find(searchMoves.begin(), searchMoves.end(), ml.move()) != searchMoves.end()) { pos.searcher()->rootMoves.push_back(RootMove(ml.move())); } } mainThread()->thinking = true; mainThread()->notifyOne(); }
void ThreadPool::startThinking(const Position& pos, const LimitsType& limits, const std::vector<Move>& searchMoves) { #if defined LEARN #else waitForThinkFinished(); #endif pos.searcher()->searchTimer.restart(); pos.searcher()->signals.stopOnPonderHit = pos.searcher()->signals.firstRootMove = false; pos.searcher()->signals.stop = pos.searcher()->signals.failedLowAtRoot = false; pos.searcher()->rootPosition = pos; pos.searcher()->limits = limits; pos.searcher()->rootMoves.clear(); #if defined LEARN // searchMoves を直接使う。 pos.searcher()->rootMoves.push_back(RootMove(searchMoves[0])); #else const MoveType MT = Legal; for (MoveList<MT> ml(pos); !ml.end(); ++ml) { if (searchMoves.empty() || std::find(searchMoves.begin(), searchMoves.end(), ml.move()) != searchMoves.end()) { pos.searcher()->rootMoves.push_back(RootMove(ml.move())); } } #endif #if defined LEARN // 浅い探索なので、thread 生成、破棄のコストが高い。余分な thread を生成せずに直接探索を呼び出す。 pos.searcher()->think(); #else mainThread()->thinking = true; mainThread()->notifyOne(); #endif }
static inline void Execute885_500(Rucksack& rucksack, Position& pos) { Flashlight flashlight[g_maxPlyPlus2]; Ply depth; // ベストムーブは何手目かだろうかなんだぜ☆?(^q^)? Ply prevBestMovePlyChanges; ScoreIndex bestScore = -ScoreInfinite; ScoreIndex delta = -ScoreInfinite; ScoreIndex alpha = -ScoreInfinite; ScoreIndex beta = ScoreInfinite; bool bestMoveNeverChanged = true; int lastInfoTime = -1; // 将棋所のコンソールが詰まる問題への対処用 memset(flashlight, 0, 4 * sizeof(Flashlight)); rucksack.ZeroclearBestMovePlyChanges(); #if defined LEARN // 高速化の為に浅い探索は反復深化しないようにする。学習時は浅い探索をひたすら繰り返す為。 depth = std::max<Ply>(0, rucksack.m_limits.GetDepth() - 1); #else depth = 0; #endif flashlight[0].m_currentMove = g_MOVE_NULL; // skip update gains rucksack.m_tt.NewSearch(); rucksack.m_history.Clear(); rucksack.m_gains.Clear(); // マルチPVの数☆? rucksack.m_pvSize = rucksack.m_engineOptions["MultiPV"]; Skill skill(rucksack.m_engineOptions["Skill_Level"], rucksack.m_engineOptions["Max_Random_Score_Diff"]); if (rucksack.m_engineOptions["Max_Random_Score_Diff_Ply"] < pos.GetGamePly()) { skill.m_maxRandomScoreDiff = ScoreZero; rucksack.m_pvSize = 1; assert(!skill.enabled()); // level による設定が出来るようになるまでは、これで良い。 } if (skill.enabled() && rucksack.m_pvSize < 3) { rucksack.m_pvSize = 3; } rucksack.m_pvSize = std::min(rucksack.m_pvSize, rucksack.m_rootMoves.size()); // 指し手が無ければ負け if (rucksack.m_rootMoves.empty()) { rucksack.m_rootMoves.push_back(RootMove(g_MOVE_NONE)); SYNCCOUT << "info depth 0 score " << rucksack.scoreToUSI(-ScoreMate0Ply) << SYNCENDL; return; } #if defined BISHOP_IN_DANGER if ((bishopInDangerFlag == BlackBishopInDangerIn28 && std::find_if(std::begin(m_rootMoves), std::IsEnd(m_rootMoves), [](const RootMove& rm) { return rm.m_pv_[0].ToCSA() == "0082KA"; }) != std::IsEnd(m_rootMoves)) || (bishopInDangerFlag == WhiteBishopInDangerIn28 && std::find_if(std::begin(m_rootMoves), std::IsEnd(m_rootMoves), [](const RootMove& rm) { return rm.m_pv_[0].ToCSA() == "0028KA"; }) != std::IsEnd(m_rootMoves)) || (bishopInDangerFlag == BlackBishopInDangerIn78 && std::find_if(std::begin(m_rootMoves), std::IsEnd(m_rootMoves), [](const RootMove& rm) { return rm.m_pv_[0].ToCSA() == "0032KA"; }) != std::IsEnd(m_rootMoves)) || (bishopInDangerFlag == WhiteBishopInDangerIn78 && std::find_if(std::begin(m_rootMoves), std::IsEnd(m_rootMoves), [](const RootMove& rm) { return rm.m_pv_[0].ToCSA() == "0078KA"; }) != std::IsEnd(m_rootMoves))) { if (m_rootMoves.m_size() != 1) m_pvSize = std::max<size_t>(m_pvSize, 2); } #endif // 反復深化で探索を行う。 while (++depth <= g_maxPly && !rucksack.m_signals.m_stop && (!rucksack.m_limits.m_depth || depth <= rucksack.m_limits.m_depth)) { // 前回の iteration の結果を全てコピー for (size_t i = 0; i < rucksack.m_rootMoves.size(); ++i) { rucksack.m_rootMoves[i].m_prevScore_ = rucksack.m_rootMoves[i].m_score_; } prevBestMovePlyChanges = rucksack.GetBestMovePlyChanges(); rucksack.ZeroclearBestMovePlyChanges(); // 退避したので、ゼロクリアーするぜ☆(^q^) // Multi PV loop for (rucksack.m_pvIdx = 0; rucksack.m_pvIdx < rucksack.m_pvSize && !rucksack.m_signals.m_stop; ++rucksack.m_pvIdx) { #if defined LEARN alpha = rucksack.m_alpha; beta = rucksack.m_beta; #else // aspiration search // alpha, beta をある程度絞ることで、探索効率を上げる。 if ( // 深さ5以上で 5 <= depth && abs(rucksack.m_rootMoves[rucksack.m_pvIdx].m_prevScore_) < PieceScore::m_ScoreKnownWin ) { delta = static_cast<ScoreIndex>(16); alpha = rucksack.m_rootMoves[rucksack.m_pvIdx].m_prevScore_ - delta; beta = rucksack.m_rootMoves[rucksack.m_pvIdx].m_prevScore_ + delta; } else { alpha = -ScoreInfinite; beta = ScoreInfinite; } #endif // aspiration search の window 幅を、初めは小さい値にして探索し、 // fail high/low になったなら、今度は window 幅を広げて、再探索を行う。 while (true) { // 探索を行う。 flashlight->m_staticEvalRaw.m_p[0][0] = (flashlight + 1)->m_staticEvalRaw.m_p[0][0] = ScoreNotEvaluated; //──────────────────────────────────────────────────────────────────────────────── // 探索☆?(^q^) 1回目のぐるんぐるんだぜ~☆ ルート~☆ //──────────────────────────────────────────────────────────────────────────────── bestScore = g_NODETYPE_PROGRAMS[NodeType::N00_Root]->GoToTheAdventure_new(rucksack, pos, flashlight + 1, alpha, beta, static_cast<Depth>(depth * OnePly), false); // 先頭が最善手になるようにソート UtilMove01::InsertionSort(rucksack.m_rootMoves.begin() + rucksack.m_pvIdx, rucksack.m_rootMoves.end()); for (size_t i = 0; i <= rucksack.m_pvIdx; ++i) { flashlight->m_staticEvalRaw.m_p[0][0] = (flashlight + 1)->m_staticEvalRaw.m_p[0][0] = ScoreNotEvaluated; rucksack.m_rootMoves[i].InsertPvInTT(pos); } #if 0 // 詰みを発見したら即指す。 if (ScoreMateInMaxPly <= abs(rucksack.m_bestScore) && abs(rucksack.m_bestScore) < ScoreInfinite) { SYNCCOUT << PvInfoToUSI(GetPos, rucksack.m_ply, rucksack.m_alpha, rucksack.m_beta) << SYNCENDL; rucksack.m_signals.m_stop = true; } #endif #if defined LEARN break; #endif if (rucksack.m_signals.m_stop) { break; } if (alpha < bestScore && bestScore < beta) { break; } if ( // 思考時間が3秒経過するまで、読み筋を出力しないぜ☆!(^q^) 3000 < rucksack.m_stopwatch.GetElapsed() // 将棋所のコンソールが詰まるのを防ぐ。 && (depth < 10 || lastInfoTime + 200 < rucksack.m_stopwatch.GetElapsed())) { lastInfoTime = rucksack.m_stopwatch.GetElapsed(); SYNCCOUT << rucksack.PvInfoToUSI(pos, depth, alpha, beta) << SYNCENDL; } // fail high/low のとき、aspiration window を広げる。 if (PieceScore::m_ScoreKnownWin <= abs(bestScore)) { // 勝ち(負け)だと判定したら、最大の幅で探索を試してみる。 alpha = -ScoreInfinite; beta = ScoreInfinite; } else if (beta <= bestScore) { beta += delta; delta += delta / 2; } else { rucksack.m_signals.m_failedLowAtRoot = true; rucksack.m_signals.m_stopOnPonderHit = false; alpha -= delta; delta += delta / 2; } assert(-ScoreInfinite <= alpha && beta <= ScoreInfinite); } UtilMove01::InsertionSort(rucksack.m_rootMoves.begin(), rucksack.m_rootMoves.begin() + rucksack.m_pvIdx + 1); if ( ( rucksack.m_pvIdx + 1 == rucksack.m_pvSize || // 思考時間が3秒経過するまで、読み筋を出力しないぜ☆!(^q^) 3000 < rucksack.m_stopwatch.GetElapsed() ) // 将棋所のコンソールが詰まるのを防ぐ。 && (depth < 10 || lastInfoTime + 200 < rucksack.m_stopwatch.GetElapsed())) { lastInfoTime = rucksack.m_stopwatch.GetElapsed(); SYNCCOUT << rucksack.PvInfoToUSI(pos, depth, alpha, beta) << SYNCENDL; } } //if (skill.enabled() && skill.timeToPick(depth)) { // skill.pickMove(); //} if ( rucksack.m_limits.IsBrandnewTimeManagement() // 反復深化探索に潜るために真であることが必要☆ && !rucksack.m_signals.m_stopOnPonderHit ) { bool stop = false; // 深さが 5 ~ 49 で、PVサイズが 1 のとき。 if (4 < depth && depth < 50 && rucksack.m_pvSize == 1) { rucksack.m_timeManager.SetPvInstability_AtIterativeDeepeningStarted(rucksack.GetBestMovePlyChanges(), prevBestMovePlyChanges); } // 次のイテレーションを回す時間が無いなら、ストップ if ( rucksack.m_timeManager.CanNotNextIteration(rucksack.m_stopwatch.GetElapsed()) ) { stop = true; } if (2 < depth && rucksack.GetBestMovePlyChanges()) { bestMoveNeverChanged = false; } // 最善手が、ある程度の深さまで同じであれば、 // その手が突出して良い手なのだろう。 if ( 12 <= depth && !stop && bestMoveNeverChanged && rucksack.m_pvSize == 1 // ここは確実にバグらせないようにする。 && -ScoreInfinite + 2 * PieceScore::m_capturePawn <= bestScore && ( rucksack.m_rootMoves.size() == 1 || // または、利用可能時間の40%が、思考経過時間未満の場合。 rucksack.m_timeManager.CanThinking02_TimeOk_ForIterativeDeepingLoop(rucksack.m_stopwatch.GetElapsed()) ) ) { const ScoreIndex rBeta = bestScore - 2 * PieceScore::m_capturePawn; (flashlight + 1)->m_staticEvalRaw.m_p[0][0] = ScoreNotEvaluated; (flashlight + 1)->m_excludedMove = rucksack.m_rootMoves[0].m_pv_[0]; (flashlight + 1)->m_skipNullMove = true; //──────────────────────────────────────────────────────────────────────────────── // さあ、探索に潜るぜ~☆!(^q^) 2回目のぐるんぐるんだぜ~☆ ノンPV~☆ //──────────────────────────────────────────────────────────────────────────────── const ScoreIndex s = g_NODETYPE_PROGRAMS[NodeType::N02_NonPV]->GoToTheAdventure_new( rucksack, pos, flashlight + 1, rBeta - 1, rBeta, (depth - 3) * OnePly, true); (flashlight + 1)->m_skipNullMove = false; (flashlight + 1)->m_excludedMove = g_MOVE_NONE; if (s < rBeta) { stop = true; } } if (stop) { if (rucksack.m_limits.m_ponder) { rucksack.m_signals.m_stopOnPonderHit = true; } else { rucksack.m_signals.m_stop = true; } } } } skill.swapIfEnabled(&rucksack); SYNCCOUT << rucksack.PvInfoToUSI(pos, depth - 1, alpha, beta) << SYNCENDL; }