00001
00002
00003
00004
00005
00006 #include "SgSystem.h"
00007
00008 #include <cmath>
00009 #include <iomanip>
00010 #include <sstream>
00011 #include <limits>
00012 #include <time.h>
00013 #include <signal.h>
00014 #include <iostream>
00015
00016 #include "SgGameReader.h"
00017 #include "SgNode.h"
00018 #include "SgTimer.h"
00019
00020 #include "BitsetIterator.hpp"
00021 #include "BoardUtils.hpp"
00022 #include "Groups.hpp"
00023 #include "HexSgUtil.hpp"
00024 #include "HexProgram.hpp"
00025 #include "HexHtpEngine.hpp"
00026 #include "Time.hpp"
00027
00028 using namespace benzene;
00029
00030
00031
00032 HexHtpEngine::HexHtpEngine(int boardsize)
00033 : GtpEngine(),
00034 m_board(boardsize, boardsize),
00035 m_game(m_board)
00036 {
00037 RegisterCmd("all_legal_moves", &HexHtpEngine::CmdAllLegalMoves);
00038 RegisterCmd("board_id", &HexHtpEngine::CmdBoardID);
00039 RegisterCmd("boardsize", &HexHtpEngine::CmdNewGame);
00040 RegisterCmd("clear_board", &HexHtpEngine::CmdClearBoard);
00041 RegisterCmd("exec", &HexHtpEngine::CmdExec);
00042 RegisterCmd("final_score", &HexHtpEngine::CmdFinalScore);
00043 RegisterCmd("genmove", &HexHtpEngine::CmdGenMove);
00044 RegisterCmd("reg_genmove", &HexHtpEngine::CmdRegGenMove);
00045 #if GTPENGINE_INTERRUPT
00046 RegisterCmd("gogui-interrupt", &HexHtpEngine::CmdInterrupt);
00047 #endif
00048 RegisterCmd("loadsgf", &HexHtpEngine::CmdLoadSgf);
00049 RegisterCmd("name", &HexHtpEngine::CmdName);
00050 RegisterCmd("param_game", &HexHtpEngine::CmdParamGame);
00051 RegisterCmd("play", &HexHtpEngine::CmdPlay);
00052 RegisterCmd("showboard", &HexHtpEngine::CmdShowboard);
00053 RegisterCmd("time_left", &HexHtpEngine::CmdTimeLeft);
00054 RegisterCmd("undo", &HexHtpEngine::CmdUndo);
00055 RegisterCmd("version", &HexHtpEngine::CmdVersion);
00056
00057 NewGame(m_board.Width(), m_board.Height());
00058 }
00059
00060 HexHtpEngine::~HexHtpEngine()
00061 {
00062 }
00063
00064
00065
00066 void HexHtpEngine::RegisterCmd(const std::string& name,
00067 GtpCallback<HexHtpEngine>::Method method)
00068 {
00069 Register(name, new GtpCallback<HexHtpEngine>(this, method));
00070 }
00071
00072 void HexHtpEngine::Play(HexColor color, HexPoint move)
00073 {
00074 bool illegal = false;
00075 std::string reason = "";
00076
00077
00078 if (move == RESIGN)
00079 return;
00080
00081 Game::ReturnType result = m_game.PlayMove(color, move);
00082 if (result == Game::INVALID_MOVE) {
00083 illegal = true;
00084 reason = " (invalid)";
00085 } else if (result == Game::OCCUPIED_CELL) {
00086 illegal = true;
00087 reason = " (occupied)";
00088 }
00089
00090 if (illegal) {
00091 throw HtpFailure() << "illegal move: " << ' '
00092 << color << ' ' << move << reason;
00093 }
00094 }
00095
00096 void HexHtpEngine::NewGame(int width, int height)
00097 {
00098 if (width != m_game.Board().Width() ||
00099 height != m_game.Board().Height())
00100 {
00101 m_board = StoneBoard(width, height);
00102 m_game.SetBoard(m_board);
00103 }
00104 m_game.NewGame();
00105 }
00106
00107 void HexHtpEngine::BeforeHandleCommand()
00108 {
00109 SgSetUserAbort(false);
00110 }
00111
00112 void HexHtpEngine::BeforeWritingResponse()
00113 {
00114 }
00115
00116
00117
00118
00119 void HexHtpEngine::CmdName(HtpCommand& cmd)
00120 {
00121 cmd << HexProgram::Get().getName();
00122 }
00123
00124
00125 void HexHtpEngine::CmdVersion(HtpCommand& cmd)
00126 {
00127 cmd << HexProgram::Get().getVersion();
00128 }
00129
00130
00131 void HexHtpEngine::CmdExec(HtpCommand& cmd)
00132 {
00133 cmd.CheckNuArg(1);
00134 std::string filename = cmd.Arg(0);
00135
00136 try {
00137 ExecuteFile(filename, std::cerr);
00138 }
00139 catch (std::exception& e) {
00140 LogInfo() << "Errors occured." << '\n';
00141 }
00142 }
00143
00144 #if GTPENGINE_INTERRUPT
00145
00146
00147
00148 void HexHtpEngine::CmdInterrupt(HtpCommand& cmd)
00149 {
00150 cmd.CheckArgNone();
00151 }
00152
00153 #endif
00154
00155
00156 void HexHtpEngine::CmdNewGame(HtpCommand& cmd)
00157 {
00158 cmd.CheckNuArgLessEqual(2);
00159 if (cmd.NuArg() == 0)
00160 throw HtpFailure() << "Must specify board dimensions!";
00161 int width = cmd.IntArg(0, 1, MAX_WIDTH);
00162 int height = width;
00163 if (cmd.NuArg() == 2)
00164 height = cmd.IntArg(1, 1, MAX_HEIGHT);
00165 NewGame(width, height);
00166 }
00167
00168
00169 void HexHtpEngine::CmdClearBoard(HtpCommand& cmd)
00170 {
00171 cmd.CheckArgNone();
00172 NewGame(m_board.Width(), m_board.Height());
00173 }
00174
00175
00176 void HexHtpEngine::CmdPlay(HtpCommand& cmd)
00177 {
00178 cmd.CheckNuArg(2);
00179 Play(HtpUtil::ColorArg(cmd, 0), HtpUtil::MoveArg(cmd, 1));
00180 }
00181
00182
00183 void HexHtpEngine::CmdGenMove(HtpCommand& cmd)
00184 {
00185 cmd.CheckNuArg(1);
00186 if (GameUtil::IsGameOver(m_game))
00187 cmd << RESIGN;
00188 else
00189 {
00190 HexColor color = HtpUtil::ColorArg(cmd, 0);
00191 SgTime::SetDefaultMode(SG_TIME_REAL);
00192 SgTimer timer;
00193 timer.Start();
00194 double oldTimeRemaining = m_game.TimeRemaining(color);
00195 HexPoint move = GenMove(color, true);
00196 timer.Stop();
00197
00198 m_game.SetTimeRemaining(color, oldTimeRemaining - timer.GetTime());
00199 if (m_game.TimeRemaining(color) < 0)
00200 LogWarning() << "**** FLAG DROPPED ****\n";
00201
00202 Play(color, move);
00203 cmd << move;
00204 }
00205 }
00206
00207
00208 void HexHtpEngine::CmdRegGenMove(HtpCommand& cmd)
00209 {
00210 cmd.CheckNuArg(1);
00211 SgRandom::SetSeed(SgRandom::Seed());
00212 if (GameUtil::IsGameOver(m_game))
00213 cmd << RESIGN;
00214 else
00215 {
00216 HexPoint move = GenMove(HtpUtil::ColorArg(cmd, 0), false);
00217 cmd << move;
00218 }
00219 }
00220
00221
00222 void HexHtpEngine::CmdUndo(HtpCommand& cmd)
00223 {
00224 cmd.CheckNuArg(0);
00225 m_game.UndoMove();
00226 }
00227
00228
00229 void HexHtpEngine::CmdShowboard(HtpCommand& cmd)
00230 {
00231 cmd << "\n";
00232 cmd << m_game.Board();
00233 }
00234
00235
00236 void HexHtpEngine::CmdBoardID(HtpCommand& cmd)
00237 {
00238 cmd.CheckNuArg(0);
00239 cmd << m_game.Board().GetBoardIDString();
00240 }
00241
00242
00243 void HexHtpEngine::CmdTimeLeft(HtpCommand& cmd)
00244 {
00245 cmd.CheckNuArgLessEqual(2);
00246 if (cmd.NuArg() == 0)
00247 {
00248 cmd << "Black: " << Time::Formatted(m_game.TimeRemaining(BLACK))
00249 << ", "
00250 << "White: " << Time::Formatted(m_game.TimeRemaining(WHITE));
00251 }
00252 else if (cmd.NuArg() == 1)
00253 {
00254 HexColor color = HtpUtil::ColorArg(cmd, 0);
00255 cmd << Time::Formatted(m_game.TimeRemaining(color));
00256 }
00257 else
00258 {
00259 HexColor color = HtpUtil::ColorArg(cmd, 0);
00260 m_game.SetTimeRemaining(color, cmd.IntArg(1));
00261 }
00262 }
00263
00264
00265
00266
00267 void HexHtpEngine::CmdFinalScore(HtpCommand& cmd)
00268 {
00269 Groups groups;
00270 GroupBuilder::Build(m_game.Board(), groups);
00271 HexColor winner = groups.GetWinner();
00272 std::string ret = "cannot score";
00273 if (winner == BLACK)
00274 ret = "B+";
00275 else if (winner == WHITE)
00276 ret = "W+";
00277 cmd << ret;
00278 }
00279
00280
00281 void HexHtpEngine::CmdAllLegalMoves(HtpCommand& cmd)
00282 {
00283 int c = 0;
00284 bitset_t legal = m_game.Board().GetLegal();
00285 for (BitsetIterator i(legal); i; ++i)
00286 {
00287 cmd << " " << *i;
00288 if ((++c % 10) == 0) cmd << "\n";
00289 }
00290 }
00291
00292
00293 void HexHtpEngine::SetPosition(const SgNode* node)
00294 {
00295 std::vector<HexPoint> black, white, empty;
00296 HexSgUtil::GetSetupPosition(node, m_game.Board().Height(),
00297 black, white, empty);
00298 for (unsigned i=0; ; ++i)
00299 {
00300 bool bdone = (i >= black.size());
00301 bool wdone = (i >= white.size());
00302 if (!bdone) Play(BLACK, black[i]);
00303 if (!wdone) Play(WHITE, white[i]);
00304 if (bdone && wdone) break;
00305 }
00306 }
00307
00308
00309
00310
00311 void HexHtpEngine::CmdLoadSgf(HtpCommand& cmd)
00312 {
00313 cmd.CheckNuArgLessEqual(2);
00314 std::string filename = cmd.Arg(0);
00315 int movenumber = 1024;
00316 if (cmd.NuArg() == 2)
00317 movenumber = cmd.IntArg(1, 0);
00318
00319 std::ifstream file(filename.c_str());
00320 if (!file) {
00321 throw HtpFailure() << "cannot load file";
00322 return;
00323 }
00324
00325 SgGameReader sgreader(file, 11);
00326 SgNode* root = sgreader.ReadGame();
00327 if (root == 0) {
00328 throw HtpFailure() << "cannot load file";
00329 return;
00330 }
00331 sgreader.PrintWarnings(std::cerr);
00332
00333 int size = root->GetIntProp(SG_PROP_SIZE);
00334
00335 NewGame(size, size);
00336
00337 const StoneBoard& brd = m_game.Board();
00338
00339 if (HexSgUtil::NodeHasSetupInfo(root)) {
00340 LogWarning() << "Root has setup info!" << '\n';
00341 SetPosition(root);
00342 }
00343
00344
00345 SgNode* cur = root;
00346 for (int mn=0; mn<movenumber;) {
00347 cur = cur->NodeInDirection(SgNode::NEXT);
00348 if (!cur) break;
00349
00350 if (HexSgUtil::NodeHasSetupInfo(cur)) {
00351 SetPosition(cur);
00352 continue;
00353 } else if (!cur->HasNodeMove()) {
00354 continue;
00355 }
00356
00357 HexColor color = HexSgUtil::SgColorToHexColor(cur->NodePlayer());
00358 HexPoint point = HexSgUtil::SgPointToHexPoint(cur->NodeMove(),
00359 brd.Height());
00360 Play(color, point);
00361 mn++;
00362 }
00363 }
00364
00365
00366
00367
00368
00369
00370
00371 void HexHtpEngine::CmdParamGame(HtpCommand& cmd)
00372 {
00373 if (cmd.NuArg() == 0)
00374 {
00375 cmd << "\n"
00376 << "[bool] allow_swap "
00377 << m_game.AllowSwap() << '\n'
00378 << "[string] game_time "
00379 << m_game.GameTime() << '\n';
00380 }
00381 else if (cmd.NuArg() == 2)
00382 {
00383 std::string name = cmd.Arg(0);
00384 if (name == "allow_swap")
00385 m_game.SetAllowSwap(cmd.BoolArg(1));
00386 else if (name == "game_time")
00387 {
00388 if (!m_game.History().empty())
00389 throw HtpFailure("Cannot set game time if game started!");
00390 m_game.SetGameTime(cmd.FloatArg(1));
00391 }
00392 }
00393 else
00394 throw HtpFailure("Expected 0 or 2 arguments");
00395 }
00396
00397 #if GTPENGINE_INTERRUPT
00398
00399 void HexHtpEngine::Interrupt()
00400 {
00401 SgSetUserAbort(true);
00402 }
00403
00404 #endif // GTPENGINE_INTERRUPT
00405
00406
00407
00408 HexColor HtpUtil::ColorArg(const HtpCommand& cmd, std::size_t number)
00409 {
00410 std::string value = cmd.ArgToLower(number);
00411 if (value == "e" || value == "empty")
00412 return EMPTY;
00413 if (value == "b" || value == "black")
00414 return BLACK;
00415 if (value == "w" || value == "white")
00416 return WHITE;
00417 throw HtpFailure() << "argument " << (number + 1) << " must be color";
00418 }
00419
00420 HexPoint HtpUtil::MoveArg(const HtpCommand& cmd, std::size_t number)
00421 {
00422 return HexPointUtil::FromString(cmd.ArgToLower(number));
00423 }
00424
00425