00001 //---------------------------------------------------------------------------- 00002 /** @file DfpnCommands.cpp 00003 */ 00004 //---------------------------------------------------------------------------- 00005 00006 #include "BitsetIterator.hpp" 00007 #include "EndgameUtils.hpp" 00008 #include "DfpnCommands.hpp" 00009 00010 using namespace benzene; 00011 00012 //---------------------------------------------------------------------------- 00013 00014 DfpnCommands::DfpnCommands(Game& game, HexEnvironment& env, 00015 DfpnSolver& solver, 00016 boost::scoped_ptr<DfpnHashTable>& tt, 00017 boost::scoped_ptr<DfpnDB>& db, 00018 DfpnStates& positions) 00019 : m_game(game), 00020 m_env(env), 00021 m_solver(solver), 00022 m_tt(tt), 00023 m_db(db), 00024 m_positions(positions) 00025 { 00026 } 00027 00028 void DfpnCommands::Register(GtpEngine& e) 00029 { 00030 Register(e, "param_dfpn", &DfpnCommands::CmdParam); 00031 Register(e, "param_dfpn_db", &DfpnCommands::CmdParamSolverDB); 00032 Register(e, "dfpn-clear-tt", &DfpnCommands::CmdClearTT); 00033 Register(e, "dfpn-get-bounds", &DfpnCommands::CmdGetBounds); 00034 Register(e, "dfpn-get-state", &DfpnCommands::CmdGetState); 00035 Register(e, "dfpn-get-work", &DfpnCommands::CmdGetWork); 00036 Register(e, "dfpn-get-pv", &DfpnCommands::CmdGetPV); 00037 Register(e, "dfpn-solve-state", &DfpnCommands::CmdSolveState); 00038 Register(e, "dfpn-solver-find-winning", &DfpnCommands::CmdFindWinning); 00039 Register(e, "dfpn-open-db", &DfpnCommands::CmdOpenDB); 00040 Register(e, "dfpn-close-db", &DfpnCommands::CmdCloseDB); 00041 Register(e, "dfpn-db-stat", &DfpnCommands::CmdDBStat); 00042 Register(e, "dfpn-evaluation-info", &DfpnCommands::CmdEvaluationInfo); 00043 } 00044 00045 void DfpnCommands::Register(GtpEngine& engine, const std::string& command, 00046 GtpCallback<DfpnCommands>::Method method) 00047 { 00048 engine.Register(command, new GtpCallback<DfpnCommands>(this, method)); 00049 } 00050 00051 //---------------------------------------------------------------------------- 00052 00053 void DfpnCommands::CmdParamSolverDB(HtpCommand& cmd) 00054 { 00055 SolverDBParameters& param = m_positions.Parameters(); 00056 if (cmd.NuArg() == 0) 00057 { 00058 cmd << '\n' 00059 << "[bool] use_flipped_states " << param.m_useFlippedStates << '\n' 00060 << "[bool] use_proof_transpositions " 00061 << param.m_useProofTranspositions << '\n' 00062 << "[string] max_stones " << param.m_maxStones << '\n' 00063 << "[string] trans_stones " << param.m_transStones << '\n'; 00064 } 00065 else if (cmd.NuArg() == 2) 00066 { 00067 std::string name = cmd.Arg(0); 00068 if (name == "use_flipped_states") 00069 param.m_useFlippedStates = cmd.BoolArg(1); 00070 else if (name == "use_proof_transpositions") 00071 param.m_useProofTranspositions = cmd.BoolArg(1); 00072 else if (name == "max_stones") 00073 param.m_maxStones = cmd.IntArg(1, 0); 00074 else if (name == "trans_stones") 00075 param.m_transStones = cmd.IntArg(1, 0); 00076 else 00077 throw HtpFailure() << "unknown parameter: " << name; 00078 } 00079 else 00080 throw HtpFailure("Expected 0 or 2 arguments"); 00081 } 00082 00083 void DfpnCommands::CmdParam(HtpCommand& cmd) 00084 { 00085 if (cmd.NuArg() == 0) 00086 { 00087 cmd << '\n' 00088 << "[bool] use_guifx " 00089 << m_solver.UseGuiFx() << '\n' 00090 << "[string] timelimit " 00091 << m_solver.Timelimit() << '\n' 00092 << "[string] tt_bits " 00093 << ((m_tt.get() == 0) ? 0 : m_tt->Bits()) << '\n' 00094 << "[string] widening_base " 00095 << m_solver.WideningBase() << '\n' 00096 << "[string] widening_factor " 00097 << m_solver.WideningFactor() << '\n'; 00098 } 00099 else if (cmd.NuArg() == 2) 00100 { 00101 std::string name = cmd.Arg(0); 00102 if (name == "use_guifx") 00103 m_solver.SetUseGuiFx(cmd.BoolArg(1)); 00104 else if (name == "timelimit") 00105 m_solver.SetTimelimit(cmd.FloatArg(1)); 00106 else if (name == "tt_bits") 00107 { 00108 int bits = cmd.IntArg(1, 0); 00109 if (bits == 0) 00110 m_tt.reset(0); 00111 else 00112 m_tt.reset(new DfpnHashTable(bits)); 00113 } 00114 else if (name == "widening_base") 00115 { 00116 int value = cmd.IntArg(1, 0); 00117 if (0 < value) 00118 m_solver.SetWideningBase(value); 00119 else 00120 throw GtpFailure() << "widening_base must be positive."; 00121 } 00122 else if (name == "widening_factor") 00123 { 00124 float value = cmd.FloatArg(1); 00125 if (0.0f < value && value <= 1.0f) 00126 m_solver.SetWideningFactor(value); 00127 else 00128 throw GtpFailure() << "widening_factor must be in (0, 1]"; 00129 } 00130 else 00131 throw GtpFailure() << "Unknown parameter: " << name; 00132 } 00133 else 00134 throw GtpFailure() << "Expected 0 or 2 arguments"; 00135 } 00136 00137 /** Solves the current state with dfpn using the current hashtable. */ 00138 void DfpnCommands::CmdSolveState(HtpCommand& cmd) 00139 { 00140 cmd.CheckNuArgLessEqual(3); 00141 HexColor colorToMove = m_game.Board().WhoseTurn(); 00142 if (cmd.NuArg() >= 1) 00143 colorToMove = HtpUtil::ColorArg(cmd, 0); 00144 DfpnBoundType maxPhi = DfpnBounds::MAX_WORK; 00145 DfpnBoundType maxDelta = DfpnBounds::MAX_WORK; 00146 if (cmd.NuArg() >= 2) 00147 maxPhi = cmd.IntArg(1, 0); 00148 if (cmd.NuArg() >= 3) 00149 maxDelta = cmd.IntArg(2, 0); 00150 DfpnBounds maxBounds(maxPhi, maxDelta); 00151 PointSequence pv; 00152 HexBoard& brd = m_env.SyncBoard(m_game.Board()); 00153 HexColor winner 00154 = m_solver.StartSearch(HexState(m_game.Board(), colorToMove), brd, 00155 m_positions, pv, maxBounds); 00156 cmd << winner; 00157 } 00158 00159 /** Finds all winning moves in the current state with dfpn, 00160 using the current hashtable. */ 00161 void DfpnCommands::CmdFindWinning(HtpCommand& cmd) 00162 { 00163 cmd.CheckNuArg(1); 00164 HexColor colorToMove = HtpUtil::ColorArg(cmd, 0); 00165 HexBoard& brd = m_env.SyncBoard(m_game.Board()); 00166 brd.ComputeAll(colorToMove); 00167 bitset_t consider = (EndgameUtils::IsDeterminedState(brd, colorToMove) ? 00168 brd.GetPosition().GetEmpty() : 00169 EndgameUtils::MovesToConsider(brd, colorToMove)); 00170 bitset_t winning; 00171 SgTimer timer; 00172 00173 HexState state(m_game.Board(), colorToMove); 00174 for (BitsetIterator p(consider); p; ++p) 00175 { 00176 state.PlayMove(*p); 00177 HexBoard& brd = m_env.SyncBoard(state.Position()); 00178 LogInfo() << "****** Trying " << *p << " ******\n" << brd << '\n'; 00179 PointSequence pv; 00180 HexColor winner = m_solver.StartSearch(state, brd, m_positions, pv); 00181 if (winner == colorToMove) 00182 winning.set(*p); 00183 LogInfo() << "****** " << winner << " wins ******\n"; 00184 state.UndoMove(*p); 00185 } 00186 LogInfo() << "Total Elapsed Time: " << timer.GetTime() << '\n'; 00187 cmd << HexPointUtil::ToString(winning); 00188 } 00189 00190 /** Clears the current dfpn hashtable. */ 00191 void DfpnCommands::CmdClearTT(HtpCommand& cmd) 00192 { 00193 UNUSED(cmd); 00194 m_tt->Clear(); 00195 } 00196 00197 /** Displays information about the current state from the 00198 hashtable. */ 00199 void DfpnCommands::CmdGetState(HtpCommand& cmd) 00200 { 00201 cmd.CheckNuArg(1); 00202 HexColor colorToMove = HtpUtil::ColorArg(cmd, 0); 00203 HexState state(m_game.Board(), colorToMove); 00204 DfpnData data; 00205 if (m_positions.Get(state, data)) 00206 cmd << data << '\n'; 00207 } 00208 00209 /** Displays bounds of every empty cell in current state. 00210 Bounds are obtained from the current hashtable. */ 00211 void DfpnCommands::CmdGetBounds(HtpCommand& cmd) 00212 { 00213 cmd.CheckNuArg(1); 00214 HexColor colorToMove = HtpUtil::ColorArg(cmd, 0); 00215 HexState state(m_game.Board(), colorToMove); 00216 for (BitsetIterator it(state.Position().GetEmpty()); it; ++it) 00217 { 00218 state.PlayMove(*it); 00219 DfpnData data; 00220 if (m_positions.Get(state, data)) 00221 { 00222 cmd << ' ' << *it << ' '; 00223 if (data.m_bounds.IsWinning()) 00224 cmd << 'L'; 00225 else if (data.m_bounds.IsLosing()) 00226 cmd << 'W'; 00227 else 00228 cmd << data.m_bounds.phi << ':' << data.m_bounds.delta; 00229 } 00230 state.UndoMove(*it); 00231 } 00232 } 00233 00234 /** Displays work of every empty cell in current state. 00235 Bounds are obtained from the current hashtable. */ 00236 void DfpnCommands::CmdGetWork(HtpCommand& cmd) 00237 { 00238 cmd.CheckNuArg(1); 00239 HexColor colorToMove = HtpUtil::ColorArg(cmd, 0); 00240 HexState state(m_game.Board(), colorToMove); 00241 for (BitsetIterator it(state.Position().GetEmpty()); it; ++it) 00242 { 00243 state.PlayMove(*it); 00244 DfpnData data; 00245 if (m_positions.Get(state, data)) 00246 cmd << ' ' << *it << ' ' << data.m_work; 00247 state.UndoMove(*it); 00248 } 00249 } 00250 00251 /** Displays PV from current position. */ 00252 void DfpnCommands::CmdGetPV(HtpCommand& cmd) 00253 { 00254 cmd.CheckNuArg(1); 00255 HexColor colorToMove = HtpUtil::ColorArg(cmd, 0); 00256 PointSequence pv; 00257 SolverDBUtil::GetVariation(HexState(m_game.Board(), colorToMove), 00258 m_positions, pv); 00259 cmd << HexPointUtil::ToString(pv); 00260 } 00261 00262 /** Opens a database. 00263 Usage: "db-open [filename]" 00264 */ 00265 void DfpnCommands::CmdOpenDB(HtpCommand& cmd) 00266 { 00267 cmd.CheckNuArgLessEqual(3); 00268 std::string filename = cmd.Arg(0); 00269 try { 00270 m_db.reset(new DfpnDB(filename)); 00271 } 00272 catch (BenzeneException& e) { 00273 m_db.reset(0); 00274 throw HtpFailure() << "Error opening db: '" << e.what() << "'\n"; 00275 } 00276 } 00277 00278 /** Closes an open database. */ 00279 void DfpnCommands::CmdCloseDB(HtpCommand& cmd) 00280 { 00281 cmd.CheckNuArg(0); 00282 if (m_db.get() == 0) 00283 throw HtpFailure("No open database!\n"); 00284 m_db.reset(0); 00285 } 00286 00287 /** Prints database statistics. */ 00288 void DfpnCommands::CmdDBStat(HtpCommand& cmd) 00289 { 00290 cmd.CheckNuArg(0); 00291 if (m_db.get() == 0) 00292 throw HtpFailure("No open database!\n"); 00293 cmd << m_db->BDBStatistics(); 00294 } 00295 00296 void DfpnCommands::CmdEvaluationInfo(HtpCommand& cmd) 00297 { 00298 cmd.CheckNuArg(0); 00299 cmd << m_solver.EvaluationInfo(); 00300 } 00301 00302 //----------------------------------------------------------------------------