00001 //---------------------------------------------------------------------------- 00002 /** @file DfsCommands.cpp 00003 */ 00004 //---------------------------------------------------------------------------- 00005 00006 #include "SgSystem.h" 00007 #include "SgTimer.h" 00008 #include "BitsetIterator.hpp" 00009 #include "EndgameUtils.hpp" 00010 #include "DfsCommands.hpp" 00011 00012 using namespace benzene; 00013 00014 //---------------------------------------------------------------------------- 00015 00016 DfsCommands::DfsCommands(Game& game, HexEnvironment& env, 00017 DfsSolver& solver, 00018 boost::scoped_ptr<DfsHashTable>& hashTable, 00019 boost::scoped_ptr<DfsDB>& db, 00020 DfsStates& positions) 00021 : m_game(game), 00022 m_env(env), 00023 m_solver(solver), 00024 m_tt(hashTable), 00025 m_db(db), 00026 m_positions(positions) 00027 { 00028 } 00029 00030 void DfsCommands::Register(GtpEngine& e) 00031 { 00032 Register(e, "param_dfs", &DfsCommands::CmdParamSolver); 00033 Register(e, "param_dfs_db", &DfsCommands::CmdParamSolverDB); 00034 Register(e, "dfs-solve-state", &DfsCommands::CmdSolveState); 00035 Register(e, "dfs-clear-tt", &DfsCommands::CmdSolverClearTT); 00036 Register(e, "dfs-solver-find-winning", 00037 &DfsCommands::CmdSolverFindWinning); 00038 Register(e, "dfs-get-state", &DfsCommands::CmdGetState); 00039 Register(e, "dfs-get-histogram", &DfsCommands::CmdHistogram); 00040 Register(e, "dfs-get-pv", &DfsCommands::CmdGetPV); 00041 Register(e, "dfs-open-db", &DfsCommands::CmdDBOpen); 00042 Register(e, "dfs-close-db", &DfsCommands::CmdDBClose); 00043 Register(e, "dfs-db-stat", &DfsCommands::CmdDBStat); 00044 } 00045 00046 void DfsCommands::Register(GtpEngine& engine, const std::string& command, 00047 GtpCallback<DfsCommands>::Method method) 00048 { 00049 engine.Register(command, new GtpCallback<DfsCommands>(this, method)); 00050 } 00051 00052 //---------------------------------------------------------------------------- 00053 00054 void DfsCommands::CmdParamSolverDB(HtpCommand& cmd) 00055 { 00056 SolverDBParameters& param = m_positions.Parameters(); 00057 if (cmd.NuArg() == 0) 00058 { 00059 cmd << '\n' 00060 << "[bool] use_flipped_states " << param.m_useFlippedStates << '\n' 00061 << "[bool] use_proof_transpositions " 00062 << param.m_useProofTranspositions << '\n' 00063 << "[string] max_stones " << param.m_maxStones << '\n' 00064 << "[string] trans_stones " << param.m_transStones << '\n'; 00065 } 00066 else if (cmd.NuArg() == 2) 00067 { 00068 std::string name = cmd.Arg(0); 00069 if (name == "use_flipped_states") 00070 param.m_useFlippedStates = cmd.BoolArg(1); 00071 else if (name == "use_proof_transpositions") 00072 param.m_useProofTranspositions = cmd.BoolArg(1); 00073 else if (name == "max_stones") 00074 param.m_maxStones = cmd.IntArg(1, 0); 00075 else if (name == "trans_stones") 00076 param.m_transStones = cmd.IntArg(1, 0); 00077 else 00078 throw HtpFailure() << "unknown parameter: " << name; 00079 } 00080 else 00081 throw HtpFailure("Expected 0 or 2 arguments"); 00082 } 00083 00084 void DfsCommands::CmdParamSolver(HtpCommand& cmd) 00085 { 00086 if (cmd.NuArg() == 0) 00087 { 00088 cmd << '\n' 00089 << "[bool] backup_ice_info " 00090 << m_solver.BackupIceInfo() << '\n' 00091 << "[bool] shrink_proofs " 00092 << m_solver.ShrinkProofs() << '\n' 00093 << "[bool] use_decompositions " 00094 << m_solver.UseDecompositions() << '\n' 00095 << "[bool] use_guifx " 00096 << m_solver.UseGuiFx() << '\n' 00097 << "[string] move_ordering " 00098 << m_solver.MoveOrdering() << '\n' // FIXME: PRINT NICELY!! 00099 << "[string] tt_bits " 00100 << ((m_tt.get() == 0) ? 0 : m_tt->Bits()) << '\n' 00101 << "[string] update_depth " 00102 << m_solver.UpdateDepth() << '\n'; 00103 } 00104 else if (cmd.NuArg() == 2) 00105 { 00106 std::string name = cmd.Arg(0); 00107 if (name == "backup_ice_info") 00108 m_solver.SetBackupIceInfo(cmd.BoolArg(1)); 00109 else if (name == "shrink_proofs") 00110 m_solver.SetShrinkProofs(cmd.BoolArg(1)); 00111 else if (name == "use_decompositions") 00112 m_solver.SetUseDecompositions(cmd.BoolArg(1)); 00113 else if (name == "use_guifx") 00114 m_solver.SetUseGuiFx(cmd.BoolArg(1)); 00115 else if (name == "move_ordering") 00116 m_solver.SetMoveOrdering(cmd.IntArg(1,0,7)); 00117 else if (name == "tt_bits") 00118 { 00119 int bits = cmd.IntArg(1, 0); 00120 if (bits == 0) 00121 m_tt.reset(0); 00122 else 00123 m_tt.reset(new DfsHashTable(bits)); 00124 } 00125 else if (name == "update_depth") 00126 m_solver.SetUpdateDepth(cmd.IntArg(1, 0)); 00127 else 00128 throw HtpFailure() << "unknown parameter: " << name; 00129 } 00130 } 00131 00132 /** Solves the given state. 00133 Usage: "solve-state [color to play] 00134 */ 00135 void DfsCommands::CmdSolveState(HtpCommand& cmd) 00136 { 00137 cmd.CheckNuArg(1); 00138 HexColor color = HtpUtil::ColorArg(cmd, 0); 00139 HexBoard& brd = m_env.SyncBoard(m_game.Board()); 00140 if (brd.ICE().FindPermanentlyInferior()) 00141 throw HtpFailure("Permanently inferior not supported in DfsSolver."); 00142 HexState state(m_game.Board(), color); 00143 DfsSolutionSet solution; 00144 HexColor winner = m_solver.Solve(state, brd, solution, m_positions); 00145 m_solver.DumpStats(solution); 00146 if (winner != EMPTY) 00147 LogInfo() << winner << " wins!\n" << brd.Write(solution.proof) << '\n'; 00148 else 00149 LogInfo() << "Search aborted!\n"; 00150 cmd << winner; 00151 } 00152 00153 /** Clears the current TT. */ 00154 void DfsCommands::CmdSolverClearTT(HtpCommand& cmd) 00155 { 00156 UNUSED(cmd); 00157 m_tt->Clear(); 00158 } 00159 00160 /** Finds all winning moves in this state by calling 'solve-state' 00161 on each child move. 00162 Usage: same as 'solve-state'. 00163 */ 00164 void DfsCommands::CmdSolverFindWinning(HtpCommand& cmd) 00165 { 00166 cmd.CheckNuArg(1); 00167 HexColor color = HtpUtil::ColorArg(cmd, 0); 00168 HexBoard& brd = m_env.SyncBoard(m_game.Board()); 00169 if (brd.ICE().FindPermanentlyInferior()) 00170 throw HtpFailure("Permanently inferior not supported in DfsSolver"); 00171 brd.ComputeAll(color); 00172 bitset_t consider = (EndgameUtils::IsDeterminedState(brd, color) ? 00173 brd.GetPosition().GetEmpty() : 00174 EndgameUtils::MovesToConsider(brd, color)); 00175 bitset_t winning; 00176 SgTimer timer; 00177 HexState state(m_game.Board(), color); 00178 for (BitsetIterator p(consider); p; ++p) 00179 { 00180 if (!consider.test(*p)) 00181 continue; 00182 state.PlayMove(*p); 00183 HexBoard& brd = m_env.SyncBoard(state.Position()); 00184 LogInfo() << "****** Trying " << *p << " ******\n" << brd << '\n'; 00185 DfsSolutionSet solution; 00186 HexColor winner = m_solver.Solve(state, brd, solution, m_positions); 00187 m_solver.DumpStats(solution); 00188 LogInfo() << "Proof:" << brd.Write(solution.proof) << '\n'; 00189 state.UndoMove(*p); 00190 00191 if (winner != EMPTY) 00192 LogInfo() << "****** " << winner << " wins ******\n"; 00193 else 00194 LogInfo() << "****** unknown ******\n"; 00195 00196 if (winner == color) 00197 winning.set(*p); 00198 else 00199 consider &= solution.proof; 00200 } 00201 LogInfo() << "****** Winning Moves ******\n" 00202 << m_game.Board().Write(winning) << '\n'; 00203 LogInfo() << "Total Elapsed Time: " << timer.GetTime() << '\n'; 00204 cmd << HexPointUtil::ToString(winning); 00205 } 00206 00207 //---------------------------------------------------------------------------- 00208 00209 /** Opens a database. 00210 Usage: "db-open [filename]" 00211 */ 00212 void DfsCommands::CmdDBOpen(HtpCommand& cmd) 00213 { 00214 cmd.CheckNuArgLessEqual(3); 00215 std::string filename = cmd.Arg(0); 00216 try { 00217 m_db.reset(new DfsDB(filename)); 00218 } 00219 catch (BenzeneException& e) { 00220 m_db.reset(0); 00221 throw HtpFailure() << "Error opening db: '" << e.what() << "'\n"; 00222 } 00223 } 00224 00225 /** Closes an open database. */ 00226 void DfsCommands::CmdDBClose(HtpCommand& cmd) 00227 { 00228 cmd.CheckNuArg(0); 00229 if (m_db.get() == 0) 00230 throw HtpFailure("No open database!\n"); 00231 m_db.reset(0); 00232 } 00233 00234 /** Dumps info from on current state. */ 00235 void DfsCommands::CmdGetState(HtpCommand& cmd) 00236 { 00237 cmd.CheckNuArg(0); 00238 HexColor toPlay = m_game.Board().WhoseTurn(); 00239 HexState state(m_game.Board(), toPlay); 00240 DfsData data; 00241 if (!m_positions.Get(state, data)) 00242 { 00243 cmd << "State not available."; 00244 return; 00245 } 00246 cmd << (data.m_win ? toPlay : !toPlay); 00247 cmd << ' ' << data.m_numMoves; 00248 00249 std::vector<int> nummoves(BITSETSIZE); 00250 std::vector<int> flags(BITSETSIZE); 00251 std::vector<HexPoint> winning, losing; 00252 for (BitsetIterator p(state.Position().GetEmpty()); p; ++p) 00253 { 00254 state.PlayMove(*p); 00255 if (m_positions.Get(state, data)) 00256 { 00257 if (data.m_win) 00258 losing.push_back(*p); 00259 else 00260 winning.push_back(*p); 00261 nummoves[*p] = data.m_numMoves; 00262 flags[*p] = data.m_flags; 00263 } 00264 state.UndoMove(*p); 00265 } 00266 cmd << " Winning"; 00267 for (unsigned i = 0; i < winning.size(); ++i) 00268 { 00269 cmd << " " << winning[i]; 00270 cmd << " " << nummoves[winning[i]]; 00271 if (flags[winning[i]] & SolverDataFlags::MIRROR_TRANSPOSITION) 00272 cmd << "m"; 00273 else if (flags[winning[i]] & SolverDataFlags::TRANSPOSITION) 00274 cmd << "t"; 00275 } 00276 cmd << " Losing"; 00277 for (unsigned i = 0; i < losing.size(); ++i) 00278 { 00279 cmd << " " << losing[i]; 00280 cmd << " " << nummoves[losing[i]]; 00281 if (flags[losing[i]] & SolverDataFlags::MIRROR_TRANSPOSITION) 00282 cmd << "m"; 00283 else if (flags[losing[i]] & SolverDataFlags::TRANSPOSITION) 00284 cmd << "t"; 00285 } 00286 } 00287 00288 /** Prints database statistics. */ 00289 void DfsCommands::CmdDBStat(HtpCommand& cmd) 00290 { 00291 cmd.CheckNuArg(0); 00292 if (m_db.get() == 0) 00293 throw HtpFailure("No open database!\n"); 00294 cmd << m_db->BDBStatistics(); 00295 } 00296 00297 /** Prints histogram of last search. */ 00298 void DfsCommands::CmdHistogram(HtpCommand& cmd) 00299 { 00300 cmd.CheckNuArg(0); 00301 cmd << m_solver.Histogram().Write(); 00302 } 00303 00304 /** Prints PV from the current state from the last search. */ 00305 void DfsCommands::CmdGetPV(HtpCommand& cmd) 00306 { 00307 cmd.CheckNuArg(1); 00308 HexColor colorToMove = HtpUtil::ColorArg(cmd, 0); 00309 PointSequence pv; 00310 SolverDBUtil::GetVariation(HexState(m_game.Board(), colorToMove), 00311 m_positions, pv); 00312 cmd << HexPointUtil::ToString(pv); 00313 } 00314 00315 //----------------------------------------------------------------------------