00001 //---------------------------------------------------------------------------- 00002 /** @file BookCommands.cpp 00003 */ 00004 //---------------------------------------------------------------------------- 00005 00006 #include "BookBuilder.hpp" 00007 #include "BookCommands.hpp" 00008 #include "VCUtils.hpp" 00009 00010 using namespace benzene; 00011 00012 //---------------------------------------------------------------------------- 00013 00014 BookCommands::BookCommands(Game& game, HexEnvironment& env, 00015 boost::scoped_ptr<Book>& book, 00016 BookCheck& bookCheck) 00017 : m_game(game), 00018 m_env(env), 00019 m_book(book), 00020 m_bookCheck(bookCheck) 00021 { 00022 } 00023 00024 BookCommands::~BookCommands() 00025 { 00026 } 00027 00028 void BookCommands::Register(GtpEngine& e) 00029 { 00030 Register(e, "book-open", &BookCommands::CmdBookOpen); 00031 Register(e, "book-close", &BookCommands::CmdBookClose); 00032 Register(e, "book-stat", &BookCommands::CmdBookStat); 00033 Register(e, "book-depths", &BookCommands::CmdBookMainLineDepth); 00034 Register(e, "book-counts", &BookCommands::CmdBookCounts); 00035 Register(e, "book-scores", &BookCommands::CmdBookScores); 00036 Register(e, "book-visualize", &BookCommands::CmdBookVisualize); 00037 Register(e, "book-dump-polarized-leafs", 00038 &BookCommands::CmdBookDumpPolarizedLeafs); 00039 Register(e, "book-import-solved", 00040 &BookCommands::CmdBookImportSolvedStates); 00041 Register(e, "book-set-value", &BookCommands::CmdBookSetValue); 00042 Register(e, "param_book", &BookCommands::CmdBookParam); 00043 } 00044 00045 void BookCommands::Register(GtpEngine& engine, const std::string& command, 00046 GtpCallback<BookCommands>::Method method) 00047 { 00048 engine.Register(command, new GtpCallback<BookCommands>(this, method)); 00049 } 00050 00051 //---------------------------------------------------------------------------- 00052 00053 /** Opens/Creates an opening book for the current boardsize. 00054 Usage: "book-expand [filename]" 00055 */ 00056 void BookCommands::CmdBookOpen(HtpCommand& cmd) 00057 { 00058 cmd.CheckNuArgLessEqual(2); 00059 std::string fn = cmd.Arg(0); 00060 try { 00061 m_book.reset(new Book(fn)); 00062 } 00063 catch (BenzeneException& e) { 00064 cmd << "Error opening book: '" << e.what() << "'\n"; 00065 } 00066 } 00067 00068 /** Closes a book if one is open. */ 00069 void BookCommands::CmdBookClose(HtpCommand& cmd) 00070 { 00071 cmd.CheckArgNone(); 00072 if (m_book.get() == 0) 00073 throw HtpFailure() << "No open book."; 00074 m_book.reset(0); 00075 } 00076 00077 void BookCommands::CmdBookStat(HtpCommand& cmd) 00078 { 00079 cmd.CheckNuArg(0); 00080 if (m_book.get() == 0) 00081 throw HtpFailure("No open book!\n"); 00082 cmd << m_book->BDBStatistics(); 00083 } 00084 00085 void BookCommands::CmdBookMainLineDepth(HtpCommand& cmd) 00086 { 00087 if (m_book.get() == 0) 00088 throw HtpFailure() << "No open book."; 00089 HexState state(m_game.Board(), m_game.Board().WhoseTurn()); 00090 for (BitsetIterator p(state.Position().GetEmpty()); p; ++p) 00091 { 00092 state.PlayMove(*p); 00093 cmd << " " << *p << " " << BookUtil::GetMainLineDepth(*m_book, state); 00094 state.UndoMove(*p); 00095 } 00096 } 00097 00098 void BookCommands::CmdBookCounts(HtpCommand& cmd) 00099 { 00100 if (m_book.get() == 0) 00101 throw HtpFailure() << "No open book."; 00102 HexState state(m_game.Board(), m_game.Board().WhoseTurn()); 00103 for (BitsetIterator p(state.Position().GetEmpty()); p; ++p) 00104 { 00105 state.PlayMove(*p); 00106 HexBookNode node; 00107 if (m_book->Get(state, node)) 00108 cmd << " " << *p << " " << node.m_count; 00109 state.UndoMove(*p); 00110 } 00111 } 00112 00113 void BookCommands::CmdBookScores(HtpCommand& cmd) 00114 { 00115 if (m_book.get() == 0) 00116 throw HtpFailure() << "No open book."; 00117 float countWeight = m_bookCheck.CountWeight(); 00118 HexState state(m_game.Board(), m_game.Board().WhoseTurn()); 00119 00120 std::map<HexPoint, HexEval> values; 00121 std::map<HexPoint, unsigned> counts; 00122 std::vector<std::pair<float, HexPoint> > scores; 00123 for (BitsetIterator p(state.Position().GetEmpty()); p; ++p) 00124 { 00125 state.PlayMove(*p); 00126 HexBookNode node; 00127 if (m_book->Get(state, node)) 00128 { 00129 counts[*p] = node.m_count; 00130 values[*p] = BookUtil::InverseEval(BookUtil::Value(node, state)); 00131 scores.push_back(std::make_pair 00132 (-BookUtil::Score(node, state, countWeight), *p)); 00133 } 00134 state.UndoMove(*p); 00135 } 00136 std::stable_sort(scores.begin(), scores.end()); 00137 std::vector<std::pair<float, HexPoint> >::const_iterator it 00138 = scores.begin(); 00139 for (; it != scores.end(); ++it) 00140 { 00141 HexPoint p = it->second; 00142 HexEval value = values[p]; 00143 cmd << ' ' << p; 00144 if (HexEvalUtil::IsWin(value)) 00145 cmd << " W"; 00146 else if (HexEvalUtil::IsLoss(value)) 00147 cmd << " L"; 00148 else 00149 cmd << " " << std::fixed << std::setprecision(3) << value; 00150 cmd << '@' << counts[p]; 00151 } 00152 } 00153 00154 void BookCommands::CmdBookVisualize(HtpCommand& cmd) 00155 { 00156 if (m_book.get() == 0) 00157 throw HtpFailure() << "No open book."; 00158 cmd.CheckNuArg(1); 00159 std::string filename = cmd.Arg(0); 00160 HexState state(m_game.Board(), m_game.Board().WhoseTurn()); 00161 std::ofstream f(filename.c_str()); 00162 if (!f) 00163 throw HtpFailure() << "Could not open file for output."; 00164 BookUtil::DumpVisualizationData(*m_book, state, 0, f); 00165 f.close(); 00166 } 00167 00168 /** Dumps variations leading to non-terminal leafs whose value is 00169 polarized. The ignore file is an optional argument that lists 00170 states that should not be ingored (not dumped again). 00171 Usage: 00172 book-dump-polarized-leafs [polarization] [output file] { [ignore file] } 00173 */ 00174 void BookCommands::CmdBookDumpPolarizedLeafs(HtpCommand& cmd) 00175 { 00176 if (m_book.get() == 0) 00177 throw HtpFailure() << "No open book."; 00178 cmd.CheckNuArgLessEqual(3); 00179 float polarization = cmd.FloatArg(0); 00180 std::string filename = cmd.Arg(1); 00181 StateSet ignoreSet; 00182 if (cmd.NuArg() == 3u) 00183 { 00184 std::string ignoreFile = cmd.Arg(2); 00185 HexState state(m_game.Board(), m_game.Board().WhoseTurn()); 00186 std::ifstream ifs(ignoreFile.c_str()); 00187 if (!ifs) 00188 throw HtpFailure() << "Could not open ignore file for reading."; 00189 std::string line; 00190 while (std::getline(ifs, line)) 00191 { 00192 PointSequence seq; 00193 HexPointUtil::FromString(line, seq); 00194 if (!seq.empty()) 00195 { 00196 state.Position().StartNewGame(); 00197 state.SetToPlay(FIRST_TO_PLAY); 00198 for (std::size_t i = 0; i < seq.size(); ++i) 00199 state.PlayMove(seq[i]); 00200 ignoreSet.Insert(state); 00201 } 00202 } 00203 LogInfo() << "Read " << ignoreSet.Size() << " positions to ignore.\n"; 00204 } 00205 HexState state(m_game.Board(), m_game.Board().WhoseTurn()); 00206 PointSequence pv; 00207 GameUtil::HistoryToSequence(m_game.History(), pv); 00208 std::ofstream f(filename.c_str()); 00209 if (!f) 00210 throw HtpFailure() << "Could not open file for output."; 00211 BookUtil::DumpPolarizedLeafs(*m_book, state, polarization, pv, f, 00212 ignoreSet); 00213 f.close(); 00214 } 00215 00216 /** Imports positions from file into book. */ 00217 void BookCommands::CmdBookImportSolvedStates(HtpCommand& cmd) 00218 { 00219 if (m_book.get() == 0) 00220 throw HtpFailure() << "No open book."; 00221 cmd.CheckNuArg(1); 00222 std::string filename = cmd.Arg(0); 00223 std::ifstream f(filename.c_str()); 00224 if (!f) 00225 throw HtpFailure() << "Could not open file for reading."; 00226 BookUtil::ImportSolvedStates(*m_book, m_game.Board().Const(), f); 00227 f.close(); 00228 } 00229 00230 /** Sets value of current state in the book. 00231 Usage: 00232 book-set-value [value] 00233 Where [value] can be one of W, L, or value in rage [0, 1]. 00234 */ 00235 void BookCommands::CmdBookSetValue(HtpCommand& cmd) 00236 { 00237 if (m_book.get() == 0) 00238 throw HtpFailure() << "No open book."; 00239 float value = 0.5; 00240 std::string vstr = cmd.ArgToLower(0); 00241 if (vstr == "w") 00242 value = IMMEDIATE_WIN; 00243 else if (vstr == "l") 00244 value = IMMEDIATE_LOSS; 00245 else 00246 value = cmd.FloatArg(0); 00247 HexBookNode node; 00248 HexState state(m_game.Board(), m_game.Board().WhoseTurn()); 00249 if (!m_book->Get(state, node)) 00250 m_book->Put(state, HexBookNode(value)); 00251 else 00252 { 00253 node.m_value = value; 00254 m_book->Put(state, node); 00255 } 00256 m_book->Flush(); 00257 } 00258 00259 void BookCommands::CmdBookParam(HtpCommand& cmd) 00260 { 00261 if (cmd.NuArg() == 0) 00262 { 00263 cmd << '\n' 00264 << "[string] book_count_weight " 00265 << m_bookCheck.CountWeight() << '\n' 00266 << "[string] book_min_count " 00267 << m_bookCheck.MinCount() << '\n'; 00268 } 00269 else if (cmd.NuArg() == 2) 00270 { 00271 std::string name = cmd.Arg(0); 00272 if (name == "book_min_count") 00273 m_bookCheck.SetMinCount(cmd.SizeTypeArg(1, 0)); 00274 else if (name == "book_count_weight") 00275 m_bookCheck.SetCountWeight(cmd.FloatArg(1)); 00276 else 00277 throw HtpFailure() << "Unknown parameter: " << name; 00278 } 00279 else 00280 throw HtpFailure("Expected 0 ore 2 arguments"); 00281 } 00282 00283 //----------------------------------------------------------------------------