00001
00002
00003
00004
00005 #include "SgSystem.h"
00006 #include "GoUctUtil.h"
00007
00008 #include <iomanip>
00009 #include <iostream>
00010 #include <boost/io/ios_state.hpp>
00011 #include <boost/format.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::format;
00019 using boost::io::ios_all_saver;
00020 using SgPointUtil::PointToString;
00021 using SgPointUtil::Pt;
00022 using SgPropUtil::PointToSgfString;
00023
00024
00025
00026 namespace {
00027
00028 bool IsRectEmpty(const GoBoard& bd, int left, int right, int top, int bottom)
00029 {
00030 for (SgRectIterator it(SgRect(left, right, top, bottom)); it; ++it)
00031 if (! bd.IsEmpty(*it))
00032 return false;
00033 return true;
00034 }
00035
00036
00037 void SaveNode(ostream& out, const SgUctTree& tree, const SgUctNode& node,
00038 SgBlackWhite toPlay, int boardSize, int maxDepth, int depth)
00039 {
00040 out << "C[MoveCount " << node.MoveCount()
00041 << "\nPosCount " << node.PosCount()
00042 << "\nMean " << fixed << setprecision(2) << node.Mean();
00043 if (! node.HasChildren())
00044 {
00045 out << "]\n";
00046 return;
00047 }
00048 out << "\n\nRave:";
00049 for (SgUctChildIterator it(tree, node); it; ++it)
00050 {
00051 const SgUctNode& child = *it;
00052 SgPoint move = child.Move();
00053 if (child.HasRaveValue())
00054 {
00055 out << '\n' << SgWritePoint(move) << ' '
00056 << fixed << setprecision(2) << child.RaveValue()
00057 << " (" << child.RaveCount() << ')';
00058 }
00059 }
00060 out << "]\nLB";
00061 for (SgUctChildIterator it(tree, node); it; ++it)
00062 {
00063 const SgUctNode& child = *it;
00064 if (! child.HasMean())
00065 continue;
00066 out << "["
00067 << PointToSgfString(child.Move(), boardSize, SG_PROPPOINTFMT_GO)
00068 << ':' << child.MoveCount() << ']';
00069 }
00070 out << '\n';
00071 if (maxDepth >= 0 && depth >= maxDepth)
00072 return;
00073 for (SgUctChildIterator it(tree, node); it; ++it)
00074 {
00075 const SgUctNode& child = *it;
00076 if (! child.HasMean())
00077 continue;
00078 SgPoint move = child.Move();
00079 out << "(;" << (toPlay == SG_BLACK ? 'B' : 'W') << '['
00080 << PointToSgfString(move, boardSize, SG_PROPPOINTFMT_GO) << ']';
00081 SaveNode(out, tree, child, SgOppBW(toPlay), boardSize, maxDepth,
00082 depth + 1);
00083 out << ")\n";
00084 }
00085 }
00086
00087 }
00088
00089
00090
00091 void GoUctUtil::ClearStatistics(SgPointArray<SgUctStatistics>& stats)
00092 {
00093 for (SgPointArray<SgUctStatistics>::NonConstIterator
00094 it(stats); it; ++it)
00095 (*it).Clear();
00096 }
00097
00098 SgPoint GoUctUtil::GenForcedOpeningMove(const GoBoard& bd)
00099 {
00100 int sz = bd.Size();
00101 if (sz < 13 || bd.TotalNumStones(SG_BLACK) > 5
00102 || bd.TotalNumStones(SG_WHITE) > 5)
00103 return SG_NULLMOVE;
00104 SgArrayList<SgPoint,4> moves;
00105 if (IsRectEmpty(bd, 1, 5, 1, 5))
00106 moves.PushBack(Pt(4, 4));
00107 if (IsRectEmpty(bd, 1, 5, sz - 4, sz))
00108 moves.PushBack(Pt(4, sz - 3));
00109 if (IsRectEmpty(bd, sz - 4, sz, 1, 5))
00110 moves.PushBack(Pt(sz - 3, 4));
00111 if (IsRectEmpty(bd, sz - 4, sz, sz - 4, sz))
00112 moves.PushBack(Pt(sz - 3, sz - 3));
00113 if (moves.IsEmpty())
00114 return SG_NULLMOVE;
00115 return moves[SgRandom::Global().SmallInt(moves.Length())];
00116 }
00117
00118 void GoUctUtil::GfxBestMove(const SgUctSearch& search, SgBlackWhite toPlay,
00119 ostream& out)
00120 {
00121 const SgUctTree& tree = search.Tree();
00122 const SgUctNode& root = tree.Root();
00123 out << "VAR";
00124 const SgUctNode* bestValueChild = search.FindBestChild(root);
00125 if (bestValueChild != 0)
00126 {
00127 SgPoint move = bestValueChild->Move();
00128 out << ' ' << (toPlay == SG_BLACK ? 'B' : 'W') << ' '
00129 << SgWritePoint(move);
00130 }
00131 out << '\n';
00132 }
00133
00134 void GoUctUtil::GfxCounts(const SgUctTree& tree, ostream& out)
00135 {
00136 const SgUctNode& root = tree.Root();
00137 out << "LABEL";
00138 if (root.HasChildren())
00139 for (SgUctChildIterator it(tree, root); it; ++it)
00140 {
00141 const SgUctNode& child = *it;
00142 if (child.HasMean())
00143 out << (format(" %s %.0f")
00144 % PointToString(child.Move()) % child.MoveCount());
00145 }
00146 out << '\n';
00147 }
00148
00149 void GoUctUtil::GfxMoveValues(const SgUctSearch& search, SgBlackWhite toPlay,
00150 ostream& out)
00151 {
00152 const SgUctTree& tree = search.Tree();
00153 const SgUctNode& root = tree.Root();
00154 out << "INFLUENCE";
00155 if (root.HasChildren())
00156 for (SgUctChildIterator it(tree, root); it; ++it)
00157 {
00158 const SgUctNode& child = *it;
00159 if (! child.HasMean())
00160 continue;
00161 SgUctValue value = SgUctSearch::InverseEval(child.Mean());
00162
00163 SgUctValue influence = value * 2 - 1;
00164 if (toPlay == SG_WHITE)
00165 influence *= -1;
00166 SgPoint move = child.Move();
00167 out << ' ' << SgWritePoint(move) << ' ' << fixed
00168 << setprecision(2) << influence;
00169 }
00170 out << '\n';
00171 }
00172 \
00173 void GoUctUtil::GfxSequence(const SgUctSearch& search, SgBlackWhite toPlay,
00174 ostream& out)
00175 {
00176 vector<SgMove> sequence;
00177 search.FindBestSequence(sequence);
00178 out << "VAR";
00179 for (size_t i = 0; i < sequence.size(); ++i)
00180 {
00181 out << (toPlay == SG_BLACK ? " B ": " W ")
00182 << SgWritePoint(sequence[i]);
00183 toPlay = SgOppBW(toPlay);
00184 }
00185 out << '\n';
00186 }
00187
00188 void GoUctUtil::GfxStatus(const SgUctSearch& search, ostream& out)
00189 {
00190 const SgUctTree& tree = search.Tree();
00191 const SgUctNode& root = tree.Root();
00192 const SgUctSearchStat& stat = search.Statistics();
00193 SgUctValue abortPercent = stat.m_aborted.Mean() * SgUctValue(100);
00194 out << (format(
00195 "TEXT N=%.0f V=%.2f Len=%.0f Tree=%.1f/%.1f Abrt=%.0f%% Gm/s=%.0f\n")
00196 % root.MoveCount() % root.Mean() % stat.m_gameLength.Mean()
00197 % stat.m_movesInTree.Mean() % stat.m_movesInTree.Max()
00198 % abortPercent % stat.m_gamesPerSecond);
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