All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
speculativeAllMoves.cc
Go to the documentation of this file.
1 /* speculativeAllMoves.cc
2  */
10 #include "osl/search/usiReporter.h"
12 #include "osl/misc/milliSeconds.h"
13 #include "osl/record/csa.h"
14 #include "osl/sennichite.h"
15 #include "osl/misc/lightMutex.h"
17 #include "osl/misc/ctime.h"
18 #include <boost/foreach.hpp>
19 #include <boost/thread.hpp>
20 #include <boost/thread/xtime.hpp>
21 #include <exception>
22 #include <iostream>
23 #include <cmath>
24 #ifndef _MSC_VER
25 # include <unistd.h>
26 #endif
27 
28 
31 {
32 }
33 
36 {
37 }
38 
40 add(Move prediction, const MoveWithComment& result)
41 {
42  SCOPED_LOCK(lk,mutex);
43  data.push_back(std::make_pair(prediction, result));
44 }
46 find(Move prediction) const
47 {
48  SCOPED_LOCK(lk,mutex);
49  BOOST_FOREACH(const vector_t::value_type& v, data) {
50  if (v.first == prediction)
51  return &v.second;
52  }
53  return 0;
54 }
57 {
58  SCOPED_LOCK(lk,mutex);
59  data.clear();
60 }
62 show(std::ostream& os) const
63 {
64  SCOPED_LOCK(lk,mutex);
65  for (size_t i=0; i<data.size(); ++i) {
66  if (i)
67  os << ", ";
68  os << record::csa::show(data[i].first) << "=>" << record::csa::show(data[i].second.move);
69  }
70  os << std::endl;
71 }
72 
73 /* ------------------------------------------------------------------------- */
74 
76 {
77  volatile Status& status;
78  boost::mutex& mutex;
79  boost::condition *condition;
80  const Status in, out;
81  StatusLock(volatile Status *s, boost::mutex *m, boost::condition* c, Status i, Status o)
82  : status(*s), mutex(*m), condition(c), in(i), out(o)
83  {
84  boost::mutex::scoped_lock lk(mutex);
85  status = in;
86  condition->notify_all();
87  }
88  StatusLock(volatile Status *s, boost::mutex *m, Status i)
89  : status(*s), mutex(*m), condition(0), in(i), out(*s)
90  {
91  boost::mutex::scoped_lock lk(mutex);
92  status = in;
93  }
95  {
96  status = out;
97  if (condition)
98  condition->notify_all();
99  }
100 };
101 
103 {
106  MoveVector tried_moves;
107  volatile Status& status;
108  boost::mutex& mutex;
109  int index, seconds;
111  Generator(GameState& s, SearchPlayer& p, SearchAllMoves& parent, int sec, bool byoyomi)
112  : state(s), player(p), status(parent.status), mutex(parent.mutex), index(-1), seconds(sec),
113  has_byoyomi(byoyomi)
114  {
115  }
117  {
118  try
119  {
120  MoveWithComment result;
121  {
122  StatusLock lk(&status, &mutex, PREDICTION2);
123  player.setRootIgnoreMoves(&tried_moves, true);
124  player.setVerbose(0);
125  const int sec = std::max(1, has_byoyomi ? seconds/10 : seconds/7);
126  result = player.selectBestMove(state, 0, 0, sec);
127  player.setRootIgnoreMoves(0, false);
128  player.setVerbose(1);
129  }
130 #ifndef NDEBUG
131  if (result.move.isNormal()) {
132  std::cerr << "search prediction ";
133  std::cerr << record::csa::show(result.move);
134  std::cerr << "\n";
135  }
136 #endif
137  return result.move;
138  }
139  catch (std::exception& e)
140  {
141  std::cerr << "Generator::bestMove " << e.what() << "\n";
142  }
143  return Move::INVALID();
144  }
145  const Move nextMove()
146  {
147  const Move move = pickUpMove();
148  if (! move.isNormal()) {
149  std::cerr << "finish\n";
150  return Move::INVALID();
151  }
152  tried_moves.push_back(move);
153  return move;
154  }
155 };
156 
159  : results(r), next_iteration_coefficient(1.0),
160  current_move(Move::INVALID()), status(INITIAL), seconds(-1),
161  stop_flag(false)
162 {
163 }
164 
167 {
168 }
169 
172  const SearchPlayer& main_player,
173  int standard_seconds, bool has_byoyomi)
174 {
175  NonBlockDelete::reset(player);
176  next_iteration_coefficient = main_player.nextIterationCoefficient();
177  try
178  {
179  player.reset(dynamic_cast<SearchPlayer*>(main_player.clone()));
180  player->setVerbose(1);
181  player->setNextIterationCoefficient(std::max(1.0, next_iteration_coefficient/2));
182  state = main_state.clone();
183  generator.reset(new Generator(*state, *player, *this, standard_seconds, has_byoyomi));
184  seconds = standard_seconds;
185  if (has_byoyomi)
186  seconds += std::min(30, standard_seconds/2);
187  }
188  catch (std::exception& e)
189  {
190  player.reset();
191  std::cerr << "setUp " << e.what() << "\n";
192  throw;
193  }
194 }
195 
198 {
199  StatusLock lk(&status, &mutex, &condition, RUNNING, FINISHED);
200  if (! player)
201  return;
202  while (true)
203  {
204  boost::thread::yield(); // test whether opponent's move has arrived
205  if (stop_flag)
206  return;
207  while (NonBlockDelete::deleteOne() && !stop_flag)
208  ;
209  if (stop_flag)
210  return;
211  Move prediction;
212  {
213  StatusLock lk(&status, &mutex, PREDICTION1);
214  prediction = generator->nextMove();
215  }
216  if (! prediction.isNormal())
217  return;
218  if (stop_flag)
219  return;
220  const MoveWithComment result = testMove(prediction);
221  results.add(prediction, result);
222  if (! stop_flag)
223  results.show(std::cerr);
224  }
225 }
226 
229 {
230  StatusLock lk(&status, &mutex, SEARCH1);
231  {
232  Mutex::scoped_lock lk(mutex);
233  current_move = predicted_move;
234  }
235  assert(state);
236  state->pushMove(predicted_move);
237  assert(player);
238  player->pushMove(predicted_move);
239  MoveWithComment result(Move::INVALID());
240  std::cerr << "\nprediction (" << seconds << ") "
241  << record::csa::show(predicted_move) << " ";
242  const time_t now = time(0);
243  char ctime_buf[64];
244  std::cerr << ctime_r(&now, ctime_buf);
245  try
246  {
247  StatusLock lk(&status, &mutex, SEARCH2);
248  if (seconds <= 0)
249  seconds = 120;
250  const MilliSeconds::Interval msec(seconds*1000);
251  result =
252  player->searchWithSecondsForThisMove(*state, search::TimeAssigned(msec, msec*5));
253  }
254  catch (std::exception& e)
255  {
256  // TODO table full はclear?
257  std::cerr << "error in speculative thread " << e.what() << "\n";
258  stop_flag = true;
259  NonBlockDelete::deleteAll();
260  }
261  catch (...)
262  {
263  std::cerr << "error in speculative thread\n";
264  stop_flag = true;
265  }
266  state->popMove();
267  player->popMove();
268  {
269  Mutex::scoped_lock lk(mutex);
270  current_move = Move::INVALID();
271  }
272  return result;
273 }
274 
277 {
278  stop_flag = true;
279  if (currentMove() != the_move)
280  stopNow();
281  else
282  {
283 #ifndef NDEBUG
284  std::cerr << "match " << record::csa::show(the_move) << "\n";
285 #endif
286 #ifndef GPSONE
287  if (OslConfig::usiMode())
289 #endif
290  assert(player);
291  player->setNextIterationCoefficient(next_iteration_coefficient);
292  player->setVerbose(2);
293  }
294 }
295 
298 {
299  stop_flag = true;
300  waitRunning();
301  if (player && status != FINISHED)
302  {
303  std::cerr << "stopNow " << status << "\n";
304  const bool success
305  = player->stopSearchNow();
306  if (! success)
307  std::cerr << "stop search failed\n";
308  }
309 }
310 
313 {
314  Mutex::scoped_lock lk(mutex);
315  while (status == INITIAL)
316  {
317  condition.wait(lk);
318  if (!player)
319  return;
320  }
321 }
322 
325 {
326  if (player && status != FINISHED)
327  {
328  waitRunning();
329  player->setTimeAssign(new_assign);
330  }
331 }
332 const osl::MilliSeconds osl::game_playing::SpeculativeAllMoves::
334 {
335  if (player && status != FINISHED)
336  {
337  waitRunning();
338  return player->startTime();
339  }
340  return MilliSeconds();
341 }
342 
345 {
346  Mutex::scoped_lock lk(mutex);
347  return current_move;
348 }
349 
350 /* ------------------------------------------------------------------------- */
351 
352 
354 {
356  Runner(SpeculativeAllMoves *p) : parent(p)
357  {
358  }
359  void
360 #ifdef __GNUC__
361 # ifdef _WIN32
362 __attribute__((noinline))
363 __attribute__((force_align_arg_pointer))
364 # endif
365 #endif
367  {
368  parent->searcher->run();
369  }
370 };
371 
374  : results(new ResultVector()), last_search_seconds(-1), has_byoyomi(false),
375  allowed(true)
376 {
377 }
378 
381 {
382  stopAll();
383  selectBestMoveCleanUp();
384 }
385 
387 startSpeculative(const boost::shared_ptr<GameState> state,
388  const SearchPlayer& main_player)
389 {
390  boost::mutex::scoped_lock lk(mutex);
391  if (! allowed)
392  return;
393 
394  try
395  {
396  search_state = HashKey(state->state());
397  results->clear();
398  searcher.reset(new SearchAllMoves(*results));
399  searcher->setUp(*state, main_player, last_search_seconds, has_byoyomi);
400  thread.reset(new boost::thread(Runner(this)));
401  }
402  catch (std::exception& e)
403  {
404  std::cerr << "startSpeculative " << e.what();
405  searcher.reset();
406  }
407 }
408 
411 {
412  boost::mutex::scoped_lock lk(mutex);
413  assert(! thread);
414  searcher.reset();
415 }
416 
419 {
420  boost::mutex::scoped_lock lk(mutex);
421  if (searcher)
422  searcher->stopOtherThan(the_move);
423 }
424 
427 {
428  boost::mutex::scoped_lock lk(mutex);
429  if (searcher)
430  searcher->stopNow();
431 }
432 
436  SearchPlayer& main_player, int byoyomi)
437 {
438  {
439  boost::mutex::scoped_lock lk(mutex);
440  if (! allowed || ! searcher)
441  return MoveWithComment(Move::INVALID());
442  }
443  last_search_seconds = (int)ceil(wait_for.standard.toSeconds());
444  has_byoyomi = (byoyomi > 0);
445 
446  const time_t start_time = time(0);
447  const MilliSeconds start_time_msec = MilliSeconds::now();
448  assert(last_move.isNormal());
449  const MoveWithComment *result = 0;
450  bool stop_now = false;
451  if (searcher->currentMove() != last_move)
452  {
453  stop_now = true;
454  wait_for = search::TimeAssigned(MilliSeconds::Interval(0));
455  }
456  // const time_t standard_time = start_time + ceil(wait_for.standard.toSeconds());
457  const time_t stop_time = start_time + static_cast<int>(ceil(wait_for.max.toSeconds()));
458 
459  const MilliSeconds started = searcher->startTime();
460  const bool already_finished = searcher->isFinished();
461  if (! already_finished)
462  {
463  char ctime_buf[64];
464  std::cerr << "wait for (" << wait_for.standard.toSeconds()
465  << "/" << wait_for.max.toSeconds()
466  << ") "
467  << ctime_r(&stop_time, ctime_buf);
468  const MilliSeconds::Interval diff = (start_time_msec - started);
469  wait_for.standard = wait_for.standard + diff;
470  wait_for.max = wait_for.max + diff;
471  searcher->setTimeAssign(wait_for);
472  }
473  {
474  int wait_count = 0;
475  while (true)
476  {
477  const bool now_finished = searcher->isFinished();
478  if ((result = results->find(last_move))) {
479 #ifndef GPSONE
480  if (wait_count == 0 && OslConfig::usiMode()) {
481  search::UsiReporter::showPV(std::cout, result->root_limit/200, result->node_count, result->elapsed,
482  last_move.player() == BLACK ? -result->value : result->value,
483  result->move, &*result->moves.begin(), &*result->moves.end(),
484  true);
485  }
486 #endif
487  break;
488  }
489  assert(searcher);
490  if (now_finished)
491  return MoveWithComment(Move::INVALID());
492  if (stop_now && ++wait_count > 60) {
493  std::cerr << "error stop now failed for 60 times\n";
494  abort();
495  }
496 
497  if (! stop_now)
498  {
499  time_t now = time(0);
500  stop_now = now >= stop_time;
501  }
502  if (stop_now) {
503  searcher->stopNow();
504  }
505  boost::mutex::scoped_lock lk(searcher->mutex);
506  boost::xtime xt;
507 #if BOOST_VERSION < 105000
508  boost::xtime_get(&xt, boost::TIME_UTC);
509 #else
510  boost::xtime_get(&xt, boost::TIME_UTC_);
511 #endif
512  if (wait_count <= 10)
513  xt.sec += 1; // 1 sec
514  else
515  xt.sec += 2; // 2 sec
516  searcher->condition.timed_wait(lk, xt);
517  }
518  }
519  if (! searcher->isFinished())
520  searcher->stopNow();
521  if (result->move.isNormal()) {
522  SearchPlayer *player = searcher->currentPlayer();
523  if (player)
524  main_player.swapTable(*player);
525  }
526  return *result;
527 }
528 
531 {
532  if (! thread)
533  return;
534 
535  {
536  boost::mutex::scoped_lock lk(mutex);
537  if (searcher && ! searcher->isFinished())
538  searcher->stopNow();
539  }
540  thread->join();
541  thread.reset();
542  if (searcher)
543  NonBlockDelete::reset(searcher);
544 }
545 
546 /* ------------------------------------------------------------------------- */
547 // ;;; Local Variables:
548 // ;;; mode:c++
549 // ;;; c-basic-offset:2
550 // ;;; coding:utf-8
551 // ;;; End: