00001
00002
00003
00004
00005
00006 #include "SgSystem.h"
00007 #include "GoUctUtil.h"
00008
00009 #include <iomanip>
00010 #include <iostream>
00011 #include <boost/io/ios_state.hpp>
00012 #include "SgBWSet.h"
00013 #include "SgPointSet.h"
00014 #include "SgProp.h"
00015 #include "SgUctSearch.h"
00016
00017 using namespace std;
00018 using boost::io::ios_all_saver;
00019 using SgPointUtil::Pt;
00020 using SgPropUtil::PointToSgfString;
00021
00022
00023
00024 namespace {
00025
00026 bool IsRectEmpty(const GoBoard& bd, int left, int right, int top, int bottom)
00027 {
00028 for (SgRectIterator it(SgRect(left, right, top, bottom)); it; ++it)
00029 if (! bd.IsEmpty(*it))
00030 return false;
00031 return true;
00032 }
00033
00034
00035 void SaveNode(ostream& out, const SgUctTree& tree, const SgUctNode& node,
00036 SgBlackWhite toPlay, int boardSize, int maxDepth, int depth)
00037 {
00038 out << "C[MoveCount " << node.MoveCount()
00039 << "\nPosCount " << node.PosCount()
00040 << "\nMean " << fixed << setprecision(2) << node.Mean();
00041 if (! node.HasChildren())
00042 {
00043 out << "]\n";
00044 return;
00045 }
00046 out << "\n\nRave:";
00047 for (SgUctChildIterator it(tree, node); it; ++it)
00048 {
00049 const SgUctNode& child = *it;
00050 SgPoint move = child.Move();
00051 if (child.HasRaveValue())
00052 {
00053 out << '\n' << SgWritePoint(move) << ' '
00054 << fixed << setprecision(2) << child.RaveValue()
00055 << " (" << child.RaveCount() << ')';
00056 }
00057 }
00058 out << "]\nLB";
00059 for (SgUctChildIterator it(tree, node); it; ++it)
00060 {
00061 const SgUctNode& child = *it;
00062 if (! child.HasMean())
00063 continue;
00064 out << "["
00065 << PointToSgfString(child.Move(), boardSize, SG_PROPPOINTFMT_GO)
00066 << ':' << child.MoveCount() << ']';
00067 }
00068 out << '\n';
00069 if (maxDepth >= 0 && depth >= maxDepth)
00070 return;
00071 for (SgUctChildIterator it(tree, node); it; ++it)
00072 {
00073 const SgUctNode& child = *it;
00074 if (! child.HasMean())
00075 continue;
00076 SgPoint move = child.Move();
00077 out << "(;" << (toPlay == SG_BLACK ? 'B' : 'W') << '['
00078 << PointToSgfString(move, boardSize, SG_PROPPOINTFMT_GO) << ']';
00079 SaveNode(out, tree, child, SgOppBW(toPlay), boardSize, maxDepth,
00080 depth + 1);
00081 out << ")\n";
00082 }
00083 }
00084
00085 }
00086
00087
00088
00089 void GoUctUtil::ClearStatistics(SgPointArray<SgUctStatistics>& stats)
00090 {
00091 for (SgPointArray<SgUctStatistics>::NonConstIterator
00092 it(stats); it; ++it)
00093 (*it).Clear();
00094 }
00095
00096 SgPoint GoUctUtil::GenForcedOpeningMove(const GoBoard& bd)
00097 {
00098 int sz = bd.Size();
00099 if (sz < 15 || bd.TotalNumStones(SG_BLACK) > 5
00100 || bd.TotalNumStones(SG_WHITE) > 5)
00101 return SG_NULLMOVE;
00102 SgSList<SgPoint,4> moves;
00103 if (IsRectEmpty(bd, 1, 5, 1, 5))
00104 moves.PushBack(Pt(4, 4));
00105 if (IsRectEmpty(bd, 1, 5, sz - 4, sz))
00106 moves.PushBack(Pt(4, sz - 3));
00107 if (IsRectEmpty(bd, sz - 4, sz, 1, 5))
00108 moves.PushBack(Pt(sz - 3, 4));
00109 if (IsRectEmpty(bd, sz - 4, sz, sz - 4, sz))
00110 moves.PushBack(Pt(sz - 3, sz - 3));
00111 if (moves.IsEmpty())
00112 return SG_NULLMOVE;
00113 return moves[SgRandom::Global().Int(moves.Length())];
00114 }
00115
00116 void GoUctUtil::GfxBestMove(const SgUctSearch& search, SgBlackWhite toPlay,
00117 ostream& out)
00118 {
00119 const SgUctTree& tree = search.Tree();
00120 const SgUctNode& root = tree.Root();
00121 out << "VAR";
00122 const SgUctNode* bestValueChild = search.FindBestChild(root);
00123 if (bestValueChild != 0)
00124 {
00125 SgPoint move = bestValueChild->Move();
00126 out << ' ' << (toPlay == SG_BLACK ? 'B' : 'W') << ' '
00127 << SgWritePoint(move);
00128 }
00129 out << '\n';
00130 }
00131
00132 void GoUctUtil::GfxCounts(const SgUctTree& tree, ostream& out)
00133 {
00134 const SgUctNode& root = tree.Root();
00135 out << "LABEL";
00136 if (root.HasChildren())
00137 for (SgUctChildIterator it(tree, root); it; ++it)
00138 {
00139 const SgUctNode& child = *it;
00140 if (child.HasMean())
00141 out << ' ' << SgWritePoint(child.Move()) << ' '
00142 << child.MoveCount();
00143 }
00144 out << '\n';
00145 }
00146
00147 void GoUctUtil::GfxMoveValues(const SgUctSearch& search, SgBlackWhite toPlay,
00148 ostream& out)
00149 {
00150 const SgUctTree& tree = search.Tree();
00151 const SgUctNode& root = tree.Root();
00152 out << "INFLUENCE";
00153 if (root.HasChildren())
00154 for (SgUctChildIterator it(tree, root); it; ++it)
00155 {
00156 const SgUctNode& child = *it;
00157 if (! child.HasMean())
00158 continue;
00159 float value = SgUctSearch::InverseEval(child.Mean());
00160
00161 double influence = value * 2 - 1;
00162 if (toPlay == SG_WHITE)
00163 influence *= -1;
00164 SgPoint move = child.Move();
00165 out << ' ' << SgWritePoint(move) << ' ' << fixed
00166 << setprecision(2) << influence;
00167 }
00168 out << '\n';
00169 }
00170 \
00171 void GoUctUtil::GfxSequence(const SgUctSearch& search, SgBlackWhite toPlay,
00172 ostream& out)
00173 {
00174 vector<SgMove> sequence;
00175 search.FindBestSequence(sequence);
00176 out << "VAR";
00177 for (size_t i = 0; i < sequence.size(); ++i)
00178 {
00179 out << (toPlay == SG_BLACK ? " B ": " W ")
00180 << SgWritePoint(sequence[i]);
00181 toPlay = SgOppBW(toPlay);
00182 }
00183 out << '\n';
00184 }
00185
00186 void GoUctUtil::GfxStatus(const SgUctSearch& search, ostream& out)
00187 {
00188 const SgUctTree& tree = search.Tree();
00189 const SgUctNode& root = tree.Root();
00190 const SgUctSearchStat& stat = search.Statistics();
00191 int abortPercent = static_cast<int>(stat.m_aborted.Mean() * 100);
00192 out << "TEXT N=" << root.MoveCount()
00193 << " V=" << setprecision(2) << root.Mean()
00194 << " Len=" << static_cast<int>(stat.m_gameLength.Mean())
00195 << " Tree=" << setprecision(1) << stat.m_movesInTree.Mean()
00196 << "/" << static_cast<int>(stat.m_movesInTree.Max())
00197 << " Abrt=" << abortPercent << '%'
00198 << " Gm/s=" << static_cast<int>(stat.m_gamesPerSecond) << '\n';
00199 }
00200
00201 void GoUctUtil::GfxTerritoryStatistics(
00202 const SgPointArray<SgUctStatistics>& territoryStatistics,
00203 const GoBoard& bd, std::ostream& out)
00204 {
00205 ios_all_saver saver(out);
00206 out << fixed << setprecision(3) << "INFLUENCE";
00207 for (GoBoard::Iterator it(bd); it; ++it)
00208 if (territoryStatistics[*it].Count() > 0)
00209
00210 out << ' ' << SgWritePoint(*it) << ' '
00211 << territoryStatistics[*it].Mean() * 2 - 1;
00212 out << '\n';
00213 }
00214
00215 void GoUctUtil::SaveTree(const SgUctTree& tree, int boardSize,
00216 const SgBWSet& stones, SgBlackWhite toPlay,
00217 ostream& out, int maxDepth)
00218 {
00219 out << "(;FF[4]GM[1]SZ[" << boardSize << "]\n";
00220 for (SgBWIterator itColor; itColor; ++itColor)
00221 {
00222 const SgPointSet& stonesColor = stones[*itColor];
00223 if (stonesColor.Size() == 0)
00224 continue;
00225 out << ((*itColor) == SG_BLACK ? "AB" : "AW");
00226 for (SgSetIterator it(stonesColor); it; ++it)
00227 out << '[' << PointToSgfString(*it, boardSize, SG_PROPPOINTFMT_GO)
00228 << ']';
00229 out << '\n';
00230 }
00231 out << "PL[" << (toPlay == SG_BLACK ? "B" : "W") << "]\n";
00232 SaveNode(out, tree, tree.Root(), toPlay, boardSize, maxDepth, 0);
00233 out << ")\n";
00234 }
00235
00236 namespace
00237 {
00238
00239
00240 bool IsMeanLess(const SgUctNode* lhs, const SgUctNode* rhs)
00241 {
00242 return (lhs->Mean() < rhs->Mean());
00243 }
00244
00245 }
00246
00247 string GoUctUtil::ChildrenStatistics(const SgUctSearch& search,
00248 bool bSort, const SgUctNode& node)
00249 {
00250 ostringstream out;
00251 vector<const SgUctNode*> vec;
00252 const SgUctTree& tree = search.Tree();
00253 for (SgUctChildIterator it(tree, node); it; ++it)
00254 {
00255 const SgUctNode& child = *it;
00256 vec.push_back(&child);
00257 }
00258 if (bSort)
00259 sort(vec.begin(), vec.end(), IsMeanLess);
00260 for (vector<const SgUctNode*>::iterator it = vec.begin(); it != vec.end();
00261 ++it)
00262 {
00263 const SgUctNode& child = **it;
00264 out << search.MoveString(child.Move()) << " -" << " value="
00265 << child.Mean() << " count=" << child.MoveCount() << '\n';
00266 }
00267 return out.str();
00268 }
00269
00270