quiescenceSearch2.tcc
Go to the documentation of this file.
00001 /* quiescenceSearch2.tcc
00002  */
00003 #ifndef OSL_QUIESCENCESEARCH2_TCC
00004 #define OSL_QUIESCENCESEARCH2_TCC
00005 
00006 #include "osl/search/quiescenceSearch2.h"
00007 #include "osl/search/quiescenceGenerator.h"
00008 #include "osl/search/quiescenceLog.h"
00009 #include "osl/search/searchTable.h"
00010 #include "osl/search/simpleHashRecord.h"
00011 #include "osl/search/simpleHashTable.h"
00012 #include "osl/search/sortCaptureMoves.h"
00013 #include "osl/search/moveStackRejections.h"
00014 #include "osl/checkmate/immediateCheckmate.h"
00015 #include "osl/hash/hashCollision.h"
00016 #include "osl/effect_util/effectUtil.h"
00017 #include "osl/move_order/captureSort.h"
00018 #include "osl/move_classifier/check_.h"
00019 #include "osl/move_classifier/moveAdaptor.h"
00020 #include "osl/move_classifier/pawnDropCheckmate.h"
00021 #include "osl/move_generator/addEffectWithEffect.h"
00022 #include "osl/effect_util/unblockableEffect.h"
00023 #include "osl/effect_util/neighboring8Direct.h"
00024 #include "osl/eval/see.h"
00025 #include "osl/stat/ratio.h"
00026 #include "osl/hash/hashRandom.h"
00027 #include "osl/oslConfig.h"
00028 #include "osl/centering3x3.h"
00029 
00030 #ifdef STAT_WIDTH_VS_LIMIT
00031 #  include "osl/stat/average.h"
00032 #  include <iostream>
00033 #endif
00034 
00035 #define quiecence_assert(x,m) assert((x) || state.abort(m))
00036 
00037 #ifdef RICH_QSEARCH
00038 // 増減1割
00039 #  define QSEARCH_LAST_CHECK_PENALTY
00040 // 5-20%
00041 #  define QSEARCH_PESSIMISTIC_ESCAPE_THREAT
00042 // 8%
00043 #  define QSEARCH_THREATMATE
00044 #endif
00045 
00046 #ifdef EXTRA_RICH_QSEARCH
00047 // 2倍
00048 #  define QSEARCH_SET_MINIMUM_MOVES
00049 #endif
00050 
00051 // recordがないと意味があまりない
00052 // #define MAKE_PV_IN_QUIESCE2
00053 
00054 const int allocate_depth_in_threatmate = 400;
00055 
00056 namespace osl
00057 {
00058   namespace search
00059   {
00060     struct QSearch2PrivateTraits
00061     {
00062       enum { 
00063         KnightCaptureDepth = 1, 
00064         PawnCaptureDepth = 3, 
00065         FullPromoteDepth = 3,
00066         UtilizePromotedDepth = 5, 
00067         AttackPinnedDepth = 6,
00068       };
00069       enum { 
00070         EscapeDepthFromRoot = 1, 
00071         EscapeFromLastMoveDepthFromRoot = 3, 
00072         AttackKnightDepthFromRoot = 2,
00073         AttackGoldSilverDepthFromRoot = 2,
00074         DropDepthFromRoot = 2,
00075         AttackMajorPieceDepthFromRoot = 2,
00076         AdvanceBishopDepthFromRoot = 2,
00077         AttackKing8DepthFromRoot = 2,
00078       };
00079       enum {
00080         ThreatMateDepthFromRoot = 2,
00081       };
00082       enum { 
00084         PassExtraDepth = 4,
00085       };
00086       enum {
00091 #ifdef QSEARCH_SET_MINIMUM_MOVES
00092         MinimumMoves = 6,
00093 #else
00094         MinimumMoves = 0,
00095 #endif
00096       };
00097     };
00098 
00099     struct QSearch2HelperBase
00100     {
00101       int& result;
00102       int alpha, beta;
00103       Move last_move;
00104       QSearch2HelperBase(int& r, int a, int b, Move l)
00105         : result(r), alpha(a), beta(b), last_move(l)
00106       {
00107       }
00108     };
00109 
00110     template <class QSearch2,Player P>
00111     struct QSearch2NextMove : public QSearch2HelperBase
00112     {
00113       typedef typename QSearch2::eval_t eval_t;
00114       QSearch2 *searcher;
00115       eval_t& ev;
00116       int additional_depth;
00117       QSearch2NextMove(int& r, QSearch2 *s, int a, int b, eval_t& e, Move l,
00118                        int additional)
00119         : QSearch2HelperBase(r, a, b, l), 
00120           searcher(s), ev(e), additional_depth(additional)
00121       {
00122       }
00123       void operator()(Square)
00124       {
00125         result = (*searcher).template searchInternal<PlayerTraits<P>::opponent>
00126           (beta, alpha, ev, last_move, additional_depth, QSearch2::BeforeUpdate);
00127       }
00128     };
00129     template <class QSearch2,Player P>
00130     struct QSearch2NextTakeBack : QSearch2HelperBase
00131     {
00132       typedef typename QSearch2::eval_t eval_t;
00133       QSearch2 *searcher;
00134       eval_t& ev;
00135       QSearch2NextTakeBack(int& r, QSearch2 *s, int a, int b, eval_t& e, Move l)
00136         : QSearch2HelperBase(r, a, b, l), searcher(s), ev(e)
00137       {
00138       }
00139       void operator()(Square)
00140       {
00141         ev.update(searcher->currentState(), last_move);
00142         result = (*searcher).template takeBackValue<PlayerTraits<P>::opponent>
00143           (beta, alpha, ev, last_move);
00144       }
00145     };
00146     template <class QSearch2,Player P>
00147     struct QSearch2TakeBackOrChase : QSearch2HelperBase
00148     {
00149       typedef typename QSearch2::eval_t eval_t;
00150       QSearch2 *searcher;
00151       eval_t& ev;
00152       QSearch2TakeBackOrChase(int& r, QSearch2 *s, int a, int b, eval_t& e, Move l)
00153         : QSearch2HelperBase(r, a, b, l), searcher(s), ev(e)
00154       {
00155       }
00156       void operator()(Square)
00157       {
00158         ev.update(searcher->currentState(), last_move);
00159         result = (*searcher).template takeBackOrChase<PlayerTraits<P>::opponent>
00160           (beta, alpha, ev, last_move);
00161       }
00162     };
00163     template <class Eval, Player P>
00164     struct QSearch2SafeEscape
00165     {
00166       const NumEffectState *state;
00167       Eval& eval;
00168       Piece target;
00169       bool has_safe_escape;
00170       bool is_invalid;
00171       Move last_move;
00172       QSearch2SafeEscape(const NumEffectState *s, Piece t, Eval& e, Move l)
00173         : state(s), eval(e), target(t), has_safe_escape(false), is_invalid(false), last_move(l)
00174       {
00175       }
00176       void operator()(Square)
00177       {
00178         const Player Turn = PlayerTraits<P>::opponent;
00179         assert(state->turn() == Turn);
00180         if (state->inCheck(alt(Turn)))
00181         {
00182           is_invalid = true;
00183           return;
00184         }
00185         eval.update(*state, last_move);
00186         MoveVector dummy;
00187         has_safe_escape
00188           = QuiescenceGenerator<Turn>::escapeByMoveOnly(*state, target, dummy);
00189       }
00190     };
00191     template <bool has_record>
00192     struct QSearch2Util
00193     {
00194       static bool moreMoves(const QuiescenceRecord *)
00195       {
00196         return false;
00197         // TODO: count number of moves outside of record
00198         // return (record->moves_size() < QSearch2PrivateTraits::MinimumMoves);
00199       }
00200     };
00201   } // namespace search
00202 } // namespace osl
00203 
00204 
00205 template <class EvalT>
00206 template <osl::Player P> 
00207 int osl::search::QuiescenceSearch2<EvalT>::
00208 searchProbCut(int alpha, int beta, eval_t& ev, Move last_move)
00209 {
00210   if (alpha != beta) {
00211     max_depth = QSearchTraits::MaxDepth/2;
00212     const int pawn_value2 = EvalT::captureValue(newPtypeO(alt(P),PAWN));
00213     const int margin = pawn_value2/2;
00214     const int alpha4 = EvalTraits<P>::max(alpha-margin, 
00215                                           base_t::winThreshold(alt(P)));
00216     assert(EvalTraits<P>::notLessThan(alpha, alpha4));
00217     const int beta4  = EvalTraits<P>::min(beta +margin,
00218                                           base_t::winThreshold(P));
00219     assert(EvalTraits<P>::notLessThan(beta4, beta));
00220     const int val4 = searchInternal<P>(alpha4, beta4, ev, last_move);
00221     if (EvalTraits<P>::betterThan(val4, beta4))
00222       return val4 - (beta4-beta);
00223     if (EvalTraits<P>::betterThan(alpha4, val4))
00224       return val4 - (alpha4-alpha);
00225   }
00226   max_depth = QSearchTraits::MaxDepth;
00227   return searchInternal<P>(alpha, beta, ev, last_move);
00228 }
00229 
00230 template <class EvalT>
00231 template <osl::Player P, osl::Ptype PTYPE> 
00232 inline
00233 bool osl::search::QuiescenceSearch2<EvalT>::
00234 generateAndExamineTakeBack2(MoveVector& moves, 
00235                             QuiescenceThreat& threat2, 
00236                             QuiescenceThreat& threat1,
00237                             int beta1, int beta2, eval_t const& ev)
00238 {
00239   mask_t pieces = state.state().effectedMask(P).template selectBit<PTYPE>()
00240     & state.state().piecesOnBoard(alt(P)).getMask(PtypeFuns<PTYPE>::indexNum);
00241   if (PTYPE == PAWN || PTYPE == LANCE || PTYPE == KNIGHT)
00242     pieces &= ~state.state().effectedMask(alt(P)).getMask(PtypeFuns<PTYPE>::indexNum);
00243   while (pieces.any())
00244   {
00245     const Piece target = state.state().pieceOf(pieces.takeOneBit()+PtypeFuns<PTYPE>::indexNum*32);
00246     assert(target.isOnBoardByOwner<PlayerTraits<P>::opponent>());
00247     assert(moves.empty());
00248     QuiescenceGenerator<P>::capture1(currentState(), target.square(), moves);
00249     const bool result
00250       = examineTakeBack2<P,false,true>(moves, threat2, threat1, 
00251                                        beta1, beta2, ev);
00252     moves.clear();
00253     if (result)
00254       return result;
00255   }
00256   return false;
00257 }
00258 
00259 
00260 template <class EvalT>
00261 template <osl::Player P, osl::Ptype PTYPE, bool has_record> 
00262 inline
00263 bool osl::search::QuiescenceSearch2<EvalT>::
00264 examineCapture(QuiescenceRecord *record,
00265                int& cur_val, MoveVector& moves, int& alpha, int beta, 
00266                eval_t const& ev, Piece last_move_piece, int additional_depth)
00267 {
00268   assert(alpha % 2);
00269   assert(beta % 2);
00270 
00271   {
00272     moves.clear();
00273     QuiescenceGenerator<P>::template capture<PTYPE,true>(state.state(), moves, last_move_piece);
00274 
00275     SortCaptureMoves::sortByTakeBack(state.state(), moves);
00276 
00277     return examineMoves<P,has_record,has_record,CAPTURE>
00278       (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev,
00279        additional_depth, last_move_piece.square());
00280   }
00281   return false;
00282 }
00283 
00284 #ifdef STAT_WIDTH_VS_LIMIT
00285 namespace osl 
00286 {
00287   namespace 
00288   {
00289     struct Reporter
00290     {
00291       stat::Average average;
00292       int count;
00293       Reporter() : count(0) {}
00294       ~Reporter()
00295       {
00296         std::cerr << "QuiescenceSearch2 " << average.getAverage() << std::endl;
00297       }
00298       void newRoot() { average.add(count); count=0; }
00299       void add() { ++count; }
00300     } _reporter;
00301   }
00302 }
00303 #endif
00304 
00305 template <class EvalT>
00306 template <osl::Player P, bool has_record, bool has_dont_capture, 
00307           osl::search::QSearchTraits::MoveType move_type> 
00308 bool osl::search::QuiescenceSearch2<EvalT>::
00309 examineMoves(QuiescenceRecord *record, int& cur_val, 
00310              const Move *first, const Move *last, 
00311              int& alpha, int beta, eval_t const& ev,
00312              int additional_depth, Square dont_capture)
00313 {
00314   assert(alpha % 2);
00315   assert(beta % 2);
00316 
00317   assert(EvalTraits<P>::notLessThan(alpha, cur_val));
00318 #if (! defined NDEBUG) && (! defined OSL_SMP)
00319   const bool in_pv = (alpha != beta);
00320 #endif
00321   while (first != last)
00322   {
00323     const Move move = *first++;
00324     if (move_type == CHECK)
00325     {
00326       if (depth() <= 0
00327           && ! move.isCapture() && ! isMajor(move.ptype()))
00328         continue;
00329     }
00330 
00331     if (has_dont_capture)
00332     {
00333       const Square to = move.to();
00334       if (to == dont_capture)
00335         continue;
00336     }
00337     assert((move_type == KING_ESCAPE) || (move_type == UNKNOWN)
00338            || (! ShouldPromoteCut::canIgnoreAndNotDrop<P>(move)));
00339 
00340     if(MoveStackRejections::probe<P>(state.state(),state.history(),state.curDepth(),move,alpha,state.repetitionCounter().checkCount(alt(P)))){
00341         continue;
00342     }
00343 #ifdef QSEARCH_DEBUG
00344     QuiescenceLog::pushMove(depth(), move, record);
00345 #endif
00346     const HashKey new_hash = state.currentHash().newHashWithMove(move);
00347     int result;
00348     // 千日手確認
00349     const Sennichite next_sennichite
00350       = state.repetitionCounter().isAlmostSennichite(new_hash);
00351     if (next_sennichite.isDraw())
00352     {
00353       result = base_t::drawValue();
00354     }
00355     else if (next_sennichite.hasWinner())
00356     {
00357       result = base_t::winByFoul(next_sennichite.winner());
00358     }
00359     else
00360     {
00361       eval_t new_ev = ev;
00362 #ifdef STAT_WIDTH_VS_LIMIT
00363       if (depthFromRoot() == 0)
00364         _reporter.add();
00365 #endif
00366       assert(next_sennichite.isNormal());
00367       typedef QSearch2NextMove<QuiescenceSearch2,P> helper_t;
00368       if (has_record && alpha != beta
00369           && record->bestMove().isNormal()) {
00370         // cut node
00371         helper_t helper(result, this, alpha, alpha, new_ev, move, 
00372                         additional_depth);
00373         state.doUndoMoveOrPass<P,helper_t>(new_hash, move, helper);
00374         if (EvalTraits<P>::betterThan(result, alpha)) {
00375           new_ev = ev;
00376           helper_t helper(result, this, alpha, beta, new_ev, move, 
00377                           additional_depth);
00378           state.doUndoMoveOrPass<P,helper_t>(new_hash, move, helper);
00379         }
00380       }
00381       else {
00382         // pv or all node
00383         helper_t helper(result, this, alpha, beta, new_ev, move, 
00384                         additional_depth);
00385         state.doUndoMoveOrPass<P,helper_t>(new_hash, move, helper);
00386       }
00387       
00388       // 打歩詰を厳密に
00389       if (base_t::isWinValue(P, result) && (! move.isPass())
00390           && move_classifier::MoveAdaptor<move_classifier::PawnDropCheckmate<P> >
00391           ::isMember(state.state(), move))
00392       {
00393         result = base_t::winByFoul(alt(P));
00394       }
00395     }
00396     if (EvalTraits<P>::betterThan(result, cur_val))
00397     {
00398       cur_val = result;
00399       if (EvalTraits<P>::betterThan(result, alpha))
00400       {
00401         alpha = result + EvalTraits<P>::delta;
00402         if (has_record)
00403         {
00404           if (base_t::isWinValue(P, cur_val))
00405           {
00406             Square king = state.state().kingSquare(alt(P));
00407             if (Ptype_Table.hasUnblockableEffect(move.ptypeO(), move.to(), king)) {
00408               record->setLowerBound(QSearchTraits::CheckmateSpecialDepth, cur_val, move);
00409             }
00410             else {
00411               // 現在は取り合いの結果詰でも本当に詰とは限らない c.f. 中合い
00412               record->setLowerBound(QSearchTraits::MaxDepth, cur_val, move);
00413             }
00414             assert(EvalTraits<P>::notLessThan(result, beta));
00415             return true;
00416           }
00417           else
00418           {
00419 #ifndef OSL_SMP
00420             assert((record->lowerDepth() < depth())
00421                    || EvalTraits<P>::notLessThan(cur_val, record->lowerBound())
00422                    || in_pv
00423                    || state.abort(move));
00424 #endif
00425             record->setLowerBound(depth(), cur_val, move);
00426           }
00427         }
00428         if (EvalTraits<P>::notLessThan(result, beta))
00429         {
00430           state.setKillerMove(move);
00431           if (! move.isCapture()) 
00432           {
00433             const int d = depth();
00434             state.historyTable().add(move, d*d);
00435           }
00436           return true;
00437         }
00438       }
00439     }
00440   }
00441   return false;
00442 }
00443 
00444 namespace osl
00445 {
00446   namespace search
00447   {
00448     inline QuiescenceRecord *qallocate(SimpleHashTable& table,
00449                                        const HashKey& key,
00450                                        int minusDepthFromRoot,
00451                                        SearchState2Core& state)
00452     {
00453       assert(minusDepthFromRoot <= 0 || minusDepthFromRoot == allocate_depth_in_threatmate);
00454       SimpleHashRecord *record 
00455         = table.allocate(key, minusDepthFromRoot);
00456       if (record) {
00457         state.setCurrentRecord(record);
00458         return &record->qrecord;
00459       }
00460       return 0;
00461     }
00462   }
00463 }
00464 
00465 template <class EvalT>
00466 template <osl::Player P, bool has_record>
00467 inline
00468 int osl::search::QuiescenceSearch2<EvalT>::
00469 staticValue(eval_t const& ev, int alpha, int beta, QuiescenceRecord *record)
00470 {
00471   const bool in_pv = (alpha != beta);
00472 #ifndef DONT_USE_CHECKMATE
00473   if (! in_pv) {
00474     bool in_threatmate = has_record && record->threatmate.maybeThreatmate(P);
00475     if (! in_threatmate
00476         && (state.hasLastRecord(1) && state.lastRecord(1)))
00477       in_threatmate
00478         = (state.lastRecord(1)->threatmate().status(P).status() == ThreatmateState::CHECK_AFTER_THREATMATE);
00479     if (in_threatmate) {
00480       const int result = ev.value() + base_t::threatmatePenalty(P);
00481       return result;
00482     }
00483   }
00484   if (in_pv) {
00485     const Move last_move = state.lastMove();
00486     const Square king = state.state().kingSquare(P);
00487     const bool one_hop_prook
00488       = (last_move.isNormal() && last_move.ptype() == PROOK
00489          && (last_move.capturePtype() == GOLD
00490              || last_move.capturePtype() == SILVER)
00491          && ((king.y() == last_move.to().y()
00492               && abs(king.x() - last_move.to().x()) < 3)
00493              || (king.x() == last_move.to().x()
00494                  && abs(king.y() - last_move.to().y()) < 3)));
00495     if (one_hop_prook && ! has_record) {
00496       record = qallocate(table, state.currentHash(), allocate_depth_in_threatmate, state);
00497     }
00498     if (has_record || record) {
00499       // try simulation if record exists
00500       Move checkmate_move=Move::INVALID();
00501       int threatmate_node = 0;
00502       if (record && record->threatmate.maybeThreatmate(P)) {
00503         threatmate_node += 50;
00504       } else if (one_hop_prook) {
00505         threatmate_node += 20;
00506       }
00507 #ifdef QSEARCH_THREATMATE
00508       else if ((depthFromRoot() < QSearch2PrivateTraits::ThreatMateDepthFromRoot)
00509                && state.tryThreatmate())
00510         threatmate_node += 20;
00511 #endif
00512       bool lose = state.isThreatmateState<P>
00513         (record->threatmateNodesLeft(threatmate_node),
00514          checkmate_move);
00515       if (! lose && record->threatmateNodesLeft(2))
00516         lose = state.isThreatmateStateShort<P>(2, checkmate_move);
00517       if (lose)
00518       {      
00519         const int result = ev.value() + base_t::threatmatePenalty(P);
00520         assert(checkmate_move.isValid());
00521         record->threatmate.setThreatmate(P, checkmate_move);
00522         record->setStaticValue(QuiescenceRecord::EXACT, result,
00523                                QSearchTraits::CheckmateSpecialDepth);
00524         assert(result % 2 == 0);
00525         return result;
00526       }
00527     }
00528   }
00529 #endif
00530   if (! in_pv && has_record) {
00531     int static_value, static_value_depth;
00532     QuiescenceRecord::StaticValueType type;
00533     if (record->hasStaticValue(static_value, static_value_depth, type)) {
00534       // upper bound は depth に因らない
00535       if (EvalTraits<P>::betterThan(alpha, static_value)) {
00536         assert(static_value % 2 == 0);
00537         return static_value;
00538       }
00539       if (type == QuiescenceRecord::EXACT
00540           && (static_value_depth >= depth())) {
00541         assert(static_value % 2 == 0);
00542         return static_value;
00543       }
00544     }
00545   }
00546   Move threatmate_move;
00547   if (ImmediateCheckmate::hasCheckmateMove<PlayerTraits<P>::opponent>
00548       (state.state(), threatmate_move))
00549   {
00550     const int result = ev.value() + base_t::threatmatePenalty(P);
00551     if (has_record)
00552     {
00553       record->threatmate.setThreatmate(P, threatmate_move);
00554       record->setStaticValue(QuiescenceRecord::EXACT, result,
00555                              QSearchTraits::CheckmateSpecialDepth);
00556     }
00557     assert(result % 2 == 0);
00558     return result;
00559   }
00560   if (alpha == beta && EvalTraits<P>::betterThan(ev.value(), beta)) {
00561     // futility pruning of threat
00562     int expect = ev.value() + ev.captureValue(newPtypeO(P, GOLD));
00563     Piece threat = state.state().findThreatenedPiece(P);
00564     if (threat.isPiece())
00565       expect += ev.captureValue(threat.ptypeO());
00566     if (EvalTraits<P>::betterThan(expect, beta))
00567       return expect;
00568   }
00569   const int eval_alpha = alpha;
00570   QuiescenceThreat threat1, threat2;
00571   const int result = staticValueWithThreat<P>(ev, eval_alpha, threat1, threat2);
00572   if (has_record)
00573   {
00574     record->setStaticValue(EvalTraits<P>::betterThan(eval_alpha, result) 
00575                            ? QuiescenceRecord::UPPER_BOUND
00576                            : QuiescenceRecord::EXACT,
00577                            result, depth(),
00578                            threat1, threat2);
00579   }
00580   assert(result % 2 == 0);
00581   return result;
00582 }
00583 
00584 template <class EvalT>
00585 template <osl::Player P>
00586 int osl::search::QuiescenceSearch2<EvalT>::
00587 searchInternal(int alpha, int beta, eval_t& ev, Move last_move,
00588                int additional_depth, EvalUpdateState need_eval_update)
00589 {
00590 #ifdef STAT_WIDTH_VS_LIMIT
00591   if (depthFromRoot() == 0)
00592     _reporter.newRoot();
00593 #endif
00594 #ifdef QSEARCH_DEBUG
00595   if (depthFromRoot() == 0)
00596     QuiescenceLog::enter(state.state());
00597 #endif
00598 #ifdef MAKE_PV_IN_QUIESCE2
00599   state.initPV();
00600 #endif
00601   ++node_count;
00602   assert(alpha % 2);
00603   assert(beta % 2);
00604   quiecence_assert(EvalTraits<P>::notLessThan(beta, alpha), last_move);
00605   assert(EvalTraits<P>::notLessThan(alpha, base_t::winThreshold(alt(P))));
00606   assert(EvalTraits<P>::notLessThan(base_t::winThreshold(P), beta));
00607   assert(last_move.player() == alt(P));
00608   
00609   // 自殺手を手生成でフィルタすると遅くなるので動かしてからチェック
00610   if (state.state().inCheck(alt(P)))
00611     return base_t::winByFoul(P);
00612 
00613   assert(state.hasLastRecord());
00614   QuiescenceRecord *record
00615     = qallocate(table, state.currentHash(), depth()-QSearchTraits::MaxDepth,
00616                 state);
00617   const QuiescenceRecord *parent 
00618     = (state.hasLastRecord(1) && state.lastRecord(1)) 
00619     ? &(state.lastRecord(1)->qrecord) : 0;
00620   const bool near_checkmate = parent 
00621     && (parent->threatmate.maybeThreatmate(alt(P))
00622         || parent->threatmate.mayHaveCheckmate(P)
00623         || (parent->threatmate.status(P).status()
00624             == ThreatmateState::CHECK_AFTER_THREATMATE));
00625   if (! record && near_checkmate)
00626   {
00627     const int depth = (alpha != beta) ? allocate_depth_in_threatmate : 0;
00628     record
00629       = qallocate(table, state.currentHash(), depth, state);
00630   }
00631   int result;
00632   if (! record) {
00633     result = searchMain<P,false>(0, alpha, beta, ev, last_move,
00634                                  additional_depth, need_eval_update);
00635     if (near_checkmate) {
00636       if ((EvalTraits<P>::betterThan(alpha, result)
00637            && parent->threatmate.maybeThreatmate(alt(P)))
00638           || (EvalTraits<P>::betterThan(result, alpha)
00639           && parent->threatmate.status(P).status()
00640            == ThreatmateState::CHECK_AFTER_THREATMATE)) {
00641         record
00642           = qallocate(table, state.currentHash(), allocate_depth_in_threatmate, state);
00643       }
00644     }
00645   }
00646   if (record)
00647   {
00648     const bool is_king_in_check = state.state().inCheck();
00649     record->updateThreatmate(P, (parent ? &(parent->threatmate) : 0), 
00650                              is_king_in_check);
00651     result = searchMain<P,true>(record, alpha, beta, ev, last_move,
00652                                 additional_depth, need_eval_update);
00653 #ifdef MAKE_PV_IN_QUIESCE2
00654     if ((alpha != beta) && EvalTraits<P>::betterThan(result, alpha)) 
00655       state.makePV(record->bestMove());
00656 #endif
00657   }
00658 #ifdef QSEARCH_DEBUG
00659   QuiescenceLog::node(depth(), alpha, beta, result);
00660 #endif
00661   assert(result % 2 == 0);
00662   return result;
00663 }
00664 
00665 template <class EvalT>
00666 int osl::search::QuiescenceSearch2<EvalT>::
00667 currentValueWithLastThreat(eval_t const& ev, Piece last_move_piece)
00668 {
00669   int static_value = ev.value();
00670   if (! (depthFromRoot() < QSearch2PrivateTraits::EscapeFromLastMoveDepthFromRoot))
00671     return static_value;
00672 
00673   assert(last_move_piece.isPiece());
00674   const Player P = last_move_piece.owner();
00675   PieceVector targets;
00676   const Square from = last_move_piece.square();
00677   EffectUtil::findThreat<EvalT>(state.state(), from, last_move_piece.ptypeO(),
00678                                 targets);
00679   if (targets.empty())
00680     return static_value;
00681   if (targets[0].ptype() == KING)
00682   {
00683     if (targets.size() < 2)
00684       return static_value;
00685     // 王手の両取り
00686     int threat = eval_t::captureValue(targets[1].ptypeO());
00687     if (state.state().hasEffectAt(alt(P), targets[1].square()))
00688       threat += eval_t::captureValue(last_move_piece.ptypeO());
00689     assert(eval::betterThan(P, threat, 0));
00690     return static_value + threat;
00691   }
00692   int first_threat = eval_t::captureValue(targets[0].ptypeO());
00693   if (state.state().hasEffectAt(alt(P), targets[0].square()))
00694     first_threat += eval_t::captureValue(last_move_piece.ptypeO());
00695   assert(eval::betterThan(P, first_threat, 0));
00696   first_threat /= SecondThreat;
00697   if (targets.size() < 2)
00698     return static_value + (first_threat & (~0x1));
00699 
00700   int second_threat = eval_t::captureValue(targets[1].ptypeO());
00701   if (state.state().hasEffectAt(alt(P), targets[1].square()))
00702     second_threat += eval_t::captureValue(last_move_piece.ptypeO());
00703   assert(eval::betterThan(P, second_threat, 0));
00704   return static_value + ((first_threat + second_threat) & (~0x1));
00705 }
00706 
00707 template <class EvalT>
00708 template <osl::Player P>
00709 int osl::search::QuiescenceSearch2<EvalT>::
00710 passValue(int alpha, int beta, eval_t const& ev)
00711 {
00712   // TODO:
00713   // - pass pass を許すならloop確認
00714   BOOST_STATIC_ASSERT(QSearch2PrivateTraits::EscapeDepthFromRoot <= 2);
00715   const Move pass = Move::PASS(P);
00716   int result;
00717   typedef QSearch2NextMove<QuiescenceSearch2,P> helper_t;
00718   helper_t helper(result, this, alpha, beta, ev, pass, 0);
00719   const HashKey new_hash = state.currentHash().newHashWithMove(pass);
00720 
00721   max_depth -= QSearch2PrivateTraits::PassExtraDepth;
00722   state.doUndoMoveOrPass<P,helper_t>(new_hash, pass, helper);
00723   max_depth += QSearch2PrivateTraits::PassExtraDepth;
00724   
00725   return result;
00726 }
00727 
00728 template <class EvalT>
00729 template <osl::Player P, bool has_record>
00730 int osl::search::QuiescenceSearch2<EvalT>::
00731 searchMain(QuiescenceRecord *record, 
00732            int alpha, int beta, eval_t& ev, Move last_move,
00733            int additional_depth, EvalUpdateState& need_eval_update)
00734 {
00735   const bool in_pv = (alpha != beta);
00736 #if (! defined NDEBUG) && (! defined OSL_USE_RACE_DETECTOR)
00737   static stat::Ratio ratio("QSearch2: cut");
00738 #endif
00739   assert((! has_record) || record);
00740   assert(alpha % 2);
00741   assert(beta % 2);
00742   assert((last_move == state.lastMove()) 
00743          || ! last_move.isNormal() || ! state.lastMove().isNormal());
00744 #if (!defined OSL_USE_RACE_DETECTOR) && (!defined MINIMAL)
00745   state.depth_node_count_quiesce[state.curDepth()]++;
00746 #endif
00747 #ifndef DONT_USE_CHECKMATE
00748   const int node_count_before = node_count;
00749 #endif
00750   const Square last_to = last_move.to();
00751   int cur_val = base_t::winByCheckmate(alt(P));
00752   if (has_record)
00753   {
00754     if ((! in_pv && record->lowerDepth() >= depth())
00755         || record->lowerDepth() >= QSearchTraits::HistorySpecialDepth)
00756     {
00757       if (EvalTraits<P>::notLessThan(record->lowerBound(), cur_val))
00758       {
00759         cur_val = record->lowerBound();
00760         if (EvalTraits<P>::betterThan(record->lowerBound(), alpha))
00761         {
00762           alpha  = record->lowerBound() + EvalTraits<P>::delta;
00763           if (EvalTraits<P>::betterThan(record->lowerBound(), beta))
00764           {
00765 #if (! defined NDEBUG) && (! defined OSL_USE_RACE_DETECTOR)
00766             ratio.add(true);
00767 #endif
00768             return record->lowerBound();
00769           }
00770         }
00771       }
00772     }
00773 #ifndef DONT_USE_CHECKMATE
00774     assert(record);
00775     // try simulation if record exists
00776     if (in_pv) {
00777       Move checkmate_move=Move::INVALID();
00778       if (need_eval_update == BeforeUpdate) {
00779         ev.update(state.state(), last_move);
00780         need_eval_update = AfterUpdate;
00781       }
00782       bool win = state.isWinningState<P>
00783         (0, checkmate_move);
00784       if (! win && record->threatmate.mayHaveCheckmate(alt(P))) {
00785         win = state.isWinningStateShort<P>(2, checkmate_move);
00786       }
00787       if (win) {      
00788         const int result = base_t::winByCheckmate(P);
00789         assert(checkmate_move.isValid());
00790         assert(state.state().isValidMove(checkmate_move));
00791         record->setLowerBound(QSearchTraits::CheckmateSpecialDepth, 
00792                               result, checkmate_move);
00793         return result;
00794       }
00795     }
00796 #endif
00797     if ((! in_pv && record->upperDepth() >= depth())
00798         || record->upperDepth() >= QSearchTraits::HistorySpecialDepth)
00799     {
00800       if (EvalTraits<P>::betterThan(beta, record->upperBound()))
00801       {
00802         beta = record->upperBound() - EvalTraits<P>::delta;
00803         if (EvalTraits<P>::betterThan(alpha, record->upperBound()))
00804         {
00805 #if (! defined NDEBUG) && (! defined OSL_USE_RACE_DETECTOR)
00806           ratio.add(true);
00807 #endif
00808           return record->upperBound();
00809         }
00810       }
00811     }
00812 #if (! defined NDEBUG) && (! defined OSL_USE_RACE_DETECTOR)
00813     ratio.add(false);
00814 #endif
00815   }
00816   if (need_eval_update == BeforeUpdate) {
00817     ev.update(state.state(), last_move);
00818     need_eval_update = AfterUpdate;
00819   }
00820   const bool is_king_in_check = state.state().inCheck();
00821   MoveVector moves;
00822   if (is_king_in_check)
00823   {
00824     if (last_move.isNormal() && last_move.isCapture()
00825         && unpromote(last_move.capturePtype()) == ROOK
00826         && unpromote(last_move.ptype()) != ROOK)
00827       ++additional_depth;
00828     else     
00829       // 王手でのtakebackの応酬の延長
00830       if (state.lastMove(2).isNormal() // hasLastMove(3)を兼ねる
00831           && state.lastMove(3).isNormal()
00832           && state.lastMove(4).isNormal()
00833           && state.lastMove(2).to() == last_move.to()
00834           && state.lastMove(3).to() == last_move.to()
00835           && state.lastMove(4).to() == last_move.to())
00836         ++additional_depth;
00837     // 王手がかかっている時はきちんと逃げる
00838     {
00839       QuiescenceGenerator<P>::escapeKing(state.state(), moves);
00840       // GenerateEscape は玉で取る手が逃げる手より後回しになることがあるので
00841       move_order::CaptureSort::sort(moves.begin(), moves.end());
00842       examineMoves<P,has_record,false,KING_ESCAPE>
00843         (record, cur_val, &*moves.begin(), &*moves.end(),alpha, beta, ev,
00844          additional_depth);
00845     }
00846     if (has_record)
00847     {
00848       if (EvalTraits<P>::betterThan(beta, cur_val))
00849         record->setUpperBound(depth(), cur_val);
00850     }
00851     return cur_val;
00852   }
00853   assert(! is_king_in_check);
00854   King8Info king_info(state.state().Iking8Info(alt(P)));
00855   PieceMask pins = state.state().pin(alt(P));
00856   Move checkmate_move=Move::INVALID();
00857   Square kingSquare=state.state().template kingSquare<PlayerTraits<P>::opponent>();
00858   if ((depth() <= 4)
00859       ? ImmediateCheckmate::hasCheckmateMove<P>(state.state(), king_info,kingSquare,checkmate_move)
00860       : state.isWinningStateShort<P>(2, checkmate_move)) {
00861     const int result = base_t::winByCheckmate(P);
00862     assert(checkmate_move.isValid());
00863     if(has_record)
00864     {
00865       assert(state.state().isValidMove(checkmate_move));
00866       record->setLowerBound(QSearchTraits::CheckmateSpecialDepth, 
00867                             result, checkmate_move);
00868     }
00869     return result;
00870   }
00871   // assert(ev.value() == eval_t(state.state()).value()); // !!! SLOW !!!
00872 
00873   if (depth() <= 0 && has_record) {
00874     if (record->threatmate.maybeThreatmate(P))
00875       return ev.value() + base_t::threatmatePenalty(P);
00876     if (record->threatmate.mayHaveCheckmate(alt(P)))
00877       return ev.value() + base_t::threatmatePenalty(alt(P));
00878   }
00879 
00880   const Ptype last_capture = last_move.isNormal() 
00881     ? last_move.capturePtype() : PTYPE_EMPTY;
00882   const Ptype last_ptype = last_move.isNormal() 
00883     ? last_move.ptype() : PTYPE_EMPTY;
00884   const bool king_escape = (last_ptype == KING) && last_capture == PTYPE_EMPTY;
00885 
00886   if ((depth() + std::min(additional_depth,2) <= -2)
00887       || (depth() <= 0 && additional_depth == 0)
00888       || (! king_escape
00889           && ((depth() + additional_depth <= 0)
00890               || (depth() <= 0 && last_capture != PTYPE_EMPTY 
00891                   && last_ptype != KING))))
00892   {
00893     if (ev.progress16().value() == 15
00894         && state.tryThreatmate()
00895         && ImmediateCheckmate::hasCheckmateMove<PlayerTraits<P>::opponent>(state.state()))
00896       return ev.value() + base_t::threatmatePenalty(P);
00897     const int base = takeBackValue<P>(alpha, beta, ev, last_move);
00898 #ifdef QSEARCH_LAST_CHECK_PENALTY
00899     if ((last_move.ptype() == KING)
00900         && (last_capture == PTYPE_EMPTY))
00901     {
00902       // 最後の手が王手回避 => ペナルティ
00903       // 銀くらい取れそう
00904       return base+eval_t::captureValue(newPtypeO(alt(P), KNIGHT));
00905     }
00906 #endif
00907     return base;
00908   }
00909   // 王手でなければパスを認めるので最初に静的評価値を求める
00910   const int static_value
00911     = ((depth() <= 0)
00912        ? takeBackValue<P>(alpha, beta, ev, last_move)
00913 #ifdef QSEARCH_REAL_PASS
00914        : ((depthFromRoot() < QSearch2PrivateTraits::EscapeDepthFromRoot)
00915           && (! last_move.isPass()))
00916        ? passValue<P>(alpha, beta, ev)
00917 #endif
00918        : staticValue<P,has_record>(ev, alpha, beta, record))
00919 #ifndef MINIMAL
00920     + (OslConfig::evalRandom() ? HashRandom::value(state.currentHash()): 0)
00921 #endif
00922     ;
00923   assert(static_value % 2 == 0);
00924   assert(! isWinValue(alt(P), static_value));
00925 #ifdef QSEARCH_DEBUG
00926   QuiescenceLog::staticValue(depth(), static_value);
00927 #endif
00928   if (EvalTraits<P>::notLessThan(static_value, cur_val))
00929   {
00930     cur_val = static_value;
00931     if (EvalTraits<P>::betterThan(cur_val, alpha))
00932     {
00933       alpha = cur_val + EvalTraits<P>::delta;
00934       if (has_record)
00935       {
00936 #ifndef OSL_SMP
00937         assert((record->lowerDepth() < depth())
00938                || EvalTraits<P>::notLessThan(cur_val, record->lowerBound())
00939                || in_pv);
00940 #endif
00941         record->setLowerBound(depth(), cur_val, record->bestMove());
00942       }
00943       if (EvalTraits<P>::betterThan(cur_val, beta))
00944         return cur_val;
00945     }
00946   }
00947 
00948   // 反映済のはず
00949   assert(alpha == EvalTraits<P>::max(alpha, cur_val + EvalTraits<P>::delta));
00950   assert(EvalTraits<P>::notLessThan(beta, alpha));
00951 
00952   Piece last_capture_piece = Piece::EMPTY();
00953   if (! has_record)
00954   {
00955     state.getBigramKillerMoves(moves);
00956     if (examineMoves<P,has_record,false,UNKNOWN>
00957         (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev,
00958          additional_depth))
00959       return cur_val;
00960     moves.clear();
00961   }
00962   else          
00963   {
00964     // has_record
00965     // best move
00966     const Move bestmove_in_record=record->bestMove();
00967     if (bestmove_in_record.isNormal())
00968     {
00969       assert(state.state().template isAlmostValidMove<true>(bestmove_in_record));
00970       assert(moves.empty());
00971       moves.push_back(bestmove_in_record);
00972       if (examineMoves<P,has_record,false,UNKNOWN>
00973           (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev,
00974            additional_depth))
00975         return cur_val;
00976       moves.clear();
00977       last_capture_piece = state.state().pieceOnBoard(bestmove_in_record.to());
00978     }
00979     // killer moves
00980     MoveVector killer_moves;
00981     state.getBigramKillerMoves(killer_moves);
00982     assert(moves.empty());
00983     MoveVector record_moves;
00984     record->loadMoves(record_moves);
00985     BOOST_FOREACH(Move move, killer_moves)
00986     {
00987       if (std::find(record_moves.begin(), record_moves.end(), move)
00988           == record_moves.end())
00989         moves.push_back(move);
00990     }
00991     record->addKillerMoves(moves);
00992     
00993     if (examineMoves<P,has_record,false,UNKNOWN>
00994         (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev,
00995          additional_depth))
00996       return cur_val;
00997     // already generated moves
00998     if (examineMoves<P,has_record,false,UNKNOWN>
00999         (record, cur_val, &*record_moves.begin(), &*record_moves.end(), alpha, beta, ev, additional_depth))
01000       return cur_val;
01001     moves.clear();
01002   }
01003 
01004   // TakeBack 優先
01005   assert(moves.empty());
01006   if (((! has_record) || record->movesEmpty())
01007       && (! last_to.isPieceStand()))
01008   {
01009     last_capture_piece = state.state().pieceOnBoard(last_to);
01010     QuiescenceGenerator<P>::capture(state.state(), 
01011                                            last_capture_piece.square(), moves);
01012     if (examineMoves<P,has_record,false,CAPTURE>
01013         (record, cur_val, &*moves.begin(), &*moves.end(),alpha, beta, ev,
01014          additional_depth))
01015     {
01016       if (has_record)
01017       {
01018         // 後で重複してしまうが記録してくれないと困るので
01019         record->addKillerMoves(moves);
01020       }
01021       return cur_val;
01022     }
01023   }
01024 
01025   // 詰めろ防止
01026   const bool has_threatmate
01027     = has_record 
01028     && record->threatmate.isThreatmate(P)
01029 #ifdef OSL_SMP
01030     && record->threatmate.threatmateMove(P).isNormal()
01031 #endif
01032     ;
01033   if (has_threatmate)
01034   {
01035     moves.clear();
01036     QuiescenceGenerator<P>::breakThreatmate
01037       (state.state(), record->threatmate.threatmateMove(P), pins, moves);
01038     if (examineMoves<P,has_record,false,KING_ESCAPE>
01039         (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev,
01040          additional_depth))
01041       return cur_val;
01042   }
01043 
01044   // 取る手
01045   if (examineCapture<P,ROOK,has_record>
01046       (record, cur_val, moves, alpha, beta, ev, last_capture_piece, additional_depth))
01047     return cur_val;
01048   if (examineCapture<P,BISHOP,has_record>
01049       (record, cur_val, moves, alpha, beta, ev, last_capture_piece, additional_depth))
01050     return cur_val;
01051   if (examineCapture<P,GOLD,has_record>
01052       (record, cur_val, moves, alpha, beta, ev, last_capture_piece, additional_depth))
01053     return cur_val;
01054   if (examineCapture<P,SILVER,has_record>
01055       (record, cur_val, moves, alpha, beta, ev, last_capture_piece, additional_depth))
01056     return cur_val;
01057   if ((depth() >= QSearch2PrivateTraits::KnightCaptureDepth)
01058       || max_depth <= 2
01059       || QSearch2Util<has_record>::moreMoves(record))
01060   {
01061     if (examineCapture<P,KNIGHT,has_record>
01062         (record, cur_val, moves, alpha, beta, ev, last_capture_piece, additional_depth))
01063       return cur_val;
01064     if (examineCapture<P,LANCE,has_record>
01065         (record, cur_val, moves, alpha, beta, ev, last_capture_piece, additional_depth))
01066       return cur_val;
01067   }
01068   // suggested move by evaluation function
01069   {
01070     const Move suggested = ev.suggestMove(state.state());
01071     if (suggested.isNormal()) {
01072       assert(state.state().isAlmostValidMove(suggested));
01073       moves.clear();
01074       moves.push_back(suggested);
01075       if (examineMoves<P,has_record,false,UNKNOWN>
01076           (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev,
01077            additional_depth)) {
01078         return cur_val;
01079       }
01080     }
01081   }
01082   // 王手
01083   const Move last2_move = state.lastMove(2);
01084   if ((depth() > 2
01085        || (depth() > 0 && !(has_record && record->threatmate.maybeThreatmate(P)))
01086        || (last2_move.isNormal() && last2_move.capturePtype() == ROOK))
01087       && ! (! in_pv && has_record && record->threatmate.maybeThreatmate(P)))
01088   {
01089     moves.clear();
01090 
01091     if (has_record)
01092       QuiescenceGenerator<P>::check(state.state(), pins,
01093                                     (king_info.liberty() == 0),
01094                                     record->sendOffSquare<P>(state.state()), 
01095                                     moves);
01096     else
01097       QuiescenceGenerator<P>::check(state.state(), pins, moves,
01098                                     (king_info.liberty() == 0));
01099     if (examineMoves<P,has_record,false,CHECK>
01100         (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev,
01101          additional_depth))
01102       return cur_val;
01103   }
01104 
01105   const Square my_king = state.state().template kingSquare<P>();
01106 
01107   if (depth() <= 0)
01108     goto finish;
01109   // futility pruning
01110   if (! in_pv
01111       && EvalTraits<P>::betterThan(alpha, ev.value() + (200+350+50*depth())*ev.captureValue(newPtypeO(alt(P),PAWN))/200))
01112     goto king_walk;
01113   if ((depth() >= QSearch2PrivateTraits::AttackPinnedDepth)
01114       || QSearch2Util<has_record>::moreMoves(record))
01115   {
01116     {
01117       moves.clear();
01118       QuiescenceGenerator<P>::attackToPinned(state.state(), pins, moves);
01119       if (examineMoves<P,has_record,false,ATTACK>
01120           (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev,
01121            additional_depth))
01122         return cur_val;
01123     }
01124   }
01125 
01126   if ((depthFromRoot() < QSearch2PrivateTraits::DropDepthFromRoot)
01127       || (isMajorBasic(last2_move.capturePtype())
01128           && ((depthFromRoot() < QSearch2PrivateTraits::DropDepthFromRoot+2)
01129               || (has_record && record->movesSizeLessThan(4))
01130             ))
01131       || QSearch2Util<has_record>::moreMoves(record))
01132   {
01133     {
01134       moves.clear();
01135       QuiescenceGenerator<P>::dropMajorPiece3(state.state(), moves, state.historyTable());
01136       if (last_move.isNormal() && isPiece(last_move.capturePtype())
01137           && unpromote(last_move.capturePtype())== BISHOP
01138           && last2_move.isNormal() && last2_move.capturePtype() == BISHOP
01139           && unpromote(last2_move.ptype()) == BISHOP) // 合わせた角を取った
01140       {
01141         const Square drop_again = last2_move.from();
01142         if (! state.state().template hasEffectAt<PlayerTraits<P>::opponent>(drop_again)
01143             // これ以降は多分常にtrue
01144             && state.state().pieceOnBoard(drop_again) == Piece::EMPTY()
01145             && state.state().template hasPieceOnStand<BISHOP>(P))
01146           moves.push_back(Move(drop_again, BISHOP, P));
01147       }
01148 
01149       if (examineMoves<P,has_record,true,OTHER>
01150           (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev,
01151            additional_depth))
01152         return cur_val;
01153     }
01154   }
01155   if ((depth() >= QSearch2PrivateTraits::PawnCaptureDepth)
01156       || max_depth <= 2
01157       || QSearch2Util<has_record>::moreMoves(record))
01158   {
01159     if (examineCapture<P,PAWN,has_record>
01160         (record, cur_val, moves, alpha, beta, ev, last_capture_piece, additional_depth))
01161       return cur_val;
01162   }
01163   if ((depth() >= QSearch2PrivateTraits::FullPromoteDepth)
01164       || max_depth <= 2)
01165   {
01166     moves.clear();
01167     QuiescenceGenerator<P>::promote(state.state(), pins, moves);
01168     if (examineMoves<P,has_record,false,PROMOTE>
01169         (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev, additional_depth))
01170       return cur_val;
01171   }
01172   else
01173   {
01174     moves.clear();
01175     QuiescenceGenerator<P>::template promoteN<ROOK,2>(state.state(), moves, state.historyTable());
01176     QuiescenceGenerator<P>::template promoteN<BISHOP,2>(state.state(), moves, state.historyTable());
01177     if (examineMoves<P,has_record,false,PROMOTE>
01178         (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev, additional_depth))
01179       return cur_val;
01180     moves.clear();
01181     QuiescenceGenerator<P>::template promoteN<PAWN,2>(state.state(), moves, state.historyTable());
01182     QuiescenceGenerator<P>::template promoteN<LANCE,1>(state.state(), moves, state.historyTable());
01183     QuiescenceGenerator<P>::template promoteN<KNIGHT,1>(state.state(), moves, state.historyTable());
01184     if (examineMoves<P,has_record,false,PROMOTE>
01185         (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev, additional_depth))
01186       return cur_val;
01187   }
01188   if (depthFromRoot() < QSearch2PrivateTraits::EscapeDepthFromRoot)
01189   {
01190     {
01191       moves.clear();
01192       QuiescenceGenerator<P>::escapeAll(state.state(), moves);
01193       if (examineMoves<P,has_record,false,ESCAPE>
01194           (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev, additional_depth))
01195         return cur_val;
01196     }
01197   }
01198   else if ((depthFromRoot() < QSearch2PrivateTraits::EscapeFromLastMoveDepthFromRoot)
01199            || (last_move.isDrop() && isMajorBasic(last_move.ptype()))
01200            || (last_move.isNormal() && last2_move.isNormal() 
01201                && isMajor(last2_move.ptype())
01202                && state.state().hasEffectByPiece
01203                (state.state().pieceOnBoard(last_to), last2_move.to()))
01204            || QSearch2Util<has_record>::moreMoves(record))
01205   {
01206     {
01207       moves.clear();
01208       QuiescenceGenerator<P>::template escapeFromLastMove<EvalT>(state.state(), last_move, moves);
01209       if (examineMoves<P,has_record,false,ESCAPE>
01210           (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev, additional_depth))
01211         return cur_val;
01212     }
01213   }
01214   if ((depthFromRoot() < QSearch2PrivateTraits::AttackMajorPieceDepthFromRoot)
01215       || (isMajor(last_move.ptype())
01216           && last_move.isCapture()
01217           && last_to.template canPromote<P>())
01218       || (state.state().hasEffectAt(P, last_to)
01219           && (state.state().
01220               template hasEffectByPtype<ROOK>(alt(P), last_to)))
01221       || ((depthFromRoot() < QSearch2PrivateTraits::AttackMajorPieceDepthFromRoot+2)
01222           && ((last2_move.capturePtype()==KNIGHT)
01223               || (last2_move.capturePtype()==LANCE)
01224               || (last2_move.capturePtype()==BISHOP)))
01225       || QSearch2Util<has_record>::moreMoves(record))
01226   {
01227     {
01228       moves.clear();
01229       QuiescenceGenerator<P>::attackMajorPiece(state.state(), pins, moves);
01230       if (examineMoves<P,has_record,true,ATTACK>
01231           (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev, additional_depth))
01232         return cur_val;
01233     }
01234   }
01235   {
01236     const QuiescenceRecord *parent 
01237       = (state.hasLastRecord(1) && state.lastRecord(1)) 
01238       ? &(state.lastRecord(1)->qrecord) : 0;
01239     if ((depthFromRoot() < QSearch2PrivateTraits::AttackKing8DepthFromRoot)
01240         || (last_move.isNormal() && last_move.ptype() == KING
01241             && last_move.isCapture())
01242         || (((parent && parent->threatmate.isThreatmate(alt(P)))
01243              || (king_info.liberty() == 0))
01244             && depthFromRoot() < 2+QSearch2PrivateTraits::AttackKing8DepthFromRoot)
01245         || QSearch2Util<has_record>::moreMoves(record))
01246     {
01247       {
01248         moves.clear();
01249         QuiescenceGenerator<P>::attackKing8(state.state(), pins, moves);
01250         if (examineMoves<P,has_record,false,ATTACK>
01251             (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev, additional_depth))
01252           return cur_val;
01253       }
01254     }
01255   }
01256   if ((depthFromRoot() < QSearch2PrivateTraits::AttackGoldSilverDepthFromRoot)
01257       || QSearch2Util<has_record>::moreMoves(record))
01258   {
01259     {
01260       moves.clear();
01261       QuiescenceGenerator<P>::attackGoldWithPawn(state.state(), pins, moves);
01262       QuiescenceGenerator<P>::attackSilverWithPawn(state.state(), pins, moves);
01263       if (examineMoves<P,has_record,false,ATTACK>
01264           (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev, additional_depth))
01265         return cur_val;
01266     }
01267   }
01268   if ((depthFromRoot() < QSearch2PrivateTraits::AttackKnightDepthFromRoot)
01269       || QSearch2Util<has_record>::moreMoves(record))
01270   {
01271     {
01272       moves.clear();
01273       QuiescenceGenerator<P>::attackKnightWithPawn(state.state(), pins, moves);
01274       if (examineMoves<P,has_record,false,ATTACK>
01275           (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev, additional_depth))
01276         return cur_val;
01277     }
01278   }
01279   if ((depth() >= QSearch2PrivateTraits::UtilizePromotedDepth)
01280       || QSearch2Util<has_record>::moreMoves(record))
01281   {
01282     if (last2_move.isNormal())
01283     {
01284       const Piece last_piece = state.state().pieceOnBoard(last2_move.to());
01285       assert(last_piece.isPiece());
01286       if (last_piece.owner() == P)
01287       {
01288         moves.clear();
01289         QuiescenceGenerator<P>::utilizePromoted(state.state(), last_piece, moves);
01290         if (examineMoves<P,has_record,true,OTHER>
01291             (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev, additional_depth))
01292           return cur_val;
01293       }
01294     }
01295   }
01296   
01297   if ((depthFromRoot() < QSearch2PrivateTraits::AdvanceBishopDepthFromRoot)
01298       || QSearch2Util<has_record>::moreMoves(record))
01299   {
01300     {
01301       moves.clear();
01302       QuiescenceGenerator<P>::advanceBishop(state.state(), moves);
01303       if (examineMoves<P,has_record,true,OTHER>
01304           (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev, additional_depth))
01305         return cur_val;
01306     }
01307   }
01308 king_walk:
01309   if (has_threatmate
01310       || (! my_king.template canPromote<PlayerTraits<P>::opponent>() //自陣以外
01311           && last2_move.isNormal() && last2_move.ptype() == KING))
01312   {                             
01313     {
01314       moves.clear();
01315       QuiescenceGenerator<P>::kingWalk(state.state(), moves);
01316       if (examineMoves<P,has_record,true,OTHER>
01317           (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev, additional_depth))
01318         return cur_val;
01319     }
01320   }
01321 finish:
01322   // cut しなかった
01323   assert(EvalTraits<P>::betterThan(beta, cur_val));
01324   assert(! isWinValue(alt(P), cur_val));
01325 #ifndef DONT_USE_CHECKMATE
01326   const bool threatmate
01327     = EvalTraits<P>::betterThan(ev.captureValue(newPtypeO(P,KING)), cur_val);
01328   int check_after_threatmate = 0;
01329   if (in_pv 
01330       && (threatmate
01331           || (check_after_threatmate = state.countCheckAfterThreatmate(alt(P),2))))
01332   {
01333     // test sudden checkmate
01334     int checkmate_nodes = (node_count - node_count_before)/2;
01335     if (check_after_threatmate)
01336     {
01337       if (depthFromRoot() == 1) 
01338       {
01339         const int sacrifice = state.countCheckAfterThreatmateSacrifice(alt(P),2);
01340         checkmate_nodes = std::max(checkmate_nodes, 
01341                                    sacrifice*125+check_after_threatmate*50);
01342       }
01343       else 
01344       {
01345         checkmate_nodes = std::max(50, checkmate_nodes);
01346       }
01347     }
01348     if (threatmate)
01349     {
01350       if (! has_record)
01351         record = qallocate(table, state.currentHash(), allocate_depth_in_threatmate, state);
01352       checkmate_nodes = std::max(checkmate_nodes, 200);
01353     }
01354     Move check_move;
01355     const bool win = (record && checkmate_nodes >= 50)
01356       ? state.isWinningState<P>(record->checkmateNodesLeft(checkmate_nodes), 
01357                                 checkmate_move)
01358       : (((record && record->checkmateNodesLeft(2))
01359           || (! has_record && threatmate))
01360          ? state.isWinningStateShort<P>(2, checkmate_move)
01361          : false);
01362     if (win)
01363     {
01364       const int result = base_t::winByCheckmate(P);
01365       assert(checkmate_move.isValid());
01366       if (! has_record && ! record)
01367         record = qallocate(table, state.currentHash(), allocate_depth_in_threatmate, state);
01368       if (has_record || record) {
01369         assert(state.state().isValidMove(checkmate_move));      
01370         record->setLowerBound(QSearchTraits::CheckmateSpecialDepth, 
01371                               result, checkmate_move);
01372       }
01373       return result;
01374     }
01375   }
01376 #if 0
01377   // cache がないと重いのでとりあえずoff
01378   // しょうがないので詰将棋 (シミュレーションのみ) を呼ぶ
01379   if (! has_record)
01380   {
01381     assert(! record);
01382     Move checkmate_move=Move::INVALID();
01383     AttackOracleAges oracle_age_dummy;
01384     const bool win_found        // TODO: last move のみとどちらが良い?
01385       = state.isWinningState<P>
01386       (0, checkmate_move, oracle_age_dummy);
01387     if (win_found)
01388     {
01389       const int result = base_t::winByCheckmate(P);
01390       assert(checkmate_move.isValid());
01391       record = qallocate(table, state.currentHash(), allocate_depth_in_threatmate, state);
01392       if (record)
01393       {
01394         record->setLowerBound(QSearchTraits::CheckmateSpecialDepth, 
01395                               result, checkmate_move);
01396       }
01397       return result;
01398     }
01399   }
01400 #endif
01401 #endif
01402 
01403   if (has_record)
01404   {
01405     if (EvalTraits<P>::betterThan(beta, cur_val))
01406       record->setUpperBound(depth(), cur_val);
01407   }
01408   return cur_val;
01409 }
01410 
01411 namespace osl
01412 {  
01413   inline bool importantMove(const NumEffectState& state, Move move,
01414                             Square my_king, Square op_king)
01415   {
01416     if (move.ptype() == KING)
01417       return true;
01418     my_king = Centering3x3::adjustCenter(my_king);
01419     op_king = Centering3x3::adjustCenter(op_king);
01420     if (Neighboring8Direct::hasEffect(state, move.ptypeO(), move.to(), op_king)
01421         || Neighboring8Direct::hasEffect(state, move.ptypeO(), move.to(), my_king))
01422       return true;
01423     return move.isCapture()
01424       && ((! move.isDrop() && state.longEffectAt(move.from()).any())
01425           || Neighboring8Direct::hasEffect(state, move.capturePtypeO(), move.to(), my_king)
01426           || Neighboring8Direct::hasEffect(state, move.capturePtypeO(), move.to(), op_king));
01427   }
01428 }
01429 
01430 template <class EvalT>
01431 template <osl::Player P>
01432 bool osl::search::QuiescenceSearch2<EvalT>::
01433 examineTakeBack(const MoveVector& moves,
01434                 int& cur_val, int& alpha, int beta, eval_t const& ev)
01435 {
01436   assert(alpha % 2);
01437   assert(beta % 2);
01438   assert(EvalTraits<P>::betterThan(alpha, cur_val));
01439   assert(EvalTraits<P>::notLessThan(beta, alpha));
01440 
01441   const Square my_king = state.state().template kingSquare<P>();
01442   const Square op_king = state.state().template kingSquare<PlayerTraits<P>::opponent>();
01443   
01444   BOOST_FOREACH(Move move, moves)
01445   {
01446 #ifdef QSEARCH_DEBUG
01447     QuiescenceLog::pushMove(depth(), move, 0);
01448 #endif
01449     const int see = See::see(state.state(), move, state.state().pin(P), state.state().pin(alt(P)), &eval_t::Piece_Value);
01450     int result;
01451     if (see > 0 && importantMove(state.state(), move, my_king, op_king)) 
01452     {
01453       eval_t new_ev = ev;
01454       // TODO: futility pruning here
01455       typedef QSearch2NextTakeBack<QuiescenceSearch2,P> helper_t;
01456       helper_t helper(result, this, alpha, beta, new_ev, move);
01457       // 表を使わないのでcast
01458       state.doUndoMoveLight<P,helper_t>(move, helper);
01459     }
01460     else 
01461     {
01462       result = ev.value() + see*eval_t::seeScale()*EvalTraits<P>::delta;
01463     }
01464     // 安い順にsortしたので一直線に読む 王手回避はする
01465     if (! base_t::isWinValue(alt(P), result))
01466     {
01467       cur_val = EvalTraits<P>::max(cur_val, result);
01468       return EvalTraits<P>::notLessThan(result, beta);
01469     }
01470   }
01471   assert(EvalTraits<P>::betterThan(beta, cur_val));
01472   return false;
01473 }
01474 
01475 template <class EvalT>
01476 template <osl::Player P, bool calm_move_only, bool first_normal_move_only>
01477 bool osl::search::QuiescenceSearch2<EvalT>::
01478 examineTakeBack2(const MoveVector& moves, 
01479                  QuiescenceThreat& threat2, QuiescenceThreat& threat1, 
01480                  int beta1, int beta2, eval_t const& ev)
01481 {
01482   if (moves.empty())
01483     return false;
01484   // P は取る側
01485   using move_classifier::Check;
01486   using move_classifier::MoveAdaptor;
01487   assert(beta1 % 2);
01488   assert(beta2 % 2);
01489   assert(EvalTraits<P>::notLessThan(threat1.value, threat2.value));     // threat1 >= threat2
01490   assert(EvalTraits<P>::betterThan(beta1, threat1.value)); // beta1 > threat1
01491   assert(EvalTraits<P>::betterThan(beta2, threat2.value)); // beta2 > threat2
01492   assert(EvalTraits<P>::notLessThan(beta1, beta2)); // beta1 >= beta2
01493   assert(state.state().turn() == P);
01494 
01495   const Square my_king = state.state().template kingSquare<P>();
01496   const Square op_king = state.state().template kingSquare<PlayerTraits<P>::opponent>();
01497 
01498   int best_value = threat2.value;
01499   BOOST_FOREACH(Move move, moves)
01500   {
01501     const Square to = move.to();
01502     assert(! ShouldPromoteCut::canIgnoreAndNotDrop<P>(move));
01503     if (calm_move_only 
01504         && (state.state().countEffect(alt(P),to) > state.state().countEffect(P,to)))
01505       continue;
01506 #ifdef QSEARCH_DEBUG
01507     QuiescenceLog::pushMove(depth(), move, 0);
01508 #endif
01509     int result;
01510     const int see = See::see(state.state(), move, state.state().pin(P), state.state().pin(alt(P)), &eval_t::Piece_Value);
01511     if (see > 0 && importantMove(state.state(), move, my_king, op_king)) 
01512     {
01513       eval_t new_ev = ev;
01514       // TODO: futility pruning here
01515       const int beta = EvalTraits<P>::notLessThan(threat1.value, beta2) ? beta2 : beta1;
01516       typedef QSearch2NextTakeBack<QuiescenceSearch2,P> helper_t;
01517       helper_t helper(result, this, 
01518                       threat2.value+EvalTraits<P>::delta, beta, new_ev, move);
01519       state.doUndoMoveLight<P,helper_t>(move, helper);
01520     }
01521     else
01522     {
01523       result = ev.value() + see*eval_t::seeScale()*EvalTraits<P>::delta;
01524     }
01525     // first_normal_move_only:安い順にsortしたので一直線に読む (王手回避はする)
01526     if (base_t::isWinValue(alt(P), result))
01527       continue;
01528 
01529     // 終了処理
01530     if (EvalTraits<P>::betterThan(result, best_value))
01531     {
01532       best_value = result;
01533       if (EvalTraits<P>::notLessThan(best_value, threat1.value))
01534       {
01535         threat2 = threat1;
01536         threat1 = QuiescenceThreat(best_value, move);
01537         if (EvalTraits<P>::betterThan(threat1.value, beta1)
01538             || EvalTraits<P>::betterThan(threat2.value, beta2))
01539           return true;
01540       } 
01541       else 
01542       {
01543         assert(EvalTraits<P>::notLessThan(best_value, threat2.value));
01544         threat2 = QuiescenceThreat(best_value, move);
01545         if (EvalTraits<P>::betterThan(threat2.value, beta2))
01546           return true;
01547       }
01548     }
01549     if (first_normal_move_only)
01550       break;
01551   }
01552   return false;
01553   
01554   // 取り返す手でcutしなかった場合:
01555   // 逃げられない脅威の評価 (Opponent が逃げる)
01556   // 逃げられない場合はthreat1 だけでなくthreat2にもsetする
01557   assert(! moves.empty());
01558   if (! EvalTraits<P>::betterThan(best_value, threat2.value))
01559     return false;
01560   const Move threat_move = *moves.begin();
01561   if (! first_normal_move_only)
01562   {
01563     assert(state.lastMove().isPass());
01564     state.popPass();
01565     bool cut_by_threat2 = false;
01566     // 成る手が防げるか? TODO: 長い利きを近くで止める
01567     const Player Opponent = PlayerTraits<P>::opponent;
01568     MoveVector moves;
01569     move_generator::GenerateAddEffectWithEffect::generate<false>
01570       (Opponent, state.state(), threat_move.to(), moves);
01571     if (moves.empty())
01572     {
01573       threat2 = QuiescenceThreat(best_value, threat_move);
01574       if (EvalTraits<P>::betterThan(threat2.value, beta2))
01575         cut_by_threat2 = true;
01576     }
01577     state.pushPass();
01578     return cut_by_threat2;
01579   }
01580   else if ((depthFromRoot() < QSearch2PrivateTraits::EscapeFromLastMoveDepthFromRoot)
01581            || (unpromote(moves[0].capturePtype()) == ROOK)
01582            || (unpromote(moves[0].capturePtype()) == BISHOP))
01583   {
01584     assert(state.lastMove().isPass());
01585     state.popPass();
01586     bool cut_by_threat2 = false;
01587     const Square to = threat_move.to();
01588     const Piece target = state.state().pieceOnBoard(to);
01589     bool tried_escape
01590       = (depthFromRoot() < QSearch2PrivateTraits::EscapeDepthFromRoot);
01591 #ifdef QSEARCH_PESSIMISTIC_ESCAPE_THREAT
01592     if (state.lastMove().isNormal())
01593     {
01594       // 直前の利きは逃げているはずなので,パスは pessimistic に
01595       // TODO: escapeFromOtherThanPawnに合わせて hasEffectIf に変更
01596       const Offset32 offset32(to, state.lastMove().to());
01597       const EffectContent effect
01598         = Ptype_Table.getEffect(state.lastMove().ptypeO(),offset32);
01599       tried_escape = effect.hasEffect();
01600     }
01601 #endif
01602     if (! tried_escape)
01603     {
01604       const Player Opponent = PlayerTraits<P>::opponent;
01605       MoveVector escape;
01606       const bool safe_escape
01607         = QuiescenceGenerator<Opponent>::escapeByMoveOnly(state.state(), 
01608                                                           target, escape);
01609       if (safe_escape)
01610         goto finish;
01611       BOOST_FOREACH(Move move, escape)
01612       {
01613         eval_t new_ev = ev;
01614         new_ev.update(state.state(), Move::PASS(P));
01615         int result;
01616         if (isMajor(move.ptype()))
01617         {
01618           typedef QSearch2TakeBackOrChase<QuiescenceSearch2,Opponent> helper_t;
01619           helper_t helper(result, this, best_value+EvalTraits<Opponent>::delta, 
01620                           threat2.value+EvalTraits<P>::delta, new_ev, move);
01621           state.doUndoMoveLight<Opponent,helper_t>(move, helper);
01622         }
01623         else
01624         {
01625           typedef QSearch2NextTakeBack<QuiescenceSearch2,Opponent> helper_t;
01626           helper_t helper(result, this, best_value+EvalTraits<Opponent>::delta, 
01627                           threat2.value+EvalTraits<P>::delta, new_ev, move);
01628           state.doUndoMoveLight<Opponent,helper_t>(move, helper);
01629         }
01630         if (EvalTraits<Opponent>::betterThan(result, best_value))
01631         {
01632           best_value = result;
01633           if (EvalTraits<Opponent>::notLessThan(result, threat2.value))
01634             break;
01635         }
01636       }
01637     }
01638     if (EvalTraits<P>::betterThan(best_value, threat2.value))
01639     {
01640       threat2 = QuiescenceThreat(best_value, threat_move);
01641       if (EvalTraits<P>::betterThan(threat2.value, beta2))
01642       {
01643         cut_by_threat2 = true;
01644         goto finish;
01645       }
01646     }
01647   finish:
01648     state.pushPass();
01649     return cut_by_threat2;
01650   }
01651   return false;
01652 }
01653 
01654 template <class EvalT>
01655 template <osl::Player P>
01656 int osl::search::QuiescenceSearch2<EvalT>::
01657 takeBackOrChase(int alpha, int beta, eval_t const& ev, Move last_move)
01658 {
01659   assert(last_move.isNormal());
01660   int best_value = takeBackValue<P>(alpha, beta, ev, last_move);
01661   if (EvalTraits<P>::betterThan(best_value, beta))
01662     return best_value;
01663 
01664   MoveVector moves;
01665   QuiescenceGenerator<P>::capture1(state.state(), last_move.from(), moves);
01666   if (moves.empty())
01667     return best_value;
01668   BOOST_FOREACH(Move move, moves)
01669   {
01670     eval_t new_ev = ev;
01671 
01672     typedef QSearch2SafeEscape<eval_t, P> helper_t;
01673     helper_t helper(&state.state(), 
01674                     state.state().pieceOnBoard(last_move.to()),
01675                     new_ev, move);
01676     state.doUndoMoveLight<P,helper_t>(move, helper);    
01677     if (helper.is_invalid)
01678       continue;
01679 
01680     int result = new_ev.value();
01681     if (! helper.has_safe_escape)
01682       result += new_ev.captureValue(last_move.ptypeO());
01683     if (state.state().template hasEffectByPtype<ROOK>(P, move.from()))
01684       result += (new_ev.captureValue(newPtypeO(alt(P),PROOK))
01685                  - new_ev.captureValue(newPtypeO(alt(P),ROOK)));
01686     best_value = EvalTraits<P>::max(result, best_value);
01687     break;                      // 追撃は一手だけ試す
01688   }
01689   return best_value;
01690 }
01691 
01692 template <class EvalT>
01693 template <osl::Player P>
01694 int osl::search::QuiescenceSearch2<EvalT>::
01695 takeBackValue(int alpha, int beta, eval_t const& ev, Move last_move)
01696 {
01697   assert(alpha % 2);
01698   assert(beta % 2);
01699   
01700   ++node_count;
01701   assert(EvalTraits<P>::notLessThan(beta, alpha));
01702   if (state.state().inCheck(alt(P)))
01703     return base_t::winByFoul(P);
01704   if (last_move.isPass())
01705     return ev.value();
01706   
01707   const Square last_to = last_move.to();
01708   MoveVector moves;
01709   const Piece last_move_piece = state.state().pieceOnBoard(last_to);
01710   int cur_val;
01711   if (state.state().inCheck())
01712   {
01713     const bool check_by_lance = state.state().hasEffectByPtypeStrict<LANCE>
01714       (alt(P), state.state().template kingSquare<P>());
01715     const bool has_safe_move
01716       = QuiescenceGenerator<P>::escapeKingInTakeBack(state.state(), moves, check_by_lance);
01717     cur_val = (has_safe_move 
01718                ? currentValueWithLastThreat(ev, last_move_piece) 
01719                : base_t::winByCheckmate(alt(P)));
01720     assert(cur_val % 2 == 0);
01721   }
01722   else
01723   {
01724     cur_val = currentValueWithLastThreat(ev, last_move_piece);
01725     assert(cur_val % 2 == 0);
01726     if (EvalTraits<P>::betterThan(cur_val, beta)) // generate の省略
01727       return cur_val;
01728     QuiescenceGenerator<P>::capture1(state.state(), 
01729                                      last_move_piece.square(), moves);
01730   }
01731   if (EvalTraits<P>::betterThan(cur_val, alpha))
01732   {
01733     alpha = cur_val + EvalTraits<P>::delta;
01734     if (EvalTraits<P>::betterThan(cur_val, beta)) {
01735       return cur_val;
01736     }
01737   }
01738 
01739   assert(EvalTraits<P>::betterThan(alpha, cur_val));
01740   if (examineTakeBack<P>(moves, cur_val, alpha, beta, ev)) {
01741     assert(cur_val % 2 == 0);    
01742     return cur_val;
01743   }
01744   
01745   // cut しなかった
01746   assert(cur_val % 2 == 0);
01747   return cur_val;
01748 }
01749 
01750 template <class EvalT>
01751 template <osl::Player P>
01752 int osl::search::QuiescenceSearch2<EvalT>::
01753 staticValueWithThreat(eval_t const& ev, int alpha, 
01754                       QuiescenceThreat& threat1, QuiescenceThreat& threat2)
01755 {
01756   assert(alpha % 2);
01757   assert(! state.state().inCheck());
01758   const int static_value = ev.value();
01759   if (EvalTraits<P>::notLessThan(alpha, static_value))
01760     return static_value;
01761   const Player O = PlayerTraits<P>::opponent;
01762   const int FirstThreat = QSearchTraits::FirstThreat;
01763   const int SecondThreat
01764     = (depthFromRoot() < QSearch2PrivateTraits::EscapeDepthFromRoot)
01765     ? 1
01766     : QSearchTraits::SecondThreat;
01767 
01768   const int o_beta1
01769     = (EvalTraits<O>::min(base_t::winByCheckmate(O),
01770                           static_value - FirstThreat*(static_value - alpha))
01771        - ((FirstThreat % 2) ? 0 : EvalTraits<O>::delta));
01772   const int o_beta2
01773     = (EvalTraits<O>::min(base_t::winByCheckmate(O),
01774                           static_value - SecondThreat*(static_value - alpha))
01775        - ((SecondThreat % 2) ? 0 : EvalTraits<O>::delta));
01776 
01777   threat1.value = static_value;
01778   threat2.value = static_value;
01779   
01780   assert(state.state().turn() == P);
01781   state.pushPass();
01782 
01783   assert(! state.state().inCheck());
01784 
01785   assert(EvalTraits<O>::betterThan(o_beta1, threat1.value));
01786   assert(EvalTraits<O>::betterThan(o_beta2, threat1.value));
01787   assert(EvalTraits<O>::notLessThan(o_beta1, o_beta2));
01788   EvalT ev2(ev);
01789   ev2.update(state.state(), Move::PASS(P));
01790 
01791   MoveVector moves;
01792   if (generateAndExamineTakeBack2<O,ROOK>(moves, threat2, threat1, o_beta1, o_beta2, ev2))
01793     goto finish;
01794   if (generateAndExamineTakeBack2<O,BISHOP>(moves, threat2, threat1, o_beta1, o_beta2, ev2))
01795     goto finish;
01796   if (generateAndExamineTakeBack2<O,GOLD>(moves, threat2, threat1, o_beta1, o_beta2, ev2))
01797     goto finish;
01798   if (generateAndExamineTakeBack2<O,SILVER>(moves, threat2, threat1, o_beta1, o_beta2, ev2))
01799     goto finish;
01800   if (generateAndExamineTakeBack2<O,KNIGHT>(moves, threat2, threat1, o_beta1, o_beta2, ev2))
01801     goto finish;
01802   if (generateAndExamineTakeBack2<O,LANCE>(moves, threat2, threat1, o_beta1, o_beta2, ev2))
01803     goto finish;
01804   // 成る手は飛車と角と歩 (TODO: 玉の近傍)
01805   QuiescenceGenerator<O>::template promoteN<ROOK,1>(state.state(), moves, state.historyTable());
01806   if (examineTakeBack2<O,true,false>(moves, threat2, threat1, o_beta1, o_beta2, ev2))
01807     goto finish;
01808   moves.clear();
01809   QuiescenceGenerator<O>::template promoteN<BISHOP,1>(state.state(), moves, state.historyTable());
01810   if (examineTakeBack2<O,true,false>(moves, threat2, threat1, o_beta1, o_beta2, ev2))
01811     goto finish;
01812   moves.clear();
01813   QuiescenceGenerator<O>::template promoteN<PAWN,1>(state.state(), moves, state.historyTable());
01814   if (examineTakeBack2<O,true,false>(moves, threat2, threat1, o_beta1, o_beta2, ev2))
01815     goto finish;
01816   moves.clear();
01817   if (depth() >= QSearch2PrivateTraits::PawnCaptureDepth 
01818       || max_depth <= 2)
01819   {
01820     if (generateAndExamineTakeBack2<O,PAWN>(moves, threat2, threat1, o_beta1, o_beta2, ev2))
01821       goto finish;
01822   }
01823 finish:
01824   state.popPass();
01825   // handle the first threat more seriously in some condition 
01826   if (threat1.move == threat2.move && threat1.move.isNormal()) {
01827     const Piece target = state.state().pieceOnBoard(threat1.move.to());
01828     if (isMajorBasic(target.ptype())
01829         && target.square().template canPromote<O>()) {
01830       assert(alt(target.owner()) == O);
01831       assert(threat1.value % 2 == 0);
01832       return threat1.value;
01833     }
01834   }
01835   // usual KFEND-like threat handling
01836   const int result1 = (static_value - (static_value - threat1.value)/FirstThreat);
01837   const int result2 = (static_value - (static_value - threat2.value)/SecondThreat);
01838 
01839   const int result = EvalTraits<O>::max(result1, result2) & (~0x1);
01840   assert(result % 2 == 0);
01841   return result;
01842 }
01843 
01844 #endif /* OSL_QUIESCENCESEARCH2_TCC */
01845 // ;;; Local Variables:
01846 // ;;; mode:c++
01847 // ;;; c-basic-offset:2
01848 // ;;; End:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines