00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include "SgSystem.h"
00018
00019 #include "SgException.h"
00020 #include "SgMove.h"
00021
00022 #include "BoardUtils.hpp"
00023 #include "BitsetIterator.hpp"
00024 #include "HexUctPolicy.hpp"
00025 #include "HexUctUtil.hpp"
00026 #include "PatternState.hpp"
00027 #include "EndgameUtils.hpp"
00028 #include "SequenceHash.hpp"
00029
00030 using namespace benzene;
00031
00032
00033 static const bool DEBUG_KNOWLEDGE = false;
00034
00035
00036
00037 static const bool TRACK_KNOWLEDGE = false;
00038
00039
00040
00041 namespace
00042 {
00043
00044
00045 bool GameOver(const StoneBoard& brd)
00046 {
00047 return brd.GetEmpty().none();
00048 }
00049
00050
00051 HexColor GetWinner(const StoneBoard& brd)
00052 {
00053 SG_ASSERT(GameOver(brd));
00054 if (BoardUtils::ConnectedOnBitset(brd.Const(), brd.GetColor(BLACK),
00055 NORTH, SOUTH))
00056 return BLACK;
00057 return WHITE;
00058 }
00059
00060
00061 HexColor CheckIfWinner(const StoneBoard& brd)
00062 {
00063 if (BoardUtils::ConnectedOnBitset(brd.Const(), brd.GetColor(BLACK),
00064 NORTH, SOUTH))
00065 return BLACK;
00066 if (BoardUtils::ConnectedOnBitset(brd.Const(), brd.GetColor(WHITE),
00067 EAST, WEST))
00068 return WHITE;
00069 return EMPTY;
00070 }
00071
00072 }
00073
00074
00075
00076 HexUctState::AssertionHandler::AssertionHandler(const HexUctState& state)
00077 : m_state(state)
00078 {
00079 }
00080
00081 void HexUctState::AssertionHandler::Run()
00082 {
00083 LogSevere() << m_state.Dump() << '\n';
00084 }
00085
00086
00087
00088 HexUctState::HexUctState(const unsigned int threadId,
00089 HexUctSearch& sch,
00090 int treeUpdateRadius,
00091 int playoutUpdateRadius)
00092 : SgUctThreadState(threadId, HexUctUtil::ComputeMaxNumMoves()),
00093 m_assertionHandler(*this),
00094
00095 m_bd(0),
00096 m_vc_brd(0),
00097 m_policy(0),
00098 m_shared_data(0),
00099 m_knowledge(*this),
00100 m_search(sch),
00101 m_treeUpdateRadius(treeUpdateRadius),
00102 m_playoutUpdateRadius(playoutUpdateRadius),
00103 m_isInPlayout(false)
00104 {
00105 }
00106
00107 HexUctState::~HexUctState()
00108 {
00109 }
00110
00111 void HexUctState::SetPolicy(HexUctSearchPolicy* policy)
00112 {
00113 m_policy.reset(policy);
00114 }
00115
00116 std::string HexUctState::Dump() const
00117 {
00118 std::ostringstream os;
00119 os << "HexUctState[" << m_threadId << "] ";
00120 if (m_isInPlayout)
00121 os << "[playout] ";
00122 os << "board:" << *m_bd;
00123 return os.str();
00124 }
00125
00126 SgUctValue HexUctState::Evaluate()
00127 {
00128 SG_ASSERT(GameOver(*m_bd));
00129 SgUctValue score = (GetWinner(*m_bd) == m_toPlay) ? 1.0 : 0.0;
00130 return score;
00131 }
00132
00133 void HexUctState::Execute(SgMove sgmove)
00134 {
00135 ExecuteTreeMove(static_cast<HexPoint>(sgmove));
00136 m_toPlay = !m_toPlay;
00137 }
00138
00139 void HexUctState::ExecutePlayout(SgMove sgmove)
00140 {
00141 ExecuteRolloutMove(static_cast<HexPoint>(sgmove));
00142 m_toPlay = !m_toPlay;
00143 }
00144
00145 void HexUctState::ExecuteTreeMove(HexPoint move)
00146 {
00147 {
00148 HexUctPolicy* blah = dynamic_cast<HexUctPolicy*>(m_policy.get());
00149 if (!blah)
00150 abort();
00151 blah->AddResponse(m_toPlay, m_lastMovePlayed, move);
00152 }
00153
00154 m_game_sequence.push_back(Move(m_toPlay, move));
00155 ExecutePlainMove(move, m_treeUpdateRadius);
00156 HexUctStoneData stones;
00157 if (m_shared_data->stones.get(SequenceHash::Hash(m_game_sequence), stones))
00158 {
00159 m_bd->StartNewGame();
00160 m_bd->SetColor(BLACK, stones.black);
00161 m_bd->SetColor(WHITE, stones.white);
00162 m_bd->SetPlayed(stones.played);
00163 m_pastate->Update();
00164 }
00165 }
00166
00167 void HexUctState::ExecuteRolloutMove(HexPoint move)
00168 {
00169 ExecutePlainMove(move, m_playoutUpdateRadius);
00170 }
00171
00172 void HexUctState::ExecutePlainMove(HexPoint cell, int updateRadius)
00173 {
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185 SG_ASSERT(m_bd->IsEmpty(cell));
00186 SG_ASSERT(m_pastate->UpdateRadius() == updateRadius);
00187
00188 m_bd->PlayMove(m_toPlay, cell);
00189 if (updateRadius == 1)
00190 m_pastate->UpdateRingGodel(cell);
00191 else
00192 m_pastate->Update(cell);
00193
00194 m_lastMovePlayed = cell;
00195 m_new_game = false;
00196 }
00197
00198 bool HexUctState::GenerateAllMoves(SgUctValue count,
00199 std::vector<SgMoveInfo>& moves,
00200 SgProvenNodeType& provenType)
00201 {
00202 moves.clear();
00203
00204
00205 if (m_new_game)
00206 {
00207 for (BitsetIterator it(m_shared_data->root_consider); it; ++it)
00208 moves.push_back(SgMoveInfo(*it));
00209 if (count == 0)
00210 m_knowledge.ProcessPosition(moves);
00211 return false;
00212 }
00213
00214 bool truncateChildTrees = false;
00215 if (count == 0)
00216 {
00217 {
00218 HexColor winner = CheckIfWinner(*m_bd);
00219 if (winner != EMPTY)
00220 {
00221 provenType = (winner == m_toPlay)
00222 ? SG_PROVEN_WIN : SG_PROVEN_LOSS;
00223 return false;
00224 }
00225 }
00226 for (BitsetIterator it(m_bd->GetEmpty()); it; ++it)
00227 moves.push_back(SgMoveInfo(*it));
00228 m_knowledge.ProcessPosition(moves);
00229 }
00230 else
00231 {
00232
00233 if (TRACK_KNOWLEDGE)
00234 {
00235 hash_t hash = SequenceHash::Hash(m_game_sequence);
00236 LogInfo() << m_threadId << ": "
00237 << HashUtil::toString(hash) << '\n';
00238 }
00239 truncateChildTrees = true;
00240 bitset_t moveset = m_bd->GetEmpty() & ComputeKnowledge(provenType);
00241 for (BitsetIterator it(moveset); it; ++it)
00242 moves.push_back(SgMoveInfo(*it));
00243 }
00244 return truncateChildTrees;
00245 }
00246
00247 SgMove HexUctState::GeneratePlayoutMove(bool& skipRaveUpdate)
00248 {
00249 skipRaveUpdate = false;
00250
00251 if (GameOver(*m_bd))
00252 return SG_NULLMOVE;
00253
00254 SgPoint move = m_policy->GenerateMove(*m_pastate, m_toPlay,
00255 m_lastMovePlayed);
00256 SG_ASSERT(move != SG_NULLMOVE);
00257 return move;
00258 }
00259
00260 void HexUctState::StartSearch()
00261 {
00262 LogInfo() << "StartSearch()[" << m_threadId <<"]" << '\n';
00263 m_shared_data = &m_search.SharedData();
00264
00265
00266
00267
00268 HexBoard& brd = const_cast<HexBoard&>(m_search.Board());
00269
00270 if (!m_bd.get()
00271 || m_bd->Width() != brd.Width()
00272 || m_bd->Height() != brd.Height())
00273 {
00274 m_bd.reset(new StoneBoard(brd.Width(), brd.Height()));
00275 m_pastate.reset(new PatternState(*m_bd));
00276 m_vc_brd.reset(new HexBoard(brd.Width(), brd.Height(),
00277 brd.ICE(), brd.Builder().Parameters()));
00278 }
00279
00280 m_policy->InitializeForSearch();
00281 }
00282
00283 void HexUctState::TakeBackInTree(std::size_t nuMoves)
00284 {
00285 SG_UNUSED(nuMoves);
00286 }
00287
00288 void HexUctState::TakeBackPlayout(std::size_t nuMoves)
00289 {
00290 SG_UNUSED(nuMoves);
00291 }
00292
00293 SgBlackWhite HexUctState::ToPlay() const
00294 {
00295 return HexUctUtil::ToSgBlackWhite(m_toPlay);
00296 }
00297
00298 void HexUctState::GameStart()
00299 {
00300 m_new_game = true;
00301 m_isInPlayout = false;
00302 m_game_sequence = m_shared_data->game_sequence;
00303 m_toPlay = m_shared_data->root_to_play;
00304 m_lastMovePlayed = m_shared_data->root_last_move_played;
00305 m_pastate->SetUpdateRadius(m_treeUpdateRadius);
00306
00307 m_bd->StartNewGame();
00308 m_bd->SetColor(BLACK, m_shared_data->root_stones.black);
00309 m_bd->SetColor(WHITE, m_shared_data->root_stones.white);
00310 m_bd->SetPlayed(m_shared_data->root_stones.played);
00311 m_pastate->Update();
00312 }
00313
00314 void HexUctState::StartPlayouts()
00315 {
00316 m_isInPlayout = true;
00317 m_pastate->SetUpdateRadius(m_playoutUpdateRadius);
00318
00319
00320
00321
00322
00323 if (m_playoutUpdateRadius > m_treeUpdateRadius)
00324 m_pastate->Update();
00325 }
00326
00327 void HexUctState::StartPlayout()
00328 {
00329 m_policy->InitializeForRollout(*m_bd);
00330 }
00331
00332 void HexUctState::EndPlayout()
00333 {
00334 }
00335
00336
00337
00338 bitset_t HexUctState::ComputeKnowledge(SgProvenNodeType& provenType)
00339 {
00340 m_vc_brd->GetPosition().StartNewGame();
00341 m_vc_brd->GetPosition().SetColor(BLACK, m_bd->GetPlayed(BLACK));
00342 m_vc_brd->GetPosition().SetColor(WHITE, m_bd->GetPlayed(WHITE));
00343 m_vc_brd->GetPosition().SetPlayed(m_bd->GetPlayed());
00344 m_vc_brd->ComputeAll(m_toPlay);
00345
00346
00347
00348
00349
00350
00351
00352 bitset_t consider;
00353 if (EndgameUtils::IsDeterminedState(*m_vc_brd, m_toPlay))
00354 {
00355 HexColor winner = m_toPlay;
00356 provenType = SG_PROVEN_WIN;
00357 if (EndgameUtils::IsLostGame(*m_vc_brd, m_toPlay))
00358 {
00359 winner = !m_toPlay;
00360 provenType = SG_PROVEN_LOSS;
00361 }
00362 if (DEBUG_KNOWLEDGE)
00363 LogInfo() << "Found win for " << winner << ": " << '\n'
00364 << *m_vc_brd << '\n';
00365 return m_bd->GetEmpty();
00366 }
00367 else
00368 {
00369 provenType = SG_NOT_PROVEN;
00370 consider = EndgameUtils::MovesToConsider(*m_vc_brd, m_toPlay);
00371 }
00372
00373 m_shared_data->stones.put(SequenceHash::Hash(m_game_sequence),
00374 HexUctStoneData(m_vc_brd->GetPosition()));
00375 if (DEBUG_KNOWLEDGE)
00376 LogInfo() << "===================================" << '\n'
00377 << "Recomputed state:" << '\n' << *m_bd << '\n'
00378 << "Consider:" << m_vc_brd->Write(consider) << '\n';
00379
00380 return consider;
00381 }
00382
00383