00001
00002
00003
00004
00005
00006 #include "SgSystem.h"
00007 #include "GoGame.h"
00008
00009 #include "GoBoardUtil.h"
00010 #include "GoInit.h"
00011 #include "GoPlayer.h"
00012 #include "SgNode.h"
00013 #include "SgNodeUtil.h"
00014 #include "SgProp.h"
00015 #include "SgSearchStatistics.h"
00016 #include "SgUtil.h"
00017
00018 using namespace std;
00019 using GoBoardUtil::PlayIfLegal;
00020 using SgUtil::ForceInRange;
00021
00022
00023
00024 namespace {
00025
00026 void AddStatisticsToNode(const SgSearchStatistics* stat, SgNode* node)
00027 {
00028 node->Add(new SgPropInt(SG_PROP_NUM_NODES, stat->NumNodes()));
00029 node->Add(new SgPropInt(SG_PROP_NUM_LEAFS, stat->NumEvals()));
00030
00031 node->Add(new SgPropMSec(SG_PROP_TIME_USED, stat->TimeUsed()));
00032 node->Add(new SgPropInt(SG_PROP_MAX_DEPTH, stat->DepthReached()));
00033 }
00034
00035
00036
00037 void AddHandicap(int size, int row, int col, int* handicap,
00038 SgVector<SgPoint>* stones)
00039 {
00040 SG_ASSERT(2 <= *handicap);
00041 stones->PushBack(SgPointUtil::Pt(size + 1 - col, row));
00042 stones->PushBack(SgPointUtil::Pt(col, size + 1 - row));
00043 if (2 < *handicap)
00044 stones->PushBack(SgPointUtil::Pt(row, col));
00045 if (3 < *handicap)
00046 stones->PushBack(SgPointUtil::Pt(size + 1 - row, size + 1 - col));
00047 if (*handicap < 4)
00048 *handicap = 0;
00049 else
00050 *handicap -= 4;
00051 }
00052
00053 }
00054
00055
00056
00057 GoGame::GoGame(int boardSize)
00058 : m_board(boardSize),
00059 m_root(new SgNode()),
00060 m_time(),
00061 m_numMovesToInsert(0)
00062 {
00063
00064
00065 GoInitCheck();
00066 Init(boardSize, GoRules());
00067 }
00068
00069 GoGame::~GoGame()
00070 {
00071 m_root->DeleteTree();
00072 #ifndef NDEBUG
00073 m_root = 0;
00074 #endif
00075 }
00076
00077 void GoGame::AddComment(const SgNode& node, const std::string& comment)
00078 {
00079 NonConstNodeRef(node).AddComment(comment);
00080 }
00081
00082 void GoGame::AddMove(SgMove move, SgBlackWhite player,
00083 const SgSearchStatistics* stat, bool makeMainVariation)
00084 {
00085
00086 SgNode* node = m_current->LeftMostSon();
00087 while (node)
00088 {
00089 SgPropMove* prop = static_cast<SgPropMove*>(node->Get(SG_PROP_MOVE));
00090 if (prop && prop->IsValue(move) && prop->IsPlayer(player))
00091 break;
00092 node = node->RightBrother();
00093 }
00094
00095
00096 if (! node)
00097 {
00098 if (m_current->HasSon() && 0 < m_numMovesToInsert)
00099 {
00100 node = m_current->LeftMostSon()->NewFather();
00101 --m_numMovesToInsert;
00102 }
00103 else
00104 {
00105 node = m_current->NewRightMostSon();
00106 m_numMovesToInsert = 0;
00107 }
00108 node->AddMoveProp(move, player);
00109 }
00110
00111 if (stat)
00112 AddStatisticsToNode(stat, node);
00113 m_time.PlayedMove(*node, player);
00114 if (makeMainVariation)
00115 node->PromoteNode();
00116 GoToNode(node);
00117 }
00118
00119 const SgNode& GoGame::AddResignNode(SgBlackWhite player)
00120 {
00121 SgNode& node = *m_current->NewRightMostSon();
00122 ostringstream comment;
00123 comment << (player == SG_BLACK ? "Black" : "White") << " resigned";
00124 node.AddComment(comment.str());
00125 return node;
00126 }
00127
00128 void GoGame::AppendChild(SgNode* child)
00129 {
00130 child->AppendTo(m_current);
00131 }
00132
00133 bool GoGame::CanGoInDirection(SgNode::Direction dir) const
00134 {
00135 SgNode* node = m_current->NodeInDirection(dir);
00136 return node && node != m_current;
00137 }
00138
00139 SgMove GoGame::CurrentMove() const
00140 {
00141 SgPropMove* prop = static_cast<SgPropMove*>(m_current->Get(SG_PROP_MOVE));
00142 if (prop)
00143 return prop->Value();
00144 return SG_NULLMOVE;
00145 }
00146
00147 int GoGame::CurrentMoveNumber() const
00148 {
00149
00150
00151
00152 return SgNodeUtil::GetMoveNumber(m_current);
00153 }
00154
00155 bool GoGame::EndOfGame() const
00156 {
00157 return GoBoardUtil::EndOfGame(m_board);
00158 }
00159
00160
00161
00162
00163 std::string GoGame::GetGameInfoStringProp(SgPropID id) const
00164 {
00165 const SgNode* node = m_current->TopProp(id);
00166 if (node->HasProp(id))
00167 {
00168 const SgPropText* prop = dynamic_cast<SgPropText*>(node->Get(id));
00169 return prop->Value();
00170 }
00171 else
00172 return "";
00173 }
00174
00175 std::string GoGame::GetGameName() const
00176 {
00177 return GetGameInfoStringProp(SG_PROP_GAME_NAME);
00178 }
00179
00180 std::string GoGame::GetPlayerName(SgBlackWhite player) const
00181 {
00182 SgPropID id = SgProp::PlayerProp(SG_PROP_PLAYER_BLACK, player);
00183 return GetGameInfoStringProp(id);
00184 }
00185
00186 std::string GoGame::GetResult() const
00187 {
00188 return GetGameInfoStringProp(SG_PROP_RESULT);
00189 }
00190
00191 void GoGame::GoInDirection(SgNode::Direction dir)
00192 {
00193 SgNode* node = m_current->NodeInDirection(dir);
00194 if (node != m_current)
00195 GoToNode(node);
00196 }
00197
00198 void GoGame::GoToNode(const SgNode* dest)
00199 {
00200 m_updater.Update(dest, m_board);
00201 SgNodeUtil::UpdateTime(Time(), dest);
00202 m_current = NonConstNodePtr(dest);
00203 if (GoBoardUtil::RemainingChineseHandicap(m_board))
00204 m_board.SetToPlay(SG_BLACK);
00205 m_time.EnterNode(*m_current, m_board.ToPlay());
00206 }
00207
00208 void GoGame::Init(int size, const GoRules& rules)
00209 {
00210 m_board.Init(size, rules);
00211 m_root->DeleteTree();
00212 m_root = new SgNode();
00213 SgPropInt* boardSizeProp = new SgPropInt(SG_PROP_SIZE, size);
00214 m_root->Add(boardSizeProp);
00215 GoKomi komi = rules.Komi();
00216 if (! komi.IsUnknown())
00217 m_root->SetRealProp(SG_PROP_KOMI, komi.ToFloat(), 1);
00218 InitHandicap(rules, m_root);
00219 GoToNode(m_root);
00220 }
00221
00222 void GoGame::Init(SgNode* root)
00223 {
00224 m_root->DeleteTree();
00225 m_root = root;
00226 int size = GO_DEFAULT_SIZE;
00227 SgPropInt* boardSizeProp =
00228 static_cast<SgPropInt*>(m_root->Get(SG_PROP_SIZE));
00229 if (boardSizeProp)
00230 {
00231 size = boardSizeProp->Value();
00232 ForceInRange(SG_MIN_SIZE, &size, SG_MAX_SIZE);
00233 }
00234 const GoRules& rules = m_board.Rules();
00235 m_board.Init(size, GoRules(rules.Handicap(), rules.Komi()));
00236
00237
00238 const int GAME_ID = 1;
00239 SgPropInt* gameId = new SgPropInt(SG_PROP_GAME, GAME_ID);
00240 m_root->Add(gameId);
00241
00242
00243 GoToNode(m_root);
00244 }
00245
00246
00247
00248
00249
00250
00251
00252
00253 SgNode* GoGame::NonConstNodePtr(const SgNode* node) const
00254 {
00255 SG_ASSERT(node->Root() == m_root);
00256 return const_cast<SgNode*>(node);
00257 }
00258
00259
00260 SgNode& GoGame::NonConstNodeRef(const SgNode& node) const
00261 {
00262 SG_ASSERT(node.Root() == m_root);
00263 return const_cast<SgNode&>(node);
00264 }
00265
00266 void GoGame::PlaceHandicap(const SgVector<SgPoint>& stones)
00267 {
00268 SG_ASSERT(GoBoardUtil::IsBoardEmpty(m_board));
00269 SgNode* node = m_current;
00270 if (node->HasSon())
00271 node = node->NewRightMostSon();
00272 SgPropAddStone* addBlack = new SgPropAddStone(SG_PROP_ADD_BLACK);
00273 for (SgVectorIterator<SgPoint> it(stones); it; ++it)
00274 addBlack->PushBack(*it);
00275 node->Add(addBlack);
00276 SgPropInt* handicap = new SgPropInt(SG_PROP_HANDICAP, stones.Length());
00277 node->Add(handicap);
00278 node->Add(new SgPropPlayer(SG_PROP_PLAYER, SG_WHITE));
00279 m_board.Rules().SetHandicap(stones.Length());
00280 GoToNode(node);
00281 }
00282
00283 void GoGame::InitHandicap(const GoRules& rules, SgNode* root)
00284 {
00285
00286
00287
00288
00289 if (2 <= rules.Handicap())
00290 {
00291 SgPropInt* handicap =
00292 new SgPropInt(SG_PROP_HANDICAP, rules.Handicap());
00293 root->Add(handicap);
00294 if (rules.JapaneseHandicap())
00295 {
00296 if (9 <= m_board.Size())
00297 {
00298 int h = rules.Handicap();
00299 int half = (m_board.Size()+1) / 2;
00300 SgVector<SgPoint> stones;
00301 if ((4 < h) && (h % 2 != 0))
00302 {
00303 stones.PushBack(SgPointUtil::Pt(half, half));
00304 --h;
00305 }
00306 if (13 <= m_board.Size())
00307 {
00308 AddHandicap(m_board.Size(), 4, 4, &h, &stones);
00309 if (0 < h)
00310 AddHandicap(m_board.Size(), half, 4, &h, &stones);
00311 if (0 < h)
00312 AddHandicap(m_board.Size(), 3, 3, &h, &stones);
00313 if (0 < h)
00314 AddHandicap(m_board.Size(), 7, 7, &h, &stones);
00315 if (0 < h)
00316 AddHandicap(m_board.Size(), half, 3, &h, &stones);
00317 if (0 < h)
00318 AddHandicap(m_board.Size(), half - (half - 4) / 2,
00319 4, &h, &stones);
00320 if (0 < h)
00321 AddHandicap(m_board.Size(), half + (half - 4) / 2,
00322 4, &h, &stones);
00323 }
00324 else
00325 {
00326 AddHandicap(m_board.Size(), 3, 3, &h, &stones);
00327 if (0 < h)
00328 AddHandicap(m_board.Size(), half, 3, &h, &stones);
00329 if (0 < h)
00330 AddHandicap(m_board.Size(), 4, 4, &h, &stones);
00331 }
00332 SgPropAddStone* addBlack =
00333 new SgPropAddStone(SG_PROP_ADD_BLACK, stones);
00334 root->Add(addBlack);
00335
00336
00337 SgPropPlayer* player =
00338 new SgPropPlayer(SG_PROP_PLAYER, SG_WHITE);
00339 root->Add(player);
00340 }
00341 }
00342 else
00343 {
00344
00345 SgPropInt* chinese =
00346 new SgPropInt(SG_PROP_CHINESE, rules.Handicap());
00347 root->Add(chinese);
00348 }
00349 }
00350 }
00351
00352 void GoGame::SetKomiGlobal(GoKomi komi)
00353 {
00354 SgNodeUtil::RemovePropInSubtree(*m_root, SG_PROP_KOMI);
00355 if (! komi.IsUnknown())
00356 m_root->SetRealProp(SG_PROP_KOMI, komi.ToFloat(), 1);
00357 m_board.Rules().SetKomi(komi);
00358 }
00359
00360 void GoGame::SetRulesGlobal(const GoRules& rules)
00361 {
00362 m_board.Rules() = rules;
00363
00364 SetKomiGlobal(rules.Komi());
00365 }
00366
00367 void GoGame::SetTimeSettingsGlobal(const GoTimeSettings& timeSettings,
00368 double overhead)
00369 {
00370 m_timeSettings = timeSettings;
00371 SgNodeUtil::RemovePropInSubtree(*m_root, SG_PROP_TIME);
00372 SgNodeUtil::RemovePropInSubtree(*m_root, SG_PROP_OT_NU_MOVES);
00373 SgNodeUtil::RemovePropInSubtree(*m_root, SG_PROP_OT_PERIOD);
00374 if (timeSettings.IsUnknown())
00375 {
00376
00377
00378 return;
00379 }
00380 double mainTime = timeSettings.MainTime();
00381 m_root->Add(new SgPropTime(SG_PROP_TIME, mainTime));
00382 double overtime = timeSettings.Overtime();
00383 if (overtime > 0)
00384 {
00385 m_root->Add(new SgPropTime(SG_PROP_OT_PERIOD, overtime));
00386 m_root->SetIntProp(SG_PROP_OT_NU_MOVES, timeSettings.OvertimeMoves());
00387 }
00388
00389
00390
00391
00392 m_time.SetOTPeriod(overtime);
00393 m_time.SetOTNumMoves(timeSettings.OvertimeMoves());
00394 m_time.SetOverhead(overhead);
00395 m_time.SetClock(*m_current, SG_BLACK, mainTime);
00396 m_time.SetClock(*m_current, SG_WHITE, mainTime);
00397 m_time.TurnClockOn(true);
00398 }
00399
00400 void GoGame::SetToPlay(SgBlackWhite toPlay)
00401 {
00402 if (toPlay == m_board.ToPlay())
00403 return;
00404 m_board.SetToPlay(toPlay);
00405 m_current->Add(new SgPropPlayer(SG_PROP_PLAYER, toPlay));
00406 m_time.EnterNode(*m_current, toPlay);
00407 }
00408
00409 void GoGame::SetupPosition(const SgBWArray<SgPointSet>& stones)
00410 {
00411 SgPropAddStone* addBlack = new SgPropAddStone(SG_PROP_ADD_BLACK);
00412 SgPropAddStone* addWhite = new SgPropAddStone(SG_PROP_ADD_WHITE);
00413 for (SgSetIterator it(stones[SG_BLACK]); it; ++it)
00414 if (m_board.GetColor(*it) != SG_BLACK)
00415 addBlack->PushBack(*it);
00416 for (SgSetIterator it(stones[SG_WHITE]); it; ++it)
00417 if (m_board.GetColor(*it) != SG_WHITE)
00418 addWhite->PushBack(*it);
00419 SgNode* node = m_current->NewRightMostSon();
00420 node->Add(addBlack);
00421 node->Add(addWhite);
00422 GoToNode(node);
00423 }
00424
00425 void GoGame::UpdateDate(const std::string& date)
00426 {
00427 UpdateGameInfoStringProp(SG_PROP_DATE, date);
00428 }
00429
00430 void GoGame::UpdateGameInfoStringProp(SgPropID id, const std::string& value)
00431 {
00432 SgNode* node = m_current->TopProp(id);
00433 node->SetStringProp(id, value);
00434 }
00435
00436 void GoGame::UpdateGameName(const std::string& name)
00437 {
00438 UpdateGameInfoStringProp(SG_PROP_GAME_NAME, name);
00439 }
00440
00441 void GoGame::UpdatePlayerName(SgBlackWhite color, const std::string& name)
00442 {
00443 SgPropID id = SgProp::PlayerProp(SG_PROP_PLAYER_BLACK, color);
00444 UpdateGameInfoStringProp(id, name);
00445 }
00446
00447 void GoGame::UpdateResult(const std::string& result)
00448 {
00449 UpdateGameInfoStringProp(SG_PROP_RESULT, result);
00450 }
00451
00452
00453
00454 bool GoGameUtil::GotoBeforeMove(GoGame* game, int moveNumber)
00455 {
00456 SG_ASSERT(game->CurrentNode() == &game->Root());
00457 SG_ASSERT(moveNumber == -1 || moveNumber > 0);
00458 if (moveNumber > 0)
00459 {
00460 while (game->CanGoInDirection(SgNode::NEXT)
00461 && ! game->CurrentNode()->HasProp(SG_PROP_MOVE)
00462 && ! game->CurrentNode()->LeftMostSon()->HasProp(SG_PROP_MOVE))
00463 game->GoInDirection(SgNode::NEXT);
00464 while (game->CurrentMoveNumber() < moveNumber - 1
00465 && game->CanGoInDirection(SgNode::NEXT))
00466 game->GoInDirection(SgNode::NEXT);
00467 if (game->CurrentMoveNumber() != moveNumber - 1)
00468 return false;
00469 }
00470 else
00471 {
00472 while (game->CanGoInDirection(SgNode::NEXT))
00473 game->GoInDirection(SgNode::NEXT);
00474 }
00475 return true;
00476 }
00477
00478