Go to the documentation of this file.00001
00002
00003
00004
00005 #include "SgSystem.h"
00006 #include "GoAutoBook.h"
00007
00008
00009
00010 GoAutoBookState::GoAutoBookState(const GoBoard& brd)
00011 : m_synchronizer(brd)
00012 {
00013 m_synchronizer.SetSubscriber(m_brd[0]);
00014 }
00015
00016 GoAutoBookState::~GoAutoBookState()
00017 {
00018 }
00019
00020 SgHashCode GoAutoBookState::GetHashCode() const
00021 {
00022 return m_hash;
00023 }
00024
00025 void GoAutoBookState::Synchronize()
00026 {
00027 m_synchronizer.UpdateSubscriber();
00028 int size = m_brd[0].Size();
00029 int numMoves = m_brd[0].MoveNumber();
00030 for (int rot = 1; rot < 8; ++rot)
00031 {
00032 m_brd[rot].Init(size, size);
00033 for (int i = 0; i < numMoves; ++i)
00034 {
00035 SgMove move = m_brd[0].Move(i).Point();
00036 m_brd[rot].Play(SgPointUtil::Rotate(rot, move, size));
00037 }
00038 }
00039 ComputeHashCode();
00040 }
00041
00042 void GoAutoBookState::Play(SgMove move)
00043 {
00044 m_hash = m_brd[0].GetHashCodeInclToPlay();
00045 for (int rot = 0; rot < 8; ++rot)
00046 m_brd[rot].Play(SgPointUtil::Rotate(rot, move, m_brd[0].Size()));
00047 ComputeHashCode();
00048 }
00049
00050 void GoAutoBookState::Undo()
00051 {
00052 for (int rot = 0; rot < 8; ++rot)
00053 m_brd[rot].Undo();
00054 ComputeHashCode();
00055 }
00056
00057 void GoAutoBookState::ComputeHashCode()
00058 {
00059 m_hash = m_brd[0].GetHashCodeInclToPlay();
00060 for (int rot = 1; rot < 8; ++rot)
00061 {
00062 SgHashCode curHash = m_brd[rot].GetHashCodeInclToPlay();
00063 if (curHash < m_hash)
00064 m_hash = curHash;
00065 }
00066 }
00067
00068
00069
00070 GoAutoBookParam::GoAutoBookParam()
00071 : m_usageCountThreshold(0),
00072 m_selectType(GO_AUTOBOOK_SELECT_VALUE)
00073 {
00074 }
00075
00076
00077
00078 GoAutoBook::GoAutoBook(const std::string& filename,
00079 const GoAutoBookParam& param)
00080 : m_param(param),
00081 m_filename(filename)
00082 {
00083 std::ifstream is(filename.c_str());
00084 if (!is)
00085 {
00086 std::ofstream of(filename.c_str());
00087 if (!of)
00088 throw SgException("Invalid file name!");
00089 of.close();
00090 }
00091 else
00092 {
00093 while (is)
00094 {
00095 std::string line;
00096 std::getline(is, line);
00097 if (line.size() < 19)
00098 continue;
00099 std::string str;
00100 std::istringstream iss(line);
00101 iss >> str;
00102 SgHashCode hash;
00103 hash.FromString(str);
00104 SgBookNode node(line.substr(19));
00105 m_data[hash] = node;
00106 }
00107 SgDebug() << "GoAutoBook: Parsed " << m_data.size() << " lines.\n";
00108 }
00109 }
00110
00111 GoAutoBook::~GoAutoBook()
00112 {
00113 }
00114
00115 bool GoAutoBook::Get(const GoAutoBookState& state, SgBookNode& node) const
00116 {
00117 Map::const_iterator it = m_data.find(state.GetHashCode());
00118 if (it != m_data.end())
00119 {
00120 node = it->second;
00121 return true;
00122 }
00123 return false;
00124 }
00125
00126 void GoAutoBook::Put(const GoAutoBookState& state, const SgBookNode& node)
00127 {
00128 m_data[state.GetHashCode()] = node;
00129 }
00130
00131 void GoAutoBook::Flush()
00132 {
00133 Save(m_filename);
00134 }
00135
00136 void GoAutoBook::Save(const std::string& filename) const
00137 {
00138 std::ofstream out(filename.c_str());
00139 for (Map::const_iterator it = m_data.begin(); it != m_data.end(); ++it)
00140 {
00141 out << it->first.ToString() << '\t'
00142 << it->second.ToString() << '\n';
00143 }
00144 out.close();
00145 }
00146
00147 void GoAutoBook::Merge(const GoAutoBook& other)
00148 {
00149 SgDebug() << "GoAutoBook::Merge()\n";
00150 std::size_t newLeafs = 0;
00151 std::size_t newInternal = 0;
00152 std::size_t leafsInCommon = 0;
00153 std::size_t internalInCommon = 0;
00154 std::size_t leafToInternal = 0;
00155 for (Map::const_iterator it = other.m_data.begin();
00156 it != other.m_data.end(); ++it)
00157 {
00158 Map::iterator mine = m_data.find(it->first);
00159 SgBookNode newNode(it->second);
00160 if (mine == m_data.end())
00161 {
00162 m_data[it->first] = it->second;
00163 if (newNode.IsLeaf())
00164 newLeafs++;
00165 else
00166 newInternal++;
00167 }
00168 else
00169 {
00170 SgBookNode oldNode(mine->second);
00171 if (newNode.IsLeaf() && oldNode.IsLeaf())
00172 {
00173 newNode.m_heurValue = 0.5f * (newNode.m_heurValue
00174 + oldNode.m_heurValue);
00175 m_data[it->first] = newNode;
00176 leafsInCommon++;
00177 }
00178 else if (!newNode.IsLeaf())
00179 {
00180
00181
00182
00183
00184
00185
00186
00187 newNode.m_count = std::max(newNode.m_count, oldNode.m_count);
00188 m_data[it->first] = newNode;
00189 if (!oldNode.IsLeaf())
00190 internalInCommon++;
00191 else
00192 leafToInternal++;
00193 }
00194 }
00195 }
00196 SgDebug() << "Statistics\n"
00197 << "New Leafs " << newLeafs << '\n'
00198 << "New Internal " << newInternal << '\n'
00199 << "Common Leafs " << leafsInCommon << '\n'
00200 << "Common Internal " << internalInCommon << '\n'
00201 << "Leaf to Internal " << leafToInternal << '\n';
00202 }
00203
00204
00205
00206 void GoAutoBook::TruncateByDepth(int depth, GoAutoBookState& state,
00207 GoAutoBook& other) const
00208 {
00209 std::set<SgHashCode> seen;
00210 TruncateByDepth(depth, state, other, seen);
00211 }
00212
00213 void GoAutoBook::TruncateByDepth(int depth, GoAutoBookState& state,
00214 GoAutoBook& other,
00215 std::set<SgHashCode>& seen) const
00216 {
00217 if (seen.count(state.GetHashCode()))
00218 return;
00219 SgBookNode node;
00220 if (!Get(state, node))
00221 return;
00222 seen.insert(state.GetHashCode());
00223 if (depth == 0)
00224 {
00225
00226
00227 node.m_count = 0;
00228 node.m_priority = SgBookNode::LEAF_PRIORITY;
00229 node.m_value = node.m_heurValue;
00230 other.Put(state, node);
00231 return;
00232 }
00233 other.Put(state, node);
00234 if (node.IsLeaf() || node.IsTerminal())
00235 return;
00236 for (GoBoard::Iterator it(state.Board()); it; ++it)
00237 {
00238 if (state.Board().IsLegal(*it))
00239 {
00240 state.Play(*it);
00241 TruncateByDepth(depth - 1, state, other, seen);
00242 state.Undo();
00243 }
00244 }
00245 }
00246
00247
00248
00249 void GoAutoBook::ImportHashValuePairs(std::istream& in)
00250 {
00251 std::size_t count = 0;
00252 while (in)
00253 {
00254 SgHashCode hash;
00255 std::string hashStr;
00256 in >> hashStr;
00257 hash.FromString(hashStr);
00258 float value;
00259 if (!in)
00260 break;
00261 in >> value;
00262 if (m_data.count(hash) == 0)
00263 {
00264 std::ostringstream os;
00265 os << "Unknown hash: " << hash << '\n';
00266 throw SgException(os.str());
00267 }
00268 SgBookNode node(m_data[hash]);
00269 node.m_heurValue = value;
00270 node.m_value = value;
00271 m_data[hash] = node;
00272 count++;
00273 }
00274 SgDebug() << "GoAutoBook::ImportHashValue: imported "
00275 << count << " values.\n";
00276 }
00277
00278
00279
00280 SgMove GoAutoBook::FindBestChild(GoAutoBookState& state) const
00281 {
00282 std::size_t bestCount = 0;
00283 SgMove bestMove = SG_NULLMOVE;
00284 float bestScore = 100.0f;
00285 SgBookNode node;
00286 if (!Get(state, node))
00287 return SG_NULLMOVE;
00288 if (node.IsLeaf())
00289 return SG_NULLMOVE;
00290 for (GoBoard::Iterator it(state.Board()); it; ++it)
00291 {
00292 if (state.Board().IsLegal(*it))
00293 {
00294 state.Play(*it);
00295 if (m_disabled.count(state.GetHashCode()) > 0)
00296 SgDebug() << "Ignoring disabled move "
00297 << SgWritePoint(*it) << '\n';
00298
00299
00300 else if (Get(state, node)
00301 && !node.IsTerminal()
00302 && node.m_count >= m_param.m_usageCountThreshold)
00303 {
00304 if (m_param.m_selectType == GO_AUTOBOOK_SELECT_COUNT)
00305 {
00306
00307 if (node.m_count > bestCount)
00308 {
00309 bestCount = node.m_count;
00310 bestMove = *it;
00311 bestScore = node.m_value;
00312 }
00313
00314
00315 else if (node.m_count == bestCount
00316 && node.m_value < bestScore)
00317 {
00318 bestMove = *it;
00319 bestScore = node.m_value;
00320 }
00321 }
00322 else if (m_param.m_selectType == GO_AUTOBOOK_SELECT_VALUE)
00323 {
00324
00325
00326 if (node.m_value < bestScore)
00327 {
00328 bestMove = *it;
00329 bestScore = node.m_value;
00330 }
00331 }
00332 }
00333 state.Undo();
00334 }
00335 }
00336 return bestMove;
00337 }
00338
00339 SgMove GoAutoBook::LookupMove(const GoBoard& brd) const
00340 {
00341 GoAutoBookState state(brd);
00342 state.Synchronize();
00343 return FindBestChild(state);
00344 }
00345
00346
00347
00348 void GoAutoBook::ExportToOldFormat(GoAutoBookState& state, std::ostream& out,
00349 std::set<SgHashCode>& seen) const
00350 {
00351 if (seen.count(state.GetHashCode()))
00352 return;
00353 SgBookNode node;
00354 if (!Get(state, node))
00355 return;
00356 if (node.IsTerminal() || node.IsLeaf())
00357 return;
00358 seen.insert(state.GetHashCode());
00359 SgPoint move = FindBestChild(state);
00360
00361 if (move == SG_NULLMOVE)
00362 return;
00363 const GoBoard& brd = state.Board();
00364 out << brd.Size() << ' ';
00365 for (int i = 0; i < brd.MoveNumber(); ++i)
00366 out << ' ' << SgWritePoint(brd.Move(i).Point());
00367 out << " | " << SgWritePoint(move);
00368 out << '\n';
00369 for (GoBoard::Iterator it(brd); it; ++it)
00370 if (brd.IsLegal(*it))
00371 {
00372 state.Play(*it);
00373 ExportToOldFormat(state, out, seen);
00374 state.Undo();
00375 }
00376 }
00377
00378 void GoAutoBook::ExportToOldFormat(GoAutoBookState& state,
00379 std::ostream& os) const
00380 {
00381 std::set<SgHashCode> seen;
00382 ExportToOldFormat(state, os, seen);
00383 }
00384
00385
00386
00387 std::vector< std::vector<SgMove> > GoAutoBook::ParseWorkList(std::istream& in)
00388 {
00389 std::vector< std::vector<SgMove> > ret;
00390 while (in)
00391 {
00392 std::string line;
00393 std::getline(in, line);
00394 if (line == "")
00395 continue;
00396 std::vector<SgMove> var;
00397 std::istringstream in2(line);
00398 while (true)
00399 {
00400 std::string s;
00401 in2 >> s;
00402 if (! in2 || s == "|")
00403 break;
00404 std::istringstream in3(s);
00405 SgPoint p;
00406 in3 >> SgReadPoint(p);
00407 if (! in3)
00408 throw SgException("Invalid point");
00409 var.push_back(p);
00410 }
00411 ret.push_back(var);
00412 }
00413 SgDebug() << "GoAutoBook::ParseWorkList: Read " << ret.size()
00414 << " variations.\n";
00415 return ret;
00416 }
00417
00418