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