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   bool already_split = false;
00720 #  endif
00721 #endif
00722 
00723   // the first move
00724   MoveLogProb m = nextMove<P>();
00725   ++tried_moves;
00726   if (! m.validMove() || m.logProb() > curLimit()) {
00727     goto move_generation_failure;
00728   }
00729 #if (defined OSL_SMP) && (! defined OSL_SMP_NO_SPLIT_INTERNAL)
00730   int first_move_node;
00731 #endif
00732   {
00733 #if (defined OSL_SMP) && (! defined OSL_SMP_NO_SPLIT_INTERNAL)
00734     const int previous_node_count = nodeCount();
00735 #endif
00736     assert(eval::betterThan(P, w.alpha(P), best_value));
00737     const int result = alphaBetaSearch<P>(m, w, in_pv);
00738     if (eval::betterThan(P, result, best_value)) {
00739       best_value = result;
00740       best_move = m;
00741       if (eval::betterThan(P, best_value, w.alpha(P))) {
00742         w.alpha(P) = result + EvalTraits<P>::delta;;
00743         assert(best_move.validMove());
00744         ++alpha_update;
00745         last_alpha_update = 1;
00746         if (eval::betterThan(P, result, w.beta(P))) {
00747           mpn_cut.add(tried_moves);
00748           if (this->move_type[this->curDepth()] >= common_t::ALL) {
00749             setKillerMove(best_move.move());
00750             if (best_move.isNormal()
00751                 && ! best_move.move().isCapture())
00752             {
00753               const int d = (curLimit()+200)/100;
00754               this->historyTable().add(best_move.move(), d*d);
00755             }
00756           }
00757           assert(best_move.validMove());
00758           assert(! this->isWinValue(alt(P), best_value));
00759           goto register_table;
00760         } else {
00761           if (in_pv) 
00762             makePV(m.move());
00763         }
00764       }
00765     }
00766 #if (defined OSL_SMP) && (! defined OSL_SMP_NO_SPLIT_INTERNAL)
00767     first_move_node = nodeCount() - previous_node_count;
00768 #endif
00769   }
00770   testStop();
00771 
00772 #ifndef DONT_USE_CHECKMATE
00773   if (in_pv)
00774   {
00775     Move checkmate_move;
00776     if (tryCheckmate<P>(record, in_pv, checkmate_move)) {
00777       assert(checkmate_move.isValid());
00778       best_value= this->winByCheckmate(P);
00779       this->recordWinByCheckmate(P, record, checkmate_move);
00780       return best_value;
00781     }
00782   }
00783 #endif
00784   search_assert(w.isConsistent(), lastMove());
00785   if (curLimit() < this->leafLimit())
00786     goto move_generation_failure;
00787   while (true) {
00788 #if (defined OSL_SMP) && (! defined OSL_SMP_NO_SPLIT_INTERNAL)
00789     const bool prefer_split = shared && curLimit() >= shared->split_min_limit
00790       && (curLimit() >= 600+this->rootLimitBias()
00791           // || (curLimit() >= 400 && this->curDepth() < 2)
00792           || (first_move_node >= 30000));
00793     try {
00794       if (prefer_split) {
00795         int cur_smp_idle; 
00796         {
00797 # ifdef OSL_USE_RACE_DETECTOR
00798           boost::mutex::scoped_lock lk(shared->lock_smp);
00799 #endif
00800           cur_smp_idle = shared->smp_idle;
00801         }
00802         if (cur_smp_idle > last_smp_idle) {
00803           last_smp_idle = cur_smp_idle;
00804           assert(! already_split);
00805           already_split = true;
00806           if (examineMovesOther<P>(w, best_move, best_value, tried_moves,
00807                                    alpha_update, last_alpha_update)) {
00808             assert(best_move.validMove());
00809             assert(best_move.player() == P);
00810             if (this->move_type[this->curDepth()] >= common_t::ALL) {
00811               setKillerMove(best_move.move());
00812               if (best_move.isNormal()
00813                   && ! best_move.move().isCapture())
00814               {
00815                 const int d = (curLimit()+200)/100;
00816                 this->historyTable().add(best_move.move(), d*d);
00817               }
00818             }
00819             mpn_cut.add(tried_moves);    
00820             goto register_table;
00821           }
00822           goto all_moves_done;
00823         }
00824       }
00825     }
00826     catch(AlphaBeta2ParallelCommon::SplitFailed&) {
00827       already_split = false;
00828       // fall through
00829     }
00830 #endif
00831     MoveLogProb m = nextMove<P>(); 
00832     if (! m.validMove())
00833       break;
00834     ++tried_moves;
00835 
00836     assert(eval::betterThan(P, w.alpha(P), best_value));
00837     const int result = alphaBetaSearch<P>(m, w, in_pv && ! best_move.validMove());
00838     if (eval::betterThan(P, result, best_value)) {
00839       best_value = result;
00840       best_move = m;
00841       if (eval::betterThan(P, best_value, w.alpha(P))) {
00842         w.alpha(P) = result + EvalTraits<P>::delta;;
00843         assert(best_move.validMove());
00844         ++alpha_update;
00845         last_alpha_update = tried_moves;
00846         if (eval::betterThan(P, result, w.beta(P))) {
00847           assert(best_move.validMove());
00848           if (this->move_type[this->curDepth()] >= common_t::ALL) {
00849             setKillerMove(best_move.move());
00850             if (best_move.isNormal()
00851                 && ! best_move.move().isCapture())
00852             {
00853               const int d = (curLimit()+200)/100;
00854               this->historyTable().add(best_move.move(), d*d);
00855             }
00856           }
00857           mpn_cut.add(tried_moves);
00858           goto register_table;
00859         } else {
00860           if (in_pv)
00861             makePV(m.move());
00862         }
00863       }
00864     }
00865   }
00866 #if (defined OSL_SMP) && (! defined OSL_SMP_NO_SPLIT_INTERNAL)
00867 all_moves_done:
00868 #endif
00869   if (tried_moves == 1 && tryPass(record, P)) {
00870     // goto quiescence search if tried move is only null move
00871     goto move_generation_failure;
00872   }
00873   mpn.add(tried_moves);
00874   if (alpha_update) {
00875     this->alpha_update.add(alpha_update);
00876     this->last_alpha_update.add(last_alpha_update);
00877   }
00878   // 宣言勝
00879   if (((this->curDepth() % 2) == 0 || OslConfig::usiMode())
00880       && EnterKing::canDeclareWin<P>(state())) {
00881     best_value = this->brinkmatePenalty(alt(P), std::max(1,16-this->curDepth())*256)
00882       + this->eval.value();
00883     record->setAbsoluteValue(Move::DeclareWin(), best_value,
00884                              SearchTable::CheckmateSpecialDepth);
00885     return best_value;
00886   }
00887   if (record) {
00888     // もう一度,相手を詰ますことを考える
00889 #ifndef DONT_USE_CHECKMATE
00890     Move checkmate_move=Move::INVALID();
00891     if (tryCheckmateAgain<P>(record, checkmate_move, 
00892                              nodeCount() - node_count_at_beginning,
00893                              best_value)) {
00894       assert(checkmate_move.isValid());
00895       best_value= this->winByCheckmate(P);
00896       this->recordWinByCheckmate(P, record, checkmate_move);
00897       return best_value;
00898     }
00899 #endif
00900   }
00901 register_table:
00902   assert(best_value == this->minusInfty(P) || best_move.validMove());
00903   assert(eval::isConsistentValue(best_value));
00904   if (this->isWinValue(alt(P), best_value))
00905   {
00906     // TODO: 直前の着手が(やけくそ)王手の連続だった場合
00907     // 必死ではなくて詰扱いの方が良い可能性はある
00908     best_value = this->brinkmatePenalty(P, std::max(1,16-this->curDepth())*256) + this->eval.value();
00909 
00910     // (この深さでは)上限==下限
00911     record->setAbsoluteValue(best_move, best_value, curLimit());
00912     return best_value;
00913   }
00914   else if (EvalTraits<P>::betterThan(w.alpha(P), initial_alpha)) {
00915     if (best_move.validMove()) {
00916       assert(best_value % 2 == 0);
00917       record->setLowerBound(P, curLimit(), best_move, best_value);
00918     }
00919   }
00920   if (EvalTraits<P>::betterThan(w.beta(P), best_value)) {
00921     if (best_move.validMove())
00922       record->setUpperBound(P, curLimit(), best_move, best_value);
00923   }
00924   return best_value;
00925 move_generation_failure:
00926   pv[this->curDepth()].clear();
00927   // 手を生成できなかった
00928   // limit が 200 未満だった場合と,以上だったが move generator が limit 以下の手を生成できなかった場合ここに来る
00929   best_value = quiesce<P>(w);
00930   if (record)
00931   {
00932     if (EvalTraits<P>::betterThan(best_value, initial_alpha)) {
00933       if (EvalTraits<P>::betterThan(w.beta(P), best_value)) {
00934         record->setAbsoluteValue(MoveLogProb(), best_value, curLimit());
00935       } else {
00936         record->setLowerBound(P, curLimit(), MoveLogProb(), best_value);
00937       }
00938     }
00939     else 
00940     {
00941       assert(EvalTraits<P>::betterThan(w.beta(P), best_value));
00942       record->setUpperBound(P, curLimit(), MoveLogProb(), best_value);
00943     }
00944   }
00945   assert(eval::isConsistentValue(best_value));
00946   return best_value;
00947 }
00948 
00949 template <class EvalT>
00950 template <osl::Player P>
00951 int osl::search::AlphaBeta2Tree<EvalT>::
00952 quiesce(Window w)
00953 {
00954 #ifdef EXPERIMENTAL_QUIESCE
00955   return quiesceExp<P>(w);
00956 #else
00957   return quiesceStable<P>(w);
00958 #endif
00959 }
00960 
00961 template <class EvalT>
00962 template <osl::Player P>
00963 int osl::search::AlphaBeta2Tree<EvalT>::
00964 quiesceStable(Window w)
00965 {
00966   testStop();
00967   initPV();
00968   
00969   typedef QuiescenceSearch2<eval_t> qsearcher_t;
00970   qsearcher_t qs(*this, *this->table);
00971   Move last_move = lastMove();
00972   if (last_move.isInvalid())
00973     last_move = Move::PASS(alt(P));
00974   assert(w.alpha(P) % 2);
00975   assert(w.beta(P) % 2);
00976 #ifdef CHECKMATE_COUNT
00977   size_t count = checkmateSearcher().totalNodeCount();
00978 #endif
00979   const int result = qs.template search<P>(w.alpha(P), w.beta(P), this->eval, last_move, 4);
00980   node_count += qs.nodeCount();
00981   this->recorder.addQuiescenceCount(qs.nodeCount());
00982 #ifdef CHECKMATE_COUNT
00983   quiesce_checkmate += checkmateSearcher().totalNodeCount() - count;
00984 #endif
00985 
00986   assert(result % 2 == 0);
00987   return result;
00988 }
00989 
00990 template <class EvalT>
00991 template <osl::Player P>
00992 int osl::search::AlphaBeta2Tree<EvalT>::
00993 quiesceExp(Window w)
00994 {
00995   testStop();
00996 
00997   SimpleHashRecord *record = lastRecord();
00998   assert(record);
00999   Move best_move;
01000   const int qdepth = 4;
01001   const int previous_node_count = nodeCount();
01002 
01003   int result =
01004     quiesceRoot<P>(w, qdepth, best_move, record->threatmate());
01005   
01006   const size_t qnode = nodeCount() - previous_node_count;
01007   this->recorder.addQuiescenceCount(qnode);
01008   record->qrecord.setLowerBound(qdepth, result, best_move);
01009   return result;
01010 }
01011 
01012 template <class EvalT>
01013 template <osl::Player P>
01014 struct osl::search::AlphaBeta2Tree<EvalT>::NextQMove
01015 {
01016   AlphaBeta2Tree *searcher;
01017   Window window;
01018   const int depth;
01019   int *result;
01020   DualThreatmateState threatmate;
01021   NextQMove(AlphaBeta2Tree *s, Window w, int d, int *r,
01022             DualThreatmateState t)
01023     : searcher(s), window(w), depth(d), result(r), threatmate(t) {
01024   }
01025   void operator()(Square /*last_to*/) {
01026     searcher->eval.update(searcher->state(), searcher->lastMove());
01027     *result = 
01028       searcher->quiesce<P>(window, depth, threatmate);
01029   }
01030 };
01031 
01032 template <class EvalT>
01033 template <osl::Player P>
01034 bool osl::search::AlphaBeta2Tree<EvalT>::
01035 quiesceWithMove(Move move, Window& w, int depth_left, Move& best_move, int& best_value, 
01036                 const DualThreatmateState& threatmate)
01037 {
01038   // TODO: futility margin
01039   const bool in_pv = ! w.null();
01040   int result;
01041   typedef NextQMove<PlayerTraits<P>::opponent> next_t;
01042   next_t helper(this, w, depth_left, &result, threatmate);
01043 
01044   const HashKey new_hash = currentHash().newHashWithMove(move);
01045   const eval_t old_eval = this->eval;
01046   doUndoMoveOrPass<P,next_t>(new_hash, move, helper);
01047   this->eval = old_eval;
01048 
01049   if (eval::betterThan(P, result, best_value)) {
01050     best_value = result;
01051     best_move = move;
01052     if (eval::betterThan(P, best_value, w.alpha(P))) {
01053       w.alpha(P) = result + EvalTraits<P>::delta;
01054       if (in_pv)
01055         makePV(best_move);
01056       if (eval::betterThan(P, result, w.beta(P))) {
01057         return true;
01058       }
01059     }
01060   }
01061   return false;
01062 }
01063 
01064 template <class EvalT>
01065 template <osl::Player P>
01066 int osl::search::AlphaBeta2Tree<EvalT>::
01067 quiesceRoot(Window w, int depth_left, Move& best_move, DualThreatmateState threatmate)
01068 {
01069   assert(! state().inCheck(alt(P)));
01070 
01071   initPV();
01072   // depth_node_count_quiesce[this->curDepth()]++;
01073   // ++node_count;
01074 
01075   SimpleHashRecord& record = *lastRecord();
01076   assert(record.inCheck() == state().inCheck());
01077   assert(depth_left > 0);
01078   
01079   int best_value = this->minusInfty(P);
01080   // stand pat 
01081   if (! record.inCheck()) {
01082     if (! threatmate.maybeThreatmate(P)) {
01083       best_value = this->eval.value();
01084     } else {
01085       const int value = this->eval.value() + this->threatmatePenalty(P);
01086       best_value = EvalTraits<P>::max(best_value, value);
01087     }
01088     best_move = Move::PASS(P);
01089     if (EvalTraits<P>::betterThan(best_value, w.alpha(P))) {
01090       if (EvalTraits<P>::betterThan(best_value, w.beta(P)))
01091         return best_value;
01092       w.alpha(P) = best_value + EvalTraits<P>::delta;
01093     }
01094   }
01095 
01096   Move prev_best = record.qrecord.bestMove();
01097   MoveGenerator& generator = makeGenerator();
01098   generator.init(200, &record, this->eval, state(), 
01099                  w.alpha(P) == w.beta(P),
01100                  prev_best, true);
01101   int tried_moves = 0;
01102   // previous 最善手を試す
01103   if (prev_best.isNormal()) {
01104     ++tried_moves;
01105     if (quiesceWithMove<P>(prev_best, w, depth_left-1, best_move, best_value,
01106                            threatmate))
01107       goto finish;
01108   }
01109 
01110 
01111   // captures or king escape
01112   for (MoveLogProb m = generator.nextTacticalMove<P>(*this); 
01113        m.validMove(); m = generator.nextTacticalMove<P>(*this)) {
01114     ++tried_moves;
01115     if (quiesceWithMove<P>(m.move(), w, depth_left-1, best_move, best_value,
01116                            threatmate))
01117       goto finish;
01118   } 
01119   for (MoveLogProb m = generator.nextMove<P>(*this); 
01120        m.validMove(); m = generator.nextMove<P>(*this)) {
01121     ++tried_moves;
01122     if (quiesceWithMove<P>(m.move(), w, depth_left-1, best_move, best_value,
01123                            threatmate))
01124       goto finish;
01125   } 
01126 
01127   // pawn drop foul?
01128   if (record.inCheck()) {
01129     if (tried_moves == 0) {
01130       if (lastMove().isNormal() && lastMove().ptype() == PAWN && lastMove().isDrop())
01131         return this->winByFoul(P);
01132       return this->winByCheckmate(alt(P));
01133     }
01134     goto finish;
01135   }  
01136 finish:
01137   return best_value;
01138 }
01139 
01140 template <class EvalT>
01141 template <osl::Player P>
01142 int osl::search::AlphaBeta2Tree<EvalT>::
01143 quiesce(Window w, int depth_left, DualThreatmateState parent_threatmate)
01144 {
01145   if (state().inCheck(alt(P))) {
01146     return this->minusInfty(alt(P));
01147   }
01148 
01149   initPV();
01150 #ifndef MINIMAL
01151   depth_node_count_quiesce[this->curDepth()]++;
01152 #endif
01153   ++node_count;
01154 
01155   SimpleHashRecord record;
01156   record.setInCheck(state().inCheck());
01157 
01158   DualThreatmateState threatmate;
01159   threatmate.updateInLock(P, &parent_threatmate, record.inCheck());
01160 
01161   int best_value = this->minusInfty(P);
01162   // TODO: 玉の回りのtakeback延長
01163   if (depth_left <= 0) {
01164     if (record.inCheck()) {
01165       if (lastMove().isCapture())
01166         depth_left +=2;
01167       else
01168         depth_left = 0;
01169     }
01170     else if (threatmate.maybeThreatmate(P)) {
01171       if (threatmate.mayHaveCheckmate(alt(P))) {
01172         Move checkmate_move;
01173         bool win = isWinningState<P>(10, checkmate_move);
01174         if (win)
01175           return this->winByCheckmate(P);
01176       }
01177       return this->eval.value() + this->threatmatePenalty(P);
01178     }
01179     else {
01180       if (threatmate.mayHaveCheckmate(alt(P)))
01181         return this->eval.value() + this->threatmatePenalty(alt(P));
01182       if (ImmediateCheckmate::hasCheckmateMove<P>(state()))
01183         return this->winByCheckmate(P);
01184       if (ImmediateCheckmate::hasCheckmateMove<PlayerTraits<P>::opponent>(state()))
01185         return this->eval.value() + this->threatmatePenalty(P);
01186       return this->eval.value();
01187     }
01188   }
01189 
01190   if (! record.inCheck()) {
01191     if (ImmediateCheckmate::hasCheckmateMove<P>(state())) {
01192       return this->winByCheckmate(P);
01193     }
01194   }
01195   if (threatmate.mayHaveCheckmate(alt(P))) {
01196     Move checkmate_move;
01197     bool win = isWinningState<P>(10, checkmate_move);
01198     if (win)
01199       return this->winByCheckmate(P);
01200   }
01201   MoveGenerator& generator = makeGenerator();
01202   generator.init(200, &record, this->eval, state(), 
01203                  w.alpha(P) == w.beta(P),
01204                  Move(), true);
01205   int tried_moves = 0;
01206   Move best_move;
01207   // stand pat
01208   if (! record.inCheck()) {
01209     if (! threatmate.maybeThreatmate(P)) {
01210       best_value = this->eval.value();
01211     } else {
01212       const int value = this->eval.value() + this->threatmatePenalty(P);
01213       best_value = EvalTraits<P>::max(best_value, value);
01214     }
01215     best_move = Move::PASS(P);
01216     if (EvalTraits<P>::betterThan(best_value, w.alpha(P))) {
01217       if (EvalTraits<P>::betterThan(best_value, w.beta(P)))
01218         return best_value;
01219       w.alpha(P) = best_value + EvalTraits<P>::delta;
01220     }
01221   }
01222 
01223   // captures or king escape
01224   for (MoveLogProb m = generator.nextTacticalMove<P>(*this); 
01225        m.validMove(); m = generator.nextTacticalMove<P>(*this)) {
01226     ++tried_moves;
01227     if (quiesceWithMove<P>(m.move(), w, depth_left-1, best_move, best_value,
01228                            threatmate))
01229       goto finish;
01230   } 
01231   for (MoveLogProb m = generator.nextMove<P>(*this); 
01232        m.validMove(); m = generator.nextMove<P>(*this)) {
01233     ++tried_moves;
01234     if (quiesceWithMove<P>(m.move(), w, depth_left-1, best_move, best_value,
01235                            threatmate))
01236       goto finish;
01237   } 
01238 
01239   // pawn drop foul?
01240   if (record.inCheck()) {
01241     if (tried_moves == 0) {
01242       if (lastMove().ptype() == PAWN && lastMove().isDrop()) 
01243         return this->winByFoul(P);
01244       return this->winByCheckmate(alt(P));
01245     }
01246     goto finish;
01247   }  
01248 finish:
01249   return best_value;
01250 }
01251 
01252 template <class EvalT>
01253 void osl::search::AlphaBeta2Tree<EvalT>::updateCheckmateCount()
01254 {
01255 #ifdef OSL_SMP
01256   if (shared) {
01257     this->recorder.setCheckmateCount(shared->checkmateCount());
01258     return;
01259   }
01260 #endif
01261   this->recorder.setCheckmateCount
01262     (checkmateSearcher().totalNodeCount());
01263 }
01264 
01265 template <class EvalT>
01266 int 
01267 osl::search::AlphaBeta2Tree<EvalT>::
01268 rootAlpha(Player P, int last_value, Progress16 progress)
01269 {
01270   int pawns = 3;
01271   if (eval::betterThan(P, last_value, eval_t::captureValue(newPtypeO(alt(P),KING))))
01272   {
01273     pawns = 10;
01274   }
01275   else if (progress.value() <= 1)
01276   {
01277     pawns = 3;
01278   }
01279   else if (progress.value() <= 7)
01280   {
01281     pawns = 4;
01282   }
01283   else if (progress.value() <= 9)
01284   {
01285     pawns = 5;
01286   }
01287   else if (progress.value() <= 10)
01288   {
01289     pawns = 6;
01290   }
01291   else
01292   {
01293     pawns = 7;
01294   }
01295   const int width = eval_t::captureValue(newPtypeO(alt(P),PAWN))*pawns/2;
01296   return last_value - width - eval::delta(P);
01297 }
01298 
01299 template <class EvalT>
01300 int 
01301 osl::search::AlphaBeta2Tree<EvalT>::
01302 stableThreshold(Player P, int last_value)
01303 {
01304   int pawns = 3;
01305   if (eval::betterThan(P, last_value, eval_t::captureValue(newPtypeO(alt(P),KING))))
01306     pawns = 10;
01307   else if (eval::betterThan(P, eval_t::captureValue(newPtypeO(alt(P),PAWN))*2, last_value)
01308            && eval::betterThan(P, last_value, eval_t::captureValue(newPtypeO(P,PAWN))*2))
01309     pawns = 2;
01310   const int width = eval_t::captureValue(newPtypeO(alt(P),PAWN))*pawns/2;
01311   return last_value - width - eval::delta(P);
01312 }
01313 
01314 template <class EvalT>
01315 void osl::search::AlphaBeta2Tree<EvalT>::
01316 updateRootPV(Player P, std::ostream& os, int result, Move m)
01317 {
01318   boost::mutex::scoped_lock lk(OslConfig::lock_io);
01319   this->makePV(m);
01320   const int last_root_value = shared_root->root_values_for_iteration.size() ? shared_root->root_values_for_iteration.back() : 0;
01321   const int threshold = stableThreshold(P, last_root_value);
01322   bool new_stable = eval::betterThan(P, result, threshold);
01323   shared_root->last_root_value_update = result;
01324 
01325   if (new_stable && m != shared_root->last_root_move
01326       && (See::see(state(), m) < -eval::Ptype_Eval_Table.value(KNIGHT)*2
01327           || eval::betterThan(P, result, eval_t::captureValue(newPtypeO(alt(P),KING))))) {
01328     new_stable = false;
01329   }
01330   if (new_stable && shared_root->root_values_for_iteration.size() > 1) {
01331     const int last_root_value2 = shared_root->root_values_for_iteration[shared_root->root_values_for_iteration.size()-2];
01332     const int threshold2 = stableThreshold(P, last_root_value2);
01333     if (eval::betterThan(P, threshold2, result)
01334         && eval::betterThan(P, last_root_value2, last_root_value))
01335       new_stable = false;
01336   }
01337   this->shared_root->last_pv.push_back(RootPV(root_limit, pv[0], result));
01338   this->setStable(new_stable);
01339 #ifndef GPSONE
01340   if (this->hasMonitor() && !this->prediction_for_speculative_search) {
01341     const double scale = OslConfig::usiOutputPawnValue()*2.0
01342       / eval_t::captureValue(newPtypeO(alt(P),PAWN));
01343     BOOST_FOREACH(const boost::shared_ptr<SearchMonitor>& monitor,
01344                   this->monitors())
01345       monitor->showPV(root_limit/200, this->recorder.allNodeCount(),
01346                      this->elapsed(), static_cast<int>(result*scale), 
01347                      m, &*pv[0].begin(), &*pv[0].end());
01348   }
01349 #endif
01350   if (this->table->isVerbose()) {
01351     showPV(os, result, m, new_stable ? ' ' : '*');
01352   }
01353 }
01354 
01355 template <class EvalT>
01356 void osl::search::AlphaBeta2Tree<EvalT>::
01357 addMultiPV(Player P, int result, Move m)
01358 {
01359   boost::mutex::scoped_lock lk(OslConfig::lock_io);
01360   this->makePV(m);
01361   this->shared_root->last_pv.push_back(RootPV(root_limit, pv[0], result));
01362   std::swap(*this->shared_root->last_pv.rbegin(), *(this->shared_root->last_pv.rbegin()+1));
01363 
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     BOOST_FOREACH(const boost::shared_ptr<SearchMonitor>& monitor,
01368                   this->monitors())
01369       monitor->showPV(root_limit/200, this->recorder.allNodeCount(),
01370                      this->elapsed(), static_cast<int>(result*scale), 
01371                      m, &*pv[0].begin(), &*pv[0].end());
01372   }
01373 
01374   if (this->table->isVerbose()) {
01375     showPV(std::cerr, result, m, '&');
01376   }
01377 }
01378 
01379 template <class EvalT>
01380 void osl::search::AlphaBeta2Tree<EvalT>::
01381 showFailLow(int result, Move m) const
01382 {
01383   if (this->root_ignore_moves)
01384     std::cerr << "[" << this->root_ignore_moves->size() << "] ";
01385   std::cerr << " <" << std::setfill(' ') << std::setw(5) 
01386             << static_cast<int>(result*200.0/this->eval.captureValue(newPtypeO(WHITE,PAWN)))
01387             << " " << record::csa::show(m) << "\n";
01388 }
01389 
01390 template <class EvalT>
01391 void osl::search::AlphaBeta2Tree<EvalT>::
01392 showPV(std::ostream& os, int result, Move m, char stable_char) const
01393 {
01394   assert(m.isNormal()); // do not pass at root
01395   if (this->root_ignore_moves)
01396     os << "[" << this->root_ignore_moves->size() << "] ";
01397   os << stable_char;
01398   os << " " << std::setfill(' ') << std::setw(5) 
01399      << static_cast<int>(result*200.0/this->eval.captureValue(newPtypeO(WHITE,PAWN))) << " ";
01400   BOOST_FOREACH(Move m, pv[0]) {
01401     os << record::csa::show(m);
01402   }
01403   const double elapsed = this->elapsed();
01404   if (elapsed > 1.0)
01405     os << " (" << elapsed << "s, " << OslConfig::memoryUseRatio()*100.0 << "%)";
01406   os << std::endl;
01407 #ifndef MINIMAL
01408 #ifndef _WIN32
01409   if (! OslConfig::usiMode())
01410   {
01411     NumEffectState state = this->state();
01412     std::string str; str.reserve(200); str = "        ";
01413     for (size_t i=0; i<pv[0].size(); ++i) {
01414       str += record::ki2::show(pv[0][i], state, i ? pv[0][i-1] : Move());
01415       state.makeMove(pv[0][i]);
01416 
01417       // threatmate?
01418       const SimpleHashRecord *record
01419         = this->table->find(HashKey(state));
01420       if (record && 
01421           record->threatmate().isThreatmate(state.turn()))
01422         str += "(" + record::K_TSUMERO + ")";
01423     }
01424     std::string converted = IconvConvert::eucToLang(str);
01425     if (! converted.empty())
01426       os << converted << std::endl;
01427   }
01428 #endif
01429 #endif
01430 
01431 #ifdef DEBUG_PV
01432   NumEffectState s = state();
01433   for (size_t i=0; i<pv[0].size(); ++i) {
01434     if (! pv[0][i].isPass() && ! s.isValidMove(pv[0][i])) {
01435       std::cerr << "root pv error " << pv[0][i] << " " << i << "\n";
01436       break;
01437     }
01438     ApplyMoveOfTurn::doMove(s, pv[0][i]);
01439   }
01440 #endif
01441 }
01442 
01443 template <class EvalT>
01444 template <osl::Player P>
01445 struct osl::search::AlphaBeta2Tree<EvalT>::NextMove
01446 {
01447   AlphaBeta2Tree *searcher;
01448   const MoveLogProb& moved;
01449   Window window;
01450   int *result;
01451   bool in_pv;
01452   NextMove(AlphaBeta2Tree *s, const MoveLogProb& md, Window w, int *r,
01453            bool p)
01454     : searcher(s), moved(md), window(w), result(r), in_pv(p) {
01455     assert(P == md.player());
01456   }
01457   void operator()(Square /*last_to*/) {
01458 #ifndef NDEBUG
01459     const int cur_limit = searcher->curLimit();
01460 #endif
01461     *result = 
01462       searcher->alphaBetaSearchAfterMove<P>(moved, window, in_pv);
01463     assert(cur_limit == searcher->curLimit() || searcher->SearchState2Core::abort());
01464   }
01465 };
01466 
01467 template <class EvalT>
01468 template <osl::Player P>
01469 int osl::search::AlphaBeta2Tree<EvalT>::
01470 alphaBetaSearch(const MoveLogProb& search_move, Window w, bool in_pv)
01471 {
01472   assert(w.alpha(P) % 2);
01473   assert(w.beta(P) % 2);
01474   const Move move = search_move.move();
01475   assert(P == move.player());
01476   assert(P == state().turn());
01477   assert(eval::notLessThan(P, w.beta(P), w.alpha(P)));
01478 
01479   testStop();
01480   pv[curDepth()+1].clear();
01481   // TODO: more efficient way to find foul
01482   if (! move.isPass() ){
01483     if(MoveStackRejections::probe<P>(state(),history(),curDepth(),move,w.alpha(P),repetitionCounter().checkCount(alt(P)))){
01484       return this->winByLoop(alt(P));
01485     }
01486     if (move_classifier::MoveAdaptor<move_classifier::PawnDropCheckmate<P> >
01487         ::isMember(state(), move))
01488       return this->winByFoul(alt(P));
01489   }
01490 
01491   const HashKey new_hash = currentHash().newHashWithMove(move);
01492   assert(P == move.player());
01493 
01494   if (move.isPass())
01495     this->pass_count.inc(P);
01496 
01497   // 千日手確認
01498   if (! this->pass_count.loopByBothPass()) {
01499     const Sennichite next_sennichite
01500       = repetition_counter.isAlmostSennichite(new_hash);
01501     if (next_sennichite.isDraw())
01502       return this->drawValue();
01503     if (next_sennichite.hasWinner())
01504       return this->winByFoul(next_sennichite.winner());
01505     assert(next_sennichite.isNormal());
01506   }
01507   
01508   if (! move.isPass()) {
01509     // 優越関係確認
01510     const DominanceCheck::Result has_dominance
01511       = DominanceCheck::detect(repetition_counter.history(), new_hash);
01512     if (has_dominance == DominanceCheck::LOSE)
01513       return this->winByLoop(alt(P));
01514     if (has_dominance == DominanceCheck::WIN)
01515       return this->winByLoop(P);
01516     // 連続王手駒捨て
01517     if (! move.isCapture()) {
01518       const int sacrifice_count = countSacrificeCheck2(this->curDepth());
01519       if (sacrifice_count == 2) {
01520         // 3回目は指さない
01521         const Square to = move.to();
01522         int offence = state().countEffect(P, to) + (move.isDrop() ? 1 : 0);
01523         const int deffense = state().hasEffectAt(alt(P), to); // max1
01524         if (offence <= deffense)
01525           offence += AdditionalEffect::count2(state(), to, P);
01526         if (offence <= deffense) {
01527           return this->winByLoop(alt(P));
01528         }
01529       }
01530     }
01531   }
01532   // 探索
01533   int result;
01534   NextMove<P> helper(this, search_move, w, &result, in_pv);
01535 
01536   this->recorder.addNodeCount();  
01537   const eval_t old_eval = this->eval;
01538   doUndoMoveOrPass<P,NextMove<P> >(new_hash, move, helper);
01539   this->eval = old_eval;
01540   if (move.isPass())
01541     this->pass_count.dec(P);
01542 
01543   return result;
01544 }
01545 
01546 template <class EvalT>
01547 template <osl::Player P>
01548 void osl::search::AlphaBeta2Tree<EvalT>::
01549 examineMovesRoot(const MoveLogProbVector& moves, size_t i, Window window,
01550                  MoveLogProb& best_move, int& best_value)
01551 {
01552   for (;i<moves.size(); ++i) {
01553     testStop();
01554 
01555 #if (defined OSL_SMP) && (! defined OSL_SMP_NO_SPLIT_ROOT)
01556     if (shared && i > 8
01557         && moves.size() > i+1) {
01558       int smp_idle;
01559       {
01560 #  ifdef OSL_USE_RACE_DETECTOR
01561         boost::mutex::scoped_lock lk(shared->lock_smp);
01562 #  endif
01563         smp_idle = shared->smp_idle;
01564       }
01565       if (smp_idle) {
01566         try {
01567           examineMovesRootPar<P>(moves, i, window, best_move, best_value);
01568           break;
01569         } catch (AlphaBeta2ParallelCommon::SplitFailed&) {
01570         }
01571       }
01572     }
01573 #endif
01574 
01575     const MoveLogProb& m = moves[i];
01576 #ifndef GPSONE
01577     if (this->elapsed() > 1.0)
01578     {
01579       boost::mutex::scoped_lock lk(OslConfig::lock_io);
01580       BOOST_FOREACH(const boost::shared_ptr<SearchMonitor>& monitor,
01581                     this->monitors())
01582         monitor->rootMove(m.move());
01583     }
01584     if (this->multi_pv) {
01585       int width = this->multi_pv*this->eval.captureValue(newPtypeO(P, PAWN))/200;
01586       if (width % 2 == 0) 
01587         width -= EvalTraits<P>::delta;
01588       window.alpha(P) = best_value + width;
01589     }
01590 #endif
01591     const int result = alphaBetaSearch<P>(m, window, false);
01592     if (eval::betterThan(P, result, best_value)) 
01593     {
01594       window.alpha(P) = result + EvalTraits<P>::delta;
01595       best_move = m;
01596       best_value = result;
01597       updateRootPV(P, std::cerr, result, m.move());
01598       if (eval::betterThan(P, result, window.beta(P))) {
01599         assert(! this->isWinValue(alt(P), result));
01600         break;
01601       }
01602     } 
01603 #ifndef GPSONE
01604     else if (this->multi_pv && eval::betterThan(P, result, window.alpha(P)))
01605     {
01606       addMultiPV(P, result, m.move());
01607     }
01608 #endif
01609     if (this->root_limit >= 1600)
01610       this->checkmate_searcher->runGC(this->table->isVerbose(),
01611                                       lastMemoryUseRatio1000());
01612   }
01613 }
01614 
01615 /* ------------------------------------------------------------------------- */
01616 
01617 template <class EvalT>
01618 osl::search::AlphaBeta2<EvalT>::
01619 AlphaBeta2(const NumEffectState& s, checkmate_t& c, 
01620            SimpleHashTable *t, CountRecorder& r)
01621   : AlphaBeta2Tree<EvalT>(s, c, t, r)
01622 {
01623   MoveGenerator::initOnce();
01624 #ifndef GPSONE
01625   if (OslConfig::usiMode()) {
01626     boost::shared_ptr<SearchMonitor> monitor(new UsiMonitor);
01627     this->addMonitor(monitor);
01628   }
01629 #endif
01630 }
01631 
01632 template <class EvalT>
01633 osl::search::AlphaBeta2<EvalT>::
01634 ~AlphaBeta2()
01635 {
01636 }
01637 
01638 template <class EvalT>
01639 typename osl::search::AlphaBeta2<EvalT>::PVCheckmateStatus osl::search::AlphaBeta2<EvalT>::
01640 findCheckmateInPV(int verify_node, CArray<bool,2>& king_in_threat)
01641 {
01642   king_in_threat.fill(false);
01643   if (this->shared_root->last_pv.empty())
01644     return PVStable;
01645   const SearchState2::PVVector& pv = this->shared_root->last_pv.back().pv;
01646   NumEffectState state = this->state();
01647   PathEncoding path = this->path();
01648   PVCheckmateStatus found = PVStable;
01649   SearchState2::checkmate_t *checkmate_searcher = this->checkmate_searcher;
01650   if (this->node_count < verify_node*pv.size())
01651     verify_node = this->node_count/(pv.size()+1)/4;
01652   for (size_t i=0; i<pv.size(); ++i)
01653   {
01654     this->checkmate_searcher->runGC(this->table->isVerbose(),
01655                                     this->lastMemoryUseRatio1000());
01656     assert(pv[i].isPass() || state.isValidMove(pv[i]));
01657     if (! pv[i].isPass() && ! state.isValidMove(pv[i]))
01658     {
01659       std::cerr << "pv error " << pv[i] << "\n" << state;
01660       return PVStable;
01661     }
01662     state.makeMove(pv[i]);
01663     path.pushMove(pv[i]);
01664     if (state.inCheck())
01665       continue;
01666     const HashKey key(state);
01667     SimpleHashRecord *record = this->table->allocate(key, 2000);
01668     if (! record)
01669       break;
01670     Move checkmate_move, threatmate_move;
01671     const bool old_win = this->isWinningState
01672       (*checkmate_searcher, state, key, path, 
01673        0, checkmate_move, pv[i]);
01674     if (! old_win) 
01675     {
01676       const bool new_win = this->isWinningState
01677         (*checkmate_searcher, state, key, path, 
01678          verify_node, checkmate_move, pv[i], true);
01679       if (new_win)
01680       {
01681         found = PVCheckmate;
01682         this->recordWinByCheckmate(state.turn(), record, checkmate_move);
01683         king_in_threat[alt(state.turn())] = true;
01684         if (this->table->isVerbose())
01685           std::cerr << "  pv checkmate " << record::csa::show(pv[i])
01686                     << "(" << i << ")\n";
01687       }
01688     }
01689     state.changeTurn();
01690     const Player T = state.turn();
01691     const bool old_threatmate_in_record = record->threatmate().isThreatmate(alt(T));
01692     const bool old_threatmate = this->isWinningState
01693       (*checkmate_searcher, state, HashKey(state), PathEncoding(T), 
01694        1, threatmate_move, Move::PASS(alt(T)));
01695     if (! old_threatmate)
01696     {
01697       const bool new_threatmate = this->isWinningState
01698         (*checkmate_searcher, state, HashKey(state), PathEncoding(T), 
01699          verify_node, threatmate_move, Move::PASS(alt(T)), this->root_limit >= 1000 + this->rootLimitBias());
01700       if (new_threatmate)
01701       {
01702         record->threatmate().setThreatmate(alt(T), threatmate_move);
01703         king_in_threat[alt(T)] = true;
01704         if (! old_threatmate_in_record) 
01705           found = PVThreatmate;
01706         else if (found == PVStable) 
01707           found = PVThreatmateNotRecord;
01708         if (this->table->isVerbose())
01709           std::cerr << "  pv threatmate " << record::csa::show(pv[i])
01710                     << "(" << i << ")\n";
01711       }
01712     }
01713     state.changeTurn();
01714   }
01715   this->checkmate_searcher->runGC(this->table->isVerbose(),
01716                                   this->lastMemoryUseRatio1000());
01717   this->updateCheckmateCount();
01718   return found;
01719 }
01720 
01721 template <class EvalT>
01722 int osl::search::AlphaBeta2<EvalT>::
01723 alphaBetaSearchRoot(MoveLogProb& best_move, int limit)
01724 {
01725   const Player Turn = this->state().turn();
01726   if (OslConfig::forceRootWindow()) {
01727     const double scale = this->eval.captureValue(newPtypeO(WHITE,PAWN))/2;
01728     std::pair<int,int> ab = OslConfig::rootWindow();
01729     ab = std::make_pair((int)(ab.first*scale/OslConfig::usiOutputPawnValue()),
01730                         (int)(ab.second*scale/OslConfig::usiOutputPawnValue()));
01731     if (ab.first % 2 == 0) 
01732       ab.first += (ab.first > 0) ? 1 : -1;
01733     if (ab.second % 2 == 0) 
01734       ab.second += (ab.second > 0) ? 1 : -1;
01735     if (eval::betterThan(Turn, ab.first, ab.second))
01736       ab = std::make_pair(ab.second, ab.first);
01737     Window root_window(Turn, ab.first, ab.second);
01738     assert(root_window.isConsistent());
01739     return alphaBetaSearchRoot(root_window, best_move, limit);
01740   }
01741   Window root_window = this->fullWindow(Turn);
01742   return alphaBetaSearchRoot(root_window, best_move, limit);
01743 }
01744 
01745 template <class EvalT>
01746 osl::Move osl::search::AlphaBeta2<EvalT>::
01747 computeBestMoveIteratively(int limit, const int step, 
01748                            int initial_limit, size_t node_limit,
01749                            const TimeAssigned& assign,
01750                            MoveWithComment *additional_info)
01751 {
01752   this->setStartTime(MilliSeconds::now());
01753   this->setTimeAssign(assign);
01754   if (this->table->verboseLevel() > 2)
01755   {
01756     const time_t now = time(0);
01757     char ctime_buf[64];
01758     std::cerr << "AlphaBeta2 " << ctime_r(&now, ctime_buf);
01759   }
01760   if (this->table->isVerbose()) {
01761     std::cerr << " time assign/max " << this->timeAssigned().standard.toSeconds()
01762               << "/" << this->timeAssigned().max.toSeconds()
01763               << " multipv " << this->multi_pv
01764               << " iteration " << this->nextIterationCoefficient()
01765               << " mem " << std::fixed << std::setprecision(2)
01766               << OslConfig::memoryUseRatio()*100.0 << "%";
01767     if (OslConfig::forceRootWindow()) {
01768       std::pair<int,int> ab = OslConfig::rootWindow();
01769       if (ab.first == ab.second)
01770         std::cerr << " root-null-window "
01771                   << (ab.first*100.0/OslConfig::usiOutputPawnValue());
01772       else
01773         std::cerr << " root-window ["
01774                   << (ab.first*100.0/OslConfig::usiOutputPawnValue())
01775                   << ", "
01776                   << (ab.second*100.0/OslConfig::usiOutputPawnValue())
01777                   << "]";
01778     }
01779     std::cerr << "\n";
01780   }
01781   initial_limit = std::min(initial_limit, limit);
01782   
01783   this->recorder.resetNodeCount();
01784 
01785   double last_iteration_consumed = 0;
01786   double total_consumed = 0;
01787   int limit_iterative = initial_limit;
01788   Move last_best_move = Move::INVALID();
01789   this->shared_root->last_pv.clear();
01790 
01791 #ifdef OSL_SMP
01792 #  ifdef SPLIT_STAT
01793   if (this->shared) {
01794     this->shared->parallel_splits = 0;
01795     this->shared->cancelled_splits.setValue(0);
01796     this->shared->parallel_abort.setValue(0);
01797   }
01798 #  endif
01799 #endif
01800   try
01801   {
01802     if (this->table->verboseLevel() > 1)
01803     {
01804       MoveVector moves;
01805       move_generator::LegalMoves::generate(this->state(), moves);
01806       BOOST_FOREACH(Move move, moves) {
01807         HashKey key = this->currentHash().newHashWithMove(move);
01808         const SimpleHashRecord *record = this->table->find(key);
01809         if (! record || record->lowerLimit() < SearchTable::HistorySpecialDepth)
01810           continue;
01811         std::cerr << "prebound value " << record::csa::show(move)
01812                   << " " << record->lowerBound() << " " << record->upperBound() << "\n";
01813       }
01814     }
01815 
01816     MoveLogProb search_move;
01817     this->shared_root->root_values.push_back(alphaBetaSearchRoot(search_move, 0));
01818     this->shared_root->last_root_move = search_move.move();
01819     this->shared_root->best_move_for_iteration.push_back(search_move.move());
01820     if (this->table->verboseLevel() > 1)
01821       std::cerr << "=> quiesce "
01822                 << record::csa::show(search_move.move()) << "\n";
01823     while (limit_iterative < limit && ! this->stopping())
01824     {
01825       if (this->table->verboseLevel() > 1)
01826         std::cerr << "=> iteration " << limit_iterative 
01827                   << " (" << last_iteration_consumed << ", " << total_consumed << " sec)"
01828                   << " mem " << OslConfig::memoryUseRatio()*100.0 << "%\n";
01829       this->recorder.startSearch(limit_iterative);
01830       const int previous_node_count = this->nodeCount();
01831       try {
01832         for (int i=0; i<8; ++i)
01833         {
01834           this->shared_root->root_values.push_back(alphaBetaSearchRoot(search_move, limit_iterative+this->rootLimitBias()));
01835           this->shared_root->last_root_move = search_move.move();
01836           last_best_move = search_move.move();
01837           if (this->stopping())
01838             break;
01839           PVCheckmateStatus need_more_verify = PVStable;
01840           CArray<bool, 2> king_in_threat;
01841           int verify_node_limit = limit <= (1200 + this->rootLimitBias()) ? 10000 : 40000;
01842           if (this->timeAssigned().standard.toSeconds() < 20)
01843             verify_node_limit /= 4;
01844 #ifdef DONT_USE_CHECKMATE
01845           break;
01846 #endif
01847           need_more_verify = findCheckmateInPV(verify_node_limit, king_in_threat);
01848           if (need_more_verify == PVStable
01849               || (i > 0 && need_more_verify == PVThreatmateNotRecord))
01850             break;
01851           if (this->isStableNow())
01852             this->setStable(i > 0 && king_in_threat[this->state().turn()] == false);
01853         } 
01854       } catch (...) {
01855         last_iteration_consumed = this->elapsed() - total_consumed;
01856         total_consumed += last_iteration_consumed;
01857         this->updateCheckmateCount();
01858         this->recorder.finishSearch(search_move.move(), total_consumed,
01859                               this->table->verboseLevel());
01860         throw;
01861       }
01862 
01863       last_iteration_consumed = this->elapsed() - total_consumed;
01864       total_consumed += last_iteration_consumed;
01865       this->shared_root->best_move_for_iteration.push_back(last_best_move);
01866       this->shared_root->root_values_for_iteration.push_back
01867         (this->shared_root->root_values.back());
01868 
01869       this->updateCheckmateCount();
01870       if (this->table->verboseLevel() > 2) {
01871         std::cerr << "<= " 
01872                   << record::csa::show(search_move.move());
01873         std::cerr << std::setprecision(4) << "  mpn " << this->mpn.getAverage() 
01874                   << " cut " << this->mpn_cut.getAverage()
01875                   << " alpha " << this->alpha_update.getAverage()
01876                   << " last " << this->last_alpha_update.getAverage()
01877                   << " ext " << 100.0*this->ext.getAverage() << "%"
01878                   << " ext_limit " << this->ext_limit.getAverage()
01879                   << " mem " << OslConfig::memoryUseRatio()*100.0;
01880 #ifdef OSL_SMP
01881 #  ifdef SPLIT_STAT
01882         if (this->shared) {
01883           std::cerr << " split " << this->shared->parallel_splits << " cancel " << this->shared->cancelled_splits.value() 
01884                     << " abort " << this->shared->parallel_abort.value();
01885         }
01886 #  endif
01887 #endif
01888         std::cerr << "\n";
01889       }
01890       bool time_over = false;
01891       if (this->hasSchedule()) {
01892         const double elapsed = this->elapsed();
01893         const double current_time_left = this->timeAssigned().standard.toSeconds() - elapsed;
01894         double coef = this->nextIterationCoefficient();
01895         if (! this->isStableNow())
01896           coef = std::min(0.5, coef);
01897         else {
01898           const int same_best_moves = this->shared_root->sameBestMoves();
01899           if (same_best_moves == 0) {
01900             if (this->table->verboseLevel() > 2 && coef > 0.75)
01901               std::cerr << "info: " << coef << " -> 0.75 by bestmove update\n";
01902             coef = std::min(0.75, coef);
01903           }
01904           else if (same_best_moves >= 3) {
01905             const Move last_move = this->lastMove();
01906             if (last_move.isNormal() && last_best_move.isNormal()
01907                 && last_move.to() == last_best_move.to()
01908                 && isMajor(last_best_move.capturePtype())
01909                 && isMajorNonPieceOK(last_move.capturePtype())) {
01910               if (coef < 5.0 && this->table->verboseLevel() > 2)
01911                 std::cerr << "info: " << coef << " -> 5.0 by takeback major piece\n";
01912               coef = std::max(5.0, coef);
01913             }
01914           }
01915         }
01916         if (current_time_left 
01917             < last_iteration_consumed * coef)
01918           time_over = true;
01919         if (! time_over) {
01920           SimpleHashRecord *record
01921             = this->table->find(this->currentHash());
01922           if (record) {
01923             record->addNodeCount(this->nodeCount() - previous_node_count);
01924           }
01925         }
01926       }
01927       bool node_limit_over = (this->recorder.nodeCount() *4 > node_limit);
01928       this->recorder.finishSearch(search_move.move(), 
01929                             total_consumed,
01930                             (time_over || node_limit_over) && this->table->verboseLevel());
01931       if (time_over || node_limit_over || this->stopping()) {
01932         if (this->table->isVerbose()) {
01933           const char *reason = "other reason";
01934           if (this->stopReason() == SearchTimerCommon::NoMoreMemory)
01935             reason = "memory full";
01936           else if (time_over || this->stopReason() == SearchTimerCommon::NoMoreTime)
01937             reason = "time";
01938           else if (node_limit_over)
01939             reason = "node count";
01940           else if (this->stopReason() == SearchTimerCommon::StopByOutside)
01941             reason = "outside";
01942           std::cerr << "iteration stop at " << limit_iterative << " by "
01943                     << reason << "\n";
01944         }
01945         goto finish;
01946       }
01947       this->testStop();
01948       limit_iterative += step;
01949     }
01950     if (this->table->verboseLevel() > 1)
01951       std::cerr << "=> final iteration " << limit_iterative 
01952                 << " (" << last_iteration_consumed << ", " << total_consumed << " sec)"
01953                 << " mem " << OslConfig::memoryUseRatio()*100.0 << "%\n";
01954     while (true) {
01955       this->recorder.startSearch(limit);
01956       try {
01957         for (int i=0; i<8; ++i)
01958         {
01959           this->shared_root->root_values.push_back(alphaBetaSearchRoot(search_move, limit+this->rootLimitBias()));
01960           this->shared_root->last_root_move = search_move.move();
01961           last_best_move = search_move.move();
01962           if (this->stopping())
01963             break;
01964           PVCheckmateStatus need_more_verify = PVStable;
01965           CArray<bool, 2> king_in_threat;
01966           int verify_node_limit = limit <= (1200 + this->rootLimitBias()) ? 10000 : 40000;
01967           if (this->timeAssigned().standard.toSeconds() < 20)
01968             verify_node_limit /= 4;
01969 #ifdef DONT_USE_CHECKMATE
01970           break;
01971 #endif
01972           need_more_verify = findCheckmateInPV(verify_node_limit, king_in_threat);
01973           if (need_more_verify == PVStable
01974               || (i > 0 && need_more_verify == PVThreatmateNotRecord))
01975             break;
01976           if (this->isStableNow())
01977             this->setStable(i > 0 && king_in_threat[this->state().turn()] == false);
01978         }
01979       } catch (...) {
01980         last_iteration_consumed = this->elapsed() - total_consumed;
01981         total_consumed += last_iteration_consumed;
01982         this->updateCheckmateCount();
01983         this->recorder.finishSearch(search_move.move(), total_consumed,
01984                               this->table->verboseLevel());
01985         throw;
01986       }
01987       last_iteration_consumed = this->elapsed() - total_consumed;
01988       total_consumed += last_iteration_consumed;
01989       this->updateCheckmateCount();
01990       this->recorder.finishSearch(search_move.move(), total_consumed,
01991                             this->table->verboseLevel());
01992       this->shared_root->best_move_for_iteration.push_back(last_best_move);
01993       this->shared_root->root_values_for_iteration.push_back
01994         (this->shared_root->root_values.back());
01995 
01996       if (last_best_move.isNormal())
01997         break;
01998       this->testStop();
01999 
02000       // ほっておくと投了
02001       if (limit >= 2000 || this->root_ignore_moves)
02002         break;
02003 
02004       limit += 200;
02005       if (this->table->isVerbose())
02006         std::cerr << "  extend limit to " << limit << " before resign\n";
02007     }
02008   }
02009   catch (std::exception& e)
02010   {
02011     if (! OslConfig::usiMode())
02012       std::cerr << "std exception " << e.what() << "\n";
02013   }
02014   catch (...)
02015   {
02016     std::cerr << "unknown exception\n";
02017 #ifndef NDEBUG
02018     throw;
02019 #endif
02020   }
02021 finish:
02022   if (this->table->verboseLevel() > 1) {
02023     std::cerr << "<= " << record::csa::show(last_best_move);
02024     std::cerr << std::setprecision(4) << "  mpn " << this->mpn.getAverage()
02025               << " cut " << this->mpn_cut.getAverage()
02026               << " alpha " << this->alpha_update.getAverage()
02027               << " last " << this->last_alpha_update.getAverage()
02028               << " ext " << this->ext.getAverage()
02029               << " ext_limit " << this->ext_limit.getAverage()
02030               << " mem " << OslConfig::memoryUseRatio()*100.0;
02031 #ifdef OSL_SMP
02032 #  ifdef SPLIT_STAT
02033     if (this->shared) {
02034       std::cerr << " split " << this->shared->parallel_splits << " cancel " << this->shared->cancelled_splits.value() 
02035                 << " abort " << this->shared->parallel_abort.value();
02036     }
02037 #  endif
02038 #endif
02039     std::cerr << "\n";
02040   }
02041 
02042   if (additional_info) {
02043     additional_info->node_count = this->nodeCount();
02044     additional_info->elapsed = this->elapsed();
02045     additional_info->moves.clear();
02046     additional_info->root_limit = this->root_limit;
02047   }
02048   if (additional_info && this->shared_root->root_values.size() > 1) { // last_root_value[0] is for quiesce
02049     assert(last_best_move == this->shared_root->last_root_move);
02050     additional_info->move = last_best_move;
02051     const double scale = 200.0/this->eval.captureValue(newPtypeO(WHITE,PAWN));
02052     additional_info->value = static_cast<int>(this->shared_root->last_root_value_update * scale);
02053     if (!this->shared_root->last_pv.empty()) {
02054       for (size_t i=1; i<this->shared_root->last_pv.back().pv.size(); ++i) {
02055         additional_info->moves.push_back(this->shared_root->last_pv.back().pv[i]);
02056       }
02057     }
02058   }
02059   return last_best_move;
02060 }
02061 
02062 template <class EvalT>
02063 template <osl::Player P>
02064 int osl::search::AlphaBeta2<EvalT>::
02065 alphaBetaSearchRoot(Window window, MoveLogProb& best_move, int limit)
02066 {
02067 #ifndef GPSONE
02068   {
02069     boost::mutex::scoped_lock lk(OslConfig::lock_io);
02070     BOOST_FOREACH(const boost::shared_ptr<SearchMonitor>& monitor,
02071                   this->monitors())
02072       monitor->newDepth(limit/200);
02073   }
02074 #endif
02075   assert(P == this->state().turn());
02076   assert(window.alpha(P) % 2);
02077   assert(window.beta(P) % 2);
02078   setRoot(limit);
02079   assert(this->curDepth() == 0);
02080   this->node_type[this->curDepth()] = base_t::PvNode;
02081 #ifdef NEW_DFPN
02082   this->checkmate_searcher->setRootPlayer(P);
02083 #endif
02084 #ifdef OSL_SMP
02085   if (this->shared)
02086     this->shared->threadStart();
02087 #endif
02088   // まずテーブルを牽く
02089   SimpleHashRecord *record_in_table
02090     = this->table->allocate(this->currentHash(), limit);
02091   SimpleHashRecord *record = record_in_table;
02092   boost::scoped_ptr<SimpleHashRecord> record_if_not_allocated;
02093   if (! record)
02094   {
02095     record_if_not_allocated.reset(new SimpleHashRecord());
02096     record = record_if_not_allocated.get();
02097   }
02098   assert(record);
02099   this->setRootRecord(record);
02100   assert(this->rootRecord() == record);
02101   assert(this->hasLastRecord() && this->lastRecord() == record);
02102   record->setInCheck(this->state().inCheck());
02103 
02104   if (limit == 0) {
02105     int result = this->template quiesce<P>(fullWindow(P));
02106     best_move = MoveLogProb(record->qrecord.bestMove(), 100);
02107     if (this->root_ignore_moves
02108         && this->root_ignore_moves->isMember(best_move.move()))
02109       best_move = MoveLogProb();
02110 #ifndef GPSONE
02111     else if (this->hasMonitor() && !this->prediction_for_speculative_search) 
02112     {
02113       const double scale = OslConfig::usiOutputPawnValue()*2.0
02114         / this->eval.captureValue(newPtypeO(alt(P),PAWN));
02115       boost::mutex::scoped_lock lk(OslConfig::lock_io);
02116       BOOST_FOREACH(const boost::shared_ptr<SearchMonitor>& monitor,
02117                     this->monitors())
02118         monitor->showPV(1, this->recorder.allNodeCount(),
02119                         this->elapsed(), static_cast<int>(result*scale), 
02120                         best_move.move(), 0, 0);
02121     }
02122 #endif
02123     return result;
02124   }
02125   if (record_in_table) {
02126     int table_value = 0;
02127     const MoveLogProb m = record_in_table->bestMove();
02128     if (! m.isNormal())
02129       record_in_table->resetValue();
02130     else if (record->hasGreaterLowerBound<P>(this->curLimit(), window.beta(P), 
02131                                              table_value)) {
02132       if (! this->root_ignore_moves 
02133           || ! this->root_ignore_moves->isMember(m.move())) {
02134         best_move = m;
02135         return table_value;
02136       }
02137     }
02138   }
02139 
02140   // gather all moves
02141   MoveLogProbVector moves;
02142   MoveGenerator& generator = this->makeGenerator();
02143   const MoveLogProb last_best_move = record->bestMove();
02144   {
02145     MoveLogProbVector raw_moves;
02146     assert(this->curLimit() > 0);
02147     const Move hash_move = last_best_move.isNormal()
02148       ? last_best_move.move() : record->qrecord.bestMove();
02149     generator.init(this->curLimit()+200, record, this->eval, this->state(), true, hash_move);
02150     if (last_best_move.isNormal())
02151       raw_moves.push_back(last_best_move);
02152     else if (record->qrecord.bestMove().isNormal())
02153       raw_moves.push_back(MoveLogProb(record->qrecord.bestMove(), 100));
02154     generator.generateAll<P>(*this, raw_moves);
02155 
02156     // clean up losing moves
02157     for (size_t i=0; i<raw_moves.size(); ++i) {
02158       const Move m = raw_moves[i].move();
02159       if (i > 0 && m == hash_move)
02160         continue;
02161       const HashKey key = this->currentHash().newHashWithMove(m);
02162       const SimpleHashRecord *record = this->table->find(key);
02163       assert(this->state().isValidMove(m));
02164       if (record) {
02165         if (record->hasUpperBound(SearchTable::HistorySpecialDepth)
02166             && this->isWinValue(alt(P), record->upperBound()))
02167           continue;
02168       }
02169       if (this->root_ignore_moves && this->root_ignore_moves->isMember(m))
02170         continue;
02171       if (! m.isDrop() && m.ptype() != KING
02172           && move_classifier::KingOpenMove<P>::isMember(this->state(), m.ptype(), m.from(), m.to()))
02173         continue;
02174       if (move_classifier::MoveAdaptor<move_classifier::PawnDropCheckmate<P> >
02175           ::isMember(this->state(), m))
02176         continue;
02177       raw_moves[i].setLogProbAtMost(limit);
02178       moves.push_back(raw_moves[i]);
02179     }
02180   }
02181 
02182   if (! OslConfig::searchExactValueInOneReply()) {
02183     if (moves.size() == 1 
02184         || (moves.size() == 2 && moves[0].move() == moves[1].move()))
02185     {
02186       best_move = moves[0];
02187 #ifndef GPSONE
02188       if (this->hasMonitor() && !this->prediction_for_speculative_search) {
02189         boost::mutex::scoped_lock lk(OslConfig::lock_io);
02190         BOOST_FOREACH(const boost::shared_ptr<SearchMonitor>& monitor,
02191                       this->monitors())
02192           monitor->rootForcedMove(best_move.move());
02193       }
02194 #endif
02195       return 0; // XXX
02196     }
02197   }
02198 
02199 #ifndef DONT_USE_CHECKMATE
02200   // 詰将棋を呼んでみる root では沢山呼んでも問題ない
02201   int checkmate_node = 0;
02202   if (! this->prediction_for_speculative_search) {
02203     int checkmate_max = 30000*std::max(limit - 300 - this->rootLimitBias(), 0)/100;
02204     if (limit >= 1000 + this->rootLimitBias())
02205       checkmate_max = std::min(400000, 60000*(limit - 800 - this->rootLimitBias())/100);
02206     if (this->timeAssigned().standard.toSeconds() < 20) {
02207       checkmate_node /= 4;
02208       if (this->timeAssigned().standard.toSeconds() < 10)
02209         checkmate_node /= 2;
02210     }
02211     checkmate_node = record->qrecord.checkmateNodesLeft(checkmate_max);
02212 #ifdef CHECKMATE_COUNT
02213     std::cerr << "limit " << limit << " checkmate " << checkmate_node << "\n";
02214 #endif
02215   }
02216   if (checkmate_node > 0)
02217   {
02218     const bool my_king_in_check
02219       = this->state().hasEffectAt(alt(P),this->state().kingSquare(P));
02220     if (my_king_in_check)
02221     {
02222       // 相手から王手がかかっている
02223       this->recorder.gotoCheckmateSearch(this->state(), checkmate_node/8);
02224       const bool lose = this->template isLosingState<P>(checkmate_node/8);
02225       this->recorder.backFromCheckmateSearch();
02226       this->updateCheckmateCount();
02227       if (lose)
02228       {
02229         best_move = MoveLogProb(Move::INVALID(),100);
02230         this->recordLoseByCheckmate(P, record);
02231         this->shared_root->last_pv.clear();
02232         this->shared_root->last_root_move = Move();
02233         this->shared_root->last_root_value_update = this->winByCheckmate(alt(P));
02234 #ifndef GPSONE
02235         boost::mutex::scoped_lock lk(OslConfig::lock_io);
02236         BOOST_FOREACH(const boost::shared_ptr<SearchMonitor>& monitor,
02237                       this->monitors())
02238           monitor->rootLossByCheckmate();
02239 #endif
02240         return this->winByCheckmate(alt(P));
02241       }
02242     }
02243     // 詰まされなければ,相手を詰ますことを考える 
02244     {
02245       Move checkmate_move;
02246 #ifdef CHECKMATE_COUNT
02247       size_t count = this->checkmateSearcher().totalNodeCount();
02248 #endif
02249       this->recorder.gotoCheckmateSearch(this->state(), checkmate_node);
02250       const bool win = this->template isWinningState<P>
02251         (checkmate_node, checkmate_move, limit >= 1000 + this->rootLimitBias());
02252       this->recorder.backFromCheckmateSearch();
02253       this->updateCheckmateCount();
02254 #ifdef CHECKMATE_COUNT
02255       root_checkmate += this->checkmateSearcher().totalNodeCount() - count;
02256 #endif
02257       if (win)
02258       {
02259         best_move = MoveLogProb(checkmate_move,100);
02260         this->recordWinByCheckmate(P, record, checkmate_move);
02261         this->shared_root->last_pv.clear();
02262         this->shared_root->last_root_move = checkmate_move;
02263         this->shared_root->last_root_value_update = this->winByCheckmate(P);
02264         this->pv[1].clear();
02265         this->updateRootPV(P, std::cerr, this->winByCheckmate(P), checkmate_move);
02266         return this->winByCheckmate(P);
02267       }
02268     }
02269     // 詰めろを考える
02270     if ((! my_king_in_check)
02271         && (! (record->threatmate().isThreatmate(P))))
02272     {
02273       Move threatmate_move;
02274 #ifdef CHECKMATE_COUNT
02275       size_t count = this->checkmateSearcher().totalNodeCount();
02276 #endif
02277       this->recorder.gotoCheckmateSearch(this->state(), checkmate_node);
02278       const bool threatmate 
02279         = this->template isThreatmateState<P>
02280         (checkmate_node, threatmate_move, limit >= 1000 + this->rootLimitBias());
02281 #ifdef CHECKMATE_COUNT
02282       root_checkmate += this->checkmateSearcher().totalNodeCount() - count;
02283 #endif
02284       this->recorder.backFromCheckmateSearch();
02285       this->updateCheckmateCount();
02286       if (threatmate)
02287       {
02288         if (record)
02289           record->threatmate().setThreatmate(P, threatmate_move);
02290         if (this->table->verboseLevel() > 1)
02291           std::cerr << "  root threatmate " << threatmate_move << "\n";
02292       }
02293       BOOST_FOREACH(Ptype ptype, PieceStand::order)
02294       {
02295         this->testStop();
02296         if (! this->state().hasPieceOnStand(P, ptype))
02297           continue;
02298         NumEffectState state(this->state().emulateHandPiece(P, alt(P), ptype));
02299         state.setTurn(alt(P));
02300         Move hand_move;
02301         this->template isWinningState<PlayerTraits<P>::opponent>
02302           (*this->checkmate_searcher, state, HashKey(state), PathEncoding(alt(P)),
02303            checkmate_node, hand_move, Move::PASS(P), limit >= 1000 + this->rootLimitBias());
02304       }
02305     }
02306     this->testStop();
02307   }
02308   this->checkmate_searcher->runGC(this->table->isVerbose(),
02309                                   this->lastMemoryUseRatio1000());
02310 #endif
02311   const int ValueNone = window.alpha(P) - EvalTraits<P>::delta;
02312   int best_value = ValueNone;
02313   try {
02314     // first move
02315     size_t i=0;
02316     if (limit >= 1000 && ! moves.empty() && window == fullWindow(P))
02317     {
02318       // try aspiration window if we have sufficient limit
02319       const int root_alpha =
02320         this->rootAlpha(P, this->shared_root->root_values.size() ? this->shared_root->root_values.back() : 0,
02321                         this->eval.progress16());
02322       if (EvalTraits<P>::betterThan(root_alpha, window.alpha(P))) {
02323         const Window window_copy = window;
02324         window.alpha(P) = root_alpha;
02325 #ifndef GPSONE
02326         {
02327           boost::mutex::scoped_lock lk(OslConfig::lock_io);
02328           BOOST_FOREACH(const boost::shared_ptr<SearchMonitor>& monitor,
02329                         this->monitors())
02330             monitor->rootFirstMove(moves[0].move());
02331         }
02332 #endif
02333         const int result = this->template alphaBetaSearch<P>(moves[0], window, true);
02334         if (EvalTraits<P>::betterThan(result, root_alpha))
02335         {
02336           window.alpha(P) = result + EvalTraits<P>::delta;
02337           best_move = moves[0];
02338           best_value = result;
02339           this->updateRootPV(P, std::cerr, result, moves[0].move());
02340           ++i;
02341         } 
02342         else
02343         {
02344           if (this->table->isVerbose())
02345             this->showFailLow(result, moves[0].move());
02346           this->setStable(false);
02347           window = window_copy;
02348         }
02349         this->checkmate_searcher->runGC(this->table->isVerbose(),
02350                                         this->lastMemoryUseRatio1000());
02351       }
02352     }
02353     for (; i<moves.size() && best_value == ValueNone
02354            && window == fullWindow(P); ++i) {
02355       const MoveLogProb& m = moves[i];
02356 #ifndef GPSONE
02357       {
02358         boost::mutex::scoped_lock lk(OslConfig::lock_io);
02359         BOOST_FOREACH(const boost::shared_ptr<SearchMonitor>& monitor,
02360                       this->monitors())
02361           monitor->rootMove(m.move());
02362       }
02363 #endif
02364       const int result = this->template alphaBetaSearch<P>(m, window, true);
02365       if (eval::betterThan(P, result, best_value)) {
02366         window.alpha(P) = result + EvalTraits<P>::delta;
02367         best_move = m;
02368         best_value = result;
02369         this->updateRootPV(P, std::cerr, result, m.move());
02370         if (eval::betterThan(P, result, window.beta(P))) {
02371           assert(! this->isWinValue(alt(P), result));
02372         }
02373       }
02374       else if (result == ValueNone)
02375         this->setStable(false);
02376       this->checkmate_searcher->runGC(this->table->isVerbose(),
02377                                       this->lastMemoryUseRatio1000());
02378     }
02379     // other moves
02380     if (! eval::betterThan(P, window.alpha(P), window.beta(P))) {
02381       this->template examineMovesRoot<P>(moves, i, window, best_move, best_value);
02382     }
02383     if (best_move.isNormal()) {
02384       if (best_value != ValueNone) {
02385         assert(! this->shared_root->last_pv.empty());
02386         assert(best_move.move() == this->shared_root->last_pv.back().pv[0]);
02387       }
02388     }
02389   } catch (std::runtime_error& e) {
02390     if (this->table->isVerbose())
02391       std::cerr << e.what() << "\n";
02392     assert(best_value % 2 == 0);
02393     this->stopNow();
02394     this->restoreRootState();
02395     if (best_value != ValueNone)
02396       record->setLowerBound(P, this->curLimit(), best_move, best_value);
02397     if (best_move.validMove()
02398         && best_move.move() != last_best_move.move()) {
02399       if (this->table->verboseLevel() > 1) {
02400         std::cerr << "! use better move than the last best move\n";
02401         if (best_value != ValueNone) {
02402           assert(! this->shared_root->last_pv.empty() &&
02403                  ! this->shared_root->last_pv.back().pv.empty());
02404           assert(best_move.move() == this->shared_root->last_pv.back().pv[0]);
02405         }
02406       }
02407     }
02408     else {
02409 #ifdef OSL_SMP
02410       if (this->shared)
02411         this->shared->waitAll();
02412 #endif      
02413       throw;
02414     }
02415   }
02416   
02417   assert(best_value % 2 == 0);
02418   if (best_value != ValueNone)
02419     record->setLowerBound(P, this->curLimit(), best_move, best_value);
02420 #ifdef OSL_SMP
02421   if (this->shared)
02422     this->shared->waitAll();
02423 #endif      
02424 #ifndef GPSONE
02425   if (best_value == ValueNone
02426       && this->hasMonitor() && !this->prediction_for_speculative_search) 
02427   {
02428     const double scale = OslConfig::usiOutputPawnValue()*2.0
02429       / this->eval.captureValue(newPtypeO(alt(P),PAWN));
02430     const int value = OslConfig::forceRootWindow() 
02431       ? ValueNone : this->winByCheckmate(alt(P));
02432     BOOST_FOREACH(const boost::shared_ptr<SearchMonitor>& monitor,
02433                   this->monitors())
02434       monitor->showPV(limit/200, this->recorder.allNodeCount(),
02435                       this->elapsed(), static_cast<int>(value*scale), 
02436                       Move::INVALID(), 0, 0);
02437   }
02438 #endif
02439   return best_value;
02440 }
02441 
02442 template <class EvalT>
02443 void osl::search::AlphaBeta2<EvalT>::setRoot(int limit)
02444 {
02445   SearchState2::setRoot(limit);
02446   SimpleHashRecord *record = this->table->allocate(this->currentHash(), std::max(1000,limit));
02447   assert(record);
02448   this->setRootRecord(record);  
02449   this->move_type[this->curDepth()] = base_t::INITIAL;
02450 }
02451 
02452 template <class EvalT>
02453 void osl::search::AlphaBeta2<EvalT>::makeMove(Move move)
02454 {
02455   assert(this->state().isValidMove(move));
02456   SearchState2::makeMove(move);
02457   this->eval.update(this->state(), move);
02458 
02459   SimpleHashRecord *record 
02460     = this->table->allocate(this->currentHash(), this->curLimit());
02461   assert(record);
02462   this->move_type[this->curDepth()] = base_t::INITIAL;
02463   record->setInCheck(this->state().inCheck());
02464   this->setCurrentRecord(record);
02465 }
02466 
02467 template <class EvalT>
02468 bool osl::search::AlphaBeta2<EvalT>::
02469 isReasonableMove(Move /*move*/, int /*pawn_sacrifice*/)
02470 {
02471   return true;
02472 }
02473 
02474 template <class EvalT>
02475 void osl::search::AlphaBeta2<EvalT>::
02476 showNodeDepth(std::ostream& os)
02477 {
02478 #ifndef MINIMAL
02479   int max_depth=0;
02480   for (int i=base_t::MaxDepth-1; i>=0; --i) {
02481     if (base_t::depth_node_count[i] || base_t::depth_node_count_quiesce[i]) {
02482       max_depth = i;
02483       break;
02484     }
02485   }
02486   int max_count=0;
02487   for (int i=0; i<=max_depth; i+=2) {
02488     max_count = std::max(max_count, 
02489                          base_t::depth_node_count[i]+base_t::depth_node_count_quiesce[i]);
02490   }
02491 
02492   int unit = std::max(max_count/79, 100);
02493   for (int i=0; i<=max_depth; i+=2) {
02494     os << std::setw(3) << i << " " 
02495        << std::string(base_t::depth_node_count[i]/unit, '*')
02496        << std::string(base_t::depth_node_count_quiesce[i]/unit, '+')
02497        << std::endl;
02498   }
02499 #  ifdef CHECKMATE_COUNT
02500   std::cerr << "checkmate root " << root_checkmate << " quiesce " << quiesce_checkmate
02501             << "\nnormal before " << checkmate_before 
02502             << " after " << checkmate_after << " threatmate " << count_threatmate
02503             << "\n";
02504 # endif
02505 #endif
02506 }
02507 
02508 template <class EvalT>
02509 void osl::search::AlphaBeta2<EvalT>::
02510 clearNodeDepth()
02511 {
02512 #ifndef MINIMAL
02513   base_t::depth_node_count.fill(0);
02514   base_t::depth_node_count_quiesce.fill(0);
02515 #endif
02516 }
02517 
02518 namespace osl
02519 {
02520   namespace search
02521   {
02522 #ifndef MINIMAL
02523     template class AlphaBeta2<eval::ProgressEval>;
02524     template class AlphaBeta2Tree<eval::ProgressEval>;
02525     template
02526     void AlphaBeta2Tree<eval::ProgressEval>::examineMovesRoot<BLACK>(const MoveLogProbVector&, size_t, Window, MoveLogProb&, int&);
02527     template
02528     void AlphaBeta2Tree<eval::ProgressEval>::examineMovesRoot<WHITE>(const MoveLogProbVector&, size_t, Window, MoveLogProb&, int&);
02529 #endif
02530     template class AlphaBeta2<eval::ml::OpenMidEndingEval>;
02531     template class AlphaBeta2Tree<eval::ml::OpenMidEndingEval>;
02532     template
02533     void AlphaBeta2Tree<eval::ml::OpenMidEndingEval>::examineMovesRoot<BLACK>(const MoveLogProbVector&, size_t, Window, MoveLogProb&, int&);
02534     template
02535     void AlphaBeta2Tree<eval::ml::OpenMidEndingEval>::examineMovesRoot<WHITE>(const MoveLogProbVector&, size_t, Window, MoveLogProb&, int&);
02536   }
02537 }
02538 
02539 /* ------------------------------------------------------------------------- */
02540 // ;;; Local Variables:
02541 // ;;; mode:c++
02542 // ;;; c-basic-offset:2
02543 // ;;; End:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines