alphaBeta2.cc
Go to the documentation of this file.
00001 /* alphaBeta2.cc
00002  */
00003 #include "osl/search/alphaBeta2.h"
00004 #ifdef OSL_SMP
00005 #  include "osl/search/alphaBeta2Parallel.h"
00006 #endif
00007 #include "osl/search/simpleHashRecord.h"
00008 #include "osl/search/simpleHashTable.h"
00009 #include "osl/search/dominanceCheck.h"
00010 #include "osl/search/moveGenerator.h"
00011 #include "osl/search/realizationProbability.h"
00012 #include "osl/search/quiescenceSearch2.h"
00013 #include "osl/search/realizationProbability.h"
00014 #include "osl/search/moveWithComment.h"
00015 #include "osl/search/moveStackRejections.h"
00016 #include "osl/search/searchMonitor.h"
00017 #include "osl/search/usiReporter.h"
00018 #include "osl/checkmate/limitToCheckCount.h"
00019 #include "osl/eval/see.h"
00020 #include "osl/eval/pieceEval.h"
00021 #include "osl/checkmate/immediateCheckmate.h"
00022 #include "osl/record/csa.h"
00023 #include "osl/record/ki2.h"
00024 #include "osl/record/kanjiCode.h"
00025 #include "osl/move_classifier/pawnDropCheckmate.h"
00026 #include "osl/move_classifier/check_.h"
00027 #include "osl/move_classifier/moveAdaptor.h"
00028 #include "osl/move_generator/legalMoves.h"
00029 #include "osl/effect_util/additionalEffect.h"
00030 #include "osl/misc/nonBlockDelete.h"
00031 #include "osl/misc/ctime.h"
00032 #include "osl/misc/iconvConvert.h"
00033 #include "osl/stat/ratio.h"
00034 #include "osl/enter_king/enterKing.h"
00035 #include <boost/foreach.hpp>
00036 #include <stdexcept>
00037 #include <iostream>
00038 #include <iomanip>
00039 
00040 #define search_assert(x, m) assert((x) || SearchState2::abort(m))
00041 
00042 typedef osl::search::RealizationProbability Probabilities_t;
00043 
00044 #ifdef CHECKMATE_COUNT
00045 static size_t root_checkmate = 0, checkmate_before = 0, checkmate_after = 0,
00046   count_threatmate = 0, quiesce_checkmate=0;
00047 #endif
00048 
00049 // #define EXPERIMENTAL_QUIESCE
00050 
00051 /* ------------------------------------------------------------------------- */
00052 void osl::search::AlphaBeta2SharedRoot::
00053 showLastPv(int limit) const
00054 {
00055   for (int i=last_pv.size()-1; i>=0 && last_pv[i].depth == limit; --i) {
00056     std::cerr << last_pv[i].eval << ' ';
00057     for (size_t j=0; j<std::min((size_t)2, last_pv[i].pv.size()); ++j)
00058       std::cerr << record::csa::show(last_pv[i].pv[j]);
00059     std::cerr << "  ";
00060   }
00061   std::cerr << "\n";
00062 }
00063 
00064 /* ------------------------------------------------------------------------- */
00065 /*      Constructors                                                         */
00066 /* ------------------------------------------------------------------------- */
00067 
00068 #ifndef MINIMAL
00069 template <class EvalT>
00070 osl::CArray<int, osl::search::SearchState2Core::MaxDepth> osl::search::AlphaBeta2Tree<EvalT>::depth_node_count;
00071 #endif
00072 
00073 template <class EvalT>
00074 osl::search::AlphaBeta2Tree<EvalT>::
00075 AlphaBeta2Tree(const NumEffectState& s, checkmate_t& c, 
00076                SimpleHashTable *t, CountRecorder& r)
00077   : SearchBase<EvalT,SimpleHashTable,CountRecorder,RealizationProbability>(r, t), 
00078     SearchState2(s, c), AlphaBeta2Common<EvalT>(s), node_count(0), shared_root(new AlphaBeta2SharedRoot)
00079 {
00080 #ifdef OSL_SMP
00081   for (int i=0; i<4; ++i) {
00082     try 
00083     {
00084       shared.reset(new AlphaBeta2Parallel<EvalT>(this));
00085       break;
00086     }
00087     catch (std::bad_alloc&)
00088     {
00089       std::cerr << "panic " << i << " allocation of AlphaBeta2Parallel failed\n";
00090 #ifdef _WIN32
00091       boost::this_thread::sleep(boost::posix_time::seconds(1));
00092 #else
00093       sleep(1);
00094 #endif
00095       NonBlockDelete::deleteAll();
00096     }
00097   }
00098 #endif
00099 }
00100 
00101 template <class EvalT>
00102 osl::search::AlphaBeta2Tree<EvalT>::
00103 AlphaBeta2Tree(const AlphaBeta2Tree<EvalT>& src, AlphaBeta2Parallel<EvalT> *)
00104   : SearchBase<EvalT,SimpleHashTable,CountRecorder,RealizationProbability>(src), 
00105     SearchState2(src), SearchTimer(src), AlphaBeta2Common<EvalT>(src), 
00106     node_count(0), shared(src.shared), shared_root(src.shared_root)
00107 {
00108   BOOST_FOREACH(PVVector& p, pv)
00109     p.clear();
00110 }
00111 
00112 template <class EvalT>
00113 osl::search::AlphaBeta2Tree<EvalT>::
00114 ~AlphaBeta2Tree()
00115 {
00116   BOOST_FOREACH(MoveGenerator *p, generators)
00117     dealloc(p);
00118 #ifdef OSL_SMP
00119   if (shared && shared.use_count() == 1)
00120     NonBlockDelete::reset(shared);
00121 #endif
00122 }
00123 
00124 template <class EvalT>
00125 osl::search::MoveGenerator *
00126 osl::search::AlphaBeta2Tree<EvalT>::alloc()
00127 {
00128   try 
00129   {
00130     return new MoveGenerator;
00131   }
00132   catch (std::bad_alloc&)
00133   {
00134     std::cerr << "panic. allocation of MoveGenerator failed\n";
00135     throw TableFull();          // stop search anyway
00136   }
00137   return 0;
00138 }
00139 
00140 template <class EvalT>
00141 void osl::search::AlphaBeta2Tree<EvalT>::dealloc(MoveGenerator *p)
00142 {
00143   delete p;
00144 }
00145 
00146 template <class EvalT>
00147 osl::search::MoveGenerator& osl::search::AlphaBeta2Tree<EvalT>::makeGenerator()
00148 {
00149   const size_t cur_depth = this->curDepth();
00150   while (generators.size() <= cur_depth)
00151     generators.push_back(0);
00152   if (generators[cur_depth] == 0)
00153     generators[cur_depth] = alloc();
00154   return *generators[cur_depth];
00155 }
00156 
00157 /* ------------------------------------------------------------------------- */
00158 /*      Methods for alpha beta search                                        */
00159 /* ------------------------------------------------------------------------- */
00160 
00161 template <class EvalT>
00162 template <osl::Player P>
00163 int osl::search::AlphaBeta2Tree<EvalT>::
00164 alphaBetaSearchAfterMove(const MoveLogProb& moved, Window w,
00165                          bool in_pv)
00166 {
00167   assert(w.alpha(P) % 2);
00168   assert(w.beta(P) % 2);
00169   assert(alt(P) == state().turn());
00170   assert(P == moved.player());
00171   assert(eval::notLessThan(P, w.beta(P), w.alpha(P)));
00172 
00173   // Pが指した後でPの王に利きがある => 直前の手が非合法手
00174   if (state().inCheck(P)) {
00175     return this->minusInfty(P);
00176   }
00177   this->eval.update(state(), moved.move());
00178   const Player Turn = PlayerTraits<P>::opponent;
00179   const size_t previous_node_count = nodeCount();
00180 
00181   pv[this->curDepth()].clear();
00182 
00183   int result;
00184   // 局面表が利用不可能の場合にこの関数と子孫で利用するrecord
00185   // TODO: class に max_depth だけ持たせるべき
00186   boost::scoped_ptr<SimpleHashRecord> record_if_unavailable;
00187   int alloc_limit = curLimit(), memory1000 = lastMemoryUseRatio1000();
00188   const SimpleHashRecord *parent = hasLastRecord(1) ? lastRecord(1) : 0;
00189   const uint64_t table_use = this->table->memoryUse();
00190   if (table_use*8 > OslConfig::memoryUseLimit()
00191       && memory1000 > 300 && (root_limit >= 1600 || memory1000 > 500)
00192       && ! in_pv && ! state().inCheck() && (!parent||! parent->inCheck()))
00193   {
00194     if (table_use*6 > OslConfig::memoryUseLimit())
00195       alloc_limit -= std::max(root_limit - 1400, 200);
00196     else
00197       alloc_limit -= std::max((root_limit - 1400)*3/4, 0);
00198     if (memory1000 > 900)
00199       alloc_limit -= 400;
00200     else if (root_limit >= 1600 && memory1000 > 800)
00201       alloc_limit -= 200;
00202     else if (root_limit >= 1600 && memory1000 > 700)
00203       alloc_limit -= 100;
00204     alloc_limit = std::max(0, alloc_limit);
00205   }
00206   SimpleHashRecord *record 
00207     = this->table->allocate(currentHash(), alloc_limit);
00208   const bool has_table_record = record;
00209   if (! record) {
00210     record_if_unavailable.reset(new SimpleHashRecord());
00211     record = record_if_unavailable.get(); // memorize してはいけない
00212   }
00213   setCurrentRecord(record);
00214   record->setInCheck(state().inCheck());
00215 #if 0
00216   // harmful now
00217   if (pass_count.loopByBothPass()) {
00218     return quiesce<Turn>(w);
00219   }
00220 #endif
00221   ++node_count;
00222   int consumption = moved.logProb();
00223   
00224   // hash の手がない場合のiid
00225   if (in_pv 
00226       && (! record->bestMove().isNormal())) {
00227     assert(node_type[this->curDepth()] == PvNode);
00228     for (int limit = curLimit() - 200+1; limit > consumption+200;
00229          limit -= 200) {
00230       searchAllMoves<Turn>(moved.move(), limit, 
00231                            record, w);
00232       if (! record->bestMove().validMove()) {
00233         Move quiesce_best = record->qrecord.bestMove();
00234         if (quiesce_best.isNormal())
00235           record->setBestMove(quiesce_best, 200);
00236       }
00237     }
00238   }
00239   if (! in_pv) {
00240     // null window search
00241     if (node_type[this->curDepth()] == PvNode)
00242       node_type[this->curDepth()] = AllNode;
00243     result = searchAllMoves<Turn>
00244       (moved.move(), consumption, record, 
00245        Window(w.alpha(P), w.alpha(P)));
00246   } else {
00247     // normal search
00248     assert(node_type[this->curDepth()] == PvNode);
00249     result = searchAllMoves<Turn>(moved.move(), consumption, 
00250                                   record, w);
00251   }
00252   bool extended = false;
00253   // extension if the alpha value is updated
00254   if (eval::betterThan(P, result, w.alpha(P))) {
00255     const SimpleHashRecord *parent = lastRecord(1);
00256     int consumption_here = consumption+1;
00257     const int re_search = 100;
00258     if (! w.null() && (! in_pv || consumption > re_search))
00259       consumption_here = std::min(consumption, re_search);
00260     else if (consumption > re_search
00261              && (record->threatmate().status(P).status() == ThreatmateState::CHECK_AFTER_THREATMATE
00262                  || record->threatmate().mayHaveCheckmate(P)))
00263       consumption_here = re_search;
00264     else if (consumption > 150
00265              && ((parent && parent->inCheck())
00266                  || state().hasEffectAt(P, state().kingSquare(alt(P)))))
00267       consumption_here = 150;
00268     if (consumption_here <= consumption) {
00269       node_type[this->curDepth()] = PvNode;
00270       extended = true;
00271       ext_limit.add(consumption - consumption_here);
00272       result = searchAllMoves<Turn>(moved.move(), consumption_here, record, w);
00273     }
00274   }
00275   ext.add(extended);
00276 
00277   if (has_table_record)
00278     record->addNodeCount(nodeCount() - previous_node_count);
00279   return result;
00280 }
00281 
00282 template <class EvalT>
00283 template <osl::Player Turn>
00284 int osl::search::AlphaBeta2Tree<EvalT>::
00285 searchAllMoves(Move m, int limit_consumption, SimpleHashRecord *record, 
00286                Window w)
00287 {
00288   if (! w.null())
00289     assert(node_type[this->curDepth()] == PvNode);
00290   const Player P = PlayerTraits<Turn>::opponent;
00291   this->recorder.tryMove(MoveLogProb(m, limit_consumption),
00292                    w.alpha(P), curLimit());
00293   subLimit(limit_consumption);
00294 
00295   const int result = searchAllMoves<Turn>(record, w);
00296 
00297   addLimit(limit_consumption);
00298   this->recorder.recordValue(MoveLogProb(m, limit_consumption),
00299                              result,eval::betterThan(P, result, w.alpha(P)),
00300                        curLimit());
00301   return result;
00302 }
00303 
00304 template <class EvalT>
00305 template <osl::Player P>
00306 void osl::search::AlphaBeta2Tree<EvalT>::
00307 testThreatmate(SimpleHashRecord *record, bool in_pv)
00308 {
00309   if ((! record->inCheck())
00310       && (! (record && record->threatmate().isThreatmate(P)))
00311       && (in_pv || (this->curDepth() > 0 
00312                     && this->node_type[this->curDepth()-1] != CutNode))
00313       && tryThreatmate())
00314   {
00315     int threatmate_limit = 0;
00316     const SimpleHashRecord *parent = lastRecord(1);
00317     size_t node_count = record->nodeCount();
00318     if (parent)
00319       node_count = std::max(node_count, parent->nodeCount()/32);
00320     threatmate_limit = 4500-this->curDepth()*1000;
00321     int threatmate_max = 0;
00322     if ((node_count >= 1000 && this->recorder.checkmateRatio() < 0.5)
00323         || (node_count >= 200 
00324             && (state().king8Info(P).libertyCount() == 0
00325                 || state().king8Info(P).dropCandidate()
00326                 || state().king8Info(P).template hasMoveCandidate<PlayerTraits<P>::opponent>(state()))))
00327       threatmate_max = 100;
00328     threatmate_limit = std::max(threatmate_limit, threatmate_max);
00329     if (! in_pv)
00330       threatmate_limit /= 2;
00331     if (root_limit < 800)
00332       threatmate_limit /= 2;
00333 #ifdef EXPERIMENTAL_QUIESCE
00334     if (curLimit() <= 400)
00335       threatmate_limit = 1;
00336     else if (curLimit() <= 500)
00337       threatmate_limit /= 16;
00338     else if (curLimit() <= 600)
00339       threatmate_limit /= 4;
00340 #endif
00341 
00342     if (curLimit() >= this->table->minimumRecordLimit())
00343     {
00344       threatmate_limit = record->qrecord.threatmateNodesLeft(threatmate_limit);
00345     }
00346     else
00347     {
00348       threatmate_limit /= 2;            // for safety against multiple calls
00349     }
00350 
00351     Move threatmate_move;
00352     this->recorder.gotoCheckmateSearch(state(), threatmate_limit);
00353 #ifdef CHECKMATE_COUNT
00354     size_t count = checkmateSearcher().totalNodeCount();
00355 #endif
00356     bool threatmate
00357       = isThreatmateState<P>(threatmate_limit, threatmate_move);
00358 #ifdef CHECKMATE_COUNT
00359     count_threatmate += checkmateSearcher().totalNodeCount() - count;
00360 #endif
00361     if (threatmate_limit > 100) {
00362       updateCheckmateCount();
00363       testStop();
00364     }
00365     this->recorder.backFromCheckmateSearch();
00366     if (!threatmate && threatmate_limit == 0
00367         && record->qrecord.threatmateNodesLeft(2)) {
00368       threatmate = isThreatmateStateShort<P>(2, threatmate_move);
00369     }
00370     if (threatmate)
00371     {
00372       record->threatmate().setThreatmate(P, threatmate_move);
00373     }
00374   }
00375 }
00376 
00377 template <class EvalT>
00378 template <osl::Player P>
00379 bool osl::search::AlphaBeta2Tree<EvalT>::
00380 tryCheckmate(SimpleHashRecord *record, bool in_pv, Move& checkmate_move)
00381 {
00382   int checkmate_limit = 1;
00383   if (! in_pv) {
00384     const SimpleHashRecord *parent = lastRecord(1);
00385     if (! (record->threatmate().mayHaveCheckmate(alt(P))
00386            || (parent && parent->threatmate().maybeThreatmate(alt(P)))))
00387       return false;
00388     // simulation only
00389   }
00390   if (in_pv && root_limit >= 500+this->rootLimitBias()) {
00391     int depth = this->curDepth();
00392     if (root_limit >= 700+this->rootLimitBias() && depth <= 3) {
00393       if (/*record_memorize &&*/ (depth <= 1))
00394         checkmate_limit = checkmate::limitToCheckCount(3500);
00395       else if (/* record_memorize &&*/ (depth == 2))
00396         checkmate_limit = 1000;
00397       else if (/* record_memorize &&*/ (depth == 3))
00398         checkmate_limit = 200;
00399     }
00400     else if (((root_limit - curLimit()) <= 500) || (depth <= 5))
00401     {
00402       assert(static_cast<unsigned int>(curLimit()) < 4096);
00403       checkmate_limit = checkmate::limitToCheckCount(std::max(0,curLimit()-200-this->rootLimitBias()));
00404     }
00405     const SimpleHashRecord *parent = lastRecord(1);
00406     if (record->threatmate().mayHaveCheckmate(alt(P))
00407         || (parent && parent->threatmate().maybeThreatmate(alt(P))))
00408       checkmate_limit += std::max(100, checkmate_limit);
00409     else
00410       checkmate_limit = std::min((long)record->nodeCount()/2, (long)checkmate_limit);
00411     if (root_limit < 800)
00412       checkmate_limit /= 2;
00413   }
00414   if (curLimit() >= this->table->minimumRecordLimit())
00415   {
00416     // 詰将棋はある程度深さが増えたときだけ呼ぶ
00417     checkmate_limit = record->qrecord.checkmateNodesLeft(checkmate_limit);
00418     if (checkmate_limit <= 0)
00419       return false;
00420   }
00421   else
00422   {
00423     checkmate_limit /= 2;               // for safety against multiple calls
00424   }
00425   
00426   // 相手を詰ますことを考える 
00427 #ifdef CHECKMATE_COUNT
00428   size_t count = checkmateSearcher().totalNodeCount();
00429 #endif
00430   this->recorder.gotoCheckmateSearch(state(), checkmate_limit);
00431   const bool win = isWinningState<P>
00432     (checkmate_limit, checkmate_move);
00433   if (checkmate_limit > 100)
00434     updateCheckmateCount();
00435   this->recorder.backFromCheckmateSearch();
00436 #ifdef CHECKMATE_COUNT
00437   checkmate_before += checkmateSearcher().totalNodeCount() - count;
00438 #endif
00439   if (this->root_limit >= 1600 && checkmate_limit >= 100)
00440     this->checkmate_searcher->runGC(this->table->isVerbose(),
00441                                     lastMemoryUseRatio1000());
00442   return win;
00443 }
00444 
00445 template <class EvalT>
00446 template <osl::Player P>
00447 bool osl::search::AlphaBeta2Tree<EvalT>::
00448 tryCheckmateAgain(SimpleHashRecord *record, Move& checkmate_move,
00449                   int node_count, int best_value)
00450 {
00451   int checkmate_limit = 1;
00452   if (record->threatmate().maybeThreatmate(P)) {
00453     if (EvalTraits<P>::betterThan(this->eval.captureValue(newPtypeO(P,KING)), best_value))
00454       checkmate_limit = node_count / 2; // この局面は必死 or 詰将棋以外のalt(P)の勝
00455     else 
00456       checkmate_limit = node_count / 8;
00457     checkmate_limit += 100;
00458     if (this->recorder.checkmateRatio() < 0.5) {
00459       int checkmate_importance_wrt_root = this->recorder.searchNodeCount()/2
00460         + this->recorder.checkmateCount()/8;
00461       for (int i=0; i<this->curDepth(); ++i) {
00462         if (this->in_pv[i])
00463           checkmate_importance_wrt_root = checkmate_importance_wrt_root*7/8;
00464         else
00465           checkmate_importance_wrt_root /= 7;
00466       }
00467       checkmate_limit = std::max(checkmate_limit, checkmate_importance_wrt_root);
00468     }
00469   } else if (record->threatmate().mayHaveCheckmate(alt(P))) {
00470     checkmate_limit = countCheckAfterThreatmate(alt(P),2)*320 + 100;
00471 #ifdef MORE_CHECKMATE_IF_CAPTURE_MAJOR
00472     if (lastMove().isNormal() && isMajorNonPieceOK(lastMove().capturePtype())
00473         && ! state().hasEffectAt(P, lastMove().to()))
00474       checkmate_limit += 20000;
00475 #endif
00476   }
00477   if (curDepth() == 1 && hasLastRecord(1)) {
00478     const SimpleHashRecord *parent = lastRecord(1); // root
00479     if (parent->inCheck() || parent->threatmate().maybeThreatmate(alt(P)))
00480       checkmate_limit = std::max(checkmate_limit, (int)parent->nodeCount()/2+parent->checkmateNodes());
00481   }
00482 
00483   // adjustment by time
00484   int checkmate_afford = this->nodeAffordable();
00485 #ifdef OSL_SMP
00486   checkmate_afford *= 1.5 / shared->max_threads;
00487 #endif
00488   if (checkmate_limit > 100 && checkmate_limit > checkmate_afford) {
00489 #ifndef NDEBUG
00490     if (checkmate_afford > 0 && this->timeAssigned().standard.toSeconds() >= 10.0)
00491       std::cerr << "adjust checkmate near timeover " << checkmate_limit << " => " << checkmate_afford << "\n";
00492 #endif
00493     checkmate_limit = checkmate_afford;
00494   }
00495 
00496   if (true /*record_memorize*/)
00497     checkmate_limit = record->qrecord.checkmateNodesLeft(checkmate_limit);
00498 
00499 #ifdef CHECKMATE_COUNT
00500   size_t count = checkmateSearcher().totalNodeCount();
00501 #endif
00502   this->recorder.gotoCheckmateSearch(state(), checkmate_limit);
00503   const bool win = isWinningState<P>
00504     (checkmate_limit, checkmate_move);
00505   if (checkmate_limit > 100)
00506     updateCheckmateCount();
00507   this->recorder.backFromCheckmateSearch();
00508 #ifdef CHECKMATE_COUNT
00509   checkmate_after += checkmateSearcher().totalNodeCount() - count;
00510 #endif
00511   if (this->root_limit >= 1600 && checkmate_limit >= 100)
00512     this->checkmate_searcher->runGC(this->table->isVerbose(),
00513                                     lastMemoryUseRatio1000());
00514   return win;
00515 }
00516 
00517 template <class EvalT>
00518 bool osl::search::
00519 AlphaBeta2Tree<EvalT>::tryPass(SimpleHashRecord *record, Player P) const
00520 {
00521   return ! record->inCheck()
00522     && ! record->threatmate().maybeThreatmate(P);
00523 }
00524 
00525 template <class EvalT>
00526 template <osl::Player P>
00527 const osl::MoveLogProb osl::search::
00528 AlphaBeta2Tree<EvalT>::nextMove()
00529 {
00530   MoveGenerator& generator = makeGenerator();
00531   SimpleHashRecord *record = lastRecord();
00532   switch (this->move_type[this->curDepth()]) {
00533   case common_t::HASH:
00534   {
00535     if (curLimit() < this->leafLimit()) {
00536       this->move_type[this->curDepth()] = common_t::FINISH;
00537       break;
00538     }
00539     this->move_type[this->curDepth()] = common_t::TACTICAL;
00540     MoveLogProb best_move_in_table = record->bestMove();
00541     assert(curLimit() > 0);
00542     generator.init<eval_t>(curLimit(), record, this->eval, state(), 
00543                            node_type[this->curDepth()] != CutNode,
00544                            best_move_in_table.move());
00545     if (best_move_in_table.validMove() && 
00546         this->validTableMove(state(), best_move_in_table, curLimit())) {
00547       if (this->in_pv[this->curDepth()] 
00548           || best_move_in_table.move().capturePtype())
00549         best_move_in_table.setLogProbAtMost(RealizationProbability::TableMove);
00550       else 
00551         best_move_in_table.setLogProbAtMost(state().inCheck() ? 120 : 150);
00552       return best_move_in_table;
00553     }
00554   }
00555   // fall through
00556   // TODO: 打歩詰めはここでチェックすると早そう
00557   case common_t::TACTICAL:
00558   {
00559     MoveLogProb m = generator.nextTacticalMove<P>(*this);
00560     if (m.validMove())
00561       return m;
00562     // fall through
00563     this->move_type[this->curDepth()] = common_t::KILLER;
00564     this->killers[this->curDepth()].clear();
00565     if ((! record->inCheck())
00566         && ! record->threatmate().maybeThreatmate(P)
00567         && (curLimit() >= 300)) {
00568       MoveVector killer_moves;  // TODO: 効率化
00569       getKillerMoves(killer_moves);
00570       BOOST_FOREACH(Move move, killer_moves) {
00571         assert(this->killers[this->curDepth()].size() < this->killers[this->curDepth()].capacity());
00572         this->killers[this->curDepth()].push_back(move);
00573       }
00574       std::reverse(this->killers[this->curDepth()].begin(), this->killers[this->curDepth()].end());
00575     }
00576   }
00577   case common_t::KILLER:
00578   {
00579     typename common_t::killer_t& killers = this->killers[this->curDepth()];
00580     if (! killers.empty()) {
00581       Move m = killers[killers.size()-1];
00582       killers.pop_back();
00583       return MoveLogProb(m, 300);
00584     }
00585     // fall through
00586     this->move_type[this->curDepth()] = common_t::PASS;
00587   }
00588   case common_t::PASS:
00589     assert(record->inCheck() == state().inCheck());
00590     this->move_type[this->curDepth()] = common_t::ALL;
00591     if (tryPass(record, P)) {
00592       const int pass_consumption = (curLimit() >= 800) ? 300 : 200;
00593       return MoveLogProb(Move::PASS(P), pass_consumption);
00594     }
00595     // TODO: pass の後の最善手
00596     // fall through
00597   case common_t::ALL:
00598   {
00599     MoveLogProb m = generator.nextMove<P>(*this);
00600     if (m.validMove())
00601       return m;
00602     this->move_type[this->curDepth()] = common_t::FINISH;
00603   }
00604   default:
00605     assert(this->move_type[this->curDepth()] == common_t::FINISH);
00606   }
00607   return MoveLogProb();
00608 }
00609   
00610 template <class EvalT>
00611 template <osl::Player P>
00612 int osl::search::AlphaBeta2Tree<EvalT>::
00613 searchAllMoves(SimpleHashRecord *record, Window w)
00614 {
00615 #ifndef NDEBUG
00616   checkPointSearchAllMoves();
00617 #endif
00618   assert(P == state().turn());
00619   search_assert(w.isConsistent(), lastMove());
00620   assert(curLimit() >= 0);
00621 
00622   assert(hasLastRecord(1));
00623   const SimpleHashRecord *parent = lastRecord(1);
00624 #ifndef DONT_USE_CHECKMATE
00625   const int node_count_at_beginning = nodeCount();
00626 #endif
00627 #if (! defined OSL_USE_RACE_DETECTOR) && (! defined MINIMAL)
00628   depth_node_count[this->curDepth()]++;
00629 #endif
00630   this->move_type[this->curDepth()] = common_t::INITIAL;
00631   const bool in_pv = this->in_pv[this->curDepth()] = ! w.null();
00632 
00633   // テーブルにある値を調べる
00634   if (record) {
00635     if (in_pv) {
00636       if (record->hasLowerBound(SearchTable::HistorySpecialDepth)) {
00637         int lower_bound = record->lowerBound();
00638         if (this->isWinValue(P, lower_bound)
00639             || (record->hasUpperBound(SearchTable::HistorySpecialDepth)
00640                 && record->upperBound() == lower_bound))
00641           return lower_bound;
00642       }
00643       if (record->hasUpperBound(SearchTable::HistorySpecialDepth)) {
00644         int upper_bound = record->upperBound();
00645         if (this->isWinValue(alt(P), upper_bound))
00646           return upper_bound;
00647       }
00648     }
00649     else {                      // ! in_pv
00650       int table_value = 0;
00651       if (record->hasGreaterLowerBound<P>(curLimit(), w.alpha(P), 
00652                                           table_value)) {
00653         assert(eval::isConsistentValue(table_value));
00654         w.alpha(P) = table_value + EvalTraits<P>::delta;
00655         if (EvalTraits<P>::betterThan(table_value, w.beta(P))) {
00656           this->recorder.tableHitLowerBound(P, table_value, w.beta(P), curLimit());
00657           return table_value;
00658         }
00659       } 
00660       if (record->hasLesserUpperBound<P>(curLimit(), w.beta(P), table_value)) {
00661         assert(eval::isConsistentValue(table_value));
00662         w.beta(P) = table_value - EvalTraits<P>::delta;
00663         if (EvalTraits<P>::betterThan(w.alpha(P), table_value))
00664         {
00665           this->recorder.tableHitUpperBound(P, table_value, w.alpha(P), curLimit());
00666           return table_value;
00667         }
00668       }
00669     }
00670 
00671     Move checkmate_move=Move::INVALID();
00672     if ((!record->inCheck())
00673         && record->qrecord.checkmateNodesLeft(1)
00674         && isWinningStateShort<P>(2, checkmate_move))
00675     {
00676       this->recordWinByCheckmate(P, record, checkmate_move);
00677       return this->winByCheckmate(P);
00678     }    
00679 #ifndef DONT_USE_CHECKMATE
00680     assert(record);
00681     // try simulation or simple checkmate search
00682     int additional_limit = 0;           // simulation only
00683     if (parent && parent->threatmate().maybeThreatmate(alt(P)))
00684     {
00685       additional_limit = std::max(100, parent->qrecord.threatmateNodes()/8);
00686       additional_limit = record->qrecord.checkmateNodesLeft(additional_limit);
00687     }
00688     this->recorder.gotoCheckmateSearch(state(), additional_limit);
00689     const bool win = isWinningState<P>(additional_limit, checkmate_move);
00690     updateCheckmateCount();
00691     this->recorder.backFromCheckmateSearch();
00692     if (win) {      
00693       assert(checkmate_move.isValid());
00694       this->recordWinByCheckmate(P, record, checkmate_move);
00695       return this->winByCheckmate(P);
00696     }
00697 #endif
00698   }
00699 
00700   search_assert(w.isConsistent(), lastMove());
00701   const int initial_alpha = w.alpha(P);
00702 
00703 #ifndef DONT_USE_CHECKMATE
00704   // 詰めろを考える
00705   testThreatmate<P>(record, in_pv);
00706 #endif
00707   // 探索前に ThreatmateState を設定
00708   record->qrecord.updateThreatmate(P, (parent ? &(parent->threatmate()) : 0), 
00709                                    state().inCheck());
00710 
00711   MoveLogProb best_move;        // invalidated
00712   int best_value = this->minusInfty(P);
00713   int tried_moves = 0;
00714   int alpha_update = 0;
00715   int last_alpha_update = 0;
00716 #if (defined OSL_SMP) 
00717   int last_smp_idle = 0;
00718 #  if (! defined OSL_SMP_NO_SPLIT_INTERNAL)
00719 #    if (! defined NDEBUG)
00720   bool already_split = false;
00721 #    endif
00722 #  endif
00723 #endif
00724 
00725   // the first move
00726   MoveLogProb m = nextMove<P>();
00727   ++tried_moves;
00728   if (! m.validMove() || m.logProb() > curLimit()) {
00729     goto move_generation_failure;
00730   }
00731 #if (defined OSL_SMP) && (! defined OSL_SMP_NO_SPLIT_INTERNAL)
00732   int first_move_node;
00733 #endif
00734   {
00735 #if (defined OSL_SMP) && (! defined OSL_SMP_NO_SPLIT_INTERNAL)
00736     const int previous_node_count = nodeCount();
00737 #endif
00738     assert(eval::betterThan(P, w.alpha(P), best_value));
00739     const int result = alphaBetaSearch<P>(m, w, in_pv);
00740     if (eval::betterThan(P, result, best_value)) {
00741       best_value = result;
00742       best_move = m;
00743       if (eval::betterThan(P, best_value, w.alpha(P))) {
00744         w.alpha(P) = result + EvalTraits<P>::delta;;
00745         assert(best_move.validMove());
00746         ++alpha_update;
00747         last_alpha_update = 1;
00748         if (eval::betterThan(P, result, w.beta(P))) {
00749           mpn_cut.add(tried_moves);
00750           if (this->move_type[this->curDepth()] >= common_t::ALL) {
00751             setKillerMove(best_move.move());
00752             if (best_move.isNormal()
00753                 && ! best_move.move().isCapture())
00754             {
00755               const int d = (curLimit()+200)/100;
00756               this->historyTable().add(best_move.move(), d*d);
00757             }
00758           }
00759           assert(best_move.validMove());
00760           assert(! this->isWinValue(alt(P), best_value));
00761           goto register_table;
00762         } else {
00763           if (in_pv) 
00764             makePV(m.move());
00765         }
00766       }
00767     }
00768 #if (defined OSL_SMP) && (! defined OSL_SMP_NO_SPLIT_INTERNAL)
00769     first_move_node = nodeCount() - previous_node_count;
00770 #endif
00771   }
00772   testStop();
00773 
00774 #ifndef DONT_USE_CHECKMATE
00775   if (in_pv)
00776   {
00777     Move checkmate_move;
00778     if (tryCheckmate<P>(record, in_pv, checkmate_move)) {
00779       assert(checkmate_move.isValid());
00780       best_value= this->winByCheckmate(P);
00781       this->recordWinByCheckmate(P, record, checkmate_move);
00782       return best_value;
00783     }
00784   }
00785 #endif
00786   search_assert(w.isConsistent(), lastMove());
00787   if (curLimit() < this->leafLimit())
00788     goto move_generation_failure;
00789   while (true) {
00790 #if (defined OSL_SMP) && (! defined OSL_SMP_NO_SPLIT_INTERNAL)
00791     const bool prefer_split = shared && curLimit() >= shared->split_min_limit
00792       && (curLimit() >= 600+this->rootLimitBias()
00793           // || (curLimit() >= 400 && this->curDepth() < 2)
00794           || (first_move_node >= 30000));
00795     try {
00796       if (prefer_split) {
00797         int cur_smp_idle; 
00798         {
00799 # ifdef OSL_USE_RACE_DETECTOR
00800           boost::mutex::scoped_lock lk(shared->lock_smp);
00801 #endif
00802           cur_smp_idle = shared->smp_idle;
00803         }
00804         if (cur_smp_idle > last_smp_idle) {
00805           last_smp_idle = cur_smp_idle;
00806           assert(! already_split);
00807 # if (! defined NDEBUG)
00808           already_split = true;
00809 # endif
00810           if (examineMovesOther<P>(w, best_move, best_value, tried_moves,
00811                                    alpha_update, last_alpha_update)) {
00812             assert(best_move.validMove());
00813             assert(best_move.player() == P);
00814             if (this->move_type[this->curDepth()] >= common_t::ALL) {
00815               setKillerMove(best_move.move());
00816               if (best_move.isNormal()
00817                   && ! best_move.move().isCapture())
00818               {
00819                 const int d = (curLimit()+200)/100;
00820                 this->historyTable().add(best_move.move(), d*d);
00821               }
00822             }
00823             mpn_cut.add(tried_moves);    
00824             goto register_table;
00825           }
00826           goto all_moves_done;
00827         }
00828       }
00829     }
00830     catch(AlphaBeta2ParallelCommon::SplitFailed&) {
00831 # if (! defined NDEBUG)
00832       already_split = false;
00833 # endif
00834       // fall through
00835     }
00836 #endif
00837     MoveLogProb m = nextMove<P>(); 
00838     if (! m.validMove())
00839       break;
00840     ++tried_moves;
00841 
00842     assert(eval::betterThan(P, w.alpha(P), best_value));
00843     const int result = alphaBetaSearch<P>(m, w, in_pv && ! best_move.validMove());
00844     if (eval::betterThan(P, result, best_value)) {
00845       best_value = result;
00846       best_move = m;
00847       if (eval::betterThan(P, best_value, w.alpha(P))) {
00848         w.alpha(P) = result + EvalTraits<P>::delta;;
00849         assert(best_move.validMove());
00850         ++alpha_update;
00851         last_alpha_update = tried_moves;
00852         if (eval::betterThan(P, result, w.beta(P))) {
00853           assert(best_move.validMove());
00854           if (this->move_type[this->curDepth()] >= common_t::ALL) {
00855             setKillerMove(best_move.move());
00856             if (best_move.isNormal()
00857                 && ! best_move.move().isCapture())
00858             {
00859               const int d = (curLimit()+200)/100;
00860               this->historyTable().add(best_move.move(), d*d);
00861             }
00862           }
00863           mpn_cut.add(tried_moves);
00864           goto register_table;
00865         } else {
00866           if (in_pv)
00867             makePV(m.move());
00868         }
00869       }
00870     }
00871   }
00872 #if (defined OSL_SMP) && (! defined OSL_SMP_NO_SPLIT_INTERNAL)
00873 all_moves_done:
00874 #endif
00875   if (tried_moves == 1 && tryPass(record, P)) {
00876     // goto quiescence search if tried move is only null move
00877     goto move_generation_failure;
00878   }
00879   mpn.add(tried_moves);
00880   if (alpha_update) {
00881     this->alpha_update.add(alpha_update);
00882     this->last_alpha_update.add(last_alpha_update);
00883   }
00884   // 宣言勝
00885   if (((this->curDepth() % 2) == 0 || OslConfig::usiMode())
00886       && EnterKing::canDeclareWin<P>(state())) {
00887     best_value = this->brinkmatePenalty(alt(P), std::max(1,16-this->curDepth())*256)
00888       + this->eval.value();
00889     record->setAbsoluteValue(Move::DeclareWin(), best_value,
00890                              SearchTable::CheckmateSpecialDepth);
00891     return best_value;
00892   }
00893   if (record) {
00894     // もう一度,相手を詰ますことを考える
00895 #ifndef DONT_USE_CHECKMATE
00896     Move checkmate_move=Move::INVALID();
00897     if (tryCheckmateAgain<P>(record, checkmate_move, 
00898                              nodeCount() - node_count_at_beginning,
00899                              best_value)) {
00900       assert(checkmate_move.isValid());
00901       best_value= this->winByCheckmate(P);
00902       this->recordWinByCheckmate(P, record, checkmate_move);
00903       return best_value;
00904     }
00905 #endif
00906   }
00907 register_table:
00908   assert(best_value == this->minusInfty(P) || best_move.validMove());
00909   assert(eval::isConsistentValue(best_value));
00910   if (this->isWinValue(alt(P), best_value))
00911   {
00912     // TODO: 直前の着手が(やけくそ)王手の連続だった場合
00913     // 必死ではなくて詰扱いの方が良い可能性はある
00914     best_value = this->brinkmatePenalty(P, std::max(1,16-this->curDepth())*256) + this->eval.value();
00915 
00916     // (この深さでは)上限==下限
00917     record->setAbsoluteValue(best_move, best_value, curLimit());
00918     return best_value;
00919   }
00920   else if (EvalTraits<P>::betterThan(w.alpha(P), initial_alpha)) {
00921     if (best_move.validMove()) {
00922       assert(best_value % 2 == 0);
00923       record->setLowerBound(P, curLimit(), best_move, best_value);
00924     }
00925   }
00926   if (EvalTraits<P>::betterThan(w.beta(P), best_value)) {
00927     if (best_move.validMove())
00928       record->setUpperBound(P, curLimit(), best_move, best_value);
00929   }
00930   return best_value;
00931 move_generation_failure:
00932   pv[this->curDepth()].clear();
00933   // 手を生成できなかった
00934   // limit が 200 未満だった場合と,以上だったが move generator が limit 以下の手を生成できなかった場合ここに来る
00935   best_value = quiesce<P>(w);
00936   if (record)
00937   {
00938     if (EvalTraits<P>::betterThan(best_value, initial_alpha)) {
00939       if (EvalTraits<P>::betterThan(w.beta(P), best_value)) {
00940         record->setAbsoluteValue(MoveLogProb(), best_value, curLimit());
00941       } else {
00942         record->setLowerBound(P, curLimit(), MoveLogProb(), best_value);
00943       }
00944     }
00945     else 
00946     {
00947       assert(EvalTraits<P>::betterThan(w.beta(P), best_value));
00948       record->setUpperBound(P, curLimit(), MoveLogProb(), best_value);
00949     }
00950   }
00951   assert(eval::isConsistentValue(best_value));
00952   return best_value;
00953 }
00954 
00955 template <class EvalT>
00956 template <osl::Player P>
00957 int osl::search::AlphaBeta2Tree<EvalT>::
00958 quiesce(Window w)
00959 {
00960 #ifdef EXPERIMENTAL_QUIESCE
00961   return quiesceExp<P>(w);
00962 #else
00963   return quiesceStable<P>(w);
00964 #endif
00965 }
00966 
00967 template <class EvalT>
00968 template <osl::Player P>
00969 int osl::search::AlphaBeta2Tree<EvalT>::
00970 quiesceStable(Window w)
00971 {
00972   testStop();
00973   initPV();
00974   
00975   typedef QuiescenceSearch2<eval_t> qsearcher_t;
00976   qsearcher_t qs(*this, *this->table);
00977   Move last_move = lastMove();
00978   if (last_move.isInvalid())
00979     last_move = Move::PASS(alt(P));
00980   assert(w.alpha(P) % 2);
00981   assert(w.beta(P) % 2);
00982 #ifdef CHECKMATE_COUNT
00983   size_t count = checkmateSearcher().totalNodeCount();
00984 #endif
00985   const int result = qs.template search<P>(w.alpha(P), w.beta(P), this->eval, last_move, 4);
00986   node_count += qs.nodeCount();
00987   this->recorder.addQuiescenceCount(qs.nodeCount());
00988 #ifdef CHECKMATE_COUNT
00989   quiesce_checkmate += checkmateSearcher().totalNodeCount() - count;
00990 #endif
00991 
00992   assert(result % 2 == 0);
00993   return result;
00994 }
00995 
00996 template <class EvalT>
00997 template <osl::Player P>
00998 int osl::search::AlphaBeta2Tree<EvalT>::
00999 quiesceExp(Window w)
01000 {
01001   testStop();
01002 
01003   SimpleHashRecord *record = lastRecord();
01004   assert(record);
01005   Move best_move;
01006   const int qdepth = 4;
01007   const int previous_node_count = nodeCount();
01008 
01009   int result =
01010     quiesceRoot<P>(w, qdepth, best_move, record->threatmate());
01011   
01012   const size_t qnode = nodeCount() - previous_node_count;
01013   this->recorder.addQuiescenceCount(qnode);
01014   record->qrecord.setLowerBound(qdepth, result, best_move);
01015   return result;
01016 }
01017 
01018 template <class EvalT>
01019 template <osl::Player P>
01020 struct osl::search::AlphaBeta2Tree<EvalT>::NextQMove
01021 {
01022   AlphaBeta2Tree *searcher;
01023   Window window;
01024   const int depth;
01025   int *result;
01026   DualThreatmateState threatmate;
01027   NextQMove(AlphaBeta2Tree *s, Window w, int d, int *r,
01028             DualThreatmateState t)
01029     : searcher(s), window(w), depth(d), result(r), threatmate(t) {
01030   }
01031   void operator()(Square /*last_to*/) {
01032     searcher->eval.update(searcher->state(), searcher->lastMove());
01033     *result = 
01034       searcher->quiesce<P>(window, depth, threatmate);
01035   }
01036 };
01037 
01038 template <class EvalT>
01039 template <osl::Player P>
01040 bool osl::search::AlphaBeta2Tree<EvalT>::
01041 quiesceWithMove(Move move, Window& w, int depth_left, Move& best_move, int& best_value, 
01042                 const DualThreatmateState& threatmate)
01043 {
01044   // TODO: futility margin
01045   const bool in_pv = ! w.null();
01046   int result;
01047   typedef NextQMove<PlayerTraits<P>::opponent> next_t;
01048   next_t helper(this, w, depth_left, &result, threatmate);
01049 
01050   const HashKey new_hash = currentHash().newHashWithMove(move);
01051   const eval_t old_eval = this->eval;
01052   doUndoMoveOrPass<P,next_t>(new_hash, move, helper);
01053   this->eval = old_eval;
01054 
01055   if (eval::betterThan(P, result, best_value)) {
01056     best_value = result;
01057     best_move = move;
01058     if (eval::betterThan(P, best_value, w.alpha(P))) {
01059       w.alpha(P) = result + EvalTraits<P>::delta;
01060       if (in_pv)
01061         makePV(best_move);
01062       if (eval::betterThan(P, result, w.beta(P))) {
01063         return true;
01064       }
01065     }
01066   }
01067   return false;
01068 }
01069 
01070 template <class EvalT>
01071 template <osl::Player P>
01072 int osl::search::AlphaBeta2Tree<EvalT>::
01073 quiesceRoot(Window w, int depth_left, Move& best_move, DualThreatmateState threatmate)
01074 {
01075   assert(! state().inCheck(alt(P)));
01076 
01077   initPV();
01078   // depth_node_count_quiesce[this->curDepth()]++;
01079   // ++node_count;
01080 
01081   SimpleHashRecord& record = *lastRecord();
01082   assert(record.inCheck() == state().inCheck());
01083   assert(depth_left > 0);
01084   
01085   int best_value = this->minusInfty(P);
01086   // stand pat 
01087   if (! record.inCheck()) {
01088     if (! threatmate.maybeThreatmate(P)) {
01089       best_value = this->eval.value();
01090     } else {
01091       const int value = this->eval.value() + this->threatmatePenalty(P);
01092       best_value = EvalTraits<P>::max(best_value, value);
01093     }
01094     best_move = Move::PASS(P);
01095     if (EvalTraits<P>::betterThan(best_value, w.alpha(P))) {
01096       if (EvalTraits<P>::betterThan(best_value, w.beta(P)))
01097         return best_value;
01098       w.alpha(P) = best_value + EvalTraits<P>::delta;
01099     }
01100   }
01101 
01102   Move prev_best = record.qrecord.bestMove();
01103   MoveGenerator& generator = makeGenerator();
01104   generator.init(200, &record, this->eval, state(), 
01105                  w.alpha(P) == w.beta(P),
01106                  prev_best, true);
01107   int tried_moves = 0;
01108   // previous 最善手を試す
01109   if (prev_best.isNormal()) {
01110     ++tried_moves;
01111     if (quiesceWithMove<P>(prev_best, w, depth_left-1, best_move, best_value,
01112                            threatmate))
01113       goto finish;
01114   }
01115 
01116 
01117   // captures or king escape
01118   for (MoveLogProb m = generator.nextTacticalMove<P>(*this); 
01119        m.validMove(); m = generator.nextTacticalMove<P>(*this)) {
01120     ++tried_moves;
01121     if (quiesceWithMove<P>(m.move(), w, depth_left-1, best_move, best_value,
01122                            threatmate))
01123       goto finish;
01124   } 
01125   for (MoveLogProb m = generator.nextMove<P>(*this); 
01126        m.validMove(); m = generator.nextMove<P>(*this)) {
01127     ++tried_moves;
01128     if (quiesceWithMove<P>(m.move(), w, depth_left-1, best_move, best_value,
01129                            threatmate))
01130       goto finish;
01131   } 
01132 
01133   // pawn drop foul?
01134   if (record.inCheck()) {
01135     if (tried_moves == 0) {
01136       if (lastMove().isNormal() && lastMove().ptype() == PAWN && lastMove().isDrop())
01137         return this->winByFoul(P);
01138       return this->winByCheckmate(alt(P));
01139     }
01140     goto finish;
01141   }  
01142 finish:
01143   return best_value;
01144 }
01145 
01146 template <class EvalT>
01147 template <osl::Player P>
01148 int osl::search::AlphaBeta2Tree<EvalT>::
01149 quiesce(Window w, int depth_left, DualThreatmateState parent_threatmate)
01150 {
01151   if (state().inCheck(alt(P))) {
01152     return this->minusInfty(alt(P));
01153   }
01154 
01155   initPV();
01156 #ifndef MINIMAL
01157   depth_node_count_quiesce[this->curDepth()]++;
01158 #endif
01159   ++node_count;
01160 
01161   SimpleHashRecord record;
01162   record.setInCheck(state().inCheck());
01163 
01164   DualThreatmateState threatmate;
01165   threatmate.updateInLock(P, &parent_threatmate, record.inCheck());
01166 
01167   int best_value = this->minusInfty(P);
01168   // TODO: 玉の回りのtakeback延長
01169   if (depth_left <= 0) {
01170     if (record.inCheck()) {
01171       if (lastMove().isCapture())
01172         depth_left +=2;
01173       else
01174         depth_left = 0;
01175     }
01176     else if (threatmate.maybeThreatmate(P)) {
01177       if (threatmate.mayHaveCheckmate(alt(P))) {
01178         Move checkmate_move;
01179         bool win = isWinningState<P>(10, checkmate_move);
01180         if (win)
01181           return this->winByCheckmate(P);
01182       }
01183       return this->eval.value() + this->threatmatePenalty(P);
01184     }
01185     else {
01186       if (threatmate.mayHaveCheckmate(alt(P)))
01187         return this->eval.value() + this->threatmatePenalty(alt(P));
01188       if (ImmediateCheckmate::hasCheckmateMove<P>(state()))
01189         return this->winByCheckmate(P);
01190       if (ImmediateCheckmate::hasCheckmateMove<PlayerTraits<P>::opponent>(state()))
01191         return this->eval.value() + this->threatmatePenalty(P);
01192       return this->eval.value();
01193     }
01194   }
01195 
01196   if (! record.inCheck()) {
01197     if (ImmediateCheckmate::hasCheckmateMove<P>(state())) {
01198       return this->winByCheckmate(P);
01199     }
01200   }
01201   if (threatmate.mayHaveCheckmate(alt(P))) {
01202     Move checkmate_move;
01203     bool win = isWinningState<P>(10, checkmate_move);
01204     if (win)
01205       return this->winByCheckmate(P);
01206   }
01207   MoveGenerator& generator = makeGenerator();
01208   generator.init(200, &record, this->eval, state(), 
01209                  w.alpha(P) == w.beta(P),
01210                  Move(), true);
01211   int tried_moves = 0;
01212   Move best_move;
01213   // stand pat
01214   if (! record.inCheck()) {
01215     if (! threatmate.maybeThreatmate(P)) {
01216       best_value = this->eval.value();
01217     } else {
01218       const int value = this->eval.value() + this->threatmatePenalty(P);
01219       best_value = EvalTraits<P>::max(best_value, value);
01220     }
01221     best_move = Move::PASS(P);
01222     if (EvalTraits<P>::betterThan(best_value, w.alpha(P))) {
01223       if (EvalTraits<P>::betterThan(best_value, w.beta(P)))
01224         return best_value;
01225       w.alpha(P) = best_value + EvalTraits<P>::delta;
01226     }
01227   }
01228 
01229   // captures or king escape
01230   for (MoveLogProb m = generator.nextTacticalMove<P>(*this); 
01231        m.validMove(); m = generator.nextTacticalMove<P>(*this)) {
01232     ++tried_moves;
01233     if (quiesceWithMove<P>(m.move(), w, depth_left-1, best_move, best_value,
01234                            threatmate))
01235       goto finish;
01236   } 
01237   for (MoveLogProb m = generator.nextMove<P>(*this); 
01238        m.validMove(); m = generator.nextMove<P>(*this)) {
01239     ++tried_moves;
01240     if (quiesceWithMove<P>(m.move(), w, depth_left-1, best_move, best_value,
01241                            threatmate))
01242       goto finish;
01243   } 
01244 
01245   // pawn drop foul?
01246   if (record.inCheck()) {
01247     if (tried_moves == 0) {
01248       if (lastMove().ptype() == PAWN && lastMove().isDrop()) 
01249         return this->winByFoul(P);
01250       return this->winByCheckmate(alt(P));
01251     }
01252     goto finish;
01253   }  
01254 finish:
01255   return best_value;
01256 }
01257 
01258 template <class EvalT>
01259 void osl::search::AlphaBeta2Tree<EvalT>::updateCheckmateCount()
01260 {
01261 #ifdef OSL_SMP
01262   if (shared) {
01263     this->recorder.setCheckmateCount(shared->checkmateCount());
01264     return;
01265   }
01266 #endif
01267   this->recorder.setCheckmateCount
01268     (checkmateSearcher().totalNodeCount());
01269 }
01270 
01271 template <class EvalT>
01272 int 
01273 osl::search::AlphaBeta2Tree<EvalT>::
01274 rootAlpha(Player P, int last_value, Progress16 progress)
01275 {
01276   int pawns = 3;
01277   if (eval::betterThan(P, last_value, eval_t::captureValue(newPtypeO(alt(P),KING))))
01278   {
01279     pawns = 10;
01280   }
01281   else if (progress.value() <= 1)
01282   {
01283     pawns = 3;
01284   }
01285   else if (progress.value() <= 7)
01286   {
01287     pawns = 4;
01288   }
01289   else if (progress.value() <= 9)
01290   {
01291     pawns = 5;
01292   }
01293   else if (progress.value() <= 10)
01294   {
01295     pawns = 6;
01296   }
01297   else
01298   {
01299     pawns = 7;
01300   }
01301   const int width = eval_t::captureValue(newPtypeO(alt(P),PAWN))*pawns/2;
01302   return last_value - width - eval::delta(P);
01303 }
01304 
01305 template <class EvalT>
01306 int 
01307 osl::search::AlphaBeta2Tree<EvalT>::
01308 stableThreshold(Player P, int last_value)
01309 {
01310   int pawns = 3;
01311   if (eval::betterThan(P, last_value, eval_t::captureValue(newPtypeO(alt(P),KING))))
01312     pawns = 10;
01313   else if (eval::betterThan(P, eval_t::captureValue(newPtypeO(alt(P),PAWN))*2, last_value)
01314            && eval::betterThan(P, last_value, eval_t::captureValue(newPtypeO(P,PAWN))*2))
01315     pawns = 2;
01316   const int width = eval_t::captureValue(newPtypeO(alt(P),PAWN))*pawns/2;
01317   return last_value - width - eval::delta(P);
01318 }
01319 
01320 namespace osl
01321 {
01322   namespace
01323   {
01324     void find_threatmate(const SimpleHashTable& table, HashKey key,
01325                          const search::SearchState2::PVVector& pv,
01326                          CArray<bool, search::SearchState2::MaxDepth>& threatmate)
01327     {
01328       for (size_t i=0; i<pv.size(); ++i) {
01329         key = key.newMakeMove(pv[i]);
01330         const SimpleHashRecord *record = table.find(key);
01331         threatmate[i] = record
01332           && record->threatmate().isThreatmate(key.turn());
01333       }
01334     }
01335   }
01336 }
01337 
01338 template <class EvalT>
01339 void osl::search::AlphaBeta2Tree<EvalT>::
01340 updateRootPV(Player P, std::ostream& os, int result, Move m)
01341 {
01342   boost::mutex::scoped_lock lk(OslConfig::lock_io);
01343   this->makePV(m);
01344   const int last_root_value = shared_root->root_values_for_iteration.size() ? shared_root->root_values_for_iteration.back() : 0;
01345   const int threshold = stableThreshold(P, last_root_value);
01346   bool new_stable = eval::betterThan(P, result, threshold);
01347   shared_root->last_root_value_update = result;
01348 
01349   if (new_stable && m != shared_root->last_root_move
01350       && (See::see(state(), m) < -eval::Ptype_Eval_Table.value(KNIGHT)*2
01351           || eval::betterThan(P, result, eval_t::captureValue(newPtypeO(alt(P),KING))))) {
01352     new_stable = false;
01353   }
01354   if (new_stable && shared_root->root_values_for_iteration.size() > 1) {
01355     const int last_root_value2 = shared_root->root_values_for_iteration[shared_root->root_values_for_iteration.size()-2];
01356     const int threshold2 = stableThreshold(P, last_root_value2);
01357     if (eval::betterThan(P, threshold2, result)
01358         && eval::betterThan(P, last_root_value2, last_root_value))
01359       new_stable = false;
01360   }
01361   this->shared_root->last_pv.push_back(RootPV(root_limit, pv[0], result));
01362   this->setStable(new_stable);
01363 #ifndef GPSONE
01364   if (this->hasMonitor() && !this->prediction_for_speculative_search) {
01365     const double scale = OslConfig::usiOutputPawnValue()*2.0
01366       / eval_t::captureValue(newPtypeO(alt(P),PAWN));
01367     CArray<bool, MaxDepth> threatmate = {{ 0 }};
01368     find_threatmate(*this->table, currentHash(), pv[0], threatmate);
01369     BOOST_FOREACH(const boost::shared_ptr<SearchMonitor>& monitor,
01370                   this->monitors())
01371       monitor->showPV(root_limit/200, this->recorder.allNodeCount(),
01372                       this->elapsed(), static_cast<int>(result*scale), 
01373                       m, &*pv[0].begin(), &*pv[0].end(),
01374                       &threatmate[0], &threatmate[0]+pv[0].size());
01375   }
01376 #endif
01377   if (this->table->isVerbose()) {
01378     showPV(os, result, m, new_stable ? ' ' : '*');
01379   }
01380 }
01381 
01382 template <class EvalT>
01383 void osl::search::AlphaBeta2Tree<EvalT>::
01384 addMultiPV(Player P, int result, Move m)
01385 {
01386   boost::mutex::scoped_lock lk(OslConfig::lock_io);
01387   this->makePV(m);
01388   this->shared_root->last_pv.push_back(RootPV(root_limit, pv[0], result));
01389   std::swap(*this->shared_root->last_pv.rbegin(), *(this->shared_root->last_pv.rbegin()+1));
01390 
01391   if (this->hasMonitor() && !this->prediction_for_speculative_search) {
01392     const double scale = OslConfig::usiOutputPawnValue()*2.0
01393       / eval_t::captureValue(newPtypeO(alt(P),PAWN));
01394     CArray<bool, MaxDepth> threatmate = {{ 0 }};
01395     find_threatmate(*this->table, currentHash(), pv[0], threatmate);
01396     BOOST_FOREACH(const boost::shared_ptr<SearchMonitor>& monitor,
01397                   this->monitors())
01398       monitor->showPV(root_limit/200, this->recorder.allNodeCount(),
01399                       this->elapsed(), static_cast<int>(result*scale), 
01400                       m, &*pv[0].begin(), &*pv[0].end(),
01401                       &threatmate[0], &threatmate[0]+pv[0].size());
01402   }
01403 
01404   if (this->table->isVerbose()) {
01405     showPV(std::cerr, result, m, '&');
01406   }
01407 }
01408 
01409 template <class EvalT>
01410 void osl::search::AlphaBeta2Tree<EvalT>::
01411 showFailLow(int result, Move m) const
01412 {
01413   if (this->root_ignore_moves)
01414     std::cerr << "[" << this->root_ignore_moves->size() << "] ";
01415   std::cerr << " <" << std::setfill(' ') << std::setw(5) 
01416             << static_cast<int>(result*200.0/this->eval.captureValue(newPtypeO(WHITE,PAWN)))
01417             << " " << record::csa::show(m) << "\n";
01418 }
01419 
01420 template <class EvalT>
01421 void osl::search::AlphaBeta2Tree<EvalT>::
01422 showPV(std::ostream& os, int result, Move m, char stable_char) const
01423 {
01424   assert(m.isNormal()); // do not pass at root
01425   if (this->root_ignore_moves)
01426     os << "[" << this->root_ignore_moves->size() << "] ";
01427   os << stable_char;
01428   os << " " << std::setfill(' ') << std::setw(5) 
01429      << static_cast<int>(result*200.0/this->eval.captureValue(newPtypeO(WHITE,PAWN))) << " ";
01430   BOOST_FOREACH(Move m, pv[0]) {
01431     os << record::csa::show(m);
01432   }
01433   const double elapsed = this->elapsed();
01434   if (elapsed > 1.0)
01435     os << " (" << elapsed << "s, " << OslConfig::memoryUseRatio()*100.0 << "%)";
01436   os << std::endl;
01437 #ifndef MINIMAL
01438 #ifndef _WIN32
01439   if (! OslConfig::usiMode())
01440   {
01441     NumEffectState state = this->state();
01442     std::string str; str.reserve(200); str = "        ";
01443     for (size_t i=0; i<pv[0].size(); ++i) {
01444       str += record::ki2::show(pv[0][i], state, i ? pv[0][i-1] : Move());
01445       state.makeMove(pv[0][i]);
01446 
01447       // threatmate?
01448       const SimpleHashRecord *record
01449         = this->table->find(HashKey(state));
01450       if (record && 
01451           record->threatmate().isThreatmate(state.turn()))
01452         str += "(" K_TSUMERO ")";
01453     }
01454     std::string converted = IconvConvert::eucToLang(str);
01455     if (! converted.empty())
01456       os << converted << std::endl;
01457   }
01458 #endif
01459 #endif
01460 
01461 #ifdef DEBUG_PV
01462   NumEffectState s = state();
01463   for (size_t i=0; i<pv[0].size(); ++i) {
01464     if (! pv[0][i].isPass() && ! s.isValidMove(pv[0][i])) {
01465       std::cerr << "root pv error " << pv[0][i] << " " << i << "\n";
01466       break;
01467     }
01468     ApplyMoveOfTurn::doMove(s, pv[0][i]);
01469   }
01470 #endif
01471 }
01472 
01473 template <class EvalT>
01474 template <osl::Player P>
01475 struct osl::search::AlphaBeta2Tree<EvalT>::NextMove
01476 {
01477   AlphaBeta2Tree *searcher;
01478   const MoveLogProb& moved;
01479   Window window;
01480   int *result;
01481   bool in_pv;
01482   NextMove(AlphaBeta2Tree *s, const MoveLogProb& md, Window w, int *r,
01483            bool p)
01484     : searcher(s), moved(md), window(w), result(r), in_pv(p) {
01485     assert(P == md.player());
01486   }
01487   void operator()(Square /*last_to*/) {
01488 #ifndef NDEBUG
01489     const int cur_limit = searcher->curLimit();
01490 #endif
01491     *result = 
01492       searcher->alphaBetaSearchAfterMove<P>(moved, window, in_pv);
01493     assert(cur_limit == searcher->curLimit() || searcher->SearchState2Core::abort());
01494   }
01495 };
01496 
01497 template <class EvalT>
01498 template <osl::Player P>
01499 int osl::search::AlphaBeta2Tree<EvalT>::
01500 alphaBetaSearch(const MoveLogProb& search_move, Window w, bool in_pv)
01501 {
01502   assert(w.alpha(P) % 2);
01503   assert(w.beta(P) % 2);
01504   const Move move = search_move.move();
01505   assert(P == move.player());
01506   assert(P == state().turn());
01507   assert(eval::notLessThan(P, w.beta(P), w.alpha(P)));
01508 
01509   testStop();
01510   pv[curDepth()+1].clear();
01511   // TODO: more efficient way to find foul
01512   if (! move.isPass() ){
01513     if(MoveStackRejections::probe<P>(state(),history(),curDepth(),move,w.alpha(P),repetitionCounter().checkCount(alt(P)))){
01514       return this->winByLoop(alt(P));
01515     }
01516     if (move_classifier::MoveAdaptor<move_classifier::PawnDropCheckmate<P> >
01517         ::isMember(state(), move))
01518       return this->winByFoul(alt(P));
01519   }
01520 
01521   const HashKey new_hash = currentHash().newHashWithMove(move);
01522   assert(P == move.player());
01523 
01524   if (move.isPass())
01525     this->pass_count.inc(P);
01526 
01527   // 千日手確認
01528   if (! this->pass_count.loopByBothPass()) {
01529     const Sennichite next_sennichite
01530       = repetition_counter.isAlmostSennichite(new_hash);
01531     if (next_sennichite.isDraw())
01532       return this->drawValue();
01533     if (next_sennichite.hasWinner())
01534       return this->winByFoul(next_sennichite.winner());
01535     assert(next_sennichite.isNormal());
01536   }
01537   
01538   if (! move.isPass()) {
01539     // 優越関係確認
01540     const DominanceCheck::Result has_dominance
01541       = DominanceCheck::detect(repetition_counter.history(), new_hash);
01542     if (has_dominance == DominanceCheck::LOSE)
01543       return this->winByLoop(alt(P));
01544     if (has_dominance == DominanceCheck::WIN)
01545       return this->winByLoop(P);
01546     // 連続王手駒捨て
01547     if (! move.isCapture()) {
01548       const int sacrifice_count = countSacrificeCheck2(this->curDepth());
01549       if (sacrifice_count == 2) {
01550         // 3回目は指さない
01551         const Square to = move.to();
01552         int offence = state().countEffect(P, to) + (move.isDrop() ? 1 : 0);
01553         const int deffense = state().hasEffectAt(alt(P), to); // max1
01554         if (offence <= deffense)
01555           offence += AdditionalEffect::count2(state(), to, P);
01556         if (offence <= deffense) {
01557           return this->winByLoop(alt(P));
01558         }
01559       }
01560     }
01561   }
01562   // 探索
01563   int result;
01564   NextMove<P> helper(this, search_move, w, &result, in_pv);
01565 
01566   this->recorder.addNodeCount();  
01567   const eval_t old_eval = this->eval;
01568   doUndoMoveOrPass<P,NextMove<P> >(new_hash, move, helper);
01569   this->eval = old_eval;
01570   if (move.isPass())
01571     this->pass_count.dec(P);
01572 
01573   return result;
01574 }
01575 
01576 template <class EvalT>
01577 template <osl::Player P>
01578 void osl::search::AlphaBeta2Tree<EvalT>::
01579 examineMovesRoot(const MoveLogProbVector& moves, size_t i, Window window,
01580                  MoveLogProb& best_move, int& best_value)
01581 {
01582   for (;i<moves.size(); ++i) {
01583     testStop();
01584 
01585 #if (defined OSL_SMP) && (! defined OSL_SMP_NO_SPLIT_ROOT)
01586     if (shared && i > 8
01587         && moves.size() > i+1) {
01588       int smp_idle;
01589       {
01590 #  ifdef OSL_USE_RACE_DETECTOR
01591         boost::mutex::scoped_lock lk(shared->lock_smp);
01592 #  endif
01593         smp_idle = shared->smp_idle;
01594       }
01595       if (smp_idle) {
01596         try {
01597           examineMovesRootPar<P>(moves, i, window, best_move, best_value);
01598           break;
01599         } catch (AlphaBeta2ParallelCommon::SplitFailed&) {
01600         }
01601       }
01602     }
01603 #endif
01604 
01605     const MoveLogProb& m = moves[i];
01606 #ifndef GPSONE
01607     if (this->elapsed() > 1.0)
01608     {
01609       boost::mutex::scoped_lock lk(OslConfig::lock_io);
01610       BOOST_FOREACH(const boost::shared_ptr<SearchMonitor>& monitor,
01611                     this->monitors())
01612         monitor->rootMove(m.move());
01613     }
01614     if (this->multi_pv) {
01615       int width = this->multi_pv*this->eval.captureValue(newPtypeO(P, PAWN))/200;
01616       if (width % 2 == 0) 
01617         width -= EvalTraits<P>::delta;
01618       window.alpha(P) = best_value + width;
01619     }
01620 #endif
01621     const int result = alphaBetaSearch<P>(m, window, false);
01622     if (eval::betterThan(P, result, best_value)) 
01623     {
01624       window.alpha(P) = result + EvalTraits<P>::delta;
01625       best_move = m;
01626       best_value = result;
01627       updateRootPV(P, std::cerr, result, m.move());
01628       if (eval::betterThan(P, result, window.beta(P))) {
01629         assert(! this->isWinValue(alt(P), result));
01630         break;
01631       }
01632     } 
01633 #ifndef GPSONE
01634     else if (this->multi_pv && eval::betterThan(P, result, window.alpha(P)))
01635     {
01636       addMultiPV(P, result, m.move());
01637     }
01638 #endif
01639     if (this->root_limit >= 1600)
01640       this->checkmate_searcher->runGC(this->table->isVerbose(),
01641                                       lastMemoryUseRatio1000());
01642   }
01643 }
01644 
01645 /* ------------------------------------------------------------------------- */
01646 
01647 template <class EvalT>
01648 osl::search::AlphaBeta2<EvalT>::
01649 AlphaBeta2(const NumEffectState& s, checkmate_t& c, 
01650            SimpleHashTable *t, CountRecorder& r)
01651   : AlphaBeta2Tree<EvalT>(s, c, t, r)
01652 {
01653   MoveGenerator::initOnce();
01654 }
01655 
01656 template <class EvalT>
01657 osl::search::AlphaBeta2<EvalT>::
01658 ~AlphaBeta2()
01659 {
01660 }
01661 
01662 template <class EvalT>
01663 typename osl::search::AlphaBeta2<EvalT>::PVCheckmateStatus osl::search::AlphaBeta2<EvalT>::
01664 findCheckmateInPV(int verify_node, CArray<bool,2>& king_in_threat)
01665 {
01666   king_in_threat.fill(false);
01667   if (this->shared_root->last_pv.empty())
01668     return PVStable;
01669   const SearchState2::PVVector& pv = this->shared_root->last_pv.back().pv;
01670   NumEffectState state = this->state();
01671   PathEncoding path = this->path();
01672   PVCheckmateStatus found = PVStable;
01673   SearchState2::checkmate_t *checkmate_searcher = this->checkmate_searcher;
01674   if (this->node_count < verify_node*pv.size())
01675     verify_node = this->node_count/(pv.size()+1)/4;
01676   for (size_t i=0; i<pv.size(); ++i)
01677   {
01678     this->checkmate_searcher->runGC(this->table->isVerbose(),
01679                                     this->lastMemoryUseRatio1000());
01680     assert(pv[i].isPass() || state.isValidMove(pv[i]));
01681     if (! pv[i].isPass() && ! state.isValidMove(pv[i]))
01682     {
01683       std::cerr << "pv error " << pv[i] << "\n" << state;
01684       return PVStable;
01685     }
01686     state.makeMove(pv[i]);
01687     path.pushMove(pv[i]);
01688     if (state.inCheck())
01689       continue;
01690     const HashKey key(state);
01691     SimpleHashRecord *record = this->table->allocate(key, 2000);
01692     if (! record)
01693       break;
01694     Move checkmate_move, threatmate_move;
01695     const bool old_win = this->isWinningState
01696       (*checkmate_searcher, state, key, path, 
01697        0, checkmate_move, pv[i]);
01698     if (! old_win) 
01699     {
01700       const bool new_win = this->isWinningState
01701         (*checkmate_searcher, state, key, path, 
01702          verify_node, checkmate_move, pv[i], true);
01703       if (new_win)
01704       {
01705         found = PVCheckmate;
01706         this->recordWinByCheckmate(state.turn(), record, checkmate_move);
01707         king_in_threat[alt(state.turn())] = true;
01708         if (this->table->isVerbose())
01709           std::cerr << "  pv checkmate " << record::csa::show(pv[i])
01710                     << "(" << i << ")\n";
01711       }
01712     }
01713     state.changeTurn();
01714     const Player T = state.turn();
01715     const bool old_threatmate_in_record = record->threatmate().isThreatmate(alt(T));
01716     const bool old_threatmate = this->isWinningState
01717       (*checkmate_searcher, state, HashKey(state), PathEncoding(T), 
01718        1, threatmate_move, Move::PASS(alt(T)));
01719     if (! old_threatmate)
01720     {
01721       const bool new_threatmate = this->isWinningState
01722         (*checkmate_searcher, state, HashKey(state), PathEncoding(T), 
01723          verify_node, threatmate_move, Move::PASS(alt(T)), this->root_limit >= 1000 + this->rootLimitBias());
01724       if (new_threatmate)
01725       {
01726         record->threatmate().setThreatmate(alt(T), threatmate_move);
01727         king_in_threat[alt(T)] = true;
01728         if (! old_threatmate_in_record) 
01729           found = PVThreatmate;
01730         else if (found == PVStable) 
01731           found = PVThreatmateNotRecord;
01732         if (this->table->isVerbose())
01733           std::cerr << "  pv threatmate " << record::csa::show(pv[i])
01734                     << "(" << i << ")\n";
01735       }
01736     }
01737     state.changeTurn();
01738   }
01739   this->checkmate_searcher->runGC(this->table->isVerbose(),
01740                                   this->lastMemoryUseRatio1000());
01741   this->updateCheckmateCount();
01742   return found;
01743 }
01744 
01745 template <class EvalT>
01746 int osl::search::AlphaBeta2<EvalT>::
01747 alphaBetaSearchRoot(MoveLogProb& best_move, int limit)
01748 {
01749   const Player Turn = this->state().turn();
01750   Window root_window = this->fullWindow(Turn);
01751   return alphaBetaSearchRoot(root_window, best_move, limit);
01752 }
01753 
01754 template <class EvalT>
01755 osl::Move osl::search::AlphaBeta2<EvalT>::
01756 computeBestMoveIteratively(int limit, const int step, 
01757                            int initial_limit, size_t node_limit,
01758                            const TimeAssigned& assign,
01759                            MoveWithComment *additional_info)
01760 {
01761   this->setStartTime(MilliSeconds::now());
01762   this->setTimeAssign(assign);
01763   if (this->table->verboseLevel() > 2)
01764   {
01765     const time_t now = time(0);
01766     char ctime_buf[64];
01767     std::cerr << "AlphaBeta2 " << ctime_r(&now, ctime_buf);
01768   }
01769   if (this->table->isVerbose()) {
01770     std::cerr << " time assign/max " << this->timeAssigned().standard.toSeconds()
01771               << "/" << this->timeAssigned().max.toSeconds()
01772               << " multipv " << this->multi_pv
01773               << " iteration " << this->nextIterationCoefficient()
01774               << " mem " << std::fixed << std::setprecision(2)
01775               << OslConfig::memoryUseRatio()*100.0 << "%";
01776     std::cerr << "\n";
01777   }
01778   initial_limit = std::min(initial_limit, limit);
01779   
01780   this->recorder.resetNodeCount();
01781 
01782   double last_iteration_consumed = 0;
01783   double total_consumed = 0;
01784   int limit_iterative = initial_limit;
01785   Move last_best_move = Move::INVALID();
01786   this->shared_root->last_pv.clear();
01787 
01788 #ifdef OSL_SMP
01789 #  ifdef SPLIT_STAT
01790   if (this->shared) {
01791     this->shared->parallel_splits = 0;
01792     this->shared->cancelled_splits.setValue(0);
01793     this->shared->parallel_abort.setValue(0);
01794   }
01795 #  endif
01796 #endif
01797   try
01798   {
01799     if (this->table->verboseLevel() > 1)
01800     {
01801       MoveVector moves;
01802       move_generator::LegalMoves::generate(this->state(), moves);
01803       BOOST_FOREACH(Move move, moves) {
01804         HashKey key = this->currentHash().newHashWithMove(move);
01805         const SimpleHashRecord *record = this->table->find(key);
01806         if (! record || record->lowerLimit() < SearchTable::HistorySpecialDepth)
01807           continue;
01808         std::cerr << "prebound value " << record::csa::show(move)
01809                   << " " << record->lowerBound() << " " << record->upperBound() << "\n";
01810       }
01811     }
01812 
01813     MoveLogProb search_move;
01814     this->shared_root->root_values.push_back(alphaBetaSearchRoot(search_move, 0));
01815     this->shared_root->last_root_move = search_move.move();
01816     this->shared_root->best_move_for_iteration.push_back(search_move.move());
01817     if (this->table->verboseLevel() > 1)
01818       std::cerr << "=> quiesce "
01819                 << record::csa::show(search_move.move()) << "\n";
01820     while (limit_iterative < limit && ! this->stopping())
01821     {
01822       if (this->table->verboseLevel() > 1)
01823         std::cerr << "=> iteration " << limit_iterative 
01824                   << " (" << last_iteration_consumed << ", " << total_consumed << " sec)"
01825                   << " mem " << OslConfig::memoryUseRatio()*100.0 << "%\n";
01826       this->recorder.startSearch(limit_iterative);
01827       const int previous_node_count = this->nodeCount();
01828       try {
01829         for (int i=0; i<8; ++i)
01830         {
01831           this->shared_root->root_values.push_back(alphaBetaSearchRoot(search_move, limit_iterative+this->rootLimitBias()));
01832           this->shared_root->last_root_move = search_move.move();
01833           last_best_move = search_move.move();
01834           if (this->stopping())
01835             break;
01836           PVCheckmateStatus need_more_verify = PVStable;
01837           CArray<bool, 2> king_in_threat;
01838           int verify_node_limit = limit <= (1200 + this->rootLimitBias()) ? 10000 : 40000;
01839           if (this->timeAssigned().standard.toSeconds() < 20)
01840             verify_node_limit /= 4;
01841 #ifdef DONT_USE_CHECKMATE
01842           break;
01843 #endif
01844           need_more_verify = findCheckmateInPV(verify_node_limit, king_in_threat);
01845           if (need_more_verify == PVStable
01846               || (i > 0 && need_more_verify == PVThreatmateNotRecord))
01847             break;
01848           if (this->isStableNow())
01849             this->setStable(i > 0 && king_in_threat[this->state().turn()] == false);
01850         } 
01851       } catch (...) {
01852         last_iteration_consumed = this->elapsed() - total_consumed;
01853         total_consumed += last_iteration_consumed;
01854         this->updateCheckmateCount();
01855         this->recorder.finishSearch(search_move.move(), total_consumed,
01856                               this->table->verboseLevel());
01857         throw;
01858       }
01859 
01860       last_iteration_consumed = this->elapsed() - total_consumed;
01861       total_consumed += last_iteration_consumed;
01862       this->shared_root->best_move_for_iteration.push_back(last_best_move);
01863       this->shared_root->root_values_for_iteration.push_back
01864         (this->shared_root->root_values.back());
01865 
01866       this->updateCheckmateCount();
01867       if (this->table->verboseLevel() > 2) {
01868         std::cerr << "<= " 
01869                   << record::csa::show(search_move.move());
01870         std::cerr << std::setprecision(4) << "  mpn " << this->mpn.getAverage() 
01871                   << " cut " << this->mpn_cut.getAverage()
01872                   << " alpha " << this->alpha_update.getAverage()
01873                   << " last " << this->last_alpha_update.getAverage()
01874                   << " ext " << 100.0*this->ext.getAverage() << "%"
01875                   << " ext_limit " << this->ext_limit.getAverage()
01876                   << " mem " << OslConfig::memoryUseRatio()*100.0;
01877 #ifdef OSL_SMP
01878 #  ifdef SPLIT_STAT
01879         if (this->shared) {
01880           std::cerr << " split " << this->shared->parallel_splits << " cancel " << this->shared->cancelled_splits.value() 
01881                     << " abort " << this->shared->parallel_abort.value();
01882         }
01883 #  endif
01884 #endif
01885         std::cerr << "\n";
01886       }
01887       bool time_over = false;
01888       if (this->hasSchedule()) {
01889         const double elapsed = this->elapsed();
01890         const double current_time_left = this->timeAssigned().standard.toSeconds() - elapsed;
01891         double coef = this->nextIterationCoefficient();
01892         if (! this->isStableNow())
01893           coef = std::min(0.5, coef);
01894         else {
01895           const int same_best_moves = this->shared_root->sameBestMoves();
01896           if (same_best_moves == 0) {
01897             if (this->table->verboseLevel() > 2 && coef > 0.75)
01898               std::cerr << "info: " << coef << " -> 0.75 by bestmove update\n";
01899             coef = std::min(0.75, coef);
01900           }
01901           else if (same_best_moves >= 3) {
01902             const Move last_move = this->lastMove();
01903             if (last_move.isNormal() && last_best_move.isNormal()
01904                 && last_move.to() == last_best_move.to()
01905                 && isMajor(last_best_move.capturePtype())
01906                 && isMajorNonPieceOK(last_move.capturePtype())) {
01907               if (coef < 5.0 && this->table->verboseLevel() > 2)
01908                 std::cerr << "info: " << coef << " -> 5.0 by takeback major piece\n";
01909               coef = std::max(5.0, coef);
01910             }
01911           }
01912         }
01913         if (current_time_left 
01914             < last_iteration_consumed * coef)
01915           time_over = true;
01916         if (! time_over) {
01917           SimpleHashRecord *record
01918             = this->table->find(this->currentHash());
01919           if (record) {
01920             record->addNodeCount(this->nodeCount() - previous_node_count);
01921           }
01922         }
01923       }
01924       bool node_limit_over = (this->recorder.nodeCount() *4 > node_limit);
01925       this->recorder.finishSearch(search_move.move(), 
01926                             total_consumed,
01927                             (time_over || node_limit_over) && this->table->verboseLevel());
01928       if (time_over || node_limit_over || this->stopping()) {
01929         if (this->table->isVerbose()) {
01930           const char *reason = "other reason";
01931           if (this->stopReason() == SearchTimerCommon::NoMoreMemory)
01932             reason = "memory full";
01933           else if (time_over || this->stopReason() == SearchTimerCommon::NoMoreTime)
01934             reason = "time";
01935           else if (node_limit_over)
01936             reason = "node count";
01937           else if (this->stopReason() == SearchTimerCommon::StopByOutside)
01938             reason = "outside";
01939           std::cerr << "iteration stop at " << limit_iterative << " by "
01940                     << reason << "\n";
01941         }
01942         goto finish;
01943       }
01944       this->testStop();
01945       limit_iterative += step;
01946     }
01947     if (this->table->verboseLevel() > 1)
01948       std::cerr << "=> final iteration " << limit_iterative 
01949                 << " (" << last_iteration_consumed << ", " << total_consumed << " sec)"
01950                 << " mem " << OslConfig::memoryUseRatio()*100.0 << "%\n";
01951     while (true) {
01952       this->recorder.startSearch(limit);
01953       try {
01954         for (int i=0; i<8; ++i)
01955         {
01956           this->shared_root->root_values.push_back(alphaBetaSearchRoot(search_move, limit+this->rootLimitBias()));
01957           this->shared_root->last_root_move = search_move.move();
01958           last_best_move = search_move.move();
01959           if (this->stopping())
01960             break;
01961           PVCheckmateStatus need_more_verify = PVStable;
01962           CArray<bool, 2> king_in_threat;
01963           int verify_node_limit = limit <= (1200 + this->rootLimitBias()) ? 10000 : 40000;
01964           if (this->timeAssigned().standard.toSeconds() < 20)
01965             verify_node_limit /= 4;
01966 #ifdef DONT_USE_CHECKMATE
01967           break;
01968 #endif
01969           need_more_verify = findCheckmateInPV(verify_node_limit, king_in_threat);
01970           if (need_more_verify == PVStable
01971               || (i > 0 && need_more_verify == PVThreatmateNotRecord))
01972             break;
01973           if (this->isStableNow())
01974             this->setStable(i > 0 && king_in_threat[this->state().turn()] == false);
01975         }
01976       } catch (...) {
01977         last_iteration_consumed = this->elapsed() - total_consumed;
01978         total_consumed += last_iteration_consumed;
01979         this->updateCheckmateCount();
01980         this->recorder.finishSearch(search_move.move(), total_consumed,
01981                               this->table->verboseLevel());
01982         throw;
01983       }
01984       last_iteration_consumed = this->elapsed() - total_consumed;
01985       total_consumed += last_iteration_consumed;
01986       this->updateCheckmateCount();
01987       this->recorder.finishSearch(search_move.move(), total_consumed,
01988                             this->table->verboseLevel());
01989       this->shared_root->best_move_for_iteration.push_back(last_best_move);
01990       this->shared_root->root_values_for_iteration.push_back
01991         (this->shared_root->root_values.back());
01992 
01993       if (last_best_move.isNormal())
01994         break;
01995       this->testStop();
01996 
01997       // ほっておくと投了
01998       if (limit >= 2000 || this->root_ignore_moves)
01999         break;
02000 
02001       limit += 200;
02002       if (this->table->isVerbose())
02003         std::cerr << "  extend limit to " << limit << " before resign\n";
02004     }
02005   }
02006   catch (std::exception& e)
02007   {
02008     if (! OslConfig::usiMode())
02009       std::cerr << "std exception " << e.what() << "\n";
02010   }
02011   catch (...)
02012   {
02013     std::cerr << "unknown exception\n";
02014 #ifndef NDEBUG
02015     throw;
02016 #endif
02017   }
02018 finish:
02019   if (this->table->verboseLevel() > 1) {
02020     std::cerr << "<= " << record::csa::show(last_best_move);
02021     std::cerr << std::setprecision(4) << "  mpn " << this->mpn.getAverage()
02022               << " cut " << this->mpn_cut.getAverage()
02023               << " alpha " << this->alpha_update.getAverage()
02024               << " last " << this->last_alpha_update.getAverage()
02025               << " ext " << this->ext.getAverage()
02026               << " ext_limit " << this->ext_limit.getAverage()
02027               << " mem " << OslConfig::memoryUseRatio()*100.0;
02028 #ifdef OSL_SMP
02029 #  ifdef SPLIT_STAT
02030     if (this->shared) {
02031       std::cerr << " split " << this->shared->parallel_splits << " cancel " << this->shared->cancelled_splits.value() 
02032                 << " abort " << this->shared->parallel_abort.value();
02033     }
02034 #  endif
02035 #endif
02036     std::cerr << "\n";
02037   }
02038 
02039   if (additional_info) {
02040     additional_info->node_count = this->nodeCount();
02041     additional_info->elapsed = this->elapsed();
02042     additional_info->moves.clear();
02043     additional_info->root_limit = this->root_limit;
02044   }
02045   if (additional_info && this->shared_root->root_values.size() > 1) { // last_root_value[0] is for quiesce
02046     assert(last_best_move == this->shared_root->last_root_move);
02047     additional_info->move = last_best_move;
02048     const double scale = 200.0/this->eval.captureValue(newPtypeO(WHITE,PAWN));
02049     additional_info->value = static_cast<int>(this->shared_root->last_root_value_update * scale);
02050     if (!this->shared_root->last_pv.empty()) {
02051       for (size_t i=1; i<this->shared_root->last_pv.back().pv.size(); ++i) {
02052         additional_info->moves.push_back(this->shared_root->last_pv.back().pv[i]);
02053       }
02054     }
02055   }
02056   return last_best_move;
02057 }
02058 
02059 template <class EvalT>
02060 template <osl::Player P>
02061 int osl::search::AlphaBeta2<EvalT>::
02062 alphaBetaSearchRoot(Window window, MoveLogProb& best_move, int limit)
02063 {
02064 #ifndef GPSONE
02065   {
02066     boost::mutex::scoped_lock lk(OslConfig::lock_io);
02067     BOOST_FOREACH(const boost::shared_ptr<SearchMonitor>& monitor,
02068                   this->monitors())
02069       monitor->newDepth(limit/200);
02070   }
02071 #endif
02072   assert(P == this->state().turn());
02073   assert(window.alpha(P) % 2);
02074   assert(window.beta(P) % 2);
02075   setRoot(limit);
02076   assert(this->curDepth() == 0);
02077   this->node_type[this->curDepth()] = base_t::PvNode;
02078 #ifdef NEW_DFPN
02079   this->checkmate_searcher->setRootPlayer(P);
02080 #endif
02081 #ifdef OSL_SMP
02082   if (this->shared)
02083     this->shared->threadStart();
02084 #endif
02085   // まずテーブルを牽く
02086   SimpleHashRecord *record_in_table
02087     = this->table->allocate(this->currentHash(), limit);
02088   SimpleHashRecord *record = record_in_table;
02089   boost::scoped_ptr<SimpleHashRecord> record_if_not_allocated;
02090   if (! record)
02091   {
02092     record_if_not_allocated.reset(new SimpleHashRecord());
02093     record = record_if_not_allocated.get();
02094   }
02095   assert(record);
02096   this->setRootRecord(record);
02097   assert(this->rootRecord() == record);
02098   assert(this->hasLastRecord() && this->lastRecord() == record);
02099   record->setInCheck(this->state().inCheck());
02100 
02101   if (limit == 0) {
02102     int result = this->template quiesce<P>(fullWindow(P));
02103     best_move = MoveLogProb(record->qrecord.bestMove(), 100);
02104     if (this->root_ignore_moves
02105         && this->root_ignore_moves->isMember(best_move.move()))
02106       best_move = MoveLogProb();
02107 #ifndef GPSONE
02108     else if (this->hasMonitor() && !this->prediction_for_speculative_search) 
02109     {
02110       const double scale = OslConfig::usiOutputPawnValue()*2.0
02111         / this->eval.captureValue(newPtypeO(alt(P),PAWN));
02112       boost::mutex::scoped_lock lk(OslConfig::lock_io);
02113       BOOST_FOREACH(const boost::shared_ptr<SearchMonitor>& monitor,
02114                     this->monitors())
02115         monitor->showPV(1, this->recorder.allNodeCount(),
02116                         this->elapsed(), static_cast<int>(result*scale), 
02117                         best_move.move(), 0, 0, 0, 0);
02118     }
02119 #endif
02120     return result;
02121   }
02122   if (record_in_table) {
02123     int table_value = 0;
02124     const MoveLogProb m = record_in_table->bestMove();
02125     if (! m.isNormal())
02126       record_in_table->resetValue();
02127     else if (record->hasGreaterLowerBound<P>(this->curLimit(), window.beta(P), 
02128                                              table_value)) {
02129       if (! this->root_ignore_moves 
02130           || ! this->root_ignore_moves->isMember(m.move())) {
02131         best_move = m;
02132         return table_value;
02133       }
02134     }
02135   }
02136 
02137   // gather all moves
02138   MoveLogProbVector moves;
02139   MoveGenerator& generator = this->makeGenerator();
02140   const MoveLogProb last_best_move = record->bestMove();
02141   {
02142     MoveLogProbVector raw_moves;
02143     assert(this->curLimit() > 0);
02144     const Move hash_move = last_best_move.isNormal()
02145       ? last_best_move.move() : record->qrecord.bestMove();
02146     generator.init(this->curLimit()+200, record, this->eval, this->state(), true, hash_move);
02147     if (last_best_move.isNormal())
02148       raw_moves.push_back(last_best_move);
02149     else if (record->qrecord.bestMove().isNormal())
02150       raw_moves.push_back(MoveLogProb(record->qrecord.bestMove(), 100));
02151     generator.generateAll<P>(*this, raw_moves);
02152 
02153     // clean up losing moves
02154     for (size_t i=0; i<raw_moves.size(); ++i) {
02155       const Move m = raw_moves[i].move();
02156       if (i > 0 && m == hash_move)
02157         continue;
02158       const HashKey key = this->currentHash().newHashWithMove(m);
02159       const SimpleHashRecord *record = this->table->find(key);
02160       assert(this->state().isValidMove(m));
02161       if (record) {
02162         if (record->hasUpperBound(SearchTable::HistorySpecialDepth)
02163             && this->isWinValue(alt(P), record->upperBound()))
02164           continue;
02165       }
02166       if (this->root_ignore_moves && this->root_ignore_moves->isMember(m))
02167         continue;
02168       if (! m.isDrop() && m.ptype() != KING
02169           && move_classifier::KingOpenMove<P>::isMember(this->state(), m.ptype(), m.from(), m.to()))
02170         continue;
02171       if (move_classifier::MoveAdaptor<move_classifier::PawnDropCheckmate<P> >
02172           ::isMember(this->state(), m))
02173         continue;
02174       raw_moves[i].setLogProbAtMost(limit);
02175       moves.push_back(raw_moves[i]);
02176     }
02177   }
02178 
02179   if (! OslConfig::searchExactValueInOneReply()) {
02180     if (moves.size() == 1 
02181         || (moves.size() == 2 && moves[0].move() == moves[1].move()))
02182     {
02183       best_move = moves[0];
02184 #ifndef GPSONE
02185       if (this->hasMonitor() && !this->prediction_for_speculative_search) {
02186         boost::mutex::scoped_lock lk(OslConfig::lock_io);
02187         BOOST_FOREACH(const boost::shared_ptr<SearchMonitor>& monitor,
02188                       this->monitors())
02189           monitor->rootForcedMove(best_move.move());
02190       }
02191 #endif
02192       return 0; // XXX
02193     }
02194   }
02195 
02196 #ifndef DONT_USE_CHECKMATE
02197   // 詰将棋を呼んでみる root では沢山呼んでも問題ない
02198   int checkmate_node = 0;
02199   if (! this->prediction_for_speculative_search) {
02200     int checkmate_max = 30000*std::max(limit - 300 - this->rootLimitBias(), 0)/100;
02201     if (limit >= 1000 + this->rootLimitBias())
02202       checkmate_max = std::min(400000, 60000*(limit - 800 - this->rootLimitBias())/100);
02203     if (this->timeAssigned().standard.toSeconds() < 20) {
02204       checkmate_node /= 4;
02205       if (this->timeAssigned().standard.toSeconds() < 10)
02206         checkmate_node /= 2;
02207     }
02208     checkmate_node = record->qrecord.checkmateNodesLeft(checkmate_max);
02209 #ifdef CHECKMATE_COUNT
02210     std::cerr << "limit " << limit << " checkmate " << checkmate_node << "\n";
02211 #endif
02212   }
02213   if (checkmate_node > 0)
02214   {
02215     const bool my_king_in_check
02216       = this->state().hasEffectAt(alt(P),this->state().kingSquare(P));
02217     if (my_king_in_check)
02218     {
02219       // 相手から王手がかかっている
02220       this->recorder.gotoCheckmateSearch(this->state(), checkmate_node/8);
02221       const bool lose = this->template isLosingState<P>(checkmate_node/8);
02222       this->recorder.backFromCheckmateSearch();
02223       this->updateCheckmateCount();
02224       if (lose)
02225       {
02226         best_move = MoveLogProb(Move::INVALID(),100);
02227         this->recordLoseByCheckmate(P, record);
02228         this->shared_root->last_pv.clear();
02229         this->shared_root->last_root_move = Move();
02230         this->shared_root->last_root_value_update = this->winByCheckmate(alt(P));
02231 #ifndef GPSONE
02232         boost::mutex::scoped_lock lk(OslConfig::lock_io);
02233         BOOST_FOREACH(const boost::shared_ptr<SearchMonitor>& monitor,
02234                       this->monitors())
02235           monitor->rootLossByCheckmate();
02236 #endif
02237         return this->winByCheckmate(alt(P));
02238       }
02239     }
02240     // 詰まされなければ,相手を詰ますことを考える 
02241     {
02242       Move checkmate_move;
02243 #ifdef CHECKMATE_COUNT
02244       size_t count = this->checkmateSearcher().totalNodeCount();
02245 #endif
02246       this->recorder.gotoCheckmateSearch(this->state(), checkmate_node);
02247       const bool win = this->template isWinningState<P>
02248         (checkmate_node, checkmate_move, limit >= 1000 + this->rootLimitBias());
02249       this->recorder.backFromCheckmateSearch();
02250       this->updateCheckmateCount();
02251 #ifdef CHECKMATE_COUNT
02252       root_checkmate += this->checkmateSearcher().totalNodeCount() - count;
02253 #endif
02254       if (win)
02255       {
02256         best_move = MoveLogProb(checkmate_move,100);
02257         this->recordWinByCheckmate(P, record, checkmate_move);
02258         this->shared_root->last_pv.clear();
02259         this->shared_root->last_root_move = checkmate_move;
02260         this->shared_root->last_root_value_update = this->winByCheckmate(P);
02261         this->pv[1].clear();
02262         this->updateRootPV(P, std::cerr, this->winByCheckmate(P), checkmate_move);
02263         return this->winByCheckmate(P);
02264       }
02265     }
02266     // 詰めろを考える
02267     if ((! my_king_in_check)
02268         && (! (record->threatmate().isThreatmate(P))))
02269     {
02270       Move threatmate_move;
02271 #ifdef CHECKMATE_COUNT
02272       size_t count = this->checkmateSearcher().totalNodeCount();
02273 #endif
02274       this->recorder.gotoCheckmateSearch(this->state(), checkmate_node);
02275       const bool threatmate 
02276         = this->template isThreatmateState<P>
02277         (checkmate_node, threatmate_move, limit >= 1000 + this->rootLimitBias());
02278 #ifdef CHECKMATE_COUNT
02279       root_checkmate += this->checkmateSearcher().totalNodeCount() - count;
02280 #endif
02281       this->recorder.backFromCheckmateSearch();
02282       this->updateCheckmateCount();
02283       if (threatmate)
02284       {
02285         if (record)
02286           record->threatmate().setThreatmate(P, threatmate_move);
02287         if (this->table->verboseLevel() > 1)
02288           std::cerr << "  root threatmate " << threatmate_move << "\n";
02289       }
02290       BOOST_FOREACH(Ptype ptype, PieceStand::order)
02291       {
02292         this->testStop();
02293         if (! this->state().hasPieceOnStand(P, ptype))
02294           continue;
02295         NumEffectState state(this->state().emulateHandPiece(P, alt(P), ptype));
02296         state.setTurn(alt(P));
02297         Move hand_move;
02298         this->template isWinningState<PlayerTraits<P>::opponent>
02299           (*this->checkmate_searcher, state, HashKey(state), PathEncoding(alt(P)),
02300            checkmate_node, hand_move, Move::PASS(P), limit >= 1000 + this->rootLimitBias());
02301       }
02302     }
02303     this->testStop();
02304   }
02305   this->checkmate_searcher->runGC(this->table->isVerbose(),
02306                                   this->lastMemoryUseRatio1000());
02307 #endif
02308   const int ValueNone = window.alpha(P) - EvalTraits<P>::delta;
02309   int best_value = ValueNone;
02310   try {
02311     // first move
02312     size_t i=0;
02313     if (limit >= 1000 && ! moves.empty() && window == fullWindow(P))
02314     {
02315       // try aspiration window if we have sufficient limit
02316       const int root_alpha =
02317         this->rootAlpha(P, this->shared_root->root_values.size() ? this->shared_root->root_values.back() : 0,
02318                         this->eval.progress16());
02319       if (EvalTraits<P>::betterThan(root_alpha, window.alpha(P))) {
02320         const Window window_copy = window;
02321         window.alpha(P) = root_alpha;
02322 #ifndef GPSONE
02323         {
02324           boost::mutex::scoped_lock lk(OslConfig::lock_io);
02325           BOOST_FOREACH(const boost::shared_ptr<SearchMonitor>& monitor,
02326                         this->monitors())
02327             monitor->rootFirstMove(moves[0].move());
02328         }
02329 #endif
02330         const int result = this->template alphaBetaSearch<P>(moves[0], window, true);
02331         if (EvalTraits<P>::betterThan(result, root_alpha))
02332         {
02333           window.alpha(P) = result + EvalTraits<P>::delta;
02334           best_move = moves[0];
02335           best_value = result;
02336           this->updateRootPV(P, std::cerr, result, moves[0].move());
02337           ++i;
02338         } 
02339         else
02340         {
02341           if (this->table->isVerbose())
02342             this->showFailLow(result, moves[0].move());
02343           this->setStable(false);
02344           window = window_copy;
02345         }
02346         this->checkmate_searcher->runGC(this->table->isVerbose(),
02347                                         this->lastMemoryUseRatio1000());
02348       }
02349     }
02350     for (; i<moves.size() && best_value == ValueNone
02351            && window == fullWindow(P); ++i) {
02352       const MoveLogProb& m = moves[i];
02353 #ifndef GPSONE
02354       {
02355         boost::mutex::scoped_lock lk(OslConfig::lock_io);
02356         BOOST_FOREACH(const boost::shared_ptr<SearchMonitor>& monitor,
02357                       this->monitors())
02358           monitor->rootMove(m.move());
02359       }
02360 #endif
02361       const int result = this->template alphaBetaSearch<P>(m, window, true);
02362       if (eval::betterThan(P, result, best_value)) {
02363         window.alpha(P) = result + EvalTraits<P>::delta;
02364         best_move = m;
02365         best_value = result;
02366         this->updateRootPV(P, std::cerr, result, m.move());
02367         if (eval::betterThan(P, result, window.beta(P))) {
02368           assert(! this->isWinValue(alt(P), result));
02369         }
02370       }
02371       else if (result == ValueNone)
02372         this->setStable(false);
02373       this->checkmate_searcher->runGC(this->table->isVerbose(),
02374                                       this->lastMemoryUseRatio1000());
02375     }
02376     // other moves
02377     if (! eval::betterThan(P, window.alpha(P), window.beta(P))) {
02378       this->template examineMovesRoot<P>(moves, i, window, best_move, best_value);
02379     }
02380     if (best_move.isNormal()) {
02381       if (best_value != ValueNone) {
02382         assert(! this->shared_root->last_pv.empty());
02383         assert(best_move.move() == this->shared_root->last_pv.back().pv[0]);
02384       }
02385     }
02386 #ifndef GPSONE
02387     {
02388       boost::mutex::scoped_lock lk(OslConfig::lock_io);
02389       BOOST_FOREACH(const boost::shared_ptr<SearchMonitor>& monitor,
02390                     this->monitors())
02391         monitor->depthFinishedNormally(limit/200);
02392     }
02393 #endif
02394   } catch (std::runtime_error& e) {
02395     if (this->table->isVerbose())
02396       std::cerr << e.what() << "\n";
02397     assert(best_value % 2 == 0);
02398     this->stopNow();
02399     this->restoreRootState();
02400     if (best_value != ValueNone)
02401       record->setLowerBound(P, this->curLimit(), best_move, best_value);
02402     if (best_move.validMove()
02403         && best_move.move() != last_best_move.move()) {
02404       if (this->table->verboseLevel() > 1) {
02405         std::cerr << "! use better move than the last best move\n";
02406         if (best_value != ValueNone) {
02407           assert(! this->shared_root->last_pv.empty() &&
02408                  ! this->shared_root->last_pv.back().pv.empty());
02409           assert(best_move.move() == this->shared_root->last_pv.back().pv[0]);
02410         }
02411       }
02412     }
02413     else {
02414 #ifdef OSL_SMP
02415       if (this->shared)
02416         this->shared->waitAll();
02417 #endif      
02418       throw;
02419     }
02420   }
02421   
02422   assert(best_value % 2 == 0);
02423   if (best_value != ValueNone)
02424     record->setLowerBound(P, this->curLimit(), best_move, best_value);
02425 #ifdef OSL_SMP
02426   if (this->shared)
02427     this->shared->waitAll();
02428 #endif      
02429 #ifndef GPSONE
02430   if (best_value == ValueNone
02431       && this->hasMonitor() && !this->prediction_for_speculative_search) 
02432   {
02433     const double scale = OslConfig::usiOutputPawnValue()*2.0
02434       / this->eval.captureValue(newPtypeO(alt(P),PAWN));
02435     const int value = this->winByCheckmate(alt(P));
02436     BOOST_FOREACH(const boost::shared_ptr<SearchMonitor>& monitor,
02437                   this->monitors())
02438       monitor->showPV(limit/200, this->recorder.allNodeCount(),
02439                       this->elapsed(), static_cast<int>(value*scale), 
02440                       Move::INVALID(), 0, 0, 0, 0);
02441   }
02442 #endif
02443   return best_value;
02444 }
02445 
02446 template <class EvalT>
02447 void osl::search::AlphaBeta2<EvalT>::setRoot(int limit)
02448 {
02449   SearchState2::setRoot(limit);
02450   SimpleHashRecord *record = this->table->allocate(this->currentHash(), std::max(1000,limit));
02451   assert(record);
02452   this->setRootRecord(record);  
02453   this->move_type[this->curDepth()] = base_t::INITIAL;
02454 }
02455 
02456 template <class EvalT>
02457 void osl::search::AlphaBeta2<EvalT>::makeMove(Move move)
02458 {
02459   assert(this->state().isValidMove(move));
02460   SearchState2::makeMove(move);
02461   this->eval.update(this->state(), move);
02462 
02463   SimpleHashRecord *record 
02464     = this->table->allocate(this->currentHash(), this->curLimit());
02465   assert(record);
02466   this->move_type[this->curDepth()] = base_t::INITIAL;
02467   record->setInCheck(this->state().inCheck());
02468   this->setCurrentRecord(record);
02469 }
02470 
02471 template <class EvalT>
02472 bool osl::search::AlphaBeta2<EvalT>::
02473 isReasonableMove(Move /*move*/, int /*pawn_sacrifice*/)
02474 {
02475   return true;
02476 }
02477 
02478 template <class EvalT>
02479 void osl::search::AlphaBeta2<EvalT>::
02480 showNodeDepth(std::ostream& os)
02481 {
02482 #ifndef MINIMAL
02483   int max_depth=0;
02484   for (int i=base_t::MaxDepth-1; i>=0; --i) {
02485     if (base_t::depth_node_count[i] || base_t::depth_node_count_quiesce[i]) {
02486       max_depth = i;
02487       break;
02488     }
02489   }
02490   int max_count=0;
02491   for (int i=0; i<=max_depth; i+=2) {
02492     max_count = std::max(max_count, 
02493                          base_t::depth_node_count[i]+base_t::depth_node_count_quiesce[i]);
02494   }
02495 
02496   int unit = std::max(max_count/79, 100);
02497   for (int i=0; i<=max_depth; i+=2) {
02498     os << std::setw(3) << i << " " 
02499        << std::string(base_t::depth_node_count[i]/unit, '*')
02500        << std::string(base_t::depth_node_count_quiesce[i]/unit, '+')
02501        << std::endl;
02502   }
02503 #  ifdef CHECKMATE_COUNT
02504   std::cerr << "checkmate root " << root_checkmate << " quiesce " << quiesce_checkmate
02505             << "\nnormal before " << checkmate_before 
02506             << " after " << checkmate_after << " threatmate " << count_threatmate
02507             << "\n";
02508 # endif
02509 #endif
02510 }
02511 
02512 template <class EvalT>
02513 void osl::search::AlphaBeta2<EvalT>::
02514 clearNodeDepth()
02515 {
02516 #ifndef MINIMAL
02517   base_t::depth_node_count.fill(0);
02518   base_t::depth_node_count_quiesce.fill(0);
02519 #endif
02520 }
02521 
02522 namespace osl
02523 {
02524   namespace search
02525   {
02526 #ifndef MINIMAL
02527     template class AlphaBeta2<eval::ProgressEval>;
02528     template class AlphaBeta2Tree<eval::ProgressEval>;
02529     template
02530     void AlphaBeta2Tree<eval::ProgressEval>::examineMovesRoot<BLACK>(const MoveLogProbVector&, size_t, Window, MoveLogProb&, int&);
02531     template
02532     void AlphaBeta2Tree<eval::ProgressEval>::examineMovesRoot<WHITE>(const MoveLogProbVector&, size_t, Window, MoveLogProb&, int&);
02533 #endif
02534     template class AlphaBeta2<eval::ml::OpenMidEndingEval>;
02535     template class AlphaBeta2Tree<eval::ml::OpenMidEndingEval>;
02536     template
02537     void AlphaBeta2Tree<eval::ml::OpenMidEndingEval>::examineMovesRoot<BLACK>(const MoveLogProbVector&, size_t, Window, MoveLogProb&, int&);
02538     template
02539     void AlphaBeta2Tree<eval::ml::OpenMidEndingEval>::examineMovesRoot<WHITE>(const MoveLogProbVector&, size_t, Window, MoveLogProb&, int&);
02540   }
02541 }
02542 
02543 /* ------------------------------------------------------------------------- */
02544 // ;;; Local Variables:
02545 // ;;; mode:c++
02546 // ;;; c-basic-offset:2
02547 // ;;; End:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines