Index   Main   Namespaces   Classes   Hierarchy   Annotated   Files   Compound   Global   Pages  

GoUctSearch.cpp

Go to the documentation of this file.
00001 //----------------------------------------------------------------------------
00002 /** @file GoUctSearch.cpp */
00003 //----------------------------------------------------------------------------
00004 
00005 #include "SgSystem.h"
00006 #include "GoUctSearch.h"
00007 
00008 #include <fstream>
00009 #include <iostream>
00010 #include "GoBoardUtil.h"
00011 #include "GoNodeUtil.h"
00012 #include "GoUctUtil.h"
00013 #include "SgDebug.h"
00014 #include "SgGameWriter.h"
00015 #include "SgNode.h"
00016 #include "SgUctTreeUtil.h"
00017 
00018 using namespace std;
00019 
00020 //----------------------------------------------------------------------------
00021 
00022 namespace {
00023 
00024 //----------------------------------------------------------------------------
00025 
00026 const int MOVERANGE = SG_PASS + 1;
00027 
00028 SgNode* AppendChild(SgNode* node, const string& comment)
00029 {
00030     SgNode* child = node->NewRightMostSon();
00031     child->AddComment(comment);
00032     return child;
00033 }
00034 
00035 SgNode* AppendChild(SgNode* node, SgBlackWhite color, SgPoint move)
00036 {
00037     SgNode* child = node->NewRightMostSon();
00038     SgPropID propId =
00039         (color == SG_BLACK ? SG_PROP_MOVE_BLACK : SG_PROP_MOVE_WHITE);
00040     child->Add(new SgPropMove(propId, move));
00041     return child;
00042 }
00043 
00044 /** Append game to saved simulations (used if m_keepGames is true) */
00045 void AppendGame(SgNode* node, SgUctValue gameNumber, unsigned int threadId,
00046                 SgBlackWhite toPlay, const SgUctGameInfo& info)
00047 {
00048     SG_ASSERT(node != 0);
00049     {
00050         ostringstream comment;
00051         comment << "Thread " << threadId << '\n'
00052                 << "Game " << gameNumber << '\n';
00053         node = AppendChild(node, comment.str());
00054     }
00055     size_t nuMovesInTree = info.m_inTreeSequence.size();
00056     for (size_t i = 0; i < nuMovesInTree; ++i)
00057     {
00058         node = AppendChild(node, toPlay, info.m_inTreeSequence[i]);
00059         toPlay = SgOppBW(toPlay);
00060     }
00061     SgNode* lastInTreeNode = node;
00062     SgBlackWhite lastInTreeToPlay = toPlay;
00063     for (size_t i = 0; i < info.m_eval.size(); ++i)
00064     {
00065         node = lastInTreeNode;
00066         toPlay = lastInTreeToPlay;
00067         ostringstream comment;
00068         comment << "Playout " << i << '\n'
00069                 << "Eval " << info.m_eval[i] << '\n'
00070                 << "Aborted " << info.m_aborted[i] << '\n';
00071         node = AppendChild(node, comment.str());
00072         for (size_t j = nuMovesInTree; j < info.m_sequence[i].size(); ++j)
00073         {
00074             node = AppendChild(node, toPlay, info.m_sequence[i][j]);
00075             toPlay = SgOppBW(toPlay);
00076         }
00077     }
00078 }
00079 
00080 //----------------------------------------------------------------------------
00081 
00082 } // namespace
00083 
00084 //----------------------------------------------------------------------------
00085 
00086 GoUctState::AssertionHandler::AssertionHandler(const GoUctState& state)
00087     : m_state(state)
00088 {
00089 }
00090 
00091 void GoUctState::AssertionHandler::Run()
00092 {
00093     m_state.Dump(SgDebug());
00094 }
00095 
00096 //----------------------------------------------------------------------------
00097 
00098 GoUctState::GoUctState(unsigned int threadId, const GoBoard& bd)
00099     : SgUctThreadState(threadId, MOVERANGE),
00100       m_assertionHandler(*this),
00101       m_uctBd(bd),
00102       m_synchronizer(bd)
00103 {
00104     m_synchronizer.SetSubscriber(m_bd);
00105     m_isInPlayout = false;
00106 }
00107 
00108 void GoUctState::Dump(ostream& out) const
00109 {
00110     out << "GoUctState[" << m_threadId << "] ";
00111     if (m_isInPlayout)
00112         out << "playout board:\n" << m_uctBd;
00113     else
00114         out << "board:\n" << m_bd;
00115 }
00116 
00117 void GoUctState::Execute(SgMove move)
00118 {
00119     SG_ASSERT(! m_isInPlayout);
00120     SG_ASSERT(move == SG_PASS || ! m_bd.Occupied(move));
00121     // Temporarily switch ko rule to SIMPLEKO to avoid slow full board
00122     // repetition test in GoBoard::Play()
00123     GoRestoreKoRule restoreKoRule(m_bd);
00124     m_bd.Rules().SetKoRule(GoRules::SIMPLEKO);
00125     m_bd.Play(move);
00126     SG_ASSERT(! m_bd.LastMoveInfo(GO_MOVEFLAG_ILLEGAL));
00127     ++m_gameLength;
00128 }
00129 
00130 void GoUctState::ExecutePlayout(SgMove move)
00131 {
00132     SG_ASSERT(m_isInPlayout);
00133     SG_ASSERT(move == SG_PASS || ! m_uctBd.Occupied(move));
00134     m_uctBd.Play(move);
00135     ++m_gameLength;
00136 }
00137 
00138 void GoUctState::GameStart()
00139 {
00140     m_isInPlayout = false;
00141     m_gameLength = 0;
00142 }
00143 
00144 void GoUctState::StartPlayout()
00145 {
00146     m_uctBd.Init(m_bd);
00147 }
00148 
00149 void GoUctState::StartPlayouts()
00150 {
00151     m_isInPlayout = true;
00152 }
00153 
00154 void GoUctState::StartSearch()
00155 {
00156     m_synchronizer.UpdateSubscriber();
00157 }
00158 
00159 void GoUctState::TakeBackInTree(std::size_t nuMoves)
00160 {
00161     for (size_t i = 0; i < nuMoves; ++i)
00162         m_bd.Undo();
00163 }
00164 
00165 void GoUctState::TakeBackPlayout(std::size_t nuMoves)
00166 {
00167     m_gameLength -= nuMoves;
00168 }
00169 
00170 //----------------------------------------------------------------------------
00171 
00172 GoUctSearch::GoUctSearch(GoBoard& bd, SgUctThreadStateFactory* factory)
00173     : SgUctSearch(factory, MOVERANGE),
00174       m_keepGames(false),
00175       m_liveGfxInterval(5000),
00176       m_toPlay(SG_BLACK),
00177       m_bd(bd),
00178       m_root(0),
00179       m_liveGfx(GOUCT_LIVEGFX_NONE)
00180 {
00181     SetRaveCheckSame(true);
00182 }
00183 
00184 GoUctSearch::~GoUctSearch()
00185 {
00186     if (m_root != 0)
00187         m_root->DeleteTree();
00188     m_root = 0;
00189 }
00190 
00191 std::string GoUctSearch::MoveString(SgMove move) const
00192 {
00193     return SgPointUtil::PointToString(move);
00194 }
00195 
00196 void GoUctSearch::OnSearchIteration(SgUctValue gameNumber,
00197                                     unsigned int threadId,
00198                                     const SgUctGameInfo& info)
00199 {
00200     SgUctSearch::OnSearchIteration(gameNumber, threadId, info);
00201 
00202     if (m_liveGfx != GOUCT_LIVEGFX_NONE && threadId == 0
00203         && gameNumber > m_nextLiveGfx)
00204     {
00205         m_nextLiveGfx = gameNumber + m_liveGfxInterval;
00206         DisplayGfx();
00207     }
00208     if (! LockFree() && m_root != 0)
00209         AppendGame(m_root, gameNumber, threadId, m_toPlay, info);
00210 }
00211 
00212 void GoUctSearch::DisplayGfx()
00213 {
00214     SgDebug() << "gogui-gfx:\n";
00215     switch (m_liveGfx)
00216     {
00217     case GOUCT_LIVEGFX_COUNTS:
00218         GoUctUtil::GfxBestMove(*this, m_toPlay, SgDebug());
00219         GoUctUtil::GfxMoveValues(*this, m_toPlay, SgDebug());
00220         GoUctUtil::GfxCounts(Tree(), SgDebug());
00221         GoUctUtil::GfxStatus(*this, SgDebug());
00222         break;
00223     case GOUCT_LIVEGFX_SEQUENCE:
00224         GoUctUtil::GfxSequence(*this, m_toPlay, SgDebug());
00225         GoUctUtil::GfxStatus(*this, SgDebug());
00226         break;
00227     case GOUCT_LIVEGFX_NONE:
00228         SG_ASSERT(false); // Should only be called when LiveGfx is enabled
00229         break;
00230     }
00231     SgDebug() << '\n';
00232 }
00233 
00234 void GoUctSearch::OnStartSearch()
00235 {
00236     SgUctSearch::OnStartSearch();
00237 
00238     if (m_root != 0)
00239     {
00240         m_root->DeleteTree();
00241         m_root = 0;
00242     }
00243     if (m_keepGames)
00244     {
00245         m_root = GoNodeUtil::CreateRoot(m_bd);
00246         if (LockFree())
00247             SgWarning() <<
00248                 "GoUctSearch: keep games will be ignored"
00249                 " in lock free search\n";
00250     }
00251     m_toPlay = m_bd.ToPlay(); // Not needed if SetToPlay() was called
00252     for (SgBWIterator it; it; ++it)
00253         m_stones[*it] = m_bd.All(*it);
00254     int size = m_bd.Size();
00255     // Limit to avoid very long games if m_simpleKo
00256     int maxGameLength = min(3 * size * size,
00257                             GO_MAX_NUM_MOVES - m_bd.MoveNumber());
00258     SetMaxGameLength(maxGameLength);
00259     m_boardHistory.SetFromBoard(m_bd);
00260 
00261     m_nextLiveGfx = m_liveGfxInterval;
00262 }
00263 
00264 void GoUctSearch::SaveGames(const string& fileName) const
00265 {
00266     if (MpiSynchronizer()->IsRootProcess())
00267     {
00268     if (m_root == 0)
00269         throw SgException("No games to save");
00270     ofstream out(fileName.c_str());
00271     SgGameWriter writer(out);
00272     writer.WriteGame(*m_root, true, 0, 1, 19);
00273     }
00274 }
00275 
00276 void GoUctSearch::SaveTree(std::ostream& out, int maxDepth) const
00277 {
00278     GoUctUtil::SaveTree(Tree(), m_bd.Size(), m_stones, m_toPlay, out,
00279                         maxDepth);
00280 }
00281 
00282 SgBlackWhite GoUctSearch::ToPlay() const
00283 {
00284     return m_toPlay;
00285 }
00286 
00287 //----------------------------------------------------------------------------
00288 
00289 SgPoint GoUctSearchUtil::TrompTaylorPassCheck(SgPoint move,
00290                                               const GoUctSearch& search)
00291 {
00292     const GoBoard& bd = search.Board();
00293     bool isFirstPass = (bd.GetLastMove() != SG_PASS);
00294     bool isTrompTaylorRules = bd.Rules().CaptureDead();
00295     if (move != SG_PASS || ! isTrompTaylorRules || ! isFirstPass)
00296         return move;
00297     float komi = bd.Rules().Komi().ToFloat();
00298     float trompTaylorScore = GoBoardUtil::TrompTaylorScore(bd, komi);
00299     if (search.ToPlay() != SG_BLACK)
00300         trompTaylorScore *= -1;
00301     const SgUctTree& tree = search.Tree();
00302     const SgUctNode& root = tree.Root();
00303     SgUctValue value = root.Mean();
00304     SgUctValue trompTaylorWinValue = (trompTaylorScore > 0 ? 1 : 0);
00305     if (value < trompTaylorWinValue)
00306         return move;
00307     SgDebug() << "GoUctSearchUtil::TrompTaylorPassCheck: bad pass move value="
00308               << value << " trompTaylorScore=" << trompTaylorScore << '\n';
00309     vector<SgMove> excludeMoves;
00310     excludeMoves.push_back(SG_PASS);
00311     const SgUctNode* bestChild = search.FindBestChild(root, &excludeMoves);
00312     if (bestChild == 0)
00313     {
00314         SgDebug() <<
00315             "GoUctSearchUtil::TrompTaylorPassCheck: "
00316             "(no second best move found)\n";
00317         return move;
00318     }
00319     return bestChild->Move();
00320 }
00321 
00322 //----------------------------------------------------------------------------


Sun Mar 13 2011 Doxygen 1.7.1