00001
00002
00003
00004
00005
00006 #include <cmath>
00007 #include <boost/numeric/conversion/bounds.hpp>
00008
00009 #include "BitsetIterator.hpp"
00010 #include "Book.hpp"
00011 #include "HexModState.hpp"
00012 #include "Time.hpp"
00013
00014 using namespace benzene;
00015
00016
00017
00018
00019 #define OUTPUT_OB_INFO 1
00020
00021
00022
00023
00024
00025
00026 const std::string Book::BOOK_DB_VERSION = "BENZENE_BOOK_VER_0001";
00027
00028
00029
00030 float BookUtil::Value(const SgBookNode& node, const HexState& state)
00031 {
00032 if (state.Position().IsLegal(SWAP_PIECES))
00033 return std::max(node.m_value, BookUtil::InverseEval(node.m_value));
00034 return node.m_value;
00035 }
00036
00037 float BookUtil::Score(const SgBookNode& node, const HexState& state,
00038 float countWeight)
00039 {
00040 float score = BookUtil::InverseEval(Value(node, state));
00041 if (!node.IsTerminal())
00042 score += log(node.m_count + 1) * countWeight;
00043 return score;
00044 }
00045
00046 float BookUtil::InverseEval(float eval)
00047 {
00048 if (HexEvalUtil::IsWinOrLoss(eval))
00049 return -eval;
00050 if (eval < 0 || eval > 1)
00051 LogInfo() << "eval = " << eval << '\n';
00052 HexAssert(0 <= eval && eval <= 1.0);
00053 return 1.0 - eval;
00054 }
00055
00056
00057
00058 int BookUtil::GetMainLineDepth(const Book& book, const HexState& origState)
00059 {
00060 int depth = 0;
00061 HexState state(origState);
00062 for (;;)
00063 {
00064 HexBookNode node;
00065 if (!book.Get(state, node))
00066 break;
00067 HexPoint move = INVALID_POINT;
00068 float value = -1e9;
00069 for (BitsetIterator p(state.Position().GetEmpty()); p; ++p)
00070 {
00071 state.PlayMove(*p);
00072 HexBookNode child;
00073 if (book.Get(state, child))
00074 {
00075 float curValue = InverseEval(BookUtil::Value(child, state));
00076 if (curValue > value)
00077 {
00078 value = curValue;
00079 move = *p;
00080 }
00081 }
00082 state.UndoMove(*p);
00083 }
00084 if (move == INVALID_POINT)
00085 break;
00086 state.PlayMove(move);
00087 depth++;
00088 }
00089 return depth;
00090 }
00091
00092 namespace
00093 {
00094
00095 std::size_t TreeSize(const Book& book, HexState& state,
00096 StateMap<std::size_t>& solved)
00097 {
00098 if (solved.Exists(state))
00099 return solved[state];
00100 HexBookNode node;
00101 if (!book.Get(state, node))
00102 return 0;
00103 std::size_t ret = 1;
00104 for (BitsetIterator p(state.Position().GetEmpty()); p; ++p)
00105 {
00106 state.PlayMove(*p);
00107 ret += TreeSize(book, state, solved);
00108 state.UndoMove(*p);
00109 }
00110 solved[state] = ret;
00111 return ret;
00112 }
00113
00114 }
00115
00116 std::size_t BookUtil::GetTreeSize(const Book& book, const HexState& origState)
00117 {
00118 StateMap<std::size_t> solved;
00119 HexState state(origState);
00120 return TreeSize(book, state, solved);
00121 }
00122
00123
00124
00125 HexPoint BookUtil::BestMove(const Book& book, const HexState& origState,
00126 unsigned minCount, float countWeight)
00127 {
00128 HexBookNode node;
00129 if (!book.Get(origState, node) || node.m_count < minCount)
00130 return INVALID_POINT;
00131
00132 float bestScore = -1e9;
00133 HexPoint bestChild = INVALID_POINT;
00134 HexState state(origState);
00135 for (BitsetIterator p(state.Position().GetEmpty()); p; ++p)
00136 {
00137 state.PlayMove(*p);
00138 HexBookNode child;
00139 if (book.Get(state, child))
00140 {
00141 float score = BookUtil::Score(child, state, countWeight);
00142 if (score > bestScore)
00143 {
00144 bestScore = score;
00145 bestChild = *p;
00146 }
00147 }
00148 state.UndoMove(*p);
00149 }
00150 HexAssert(bestChild != INVALID_POINT);
00151 return bestChild;
00152 }
00153
00154
00155
00156 void BookUtil::DumpVisualizationData(const Book& book,
00157 const HexState& origState, int depth,
00158 std::ostream& out)
00159 {
00160 HexBookNode node;
00161 if (!book.Get(origState, node))
00162 return;
00163 if (node.IsLeaf())
00164 {
00165 out << BookUtil::Value(node, origState) << " " << depth << '\n';
00166 return;
00167 }
00168 HexModState modState(origState);
00169 HexState state = modState.State();
00170 for (BitsetIterator i(state.Position().GetEmpty()); i; ++i)
00171 {
00172 state.PlayMove( *i);
00173 DumpVisualizationData(book, state, depth + 1, out);
00174 state.UndoMove(*i);
00175 }
00176 }
00177
00178 namespace {
00179
00180 void DumpPolarizedLeafs(const Book& book, HexState& state,
00181 float polarization, StateSet& seen,
00182 PointSequence& pv, std::ostream& out,
00183 const StateSet& ignoreSet)
00184 {
00185 if (seen.Exists(state))
00186 return;
00187 HexBookNode node;
00188 if (!book.Get(state, node))
00189 return;
00190 if (fabs(BookUtil::Value(node, state) - 0.5) >= polarization
00191 && node.IsLeaf() && !node.IsTerminal()
00192 && ignoreSet.Exists(state))
00193 {
00194 out << HexPointUtil::ToString(pv) << '\n';
00195 seen.Insert(state);
00196 }
00197 else
00198 {
00199 if (node.IsLeaf() || node.IsTerminal())
00200 return;
00201 for (BitsetIterator i(state.Position().GetEmpty()); i; ++i)
00202 {
00203 state.PlayMove(*i);
00204 pv.push_back(*i);
00205 DumpPolarizedLeafs(book, state, polarization, seen, pv, out,
00206 ignoreSet);
00207 pv.pop_back();
00208 state.UndoMove(*i);
00209 }
00210 seen.Insert(state);
00211 }
00212 }
00213
00214 }
00215
00216 void BookUtil::DumpPolarizedLeafs(const Book& book, const HexState& origState,
00217 float polarization, PointSequence& pv,
00218 std::ostream& out,
00219 const StateSet& ignoreSet)
00220 {
00221 StateSet seen;
00222 HexModState modState(origState);
00223 HexState state = modState.State();
00224 ::DumpPolarizedLeafs(book, state, polarization, seen, pv, out, ignoreSet);
00225 }
00226
00227 void BookUtil::ImportSolvedStates(Book& book, const ConstBoard& constBoard,
00228 std::istream& positions)
00229 {
00230 StoneBoard brd(constBoard.Width(), constBoard.Height());
00231 HexState state(brd, FIRST_TO_PLAY);
00232 std::string text;
00233 std::size_t lineNumber = 0;
00234 std::size_t numParsed = 0;
00235 std::size_t numReplaced = 0;
00236 std::size_t numNew = 0;
00237 while (std::getline(positions, text))
00238 {
00239 ++lineNumber;
00240 std::istringstream is(text);
00241 PointSequence points;
00242 HexColor winner = EMPTY;
00243 bool parsed = false;
00244 while (true)
00245 {
00246 std::string token;
00247 is >> token;
00248 if (token == "black")
00249 {
00250 winner = BLACK;
00251 parsed = true;
00252 break;
00253 }
00254 else if (token == "white")
00255 {
00256 winner = WHITE;
00257 parsed = true;
00258 break;
00259 }
00260 else
00261 {
00262 HexPoint p = HexPointUtil::FromString(token);
00263 if (p == INVALID_POINT)
00264 break;
00265 points.push_back(p);
00266 }
00267 }
00268 if (!parsed)
00269 {
00270 LogInfo() << "Skipping badly formed line " << lineNumber << ".\n";
00271 continue;
00272 }
00273 HexAssert(winner != EMPTY);
00274
00275 ++numParsed;
00276 state.Position().StartNewGame();
00277 state.SetToPlay(FIRST_TO_PLAY);
00278 for (std::size_t i = 0; i < points.size(); ++i)
00279 state.PlayMove(points[i]);
00280 HexEval ourValue = (state.ToPlay() == winner)
00281 ? IMMEDIATE_WIN : IMMEDIATE_LOSS;
00282 HexBookNode node;
00283 if (book.Get(state, node))
00284 {
00285 HexAssert(node.IsLeaf());
00286 HexAssert(!node.IsTerminal());
00287 node.m_value = ourValue;
00288 ++numReplaced;
00289 }
00290 else
00291 {
00292 node = HexBookNode(ourValue);
00293 ++numNew;
00294 }
00295 book.Put(state, node);
00296 }
00297 book.Flush();
00298 LogInfo() << " Lines: " << lineNumber << '\n';
00299 LogInfo() << " Parsed: " << numParsed << '\n';
00300 LogInfo() << "Replaced: " << numReplaced << '\n';
00301 LogInfo() << " New: " << numNew << '\n';
00302 }
00303
00304