00001 //---------------------------------------------------------------------------- 00002 /** @file GoUctCommands.cpp */ 00003 //---------------------------------------------------------------------------- 00004 00005 #include "SgSystem.h" 00006 #include "GoUctCommands.h" 00007 00008 #include <fstream> 00009 #include <boost/format.hpp> 00010 #include "GoEyeUtil.h" 00011 #include "GoGtpCommandUtil.h" 00012 #include "GoBoardUtil.h" 00013 #include "GoSafetySolver.h" 00014 #include "GoUctDefaultPriorKnowledge.h" 00015 #include "GoUctDefaultRootFilter.h" 00016 #include "GoUctEstimatorStat.h" 00017 #include "GoUctGlobalSearch.h" 00018 #include "GoUctPatterns.h" 00019 #include "GoUctPlayer.h" 00020 #include "GoUctPlayoutPolicy.h" 00021 #include "GoUctUtil.h" 00022 #include "GoUtil.h" 00023 #include "SgException.h" 00024 #include "SgPointSetUtil.h" 00025 #include "SgRestorer.h" 00026 #include "SgUctTreeUtil.h" 00027 #include "SgWrite.h" 00028 00029 using namespace std; 00030 using boost::format; 00031 using GoGtpCommandUtil::BlackWhiteArg; 00032 using GoGtpCommandUtil::EmptyPointArg; 00033 using GoGtpCommandUtil::PointArg; 00034 00035 typedef GoUctPlayer<GoUctGlobalSearch<GoUctPlayoutPolicy<GoUctBoard>, 00036 GoUctPlayoutPolicyFactory<GoUctBoard> >, 00037 GoUctGlobalSearchState<GoUctPlayoutPolicy<GoUctBoard> > > 00038 GoUctPlayerType; 00039 00040 00041 //---------------------------------------------------------------------------- 00042 00043 namespace { 00044 00045 GoUctLiveGfx LiveGfxArg(const GtpCommand& cmd, size_t number) 00046 { 00047 string arg = cmd.ArgToLower(number); 00048 if (arg == "none") 00049 return GOUCT_LIVEGFX_NONE; 00050 if (arg == "counts") 00051 return GOUCT_LIVEGFX_COUNTS; 00052 if (arg == "sequence") 00053 return GOUCT_LIVEGFX_SEQUENCE; 00054 throw GtpFailure() << "unknown live-gfx argument \"" << arg << '"'; 00055 } 00056 00057 string LiveGfxToString(GoUctLiveGfx mode) 00058 { 00059 switch (mode) 00060 { 00061 case GOUCT_LIVEGFX_NONE: 00062 return "none"; 00063 case GOUCT_LIVEGFX_COUNTS: 00064 return "counts"; 00065 case GOUCT_LIVEGFX_SEQUENCE: 00066 return "sequence"; 00067 default: 00068 SG_ASSERT(false); 00069 return "?"; 00070 } 00071 } 00072 00073 SgUctMoveSelect MoveSelectArg(const GtpCommand& cmd, size_t number) 00074 { 00075 string arg = cmd.ArgToLower(number); 00076 if (arg == "value") 00077 return SG_UCTMOVESELECT_VALUE; 00078 if (arg == "count") 00079 return SG_UCTMOVESELECT_COUNT; 00080 if (arg == "bound") 00081 return SG_UCTMOVESELECT_BOUND; 00082 if (arg == "estimate") 00083 return SG_UCTMOVESELECT_ESTIMATE; 00084 throw GtpFailure() << "unknown move select argument \"" << arg << '"'; 00085 } 00086 00087 string MoveSelectToString(SgUctMoveSelect moveSelect) 00088 { 00089 switch (moveSelect) 00090 { 00091 case SG_UCTMOVESELECT_VALUE: 00092 return "value"; 00093 case SG_UCTMOVESELECT_COUNT: 00094 return "count"; 00095 case SG_UCTMOVESELECT_BOUND: 00096 return "bound"; 00097 case SG_UCTMOVESELECT_ESTIMATE: 00098 return "estimate"; 00099 default: 00100 SG_ASSERT(false); 00101 return "?"; 00102 } 00103 } 00104 00105 GoUctGlobalSearchMode SearchModeArg(const GtpCommand& cmd, size_t number) 00106 { 00107 string arg = cmd.ArgToLower(number); 00108 if (arg == "playout_policy") 00109 return GOUCT_SEARCHMODE_PLAYOUTPOLICY; 00110 if (arg == "uct") 00111 return GOUCT_SEARCHMODE_UCT; 00112 if (arg == "one_ply") 00113 return GOUCT_SEARCHMODE_ONEPLY; 00114 throw GtpFailure() << "unknown search mode argument \"" << arg << '"'; 00115 } 00116 00117 string SearchModeToString(GoUctGlobalSearchMode mode) 00118 { 00119 switch (mode) 00120 { 00121 case GOUCT_SEARCHMODE_PLAYOUTPOLICY: 00122 return "playout_policy"; 00123 case GOUCT_SEARCHMODE_UCT: 00124 return "uct"; 00125 case GOUCT_SEARCHMODE_ONEPLY: 00126 return "one_ply"; 00127 default: 00128 SG_ASSERT(false); 00129 return "?"; 00130 } 00131 } 00132 00133 string KnowledgeThresholdToString(const std::vector<SgUctValue>& t) 00134 { 00135 if (t.empty()) 00136 return "0"; 00137 std::ostringstream os; 00138 os << '\"'; 00139 for (std::size_t i = 0; i < t.size(); ++i) 00140 { 00141 if (i > 0) 00142 os << ' '; 00143 os << t[i]; 00144 } 00145 os << '\"'; 00146 return os.str(); 00147 } 00148 00149 std::vector<SgUctValue> KnowledgeThresholdFromString(const std::string& val) 00150 { 00151 std::vector<SgUctValue> v; 00152 std::istringstream is(val); 00153 std::size_t t; 00154 while (is >> t) 00155 v.push_back(SgUctValue(t)); 00156 if (v.size() == 1 && v[0] == 0) 00157 v.clear(); 00158 return v; 00159 } 00160 00161 } // namespace 00162 00163 //---------------------------------------------------------------------------- 00164 00165 GoUctCommands::GoUctCommands(const GoBoard& bd, GoPlayer*& player) 00166 : m_bd(bd), 00167 m_player(player) 00168 { 00169 } 00170 00171 void GoUctCommands::AddGoGuiAnalyzeCommands(GtpCommand& cmd) 00172 { 00173 cmd << 00174 "gfx/Uct Bounds/uct_bounds\n" 00175 "plist/Uct Default Policy/uct_default_policy\n" 00176 "gfx/Uct Gfx/uct_gfx\n" 00177 "none/Uct Max Memory/uct_max_memory %s\n" 00178 "plist/Uct Moves/uct_moves\n" 00179 "param/Uct Param GlobalSearch/uct_param_globalsearch\n" 00180 "param/Uct Param Policy/uct_param_policy\n" 00181 "param/Uct Param Player/uct_param_player\n" 00182 "param/Uct Param RootFilter/uct_param_rootfilter\n" 00183 "param/Uct Param Search/uct_param_search\n" 00184 "plist/Uct Patterns/uct_patterns\n" 00185 "pstring/Uct Policy Moves/uct_policy_moves\n" 00186 "gfx/Uct Prior Knowledge/uct_prior_knowledge\n" 00187 "sboard/Uct Rave Values/uct_rave_values\n" 00188 "plist/Uct Root Filter/uct_root_filter\n" 00189 "none/Uct SaveGames/uct_savegames %w\n" 00190 "none/Uct SaveTree/uct_savetree %w\n" 00191 "gfx/Uct Sequence/uct_sequence\n" 00192 "hstring/Uct Stat Player/uct_stat_player\n" 00193 "none/Uct Stat Player Clear/uct_stat_player_clear\n" 00194 "hstring/Uct Stat Policy/uct_stat_policy\n" 00195 "none/Uct Stat Policy Clear/uct_stat_policy_clear\n" 00196 "hstring/Uct Stat Search/uct_stat_search\n" 00197 "dboard/Uct Stat Territory/uct_stat_territory\n"; 00198 } 00199 00200 /** Show UCT bounds of moves in root node. 00201 This command is compatible with the GoGui analyze command type "gfx". 00202 Move bounds are shown as labels on the board, the pass move bound is 00203 shown as text in the status line. 00204 @see SgUctSearch::GetBound */ 00205 void GoUctCommands::CmdBounds(GtpCommand& cmd) 00206 { 00207 cmd.CheckArgNone(); 00208 const GoUctSearch& search = Search(); 00209 const SgUctTree& tree = search.Tree(); 00210 const SgUctNode& root = tree.Root(); 00211 bool hasPass = false; 00212 SgUctValue passBound = 0; 00213 cmd << "LABEL"; 00214 for (SgUctChildIterator it(tree, root); it; ++it) 00215 { 00216 const SgUctNode& child = *it; 00217 SgPoint move = child.Move(); 00218 SgUctValue bound = search.GetBound(search.Rave(), root, child); 00219 if (move == SG_PASS) 00220 { 00221 hasPass = true; 00222 passBound = bound; 00223 } 00224 else 00225 cmd << ' ' << SgWritePoint(move) << ' ' << fixed 00226 << setprecision(2) << bound; 00227 } 00228 cmd << '\n'; 00229 if (hasPass) 00230 cmd << "TEXT PASS=" << fixed << setprecision(2) << passBound << '\n'; 00231 } 00232 00233 00234 void GoUctCommands::CmdDefaultPolicy(GtpCommand& cmd) 00235 { 00236 cmd.CheckArgNone(); 00237 GoUctDefaultPriorKnowledge knowledge(m_bd, GoUctPlayoutPolicyParam()); 00238 SgPointSet pattern; 00239 SgPointSet atari; 00240 GoPointList empty; 00241 knowledge.FindGlobalPatternAndAtariMoves(pattern, atari, empty); 00242 cmd << SgWritePointSet(atari, "", false) << '\n'; 00243 } 00244 00245 /** Compute estimator statistics. 00246 Arguments: trueValueMaxGames maxGames stepSize fileName 00247 @see GoUctEstimatorStat::Compute() */ 00248 void GoUctCommands::CmdEstimatorStat(GtpCommand& cmd) 00249 { 00250 cmd.CheckNuArg(4); 00251 size_t trueValueMaxGames = cmd.Arg<size_t>(0); 00252 size_t maxGames = cmd.Arg<size_t>(1); 00253 size_t stepSize = cmd.Arg<size_t>(2); 00254 string fileName = cmd.Arg(3); 00255 GoUctEstimatorStat::Compute(Search(), trueValueMaxGames, maxGames, 00256 stepSize, fileName); 00257 } 00258 00259 /** Return final score. 00260 Does a small search and uses the territory statistics to determine the 00261 status of blocks. */ 00262 void GoUctCommands::CmdFinalScore(GtpCommand& cmd) 00263 { 00264 cmd.CheckArgNone(); 00265 SgPointSet deadStones = DoFinalStatusSearch(); 00266 float score; 00267 if (! GoBoardUtil::ScorePosition(m_bd, deadStones, score)) 00268 throw GtpFailure("cannot score"); 00269 cmd << GoUtil::ScoreToString(score); 00270 } 00271 00272 /** Return final status of stones. 00273 Does a small search and uses the territory statistics to determine the 00274 status of blocks. The engine cannot detect seki, so according to the 00275 GTP standard, all stones that are not dead are reported as alive, the 00276 response to seki is an empty list. <br> 00277 Arguments: alive|seki|dead */ 00278 void GoUctCommands::CmdFinalStatusList(GtpCommand& cmd) 00279 { 00280 string arg = cmd.Arg(); 00281 if (arg == "seki") 00282 return; 00283 bool getDead; 00284 if (arg == "alive") 00285 getDead = false; 00286 else if (arg == "dead") 00287 getDead = true; 00288 else 00289 throw GtpFailure("invalid final status argument"); 00290 SgPointSet deadPoints = DoFinalStatusSearch(); 00291 // According to GTP standard the response should be one string(=block) 00292 // per line 00293 for (GoBlockIterator it(m_bd); it; ++it) 00294 { 00295 if ((getDead && deadPoints.Contains(*it)) 00296 || (! getDead && ! deadPoints.Contains(*it))) 00297 { 00298 for (GoBoard::StoneIterator it2(m_bd, *it); it2; ++it2) 00299 cmd << SgWritePoint(*it2) << ' '; 00300 cmd << '\n'; 00301 } 00302 } 00303 } 00304 00305 /** Show move values and sample numbers of last search. 00306 Arguments: none 00307 @see GoUctSearch::GoGuiGfx() */ 00308 void GoUctCommands::CmdGfx(GtpCommand& cmd) 00309 { 00310 cmd.CheckArgNone(); 00311 const GoUctSearch& s = Search(); 00312 SgBlackWhite toPlay = s.ToPlay(); 00313 GoUctUtil::GfxBestMove(s, toPlay, cmd); 00314 GoUctUtil::GfxMoveValues(s, toPlay, cmd); 00315 GoUctUtil::GfxCounts(s.Tree(), cmd); 00316 GoUctUtil::GfxStatus(s, cmd); 00317 } 00318 00319 /** Computes the maximum number of nodes in search tree given the 00320 maximum allowed memory for the tree. Assumes two trees. Returns 00321 current memory usage if no arguments. 00322 Arguments: max memory for trees */ 00323 void GoUctCommands::CmdMaxMemory(GtpCommand& cmd) 00324 { 00325 cmd.CheckNuArgLessEqual(1); 00326 if (cmd.NuArg() == 0) 00327 cmd << Search().MaxNodes() * 2 * sizeof(SgUctNode); 00328 else 00329 { 00330 std::size_t memory = cmd.ArgMin<size_t>(0, 2 * sizeof(SgUctNode)); 00331 Search().SetMaxNodes(memory / 2 / sizeof(SgUctNode)); 00332 } 00333 } 00334 00335 /** Return a list of all moves that the search would generate in the current 00336 position. 00337 Arguments: none 00338 @see SgUctSearch::GenerateAllMoves() */ 00339 void GoUctCommands::CmdMoves(GtpCommand& cmd) 00340 { 00341 cmd.CheckArgNone(); 00342 vector<SgUctMoveInfo> moves; 00343 Search().GenerateAllMoves(moves); 00344 for (std::size_t i = 0; i < moves.size(); ++i) 00345 cmd << SgWritePoint(moves[i].m_move) << ' '; 00346 cmd << '\n'; 00347 } 00348 00349 /** Get and set GoUctGlobalSearch parameters. 00350 This command is compatible with the GoGui analyze command type "param". 00351 00352 Parameters: 00353 @arg @c live_gfx See GoUctGlobalSearch::GlobalSearchLiveGfx 00354 @arg @c mercy_rule See GoUctGlobalSearchStateParam::m_mercyRule 00355 @arg @c territory_statistics See 00356 GoUctGlobalSearchStateParam::m_territoryStatistics 00357 @arg @c length_modification See 00358 GoUctGlobalSearchStateParam::m_langthModification 00359 @arg @c score_modification See 00360 GoUctGlobalSearchStateParam::m_scoreModification */ 00361 void GoUctCommands::CmdParamGlobalSearch(GtpCommand& cmd) 00362 { 00363 cmd.CheckNuArgLessEqual(2); 00364 GoUctGlobalSearch<GoUctPlayoutPolicy<GoUctBoard>, 00365 GoUctPlayoutPolicyFactory<GoUctBoard> >& 00366 s = GlobalSearch(); 00367 GoUctGlobalSearchStateParam& p = s.m_param; 00368 if (cmd.NuArg() == 0) 00369 { 00370 // Boolean parameters first for better layout of GoGui parameter 00371 // dialog, alphabetically otherwise 00372 cmd << "[bool] live_gfx " << s.GlobalSearchLiveGfx() << '\n' 00373 << "[bool] mercy_rule " << p.m_mercyRule << '\n' 00374 << "[bool] territory_statistics " << p.m_territoryStatistics 00375 << '\n' 00376 << "[string] length_modification " << p.m_lengthModification 00377 << '\n' 00378 << "[string] score_modification " << p.m_scoreModification 00379 << '\n'; 00380 } 00381 else if (cmd.NuArg() == 2) 00382 { 00383 string name = cmd.Arg(0); 00384 if (name == "live_gfx") 00385 s.SetGlobalSearchLiveGfx(cmd.Arg<bool>(1)); 00386 else if (name == "mercy_rule") 00387 p.m_mercyRule = cmd.Arg<bool>(1); 00388 else if (name == "territory_statistics") 00389 p.m_territoryStatistics = cmd.Arg<bool>(1); 00390 else if (name == "length_modification") 00391 p.m_lengthModification = cmd.Arg<SgUctValue>(1); 00392 else if (name == "score_modification") 00393 p.m_scoreModification = cmd.Arg<SgUctValue>(1); 00394 else 00395 throw GtpFailure() << "unknown parameter: " << name; 00396 } 00397 else 00398 throw GtpFailure() << "need 0 or 2 arguments"; 00399 } 00400 00401 /** Get and set GoUctPlayer parameters. 00402 This command is compatible with the GoGui analyze command type "param". 00403 00404 Parameters: 00405 @arg @c auto_param See GoUctPlayer::AutoParam 00406 @arg @c early_pass See GoUctPlayer::EarlyPass 00407 @arg @c forced_opening_moves See GoUctPlayer::ForcedOpeningMoves 00408 @arg @c ignore_clock See GoUctPlayer::IgnoreClock 00409 @arg @c ponder See GoUctPlayer::EnablePonder 00410 @arg @c reuse_subtree See GoUctPlayer::ReuseSubtree 00411 @arg @c use_root_filter See GoUctPlayer::UseRootFilter 00412 @arg @c max_games See GoUctPlayer::MaxGames 00413 @arg @c max_ponder_time See GoUctPlayer::MaxPonderTime 00414 @arg @c resign_min_games See GoUctPlayer::ResignMinGames 00415 @arg @c resign_threshold See GoUctPlayer::ResignThreshold 00416 @arg @c search_mode @c playout|uct|one_ply See GoUctPlayer::SearchMode */ 00417 void GoUctCommands::CmdParamPlayer(GtpCommand& cmd) 00418 { 00419 cmd.CheckNuArgLessEqual(2); 00420 GoUctPlayerType& p = Player(); 00421 if (cmd.NuArg() == 0) 00422 { 00423 // Boolean parameters first for better layout of GoGui parameter 00424 // dialog, alphabetically otherwise 00425 cmd << "[bool] auto_param " << p.AutoParam() << '\n' 00426 << "[bool] early_pass " << p.EarlyPass() << '\n' 00427 << "[bool] forced_opening_moves " << p.ForcedOpeningMoves() << '\n' 00428 << "[bool] ignore_clock " << p.IgnoreClock() << '\n' 00429 << "[bool] ponder " << p.EnablePonder() << '\n' 00430 << "[bool] reuse_subtree " << p.ReuseSubtree() << '\n' 00431 << "[bool] use_root_filter " << p.UseRootFilter() << '\n' 00432 << "[string] max_games " << p.MaxGames() << '\n' 00433 << "[string] max_ponder_time " << p.MaxPonderTime() << '\n' 00434 << "[string] resign_min_games " << p.ResignMinGames() << '\n' 00435 << "[string] resign_threshold " << p.ResignThreshold() << '\n' 00436 << "[list/playout_policy/uct/one_ply] search_mode " 00437 << SearchModeToString(p.SearchMode()) << '\n'; 00438 } 00439 else if (cmd.NuArg() >= 1 && cmd.NuArg() <= 2) 00440 { 00441 string name = cmd.Arg(0); 00442 if (name == "auto_param") 00443 p.SetAutoParam(cmd.Arg<bool>(1)); 00444 else if (name == "early_pass") 00445 p.SetEarlyPass(cmd.Arg<bool>(1)); 00446 else if (name == "forced_opening_moves") 00447 p.SetForcedOpeningMoves(cmd.Arg<bool>(1)); 00448 else if (name == "ignore_clock") 00449 p.SetIgnoreClock(cmd.Arg<bool>(1)); 00450 else if (name == "ponder") 00451 p.SetEnablePonder(cmd.Arg<bool>(1)); 00452 else if (name == "reuse_subtree") 00453 p.SetReuseSubtree(cmd.Arg<bool>(1)); 00454 else if (name == "use_root_filter") 00455 p.SetUseRootFilter(cmd.Arg<bool>(1)); 00456 else if (name == "max_games") 00457 p.SetMaxGames(cmd.ArgMin<SgUctValue>(1, SgUctValue(1))); 00458 else if (name == "max_ponder_time") 00459 p.SetMaxPonderTime(cmd.ArgMin<SgUctValue>(1, 0)); 00460 else if (name == "resign_min_games") 00461 p.SetResignMinGames(cmd.ArgMin<SgUctValue>(1, SgUctValue(0))); 00462 else if (name == "resign_threshold") 00463 p.SetResignThreshold(cmd.ArgMinMax<SgUctValue>(1, 0, 1)); 00464 else if (name == "search_mode") 00465 p.SetSearchMode(SearchModeArg(cmd, 1)); 00466 else 00467 throw GtpFailure() << "unknown parameter: " << name; 00468 } 00469 else 00470 throw GtpFailure() << "need 0 or 2 arguments"; 00471 } 00472 00473 /** Get and set GoUctPlayoutPolicy parameters. 00474 This command is compatible with the GoGui analyze command type "param". 00475 00476 Parameters: 00477 @arg @c statistics_enabled 00478 See GoUctPlayoutPolicyParam::m_statisticsEnabled 00479 @arg @c nakade_heuristic 00480 See GoUctPlayoutPolicyParam::m_useNakadeHeuristic 00481 @arg @c fillboard_tries 00482 See GoUctPlayoutPolicyParam::m_fillboardTries */ 00483 void GoUctCommands::CmdParamPolicy(GtpCommand& cmd) 00484 { 00485 cmd.CheckNuArgLessEqual(2); 00486 GoUctPlayoutPolicyParam& p = Player().m_playoutPolicyParam; 00487 if (cmd.NuArg() == 0) 00488 { 00489 // Boolean parameters first for better layout of GoGui parameter 00490 // dialog, alphabetically otherwise 00491 cmd << "[bool] nakade_heuristic " << p.m_useNakadeHeuristic << '\n' 00492 << "[bool] statistics_enabled " << p.m_statisticsEnabled << '\n' 00493 << "fillboard_tries " << p.m_fillboardTries << '\n'; 00494 } 00495 else if (cmd.NuArg() == 2) 00496 { 00497 string name = cmd.Arg(0); 00498 if (name == "nakade_heuristic") 00499 p.m_useNakadeHeuristic = cmd.Arg<bool>(1); 00500 else if (name == "statistics_enabled") 00501 p.m_statisticsEnabled = cmd.Arg<bool>(1); 00502 else if (name == "fillboard_tries") 00503 p.m_fillboardTries = cmd.Arg<int>(1); 00504 else 00505 throw GtpFailure() << "unknown parameter: " << name; 00506 } 00507 else 00508 throw GtpFailure() << "need 0 or 2 arguments"; 00509 } 00510 00511 /** Get and set GoUctDefaultRootFilter parameters. 00512 This command is compatible with the GoGui analyze command type "param". 00513 00514 Parameters: 00515 @arg @c check_ladders See GoUctDefaultRootFilter::CheckLadders() */ 00516 void GoUctCommands::CmdParamRootFilter(GtpCommand& cmd) 00517 { 00518 cmd.CheckNuArgLessEqual(2); 00519 GoUctDefaultRootFilter* f = 00520 dynamic_cast<GoUctDefaultRootFilter*>(&Player().RootFilter()); 00521 if (f == 0) 00522 throw GtpFailure("root filter is not GoUctDefaultRootFilter"); 00523 if (cmd.NuArg() == 0) 00524 { 00525 // Boolean parameters first for better layout of GoGui parameter 00526 // dialog, alphabetically otherwise 00527 cmd << "[bool] check_ladders " << f->CheckLadders() << '\n'; 00528 } 00529 else if (cmd.NuArg() == 2) 00530 { 00531 string name = cmd.Arg(0); 00532 if (name == "check_ladders") 00533 f->SetCheckLadders(cmd.Arg<bool>(1)); 00534 else 00535 throw GtpFailure() << "unknown parameter: " << name; 00536 } 00537 else 00538 throw GtpFailure() << "need 0 or 2 arguments"; 00539 } 00540 00541 /** Get and set SgUctSearch and GoUctSearch parameters. 00542 This command is compatible with the GoGui analyze command type "param". 00543 00544 Parameters: 00545 @arg @c check_float_precision See GoUctSearch::CheckFloatPrecision 00546 @arg @c keep_games See GoUctSearch::KeepGames 00547 @arg @c lock_free See SgUctSearch::LockFree 00548 @arg @c log_games See SgUctSearch::LogGames 00549 @arg @c prune_full_tree See SgUctSearch::PruneFullTree 00550 @arg @c rave See SgUctSearch::Rave 00551 @arg @c weight_rave_updates SgUctSearch::WeightRaveUpdates 00552 @arg @c bias_term_constant See SgUctSearch::BiasTermConstant 00553 @arg @c expand_threshold See SgUctSearch::ExpandThreshold 00554 @arg @c first_play_urgency See SgUctSearch::FirstPlayUrgency 00555 @arg @c knowledge_threshold See SgUctSearch::KnowledgeThreshold 00556 @arg @c live_gfx @c none|counts|sequence See GoUctSearch::LiveGfx 00557 @arg @c live_gfx_interval See GoUctSearch::LiveGfxInterval 00558 @arg @c max_nodes See SgUctSearch::MaxNodes 00559 @arg @c move_select @c value|count|bound|rave See SgUctSearch::MoveSelect 00560 @arg @c number_threads See SgUctSearch::NumberThreads 00561 @arg @c number_playouts See SgUctSearch::NumberPlayouts 00562 @arg @c prune_min_count See SgUctSearch::PruneMinCount 00563 @arg @c rave_weight_final See SgUctSearch::RaveWeightFinal 00564 @arg @c rave_weight_initial See SgUctSearch::RaveWeightInitial */ 00565 void GoUctCommands::CmdParamSearch(GtpCommand& cmd) 00566 { 00567 cmd.CheckNuArgLessEqual(2); 00568 GoUctSearch& s = Search(); 00569 if (cmd.NuArg() == 0) 00570 { 00571 // Boolean parameters first for better layout of GoGui parameter 00572 // dialog, alphabetically otherwise 00573 cmd << "[bool] check_float_precision " << s.CheckFloatPrecision() 00574 << '\n' 00575 << "[bool] keep_games " << s.KeepGames() << '\n' 00576 << "[bool] lock_free " << s.LockFree() << '\n' 00577 << "[bool] log_games " << s.LogGames() << '\n' 00578 << "[bool] prune_full_tree " << s.PruneFullTree() << '\n' 00579 << "[bool] rave " << s.Rave() << '\n' 00580 << "[bool] virtual_loss " << s.VirtualLoss() << '\n' 00581 << "[bool] weight_rave_updates " << s.WeightRaveUpdates() << '\n' 00582 << "[string] bias_term_constant " << s.BiasTermConstant() << '\n' 00583 << "[string] expand_threshold " << s.ExpandThreshold() << '\n' 00584 << "[string] first_play_urgency " << s.FirstPlayUrgency() << '\n' 00585 << "[string] knowledge_threshold " 00586 << KnowledgeThresholdToString(s.KnowledgeThreshold()) << '\n' 00587 << "[list/none/counts/sequence] live_gfx " 00588 << LiveGfxToString(s.LiveGfx()) << '\n' 00589 << "[string] live_gfx_interval " << s.LiveGfxInterval() << '\n' 00590 << "[string] max_nodes " << s.MaxNodes() << '\n' 00591 << "[list/value/count/bound/estimate] move_select " 00592 << MoveSelectToString(s.MoveSelect()) << '\n' 00593 << "[string] number_threads " << s.NumberThreads() << '\n' 00594 << "[string] number_playouts " << s.NumberPlayouts() << '\n' 00595 << "[string] prune_min_count " << s.PruneMinCount() << '\n' 00596 << "[string] randomize_rave_frequency " 00597 << s.RandomizeRaveFrequency() << '\n' 00598 << "[string] rave_weight_final " << s.RaveWeightFinal() << '\n' 00599 << "[string] rave_weight_initial " 00600 << s.RaveWeightInitial() << '\n'; 00601 00602 } 00603 else if (cmd.NuArg() == 2) 00604 { 00605 string name = cmd.Arg(0); 00606 if (name == "check_float_precision") 00607 s.SetCheckFloatPrecision(cmd.Arg<bool>(1)); 00608 else if (name == "keep_games") 00609 s.SetKeepGames(cmd.Arg<bool>(1)); 00610 else if (name == "knowledge_threshold") 00611 s.SetKnowledgeThreshold(KnowledgeThresholdFromString(cmd.Arg(1))); 00612 else if (name == "lock_free") 00613 s.SetLockFree(cmd.Arg<bool>(1)); 00614 else if (name == "log_games") 00615 s.SetLogGames(cmd.Arg<bool>(1)); 00616 else if (name == "prune_full_tree") 00617 s.SetPruneFullTree(cmd.Arg<bool>(1)); 00618 else if (name == "randomize_rave_frequency") 00619 s.SetRandomizeRaveFrequency(cmd.ArgMin<int>(1, 0)); 00620 else if (name == "rave") 00621 s.SetRave(cmd.Arg<bool>(1)); 00622 else if (name == "weight_rave_updates") 00623 s.SetWeightRaveUpdates(cmd.Arg<bool>(1)); 00624 else if (name == "virtual_loss") 00625 s.SetVirtualLoss(cmd.Arg<bool>(1)); 00626 else if (name == "bias_term_constant") 00627 s.SetBiasTermConstant(cmd.Arg<float>(1)); 00628 else if (name == "expand_threshold") 00629 s.SetExpandThreshold(cmd.ArgMin<SgUctValue>(1, 0)); 00630 else if (name == "first_play_urgency") 00631 s.SetFirstPlayUrgency(cmd.Arg<SgUctValue>(1)); 00632 else if (name == "live_gfx") 00633 s.SetLiveGfx(LiveGfxArg(cmd, 1)); 00634 else if (name == "live_gfx_interval") 00635 s.SetLiveGfxInterval(cmd.ArgMin<SgUctValue>(1, 1)); 00636 else if (name == "max_nodes") 00637 s.SetMaxNodes(cmd.ArgMin<size_t>(1, 1)); 00638 else if (name == "move_select") 00639 s.SetMoveSelect(MoveSelectArg(cmd, 1)); 00640 else if (name == "number_threads") 00641 s.SetNumberThreads(cmd.ArgMin<unsigned int>(1, 1)); 00642 else if (name == "number_playouts") 00643 s.SetNumberPlayouts(cmd.ArgMin<int>(1, 1)); 00644 else if (name == "prune_min_count") 00645 s.SetPruneMinCount(cmd.ArgMin<SgUctValue>(1, SgUctValue(1))); 00646 else if (name == "rave_weight_final") 00647 s.SetRaveWeightFinal(cmd.Arg<float>(1)); 00648 else if (name == "rave_weight_initial") 00649 s.SetRaveWeightInitial(cmd.Arg<float>(1)); 00650 else 00651 throw GtpFailure() << "unknown parameter: " << name; 00652 } 00653 else 00654 throw GtpFailure() << "need 0 or 2 arguments"; 00655 } 00656 00657 /** Show matching patterns. 00658 Returns: List of points for matching patterns 00659 @see GoUctPatterns */ 00660 void GoUctCommands::CmdPatterns(GtpCommand& cmd) 00661 { 00662 cmd.CheckArgNone(); 00663 GoUctPatterns<GoBoard> patterns(m_bd); 00664 for (GoBoard::Iterator it(m_bd); it; ++it) 00665 if (m_bd.IsEmpty(*it) && patterns.MatchAny(*it)) 00666 cmd << SgWritePoint(*it) << ' '; 00667 } 00668 00669 /** Return equivalent best moves in playout policy. 00670 See GoUctPlayoutPolicy::GetEquivalentBestMoves() <br> 00671 Arguments: none <br> 00672 Returns: Move type string followed by move list on a single line. */ 00673 void GoUctCommands::CmdPolicyMoves(GtpCommand& cmd) 00674 { 00675 cmd.CheckArgNone(); 00676 GoUctPlayoutPolicy<GoBoard> policy(m_bd, Player().m_playoutPolicyParam); 00677 policy.StartPlayout(); 00678 policy.GenerateMove(); 00679 cmd << GoUctPlayoutPolicyTypeStr(policy.MoveType()); 00680 GoPointList moves = policy.GetEquivalentBestMoves(); 00681 // Sort for deterministic response 00682 // (GoUctPlayoutPolicy::GetEquivalentBestMoves() does not return 00683 // a deterministic list, because GoUctUtil::SelectRandom() may modify 00684 // the list in a non-deterministic way) 00685 moves.Sort(); 00686 for (int i = 0; i < moves.Length(); ++i) 00687 cmd << ' ' << SgWritePoint(moves[i]); 00688 } 00689 00690 /** Show prior knowledge. 00691 The response is compatible to the GoGui analyze command type @c 00692 gfx and shows the prior knowledge values as influence and the 00693 counts as labels. */ 00694 void GoUctCommands::CmdPriorKnowledge(GtpCommand& cmd) 00695 { 00696 cmd.CheckNuArgLessEqual(1); 00697 SgUctValue count = 0; 00698 if (cmd.NuArg() == 1) 00699 count = SgUctValue(cmd.ArgMin<size_t>(0, 0)); 00700 GoUctGlobalSearchState<GoUctPlayoutPolicy<GoUctBoard> >& state 00701 = ThreadState(0); 00702 state.StartSearch(); // Updates thread state board 00703 vector<SgUctMoveInfo> moves; 00704 SgUctProvenType provenType; 00705 state.GenerateAllMoves(count, moves, provenType); 00706 00707 cmd << "INFLUENCE "; 00708 for (size_t i = 0; i < moves.size(); ++i) 00709 { 00710 SgMove move = moves[i].m_move; 00711 SgUctValue value = SgUctSearch::InverseEval(moves[i].m_value); 00712 SgUctValue count = moves[i].m_count; 00713 if (count > 0) 00714 { 00715 SgUctValue scaledValue = (value * 2 - 1); 00716 if (m_bd.ToPlay() != SG_BLACK) 00717 scaledValue *= -1; 00718 cmd << ' ' << SgWritePoint(move) << ' ' << scaledValue; 00719 } 00720 } 00721 cmd << "\nLABEL "; 00722 for (size_t i = 0; i < moves.size(); ++i) 00723 { 00724 SgMove move = moves[i].m_move; 00725 SgUctValue count = moves[i].m_count; 00726 if (count > 0) 00727 cmd << ' ' << SgWritePoint(move) << ' ' << count; 00728 } 00729 cmd << '\n'; 00730 } 00731 00732 /** Show RAVE values of last search at root position. 00733 This command is compatible to the GoGui analyze command type @c sboard. 00734 The values are scaled to [-1,+1] from Black's point of view. 00735 @see SgUctSearch::Rave */ 00736 void GoUctCommands::CmdRaveValues(GtpCommand& cmd) 00737 { 00738 cmd.CheckArgNone(); 00739 const GoUctSearch& search = Search(); 00740 if (! search.Rave()) 00741 throw GtpFailure("RAVE not enabled"); 00742 SgPointArray<string> array("\"\""); 00743 const SgUctTree& tree = search.Tree(); 00744 for (SgUctChildIterator it(tree, tree.Root()); it; ++it) 00745 { 00746 const SgUctNode& child = *it; 00747 SgPoint p = child.Move(); 00748 if (p == SG_PASS || ! child.HasRaveValue()) 00749 continue; 00750 ostringstream out; 00751 out << fixed << setprecision(2) << child.RaveValue(); 00752 array[p] = out.str(); 00753 } 00754 cmd << '\n' 00755 << SgWritePointArray<string>(array, m_bd.Size()); 00756 } 00757 00758 /** Return filtered root moves. 00759 @see GoUctRootFilter::Get() */ 00760 void GoUctCommands::CmdRootFilter(GtpCommand& cmd) 00761 { 00762 cmd.CheckArgNone(); 00763 cmd << SgWritePointList(Player().RootFilter().Get(), "", false); 00764 } 00765 00766 /** Save the UCT tree in SGF format. 00767 Arguments: filename [max_depth] <br> 00768 max_depth is an optional argument to cut the tree at a certain depth 00769 (the root node has depth 0). If it is not used, the full tree will be 00770 saved. 00771 @see GoUctSearch::SaveTree() */ 00772 void GoUctCommands::CmdSaveTree(GtpCommand& cmd) 00773 { 00774 if (Search().MpiSynchronizer()->IsRootProcess()) 00775 { 00776 cmd.CheckNuArgLessEqual(2); 00777 string fileName = cmd.Arg(0); 00778 int maxDepth = -1; 00779 if (cmd.NuArg() == 2) 00780 maxDepth = cmd.ArgMin<int>(1, 0); 00781 ofstream out(fileName.c_str()); 00782 if (! out) 00783 throw GtpFailure() << "Could not open " << fileName; 00784 Search().SaveTree(out, maxDepth); 00785 } 00786 } 00787 00788 /** Save all random games. 00789 Arguments: filename 00790 @see GoUctSearch::SaveGames() */ 00791 void GoUctCommands::CmdSaveGames(GtpCommand& cmd) 00792 { 00793 string fileName = cmd.Arg(); 00794 try 00795 { 00796 Search().SaveGames(fileName); 00797 } 00798 catch (const SgException& e) 00799 { 00800 throw GtpFailure(e.what()); 00801 } 00802 } 00803 00804 /** Count the score using the scoring function of UCT. 00805 Arguments: none <br> 00806 Returns: Score (Win/Loss) 00807 @see GoBoardUtil::ScoreSimpleEndPosition() */ 00808 void GoUctCommands::CmdScore(GtpCommand& cmd) 00809 { 00810 cmd.CheckArgNone(); 00811 try 00812 { 00813 float komi = m_bd.Rules().Komi().ToFloat(); 00814 cmd << GoBoardUtil::ScoreSimpleEndPosition(m_bd, komi); 00815 } 00816 catch (const SgException& e) 00817 { 00818 throw GtpFailure(e.what()); 00819 } 00820 } 00821 00822 /** Show the best sequence from last search. 00823 This command is compatible with the GoGui analyze command type "gfx" 00824 (There is no "var" command type supported in GoGui 1.1, which allows 00825 to specify the first color to move within the response, and this command 00826 returns the sequence of the last search, which is unrelated to the current 00827 color to play on the board.) <br> 00828 Arguments: none */ 00829 void GoUctCommands::CmdSequence(GtpCommand& cmd) 00830 { 00831 cmd.CheckArgNone(); 00832 GoUctUtil::GfxSequence(Search(), Search().ToPlay(), cmd); 00833 } 00834 00835 /** Write statistics of GoUctPlayer. 00836 Arguments: none 00837 @see GoUctPlayer::Statistics */ 00838 void GoUctCommands::CmdStatPlayer(GtpCommand& cmd) 00839 { 00840 cmd.CheckArgNone(); 00841 Player().GetStatistics().Write(cmd); 00842 } 00843 00844 /** Clear statistics of GoUctPlayer. 00845 Arguments: none 00846 @see GoUctPlayer::Statistics */ 00847 void GoUctCommands::CmdStatPlayerClear(GtpCommand& cmd) 00848 { 00849 cmd.CheckArgNone(); 00850 Player().ClearStatistics(); 00851 } 00852 00853 /** Write statistics of playout policy. 00854 Arguments: none <br> 00855 Needs enabling the statistics with 00856 <code>uct_param_policy statistics_enabled</code> 00857 Only the statistics of the first thread's policy used. 00858 @see GoUctPlayoutPolicyStat */ 00859 void GoUctCommands::CmdStatPolicy(GtpCommand& cmd) 00860 { 00861 cmd.CheckArgNone(); 00862 if (! Player().m_playoutPolicyParam.m_statisticsEnabled) 00863 SgWarning() << "statistics not enabled in policy parameters\n"; 00864 cmd << "Black Statistics:\n"; 00865 Policy(0).Statistics(SG_BLACK).Write(cmd); 00866 cmd << "\nWhite Statistics:\n"; 00867 Policy(0).Statistics(SG_WHITE).Write(cmd); 00868 } 00869 00870 /** Clear statistics of GoUctPlayoutPolicy 00871 Arguments: none <br> 00872 Only the statistics of the first thread's policy used. 00873 @see GoUctPlayoutPolicyStat */ 00874 void GoUctCommands::CmdStatPolicyClear(GtpCommand& cmd) 00875 { 00876 cmd.CheckArgNone(); 00877 Policy(0).ClearStatistics(); 00878 } 00879 00880 /** Write statistics of search and tree. 00881 Arguments: none 00882 @see SgUctSearch::WriteStatistics() */ 00883 void GoUctCommands::CmdStatSearch(GtpCommand& cmd) 00884 { 00885 cmd.CheckArgNone(); 00886 const GoUctSearch& search = Search(); 00887 SgUctTreeStatistics treeStatistics; 00888 treeStatistics.Compute(search.Tree()); 00889 cmd << "SearchStatistics:\n"; 00890 search.WriteStatistics(cmd); 00891 cmd << "TreeStatistics:\n" 00892 << treeStatistics; 00893 } 00894 00895 /** Write average point status. 00896 This command is compatible with the GoGui analyze type @c dboard. <br> 00897 Statistics are only collected, if enabled with 00898 <code>uct_param_global_search territory_statistics 1</code>. <br> 00899 Arguments: none 00900 @see GoUctGlobalSearchState::m_territoryStatistics */ 00901 void GoUctCommands::CmdStatTerritory(GtpCommand& cmd) 00902 { 00903 cmd.CheckArgNone(); 00904 SgPointArray<SgUctStatistics> territoryStatistics 00905 = ThreadState(0).m_territoryStatistics; 00906 SgPointArray<SgUctValue> array; 00907 for (GoBoard::Iterator it(m_bd); it; ++it) 00908 { 00909 if (territoryStatistics[*it].Count() == 0) 00910 throw GtpFailure("no statistics available: enable them and run search first"); 00911 array[*it] = territoryStatistics[*it].Mean() * 2 - 1; 00912 } 00913 cmd << '\n' 00914 << SgWritePointArrayFloat<SgUctValue>(array, m_bd.Size(), true, 3); 00915 } 00916 00917 /** Return value of root node from last search. 00918 Arguments: none */ 00919 void GoUctCommands::CmdValue(GtpCommand& cmd) 00920 { 00921 cmd.CheckArgNone(); 00922 cmd << Search().Tree().Root().Mean(); 00923 } 00924 00925 /** Return value of root node from last search, from Black's point of view. 00926 Arguments: none */ 00927 void GoUctCommands::CmdValueBlack(GtpCommand& cmd) 00928 { 00929 cmd.CheckArgNone(); 00930 SgUctValue value = Search().Tree().Root().Mean(); 00931 if (Search().ToPlay() == SG_WHITE) 00932 value = SgUctSearch::InverseEval(value); 00933 cmd << value; 00934 } 00935 00936 /** Do a small search with territory statistics enabled to determine what 00937 blocks are dead for the final_status_list and final_score commands. 00938 @return Point set containing dead stones. */ 00939 SgPointSet GoUctCommands::DoFinalStatusSearch() 00940 { 00941 SgPointSet deadStones; 00942 if (GoBoardUtil::TwoPasses(m_bd) && m_bd.Rules().CaptureDead()) 00943 // Everything is alive if end position and Tromp-Taylor rules 00944 return deadStones; 00945 00946 const size_t MAX_GAMES = 10000; 00947 SgDebug() << "GoUctCommands::DoFinalStatusSearch: doing a search with " 00948 << MAX_GAMES << " games to determine final status\n"; 00949 GoUctGlobalSearch<GoUctPlayoutPolicy<GoUctBoard>, 00950 GoUctPlayoutPolicyFactory<GoUctBoard> >& 00951 search = GlobalSearch(); 00952 SgRestorer<bool> restorer(&search.m_param.m_territoryStatistics); 00953 search.m_param.m_territoryStatistics = true; 00954 // Undo passes, because UCT search always scores with Tromp-Taylor after 00955 // two passes in-tree 00956 int nuUndoPass = 0; 00957 SgBlackWhite toPlay = m_bd.ToPlay(); 00958 GoModBoard modBoard(m_bd); 00959 GoBoard& bd = modBoard.Board(); 00960 while (bd.GetLastMove() == SG_PASS) 00961 { 00962 bd.Undo(); 00963 toPlay = SgOppBW(toPlay); 00964 ++nuUndoPass; 00965 } 00966 m_player->UpdateSubscriber(); 00967 if (nuUndoPass > 0) 00968 SgDebug() << "Undoing " << nuUndoPass << " passes\n"; 00969 vector<SgMove> sequence; 00970 search.Search(MAX_GAMES, numeric_limits<double>::max(), sequence); 00971 SgDebug() << SgWriteLabel("Sequence") 00972 << SgWritePointList(sequence, "", false); 00973 for (int i = 0; i < nuUndoPass; ++i) 00974 { 00975 bd.Play(SG_PASS, toPlay); 00976 toPlay = SgOppBW(toPlay); 00977 } 00978 m_player->UpdateSubscriber(); 00979 00980 SgPointArray<SgUctStatistics> territoryStatistics = 00981 ThreadState(0).m_territoryStatistics; 00982 GoSafetySolver safetySolver(bd); 00983 SgBWSet safe; 00984 safetySolver.FindSafePoints(&safe); 00985 for (GoBlockIterator it(bd); it; ++it) 00986 { 00987 SgBlackWhite c = bd.GetStone(*it); 00988 bool isDead = safe[SgOppBW(c)].Contains(*it); 00989 if (! isDead && ! safe[c].Contains(*it)) 00990 { 00991 SgStatistics<SgUctValue,int> averageStatus; 00992 for (GoBoard::StoneIterator it2(bd, *it); it2; ++it2) 00993 { 00994 if (territoryStatistics[*it2].Count() == 0) 00995 // No statistics, maybe all simulations aborted due to 00996 // max length or mercy rule. 00997 return deadStones; 00998 averageStatus.Add(territoryStatistics[*it2].Mean()); 00999 } 01000 const float threshold = 0.3f; 01001 isDead = 01002 ((c == SG_BLACK && averageStatus.Mean() < threshold) 01003 || (c == SG_WHITE && averageStatus.Mean() > 1 - threshold)); 01004 } 01005 if (isDead) 01006 for (GoBoard::StoneIterator it2(bd, *it); it2; ++it2) 01007 deadStones.Include(*it2); 01008 } 01009 return deadStones; 01010 } 01011 01012 GoUctGlobalSearch<GoUctPlayoutPolicy<GoUctBoard>, 01013 GoUctPlayoutPolicyFactory<GoUctBoard> >& 01014 GoUctCommands::GlobalSearch() 01015 { 01016 return Player().GlobalSearch(); 01017 } 01018 01019 GoUctPlayerType& GoUctCommands::Player() 01020 { 01021 if (m_player == 0) 01022 throw GtpFailure("player not GoUctPlayer"); 01023 try 01024 { 01025 return dynamic_cast<GoUctPlayerType&>(*m_player); 01026 } 01027 catch (const bad_cast&) 01028 { 01029 throw GtpFailure("player not GoUctPlayer"); 01030 } 01031 } 01032 01033 GoUctPlayoutPolicy<GoUctBoard>& 01034 GoUctCommands::Policy(unsigned int threadId) 01035 { 01036 GoUctPlayoutPolicy<GoUctBoard>* policy = 01037 dynamic_cast<GoUctPlayoutPolicy<GoUctBoard>*>( 01038 ThreadState(threadId).Policy()); 01039 if (policy == 0) 01040 throw GtpFailure("player has no GoUctPlayoutPolicy"); 01041 return *policy; 01042 } 01043 01044 void GoUctCommands::Register(GtpEngine& e) 01045 { 01046 Register(e, "final_score", &GoUctCommands::CmdFinalScore); 01047 Register(e, "final_status_list", &GoUctCommands::CmdFinalStatusList); 01048 Register(e, "uct_bounds", &GoUctCommands::CmdBounds); 01049 Register(e, "uct_default_policy", &GoUctCommands::CmdDefaultPolicy); 01050 Register(e, "uct_estimator_stat", &GoUctCommands::CmdEstimatorStat); 01051 Register(e, "uct_gfx", &GoUctCommands::CmdGfx); 01052 Register(e, "uct_max_memory", &GoUctCommands::CmdMaxMemory); 01053 Register(e, "uct_moves", &GoUctCommands::CmdMoves); 01054 Register(e, "uct_param_globalsearch", 01055 &GoUctCommands::CmdParamGlobalSearch); 01056 Register(e, "uct_param_policy", &GoUctCommands::CmdParamPolicy); 01057 Register(e, "uct_param_player", &GoUctCommands::CmdParamPlayer); 01058 Register(e, "uct_param_rootfilter", &GoUctCommands::CmdParamRootFilter); 01059 Register(e, "uct_param_search", &GoUctCommands::CmdParamSearch); 01060 Register(e, "uct_patterns", &GoUctCommands::CmdPatterns); 01061 Register(e, "uct_policy_moves", &GoUctCommands::CmdPolicyMoves); 01062 Register(e, "uct_prior_knowledge", &GoUctCommands::CmdPriorKnowledge); 01063 Register(e, "uct_rave_values", &GoUctCommands::CmdRaveValues); 01064 Register(e, "uct_root_filter", &GoUctCommands::CmdRootFilter); 01065 Register(e, "uct_savegames", &GoUctCommands::CmdSaveGames); 01066 Register(e, "uct_savetree", &GoUctCommands::CmdSaveTree); 01067 Register(e, "uct_sequence", &GoUctCommands::CmdSequence); 01068 Register(e, "uct_score", &GoUctCommands::CmdScore); 01069 Register(e, "uct_stat_player", &GoUctCommands::CmdStatPlayer); 01070 Register(e, "uct_stat_player_clear", &GoUctCommands::CmdStatPlayerClear); 01071 Register(e, "uct_stat_policy", &GoUctCommands::CmdStatPolicy); 01072 Register(e, "uct_stat_policy_clear", &GoUctCommands::CmdStatPolicyClear); 01073 Register(e, "uct_stat_search", &GoUctCommands::CmdStatSearch); 01074 Register(e, "uct_stat_territory", &GoUctCommands::CmdStatTerritory); 01075 Register(e, "uct_value", &GoUctCommands::CmdValue); 01076 Register(e, "uct_value_black", &GoUctCommands::CmdValueBlack); 01077 } 01078 01079 void GoUctCommands::Register(GtpEngine& engine, const std::string& command, 01080 GtpCallback<GoUctCommands>::Method method) 01081 { 01082 engine.Register(command, new GtpCallback<GoUctCommands>(this, method)); 01083 } 01084 01085 GoUctSearch& GoUctCommands::Search() 01086 { 01087 try 01088 { 01089 GoUctObjectWithSearch& object = 01090 dynamic_cast<GoUctObjectWithSearch&>(*m_player); 01091 return object.Search(); 01092 } 01093 catch (const bad_cast&) 01094 { 01095 throw GtpFailure("player is not a GoUctObjectWithSearch"); 01096 } 01097 } 01098 01099 /** Return state of first thread, if search is of type GoUctGlobalSearch. 01100 @throws GtpFailure, if search is a different subclass or threads are not 01101 yet created. */ 01102 GoUctGlobalSearchState<GoUctPlayoutPolicy<GoUctBoard> >& 01103 GoUctCommands::ThreadState(unsigned int threadId) 01104 { 01105 GoUctSearch& search = Search(); 01106 if (! search.ThreadsCreated()) 01107 search.CreateThreads(); 01108 try 01109 { 01110 return dynamic_cast< 01111 GoUctGlobalSearchState<GoUctPlayoutPolicy<GoUctBoard> >&>( 01112 search.ThreadState(threadId)); 01113 } 01114 catch (const bad_cast&) 01115 { 01116 throw GtpFailure("player has no GoUctGlobalSearchState"); 01117 } 01118 } 01119 01120 //----------------------------------------------------------------------------