Main   Namespaces   Classes   Hierarchy   Annotated   Files   Compound   Global   Pages  

MoHexEngine.cpp

Go to the documentation of this file.
00001 //----------------------------------------------------------------------------
00002 /** @file MoHexEngine.cpp
00003  */
00004 //----------------------------------------------------------------------------
00005 
00006 #include "SgSystem.h"
00007 
00008 #include "BitsetIterator.hpp"
00009 #include "MoHexEngine.hpp"
00010 #include "MoHexPlayer.hpp"
00011 #include "PlayAndSolve.hpp"
00012 #include "SwapCheck.hpp"
00013 
00014 using namespace benzene;
00015 
00016 //----------------------------------------------------------------------------
00017 
00018 namespace {
00019 
00020 std::string KnowledgeThresholdToString(const std::vector<SgUctValue>& t)
00021 {
00022     if (t.empty())
00023         return "0";
00024     std::ostringstream os;
00025     os << '\"';
00026     for (std::size_t i = 0; i < t.size(); ++i)
00027     {
00028         if (i > 0) 
00029             os << ' ';
00030         os << t[i];
00031     }
00032     os << '\"';
00033     return os.str();
00034 }
00035 
00036 std::vector<SgUctValue> KnowledgeThresholdFromString(const std::string& val)
00037 {
00038     std::vector<SgUctValue> v;
00039     std::istringstream is(val);
00040     SgUctValue t;
00041     while (is >> t)
00042         v.push_back(t);
00043     if (v.size() == 1 && v[0] == 0)
00044         v.clear();
00045     return v;
00046 }
00047 
00048 }
00049 
00050 //----------------------------------------------------------------------------
00051 
00052 MoHexEngine::MoHexEngine(int boardsize, MoHexPlayer& player)
00053     : BenzeneHtpEngine(boardsize),
00054       m_player(player), 
00055       m_book(0),
00056       m_bookCheck(m_book),
00057       m_bookCommands(m_game, m_pe, m_book, m_bookCheck, m_player)
00058 {
00059     m_bookCommands.Register(*this);
00060     RegisterCmd("param_mohex", &MoHexEngine::MoHexParam);
00061     RegisterCmd("param_mohex_policy", &MoHexEngine::MoHexPolicyParam);
00062     RegisterCmd("mohex-save-tree", &MoHexEngine::SaveTree);
00063     RegisterCmd("mohex-save-games", &MoHexEngine::SaveGames);
00064     RegisterCmd("mohex-values", &MoHexEngine::Values);
00065     RegisterCmd("mohex-rave-values", &MoHexEngine::RaveValues);
00066     RegisterCmd("mohex-bounds", &MoHexEngine::Bounds);
00067 }
00068 
00069 MoHexEngine::~MoHexEngine()
00070 {
00071 }
00072 
00073 //----------------------------------------------------------------------------
00074 
00075 void MoHexEngine::RegisterCmd(const std::string& name,
00076                               GtpCallback<MoHexEngine>::Method method)
00077 {
00078     Register(name, new GtpCallback<MoHexEngine>(this, method));
00079 }
00080 
00081 double MoHexEngine::TimeForMove(HexColor color)
00082 {
00083     if (m_player.UseTimeManagement())
00084         return m_game.TimeRemaining(color) * 0.08;
00085     return m_player.MaxTime();
00086 }
00087 
00088 HexPoint MoHexEngine::GenMove(HexColor color, bool useGameClock)
00089 {
00090     SG_UNUSED(useGameClock);
00091     if (SwapCheck::PlaySwap(m_game, color))
00092         return SWAP_PIECES;
00093     HexPoint bookMove = m_bookCheck.BestMove(HexState(m_game.Board(), color));
00094     if (bookMove != INVALID_POINT)
00095         return bookMove;
00096     double maxTime = TimeForMove(color);
00097     return DoSearch(color, maxTime);
00098 }
00099 
00100 HexPoint MoHexEngine::DoSearch(HexColor color, double maxTime)
00101 {
00102     HexState state(m_game.Board(), color);
00103     if (m_useParallelSolver)
00104     {
00105         PlayAndSolve ps(*m_pe.brd, *m_se.brd, m_player, m_dfpnSolver, 
00106                         m_dfpnPositions, m_game);
00107         return ps.GenMove(state, maxTime);
00108     }
00109     else
00110     {
00111         double score;
00112         return m_player.GenMove(state, m_game, m_pe.SyncBoard(m_game.Board()),
00113                                 maxTime, score);
00114     }
00115 }
00116 
00117 //----------------------------------------------------------------------------
00118 
00119 void MoHexEngine::MoHexPolicyParam(HtpCommand& cmd)
00120 {
00121     HexUctPolicyConfig& config = m_player.SharedPolicy().Config();
00122     if (cmd.NuArg() == 0)
00123     {
00124         cmd << '\n'
00125             << "pattern_check_percent "
00126             << config.pattern_check_percent << '\n'
00127             << "pattern_heuristic "
00128             << config.patternHeuristic << '\n'
00129             << "response_heuristic "
00130             << config.responseHeuristic << '\n'
00131             << "response_threshold "
00132             << config.response_threshold << '\n';
00133     }
00134     else if (cmd.NuArg() == 2)
00135     {
00136         std::string name = cmd.Arg(0);
00137         if (name == "pattern_check_percent")
00138             config.pattern_check_percent = cmd.IntArg(1, 0, 100);
00139         else if (name == "pattern_heuristic")
00140             config.patternHeuristic = cmd.BoolArg(1);
00141         else if (name == "response_heuristic")
00142             config.responseHeuristic = cmd.BoolArg(1);
00143         else if (name == "response_threshold")
00144             config.response_threshold = cmd.SizeTypeArg(1, 0);
00145         else
00146             throw HtpFailure("Unknown option!");
00147     }
00148     else
00149         throw HtpFailure("Expected 0 or 2 arguments!");
00150 }
00151 
00152 void MoHexEngine::MoHexParam(HtpCommand& cmd)
00153 {
00154     HexUctSearch& search = m_player.Search();
00155 
00156     if (cmd.NuArg() == 0) 
00157     {
00158         cmd << '\n'
00159             << "[bool] backup_ice_info "
00160             << m_player.BackupIceInfo() << '\n'
00161             << "[bool] lock_free " 
00162             << search.LockFree() << '\n'
00163             << "[bool] keep_games "
00164             << search.KeepGames() << '\n'
00165             << "[bool] perform_pre_search " 
00166             << m_player.PerformPreSearch() << '\n'
00167             << "[bool] ponder "
00168             << m_player.Ponder() << '\n'
00169             << "[bool] reuse_subtree " 
00170             << m_player.ReuseSubtree() << '\n'
00171             << "[bool] search_singleton "
00172             << m_player.SearchSingleton() << '\n'
00173             << "[bool] use_livegfx "
00174             << search.LiveGfx() << '\n'
00175             << "[bool] use_parallel_solver "
00176             << m_useParallelSolver << '\n'
00177             << "[bool] use_rave "
00178             << search.Rave() << '\n'
00179             << "[bool] use_time_management "
00180             << m_player.UseTimeManagement() << '\n'
00181             << "[bool] weight_rave_updates "
00182             << search.WeightRaveUpdates() << '\n'
00183             << "[bool] virtual_loss "
00184             << search.VirtualLoss() << '\n'
00185             << "[string] bias_term "
00186             << search.BiasTermConstant() << '\n'
00187             << "[string] expand_threshold "
00188             << search.ExpandThreshold() << '\n'
00189             << "[string] knowledge_threshold "
00190             << KnowledgeThresholdToString(search.KnowledgeThreshold()) << '\n'
00191             << "[string] livegfx_interval "
00192             << search.LiveGfxInterval() << '\n'
00193             << "[string] max_games "
00194             << m_player.MaxGames() << '\n'
00195             << "[string] max_memory "
00196             << search.MaxNodes() * 2 * sizeof(SgUctNode) << '\n'
00197             << "[string] max_nodes "
00198             << search.MaxNodes() << '\n'
00199             << "[string] max_time "
00200             << m_player.MaxTime() << '\n'
00201             << "[string] num_threads "
00202             << search.NumberThreads() << '\n'
00203             << "[string] playout_update_radius "
00204             << search.PlayoutUpdateRadius() << '\n'
00205             << "[string] randomize_rave_frequency "
00206             << search.RandomizeRaveFrequency() << '\n'
00207             << "[string] rave_weight_final "
00208             << search.RaveWeightFinal() << '\n'
00209             << "[string] rave_weight_initial "
00210             << search.RaveWeightInitial() << '\n'
00211             << "[string] tree_update_radius " 
00212             << search.TreeUpdateRadius() << '\n';
00213     }
00214     else if (cmd.NuArg() == 2)
00215     {
00216         std::string name = cmd.Arg(0);
00217         if (name == "backup_ice_info")
00218             m_player.SetBackupIceInfo(cmd.BoolArg(1));
00219         else if (name == "lock_free")
00220             search.SetLockFree(cmd.BoolArg(1));
00221         else if (name == "keep_games")
00222             search.SetKeepGames(cmd.BoolArg(1));
00223         else if (name == "perform_pre_search")
00224             m_player.SetPerformPreSearch(cmd.BoolArg(1));
00225         else if (name == "ponder")
00226             m_player.SetPonder(cmd.BoolArg(1));
00227         else if (name == "use_livegfx")
00228             search.SetLiveGfx(cmd.BoolArg(1));
00229         else if (name == "use_rave")
00230             search.SetRave(cmd.BoolArg(1));
00231         else if (name == "randomize_rave_frequency")
00232             search.SetRandomizeRaveFrequency(cmd.IntArg(1, 0));
00233         else if (name == "reuse_subtree")
00234            m_player.SetReuseSubtree(cmd.BoolArg(1));
00235         else if (name == "bias_term")
00236             search.SetBiasTermConstant(cmd.FloatArg(1));
00237         else if (name == "expand_threshold")
00238             search.SetExpandThreshold(cmd.IntArg(1, 0));
00239         else if (name == "knowledge_threshold")
00240             search.SetKnowledgeThreshold
00241                 (KnowledgeThresholdFromString(cmd.Arg(1)));
00242         else if (name == "livegfx_interval")
00243             search.SetLiveGfxInterval(cmd.IntArg(1, 0));
00244         else if (name == "max_games")
00245             m_player.SetMaxGames(cmd.IntArg(1, 0));
00246         else if (name == "max_memory")
00247             search.SetMaxNodes(cmd.SizeTypeArg(1, 1) / sizeof(SgUctNode) / 2);
00248         else if (name == "max_time")
00249             m_player.SetMaxTime(cmd.FloatArg(1));
00250         else if (name == "max_nodes")
00251             search.SetMaxNodes(cmd.SizeTypeArg(1, 1));
00252         else if (name == "num_threads")
00253             search.SetNumberThreads(cmd.IntArg(1, 0));
00254         else if (name == "playout_update_radius")
00255             search.SetPlayoutUpdateRadius(cmd.IntArg(1, 0));
00256         else if (name == "rave_weight_final")
00257             search.SetRaveWeightFinal(cmd.IntArg(1, 0));
00258         else if (name == "rave_weight_initial")
00259             search.SetRaveWeightInitial(cmd.IntArg(1, 0));
00260         else if (name == "weight_rave_updates")
00261             search.SetWeightRaveUpdates(cmd.BoolArg(1));
00262         else if (name == "tree_update_radius")
00263             search.SetTreeUpdateRadius(cmd.IntArg(1, 0));
00264         else if (name == "search_singleton")
00265             m_player.SetSearchSingleton(cmd.BoolArg(1));
00266         else if (name == "use_parallel_solver")
00267             m_useParallelSolver = cmd.BoolArg(1);
00268         else if (name == "use_time_management")
00269             m_player.SetUseTimeManagement(cmd.BoolArg(1));
00270         else if (name == "virtual_loss")
00271             search.SetVirtualLoss(cmd.BoolArg(1));
00272         else
00273             throw HtpFailure() << "Unknown parameter: " << name;
00274     }
00275     else 
00276         throw HtpFailure("Expected 0 or 2 arguments");
00277 }
00278 
00279 /** Saves the search tree from the previous search to the specified
00280     file.  The optional second parameter sets the max depth to
00281     output. If not given, entire tree is saved.    
00282 */
00283 void MoHexEngine::SaveTree(HtpCommand& cmd)
00284 {
00285     HexUctSearch& search = m_player.Search();
00286 
00287     cmd.CheckNuArg(1);
00288     std::string filename = cmd.Arg(0);
00289     int maxDepth = -1;
00290     std::ofstream file(filename.c_str());
00291     if (!file)
00292         throw HtpFailure() << "Could not open '" << filename << "'";
00293     if (cmd.NuArg() == 2)
00294         maxDepth = cmd.IntArg(1, 0);
00295     search.SaveTree(file, maxDepth);
00296 }
00297 
00298 /** Saves games from last search to a SGF. */
00299 void MoHexEngine::SaveGames(HtpCommand& cmd)
00300 {
00301     HexUctSearch& search = m_player.Search();
00302     cmd.CheckNuArg(1);
00303     std::string filename = cmd.Arg(0);
00304     search.SaveGames(filename);
00305 }
00306 
00307 void MoHexEngine::Values(HtpCommand& cmd)
00308 {
00309     HexUctSearch& search = m_player.Search();
00310     const SgUctTree& tree = search.Tree();
00311     for (SgUctChildIterator it(tree, tree.Root()); it; ++it)
00312     {
00313         const SgUctNode& child = *it;
00314         SgPoint p = child.Move();
00315         std::size_t count = child.MoveCount();
00316         float mean = 0.0;
00317         if (count > 0)
00318             mean = child.Mean();
00319         cmd << ' ' << static_cast<HexPoint>(p)
00320             << ' ' << std::fixed << std::setprecision(3) << mean
00321             << '@' << count;
00322     }
00323 }
00324 
00325 void MoHexEngine::RaveValues(HtpCommand& cmd)
00326 {
00327     HexUctSearch& search = m_player.Search();
00328     const SgUctTree& tree = search.Tree();
00329     for (SgUctChildIterator it(tree, tree.Root()); it; ++it)
00330     {
00331         const SgUctNode& child = *it;
00332         SgPoint p = child.Move();
00333         if (p == SG_PASS || ! child.HasRaveValue())
00334             continue;
00335         cmd << ' ' << static_cast<HexPoint>(p)
00336             << ' ' << std::fixed << std::setprecision(3) << child.RaveValue();
00337     }
00338 }
00339 
00340 void MoHexEngine::Bounds(HtpCommand& cmd)
00341 {
00342     HexUctSearch& search = m_player.Search();
00343     const SgUctTree& tree = search.Tree();
00344     for (SgUctChildIterator it(tree, tree.Root()); it; ++it)
00345     {
00346         const SgUctNode& child = *it;
00347         SgPoint p = child.Move();
00348         if (p == SG_PASS || ! child.HasRaveValue())
00349             continue;
00350         float bound = search.GetBound(search.Rave(), tree.Root(), child);
00351         cmd << ' ' << static_cast<HexPoint>(p) 
00352             << ' ' << std::fixed << std::setprecision(3) << bound;
00353     }
00354 }
00355 
00356 //----------------------------------------------------------------------------
00357 // Pondering
00358 
00359 #if GTPENGINE_PONDER
00360 
00361 void MoHexEngine::InitPonder()
00362 {
00363     SgSetUserAbort(false);
00364 }
00365 
00366 void MoHexEngine::Ponder()
00367 {
00368     if (!m_player.Ponder())
00369         return;
00370     if (!m_player.ReuseSubtree())
00371     {
00372         LogWarning() << "Pondering requires reuse_subtree.\n";
00373         return;
00374     }
00375     // Call genmove() after 0.2 seconds delay to avoid calls 
00376     // in very short intervals between received commands
00377     boost::xtime time;
00378     boost::xtime_get(&time, boost::TIME_UTC);
00379     for (int i = 0; i < 200; ++i)
00380     {
00381         if (SgUserAbort())
00382             return;
00383         time.nsec += 1000000; // 1 msec
00384         boost::thread::sleep(time);
00385     }
00386     LogInfo() << "MoHexEngine::Ponder: start\n";
00387     // Search for at most 10 minutes
00388     DoSearch(m_game.Board().WhoseTurn(), 600);
00389 }
00390 
00391 void MoHexEngine::StopPonder()
00392 {
00393     SgSetUserAbort(true);
00394 }
00395 
00396 #endif // GTPENGINE_PONDER
00397 
00398 //----------------------------------------------------------------------------
00399 


6 Jan 2011 Doxygen 1.6.3