00001
00002
00003 #include "osl/game_playing/speculativeAllMoves.h"
00004 #include "osl/game_playing/gameState.h"
00005 #include "osl/game_playing/searchPlayer.h"
00006 #include "osl/search/timeControl.h"
00007 #include "osl/search/searchRecorder.h"
00008 #include "osl/search/shouldPromoteCut.h"
00009 #include "osl/search/searchMoveVector.h"
00010 #include "osl/search/simpleHashTable.h"
00011 #include "osl/category/categoryListUtil.h"
00012 #include "osl/category/standardMoveGenerator.h"
00013 #include "osl/move_generator/legalMoves.h"
00014 #include "osl/misc/realTime.h"
00015 #include "osl/record/csa.h"
00016 #include "osl/sennichite.h"
00017 #include "osl/misc/lightMutex.h"
00018 #include "osl/misc/nonBlockDelete.h"
00019 #include <boost/thread.hpp>
00020 #include <boost/thread/xtime.hpp>
00021 #include <exception>
00022 #include <iostream>
00023 #include <ctime>
00024 #include <unistd.h>
00025
00026 osl::game_playing::SpeculativeAllMoves::
00027 ResultVector::ResultVector()
00028 {
00029 }
00030
00031 osl::game_playing::SpeculativeAllMoves::
00032 ResultVector::~ResultVector()
00033 {
00034 }
00035
00036 void osl::game_playing::SpeculativeAllMoves::ResultVector::
00037 add(Move prediction, const MoveWithComment& result)
00038 {
00039 Mutex::scoped_lock lk(mutex);
00040 data.push_back(std::make_pair(prediction, result));
00041 }
00042 const osl::game_playing::MoveWithComment* osl::game_playing::SpeculativeAllMoves::ResultVector::
00043 find(Move prediction) const
00044 {
00045 Mutex::scoped_lock lk(mutex);
00046 for (vector_t::const_iterator p=data.begin(); p!=data.end(); ++p) {
00047 if (p->first == prediction)
00048 return &p->second;
00049 }
00050 return 0;
00051 }
00052 void osl::game_playing::SpeculativeAllMoves::ResultVector::
00053 clear()
00054 {
00055 Mutex::scoped_lock lk(mutex);
00056 data.clear();
00057 }
00058
00059
00060
00061 struct osl::game_playing::SpeculativeAllMoves::SearchAllMoves::StatusLock
00062 {
00063 volatile Status& status;
00064 boost::mutex& mutex;
00065 boost::condition *condition;
00066 const Status in, out;
00067 StatusLock(volatile Status *s, boost::mutex *m, boost::condition* c, Status i, Status o)
00068 : status(*s), mutex(*m), condition(c), in(i), out(o)
00069 {
00070 boost::mutex::scoped_lock lk(mutex);
00071 status = in;
00072 condition->notify_all();
00073 }
00074 StatusLock(volatile Status *s, boost::mutex *m, Status i)
00075 : status(*s), mutex(*m), condition(0), in(i), out(*s)
00076 {
00077 boost::mutex::scoped_lock lk(mutex);
00078 status = in;
00079 }
00080 ~StatusLock()
00081 {
00082 status = out;
00083 if (condition)
00084 condition->notify_all();
00085 }
00086 };
00087
00088 struct osl::game_playing::SpeculativeAllMoves::SearchAllMoves::Generator
00089 {
00090 GameState& state;
00091 SearchPlayer& player;
00092 MoveVector tried_moves;
00093 volatile Status& status;
00094 boost::mutex& mutex;
00095 int index;
00096 Generator(GameState& s, SearchPlayer& p, SearchAllMoves& parent)
00097 : state(s), player(p), status(parent.status), mutex(parent.mutex), index(-1)
00098 {
00099 }
00100 Move pickUpMove()
00101 {
00102 try
00103 {
00104 MoveWithComment result;
00105 {
00106 StatusLock lk(&status, &mutex, PREDICTION2);
00107 player.setRootIgnoreMoves(&tried_moves);
00108 result = player.selectBestMove(state, 1, 0);
00109 player.setRootIgnoreMoves(0);
00110 }
00111 #ifndef NDEBUG
00112 if (result.move.isNormal()) {
00113 std::cerr << "search prediction ";
00114 std::cerr << record::csa::show(result.move);
00115 std::cerr << "\n";
00116 }
00117 #endif
00118 return result.move;
00119 }
00120 catch (std::exception& e)
00121 {
00122 std::cerr << "Generator::bestMove " << e.what() << "\n";
00123 }
00124 return Move::INVALID();
00125 }
00126 const Move nextMove()
00127 {
00128 const Move move = pickUpMove();
00129 if (! move.isNormal()) {
00130 std::cerr << "finish\n";
00131 return Move::INVALID();
00132 }
00133 tried_moves.push_back(move);
00134 return move;
00135 }
00136 };
00137
00138 osl::game_playing::SpeculativeAllMoves::
00139 SearchAllMoves::SearchAllMoves(ResultVector& r)
00140 : results(r), current_move(Move::INVALID()), status(INITIAL), seconds(-1),
00141 stop_flag(false)
00142 {
00143 }
00144
00145 osl::game_playing::SpeculativeAllMoves::
00146 SearchAllMoves::~SearchAllMoves()
00147 {
00148 }
00149
00150 void osl::game_playing::SpeculativeAllMoves::
00151 SearchAllMoves::setUp(const GameState& main_state,
00152 const SearchPlayer& main_player,
00153 int standard_seconds, bool has_byoyomi)
00154 {
00155 NonBlockDelete::reset(player);
00156 try
00157 {
00158 player.reset(dynamic_cast<SearchPlayer*>(main_player.clone()));
00159 player->setVerbose(1);
00160 player->setNextIterationCoefficient(has_byoyomi ? 1 : 2);
00161 state = main_state.clone();
00162 generator.reset(new Generator(*state, *player, *this));
00163 seconds = standard_seconds;
00164 }
00165 catch (std::exception& e)
00166 {
00167 player.reset();
00168 std::cerr << "setUp " << e.what() << "\n";
00169 throw;
00170 }
00171 }
00172
00173 void osl::game_playing::SpeculativeAllMoves::
00174 SearchAllMoves::run()
00175 {
00176 StatusLock lk(&status, &mutex, &condition, RUNNING, FINISHED);
00177 if (! player)
00178 return;
00179 while (true)
00180 {
00181 boost::thread::yield();
00182 if (stop_flag)
00183 return;
00184 Move prediction;
00185 {
00186 StatusLock lk(&status, &mutex, PREDICTION1);
00187 prediction = generator->nextMove();
00188 }
00189 if (! prediction.isNormal())
00190 return;
00191 if (stop_flag)
00192 return;
00193 const MoveWithComment result = testMove(prediction);
00194 results.add(prediction, result);
00195 }
00196 }
00197
00198 const osl::game_playing::MoveWithComment osl::game_playing::SpeculativeAllMoves::
00199 SearchAllMoves::testMove(Move predicted_move)
00200 {
00201 StatusLock lk(&status, &mutex, SEARCH1);
00202 {
00203 Mutex::scoped_lock lk(mutex);
00204 current_move = predicted_move;
00205 }
00206 assert(state);
00207 state->pushMove(predicted_move);
00208 assert(player);
00209 player->pushMove(predicted_move);
00210 MoveWithComment result(Move::INVALID());
00211 std::cerr << "\nprediction (" << seconds << ") "
00212 << record::csa::show(predicted_move) << " ";
00213 const time_t now = time(0);
00214 char ctime_buf[64];
00215 std::cerr << ctime_r(&now, ctime_buf);
00216 try
00217 {
00218 StatusLock lk(&status, &mutex, SEARCH2);
00219 result = (seconds > 0)
00220 ? player->searchWithSecondsForThisMove(*state, seconds)
00221 : player->selectBestMove(*state, -1, -1);
00222 if (! stop_flag)
00223 std::cerr << record::csa::show(result.move) << "\n";
00224 }
00225 catch (std::exception& e)
00226 {
00227
00228 std::cerr << "error in speculative thread " << e.what() << "\n";
00229 stop_flag = true;
00230 NonBlockDelete::deleteAll();
00231 }
00232 catch (...)
00233 {
00234 std::cerr << "error in speculative thread\n";
00235 stop_flag = true;
00236 }
00237 state->popMove();
00238 player->popMove();
00239 {
00240 Mutex::scoped_lock lk(mutex);
00241 current_move = Move::INVALID();
00242 }
00243 return result;
00244 }
00245
00246 void osl::game_playing::SpeculativeAllMoves::
00247 SearchAllMoves::stopOtherThan(Move the_move)
00248 {
00249 stop_flag = true;
00250 if (currentMove() != the_move)
00251 stopNow();
00252 else
00253 {
00254 std::cerr << "match " << record::csa::show(the_move) << "\n";
00255 assert(player);
00256 player->setNextIterationCoefficient(4);
00257 player->setVerbose(2);
00258 }
00259 }
00260
00261 void osl::game_playing::SpeculativeAllMoves::
00262 SearchAllMoves::stopNow()
00263 {
00264 stop_flag = true;
00265 waitRunning();
00266 if (player && status != FINISHED)
00267 {
00268 std::cerr << "stopNow " << status << "\n";
00269 const bool success
00270 = player->stopSearchNow();
00271 if (! success)
00272 std::cerr << "stop search failed\n";
00273 }
00274 }
00275
00276 void osl::game_playing::SpeculativeAllMoves::
00277 SearchAllMoves::waitRunning()
00278 {
00279 Mutex::scoped_lock lk(mutex);
00280 while (status == INITIAL)
00281 {
00282 condition.wait(lk);
00283 if (!player)
00284 return;
00285 }
00286 }
00287
00288 void osl::game_playing::SpeculativeAllMoves::
00289 SearchAllMoves::setStopSchedule(const misc::RealTime& timer)
00290 {
00291 if (player && status != FINISHED)
00292 {
00293 waitRunning();
00294 player->setStopSchedule(timer);
00295 }
00296 }
00297
00298 const osl::Move osl::game_playing::SpeculativeAllMoves::
00299 SearchAllMoves::currentMove() const
00300 {
00301 Mutex::scoped_lock lk(mutex);
00302 return current_move;
00303 }
00304
00305
00306
00307
00308 struct osl::game_playing::SpeculativeAllMoves::Runner
00309 {
00310 SpeculativeAllMoves *parent;
00311 Runner(SpeculativeAllMoves *p) : parent(p)
00312 {
00313 }
00314 void operator()()
00315 {
00316 parent->searcher->run();
00317 }
00318 };
00319
00320 osl::game_playing::SpeculativeAllMoves::
00321 SpeculativeAllMoves()
00322 : results(new ResultVector()), last_search_seconds(-1), has_byoyomi(false),
00323 allowed(true)
00324 {
00325 }
00326
00327 osl::game_playing::
00328 SpeculativeAllMoves::~SpeculativeAllMoves()
00329 {
00330 stopAll();
00331 selectBestMoveCleanUp();
00332 }
00333
00334 void osl::game_playing::SpeculativeAllMoves::
00335 startSpeculative(const boost::shared_ptr<GameState> state,
00336 const SearchPlayer& main_player)
00337 {
00338 if (! allowed)
00339 return;
00340
00341 try
00342 {
00343 results->clear();
00344 searcher.reset(new SearchAllMoves(*results));
00345 searcher->setUp(*state, main_player, last_search_seconds, has_byoyomi);
00346 thread.reset(new boost::thread(Runner(this)));
00347 }
00348 catch (std::exception& e)
00349 {
00350 std::cerr << "startSpeculative " << e.what();
00351 searcher.reset();
00352 }
00353 }
00354
00355 void osl::game_playing::SpeculativeAllMoves::
00356 clearResource()
00357 {
00358 assert(! thread);
00359 searcher.reset();
00360 }
00361
00362 void osl::game_playing::SpeculativeAllMoves::
00363 stopOtherThan(Move the_move)
00364 {
00365 if (searcher)
00366 searcher->stopOtherThan(the_move);
00367 }
00368
00369 void osl::game_playing::SpeculativeAllMoves::
00370 stopAll()
00371 {
00372 if (searcher)
00373 searcher->stopNow();
00374 }
00375
00376 const osl::game_playing::MoveWithComment
00377 osl::game_playing::SpeculativeAllMoves::
00378 waitResult(Move last_move, int wait_for,
00379 SearchPlayer& main_player, int byoyomi)
00380 {
00381 if (! allowed || ! searcher)
00382 return MoveWithComment(Move::INVALID());
00383
00384 last_search_seconds = wait_for;
00385 has_byoyomi = (byoyomi > 0);
00386
00387 const time_t start_time = time(0);
00388 assert(last_move.isNormal());
00389 const MoveWithComment *result = 0;
00390 bool stop_now = false;
00391 if (searcher->currentMove() != last_move)
00392 {
00393 stop_now = true;
00394 wait_for = 0;
00395 }
00396 const time_t stop_time = start_time + wait_for;
00397
00398 if (searcher->isFinished())
00399 {
00400 if ((result = results->find(last_move)))
00401 goto found;
00402 return MoveWithComment(Move::INVALID());
00403 }
00404 searcher->setStopSchedule(misc::RealTime(wait_for));
00405 {
00406 char ctime_buf[64];
00407 std::cerr << "wait for (" << wait_for << ") "
00408 << ctime_r(&stop_time, ctime_buf);
00409
00410 while (true)
00411 {
00412 if ((result = results->find(last_move)))
00413 break;
00414 assert(searcher);
00415 if (searcher->isFinished())
00416 return MoveWithComment(Move::INVALID());
00417
00418 if (! stop_now)
00419 {
00420 time_t now = time(0);
00421 stop_now = now >= stop_time;
00422 }
00423 if (stop_now) {
00424 searcher->stopNow();
00425 }
00426 boost::mutex::scoped_lock lk(searcher->mutex);
00427 boost::xtime xt;
00428 boost::xtime_get(&xt, boost::TIME_UTC);
00429 xt.sec += 1;
00430 searcher->condition.timed_wait(lk, xt);
00431 }
00432 }
00433 found:
00434 if (! searcher->isFinished())
00435 searcher->stopNow();
00436 if (result->move.isNormal()) {
00437 SearchPlayer *player = searcher->currentPlayer();
00438 if (player)
00439 main_player.swapTable(*player);
00440 }
00441 return *result;
00442 }
00443
00444 void osl::game_playing::SpeculativeAllMoves::
00445 selectBestMoveCleanUp()
00446 {
00447 if (! thread)
00448 return;
00449
00450 if (searcher && ! searcher->isFinished())
00451 searcher->stopNow();
00452 thread->join();
00453 thread.reset();
00454 if (searcher)
00455 NonBlockDelete::reset(searcher);
00456 }
00457
00458
00459
00460
00461
00462