quiescenceGenerator.tcc
Go to the documentation of this file.
00001 /* quiescenceGenerator.tcc
00002  */
00003 #ifndef QUIESCENCEGENERATOR_TCC
00004 #define QUIESCENCEGENERATOR_TCC
00005 
00006 #include "osl/search/quiescenceGenerator.h"
00007 #include "osl/search/breakThreatmate.h"
00008 #include "osl/effect_util/unblockableEffect.h"
00009 #include "osl/effect_util/sendOffSquare.h"
00010 #include "osl/effect_util/additionalEffect.h"
00011 #include "osl/effect_util/shadowEffect.h"
00012 #include "osl/effect_util/neighboring8Direct.h"
00013 #include "osl/effect_util/effectUtil.h"
00014 #include "osl/effect_util/pin.h"
00015 #include "osl/move_generator/attackToPinned.h"
00016 #include "osl/move_generator/addEffectWithEffect.h"
00017 #include "osl/neighboring8.h"
00018 
00019 template <osl::Player P> 
00020 template <osl::Ptype PTYPE, bool has_dont_capture> 
00021 void osl::search::QuiescenceGenerator<P>::
00022 capture(const NumEffectState& state, MoveVector& moves, Piece dont_capture)
00023 {
00024   mask_t pieces = state.effectedMask(P).template selectBit<PTYPE>()
00025     & state.piecesOnBoard(alt(P)).getMask(PtypeFuns<PTYPE>::indexNum);
00026   
00027   if (has_dont_capture && dont_capture.isPiece() && (dont_capture.ptype() == PTYPE))
00028   {
00029     while (pieces.any()) {
00030       const Piece target = state.pieceOf(pieces.takeOneBit()+PtypeFuns<PTYPE>::indexNum*32);
00031       if (target != dont_capture)
00032         capture(state, target.square(), moves);
00033     }
00034   }
00035   else
00036   {
00037     while (pieces.any()) {
00038       const Piece target = state.pieceOf(pieces.takeOneBit()+PtypeFuns<PTYPE>::indexNum*32);
00039       capture(state, target.square(), moves);
00040     }
00041   }
00042   if (((PTYPE == KNIGHT) || (PTYPE == BISHOP))
00043       && state.hasPieceOnStand<LANCE>(P))
00044   {
00045     // 歩で駒を取る手がある場合は,追加利きをつける
00046 
00047     // NOTE: MoveVector はpush_backしてもiteratorをinvalidate
00048     // しないという仕様に依存
00049     MoveVector::const_iterator original_end = moves.end();
00050     for (MoveVector::const_iterator p=moves.begin(); p!=original_end; ++p)
00051     {
00052       const Square from = p->from();
00053       if ((p->oldPtype() == PAWN)
00054           && (state.hasEffectAt<PlayerTraits<P>::opponent>(p->to())))
00055       {
00056         move_generator::AdditionalLance<P>::generate(state, from, moves);
00057       }
00058     }
00059   }
00060 }
00061 
00062 template <osl::Player P> inline
00063 void osl::search::QuiescenceGenerator<P>::
00064 attackMajorPieceFirstSelection(const NumEffectState& state,
00065                                PieceMask pins, const MoveVector& all_moves,
00066                                MoveVector& moves,
00067                                MoveVector& expensive_drops)
00068 {
00069   BOOST_FOREACH(Move m, all_moves)
00070   {
00071     const Square to = m.to();
00072     {
00073       const int defense = state.countEffect(alt(P),to, pins);
00074       int offense = state.countEffect(P,to) + (m.isDrop() ? 1 : 0);
00075       if (defense >= offense)
00076         offense += AdditionalEffect::count2(state, to, P);
00077       if (m.ptype() != PAWN)
00078       {
00079         if (defense > offense)
00080           continue;
00081       }
00082       else
00083       {
00084         if (defense && (offense==1))
00085         {
00086           if (! (state.hasEffectByPtype<ROOK>(alt(P),to)
00087                  && state.hasEffectByPtype<BISHOP>(alt(P),to)))
00088             continue;
00089         }
00090       }
00091       const Ptype ptype = m.ptype();
00092       if ((defense >= offense)
00093           && (unpromote(ptype) != PAWN))
00094         continue;
00095       if (ptype != PAWN)
00096       {
00097         const Square front_position
00098           = to + DirectionPlayerTraits<U,P>::offset();
00099         const Piece front_piece = state.pieceAt(front_position);
00100         if (front_piece.ptypeO() == newPtypeO(alt(P),PAWN))
00101           continue;
00102       }
00103       if (m.isDrop() && (m.ptype() == PAWN)
00104           && to.canPromote<P>())
00105       {
00106         // 垂れ歩
00107         const Square back_position
00108           = to + DirectionPlayerTraits<D,P>::offset();
00109         if (state.pieceOnBoard(back_position).isEmpty())
00110           moves.push_back(Move(back_position, PAWN, P));
00111       }
00112       const int ptype_value = eval::Ptype_Eval_Table.value(ptype);
00113       const bool is_large_piece
00114         = (ptype_value > eval::PtypeEvalTraits<BISHOP>::val);
00115       if ((m.isDrop() 
00116            && (ptype_value > eval::PtypeEvalTraits<KNIGHT>::val))
00117           || (is_large_piece && defense))
00118         expensive_drops.push_back(m);
00119       else
00120         moves.push_back(m);
00121     }
00122   }
00123 }
00124 
00125 template <osl::Player P> inline
00126 void osl::search::QuiescenceGenerator<P>::
00127 attackMajorPieceSecondSelection(bool target_has_support,
00128                                 const MoveVector& src,
00129                                 MoveVector& out)
00130 {
00131   BOOST_FOREACH(Move m, src)
00132   {
00133     const Ptype ptype = m.ptype();
00134     if (target_has_support
00135         && (eval::Ptype_Eval_Table.value(ptype) 
00136             >= eval::PtypeEvalTraits<GOLD>::val))
00137       continue;
00138 
00139     out.push_back(m);
00140   }
00141 }
00142 
00143 template <osl::Player P>
00144 void osl::search::QuiescenceGenerator<P>::
00145 attackMajorPieceZerothSelection(const NumEffectState& state,
00146                                 const MoveVector& src,
00147                                 Square target,
00148                                 MoveVector& open_out,
00149                                 MoveVector& out)
00150 {
00151   BOOST_FOREACH(Move m, src)
00152   {
00153     assert(!ShouldPromoteCut::canIgnoreAndNotDrop<P>(m));
00154     const bool is_open
00155       = (! m.isDrop())
00156       && state.hasEffectAt<P>(m.from())
00157       && (state.hasEffectByPtype<LANCE>(P, m.from())
00158           || state.hasEffectByPtype<BISHOP>(P, m.from())
00159           || state.hasEffectByPtype<ROOK>(P, m.from()))
00160       && ! state.hasEffectIf(m.ptypeO(), m.to(), target);
00161     // 取る手は重複
00162     const bool may_overlap = m.isCaptureOrPromotion();
00163     if (is_open) 
00164     {
00165       if (! may_overlap         // 取り返される場合はたぶん重複しない
00166           || state.hasEffectAt<PlayerTraits<P>::opponent>(m.to()))
00167         open_out.push_back(m);
00168     }
00169     else 
00170     {
00171       if (! may_overlap)
00172         out.push_back(m);
00173     }
00174   }
00175 }
00176 
00177 template <osl::Player P>
00178 void osl::search::QuiescenceGenerator<P>::
00179 attackMajorPiece(const NumEffectState& state, PieceMask pins,
00180                  MoveVector& moves) 
00181 {
00182   using namespace move_action;
00183   MoveVector work;
00184   MoveVector unsupported, supported;
00185   assert(PtypeTraits<BISHOP>::indexLimit == PtypeTraits<ROOK>::indexMin);
00186   for (int i = PtypeTraits<BISHOP>::indexMin;
00187        i < PtypeTraits<ROOK>::indexLimit; i++)
00188   {
00189     const Piece p = state.pieceOf(i);
00190     if (p.isOnBoardByOwner<PlayerTraits<P>::opponent>())
00191     {
00192       const Square target = p.square();
00193       assert(isMajor(p.ptype()));
00194       const bool unstable_rook = (p.ptype() == ROOK)
00195         && (state.pieceAt(target + DirectionPlayerTraits<U, PlayerTraits<P>::opponent>::offset())
00196             != Piece::EMPTY()); // 前に進めない
00197       work.clear();
00198       if (state.hasEffectAt(alt(P), target) && (! unstable_rook))
00199       {
00200         move_generator::GenerateAddEffectWithEffect::generate<false>
00201           (P, state, target, work);
00202         attackMajorPieceZerothSelection(state, work, target, moves, supported); 
00203       }
00204       else if (unstable_rook || (! state.hasEffectAt(P, target)))
00205       {
00206         // ただで取れる時には利きをつけない
00207         move_generator::GenerateAddEffectWithEffect::generate<false>
00208           (P, state, target, work);
00209         attackMajorPieceZerothSelection(state, work, target, moves, unsupported);
00210       }
00211     }
00212   }
00213 
00214   // first pass
00215   MoveVector drops_supported, drops_unsupported;
00216   attackMajorPieceFirstSelection(state, pins, unsupported, moves, 
00217                                  drops_unsupported);
00218   attackMajorPieceFirstSelection(state, pins, supported, moves, 
00219                                  drops_supported);
00220   // second pass
00221   if (moves.size() > 5)
00222     return;
00223   attackMajorPieceSecondSelection(false, drops_unsupported, moves);
00224   if (moves.size() > 5)
00225     return;
00226   attackMajorPieceSecondSelection(true, drops_supported, moves);
00227 }
00228 
00229 template <osl::Player P>
00230 void osl::search::QuiescenceGenerator<P>::
00231 escapeNormalPiece(const NumEffectState& state, 
00232                   Piece escape, MoveVector& moves, bool add_support_only)
00233 {
00234   assert(escape.ptype() != KING);
00235   using namespace move_action;
00236   MoveVector all_moves;
00237   const Piece attack_piece
00238     = state.findCheapAttack(alt(P), escape.square());
00239   const int attack_ptype_value 
00240     = eval::Ptype_Eval_Table.value(unpromote(attack_piece.ptype()));
00241   const Square escape_from = escape.square();
00242   if (! add_support_only)
00243   {
00244     GenerateEscape<P>::generateCheap(state, escape, all_moves);
00245     BOOST_FOREACH(Move m, all_moves)
00246     {
00247       const Square to = m.to();
00248       if (m.isDrop())
00249       {
00250         if (! state.hasEffectAt<P>(to))
00251           continue;     // 中合
00252 #ifdef QSEARCH_EXPENSIVE_BLOCK
00253         if (eval::Ptype_Eval_Table.value(m.ptype()) > attack_ptype_value)
00254           continue;
00255 #else
00256         if (m.ptype() != PAWN)
00257           continue;
00258 #endif
00259         moves.push_back(m);
00260       }
00261       else
00262       {
00263         if (m.from() != escape_from)
00264         {
00265           // 移動合
00266           if (! state.hasMultipleEffectAt(P, to))
00267             continue;
00268           if (eval::Ptype_Eval_Table.value(m.ptype()) > attack_ptype_value)
00269             continue;
00270         }
00271         // 取る手は重複
00272         // TODO: KnightCaptureDepth
00273         assert(! ShouldPromoteCut::canIgnoreMove<P>(m));
00274         if (! m.isCaptureOrPromotion())
00275         {
00276           moves.push_back(m);
00277         }
00278       }
00279     }
00280   }
00281   // 紐をつける
00282   if (unpromote(attack_piece.ptype()) == PAWN)
00283     return;
00284   if ((eval::Ptype_Eval_Table.value(escape.ptype()) - attack_ptype_value)
00285       >= (eval::PtypeEvalTraits<BISHOP>::val - eval::PtypeEvalTraits<KNIGHT>::val))
00286     return;
00287   if (state.hasEffectAt<P>(escape_from)
00288       || (state.countEffect(alt(P), escape_from) != 1))
00289     return;
00290   all_moves.clear();
00291   move_generator::GenerateAddEffectWithEffect::generate<false>
00292     (P, state, escape_from, all_moves);
00293   const size_t escape_moves = moves.size();
00294   MoveVector not_drop;
00295   BOOST_FOREACH(Move m, all_moves)
00296   {
00297     const Square to = m.to();
00298     if (m.isDrop())
00299     {
00300       if (state.hasEffectAt<PlayerTraits<P>::opponent>(to)
00301           && (! state.hasEffectAt<P>(to)))
00302         continue;
00303       // 打つ手は歩か香車だけ
00304       if ((m.ptype() != PAWN) && (m.ptype() != LANCE))
00305         continue;
00306       moves.push_back(m);
00307     }
00308     else
00309     {
00310       // 移動
00311       const int defense = state.countEffect(P,to);
00312       const int offense = state.countEffect(alt(P),to);
00313       if (offense >= defense)
00314         continue;
00315       // 取る手は重複
00316       // TODO: KnightCaptureDepth
00317       assert(! ShouldPromoteCut::canIgnoreMove<P>(m));
00318       if (! m.isCaptureOrPromotion())
00319       {
00320         moves.push_back(m);
00321       }
00322     }
00323   }
00324   // 合わせ角
00325   if (state.hasEffectByPtype<BISHOP>(alt(P), escape_from)
00326       && state.hasPieceOnStand<BISHOP>(P))
00327   {
00328     const Piece bishop = state.findAttackAt<BISHOP>(alt(P), escape_from);
00329     assert(unpromote(bishop.ptype()) == BISHOP);
00330     {
00331       Square p = bishop.square();
00332       const Offset offset = Board_Table.getShortOffset(Offset32(p,escape_from));
00333       p += offset;
00334       while (state.pieceAt(p).isEmpty())
00335       {
00336         if (state.hasEffectAt<P>(p))
00337         {
00338           moves.push_back(Move(p, BISHOP, P));
00339           break;
00340         }
00341         p += offset;
00342       }
00343     }
00344   }
00345   
00346   if (escape_moves == moves.size()) // drop not found
00347     moves.push_back(not_drop.begin(), not_drop.end());
00348 }
00349 
00350 template <osl::Player P>
00351 void osl::search::QuiescenceGenerator<P>::
00352 escapeAll(const NumEffectState& state, MoveVector& moves) 
00353 {
00354   // 逃げるのは大駒か価値の一番高い駒のみ
00355   const PieceMask pieces = state.effectedMask(alt(P)) & state.piecesOnBoard(P);
00356   bool found_attacked_piece = false;
00357   mask_t m = pieces.selectBit<ROOK>();
00358   while (m.any())
00359   {
00360     const Piece p = state.pieceOf(m.takeOneBit()+PtypeFuns<ROOK>::indexNum*32);
00361     assert(p.isOnBoardByOwner<P>()
00362            && state.hasEffectAt<PlayerTraits<P>::opponent>(p.square()));
00363     found_attacked_piece = true;
00364     escapeNormalPiece(state, p, moves);
00365   }
00366   m = pieces.selectBit<BISHOP>();
00367   while (m.any())
00368   {
00369     const Piece p = state.pieceOf(m.takeOneBit()+PtypeFuns<BISHOP>::indexNum*32);
00370     assert(p.isOnBoardByOwner<P>()
00371            && state.hasEffectAt<PlayerTraits<P>::opponent>(p.square()));
00372     found_attacked_piece = true;
00373     escapeNormalPiece(state, p, moves);
00374   }
00375 
00376   if (found_attacked_piece)
00377     goto finish;
00378   m = pieces.selectBit<GOLD>();
00379   while (m.any())
00380   {
00381     const Piece p = state.pieceOf(m.takeOneBit()+PtypeFuns<GOLD>::indexNum*32);
00382     assert(p.isOnBoardByOwner<P>()
00383            && state.hasEffectAt<PlayerTraits<P>::opponent>(p.square()));
00384     escapeNormalPiece(state, p, moves);
00385     goto finish;
00386   }
00387   m = pieces.selectBit<SILVER>();
00388   while (m.any())
00389   {
00390     const Piece p = state.pieceOf(m.takeOneBit()+PtypeFuns<SILVER>::indexNum*32);
00391     assert(p.isOnBoardByOwner<P>()
00392            && state.hasEffectAt<PlayerTraits<P>::opponent>(p.square()));
00393     escapeNormalPiece(state, p, moves);
00394     goto finish;
00395   }
00396   m = pieces.selectBit<KNIGHT>();
00397   while (m.any())
00398   {
00399     // 成桂は逃げない
00400     const Piece p = state.pieceOf(m.takeOneBit()+PtypeFuns<KNIGHT>::indexNum*32);
00401     assert(p.isOnBoardByOwner<P>()
00402            && state.hasEffectAt<PlayerTraits<P>::opponent>(p.square()));
00403     escapeNormalPiece(state, p, moves, p.ptype()==PKNIGHT);
00404     goto finish;
00405   }
00406   m = pieces.selectBit<LANCE>();
00407   while (m.any())
00408   {
00409     // 香,成香は逃げない
00410     const Piece p = state.pieceOf(m.takeOneBit()+PtypeFuns<LANCE>::indexNum*32);
00411     assert(p.isOnBoardByOwner<P>()
00412            && state.hasEffectAt<PlayerTraits<P>::opponent>(p.square()));
00413     escapeNormalPiece(state, p, moves, true);
00414     goto finish;
00415   }
00416   m = pieces.selectBit<PAWN>();
00417   while (m.any())
00418   {
00419     // 歩,と金は逃げない
00420     const Piece p = state.pieceOf(m.takeOneBit()+PtypeFuns<PAWN>::indexNum*32);
00421     assert(p.isOnBoardByOwner<P>()
00422            && state.hasEffectAt<PlayerTraits<P>::opponent>(p.square()));
00423     escapeNormalPiece(state, p, moves, true);
00424     goto finish;
00425   }
00426 finish:
00427   return;
00428 }
00429 
00430 template <osl::Player P>
00431 template <class EvalT>
00432 void osl::search::QuiescenceGenerator<P>::
00433 escapeFromLastMoveOtherThanPawn(const NumEffectState& state, Move last_move, 
00434                                 MoveVector& moves)
00435 {
00436   if (! last_move.isNormal())
00437     return;
00438   assert(last_move.ptype() != PAWN);
00439 
00440   PieceVector targets;
00441   const Square from = last_move.to();
00442   EffectUtil::findThreat<EvalT>(state, from, last_move.ptypeO(), targets);
00443   if (targets.empty())
00444     return;
00445   assert(targets[0].ptype() != KING);
00446 
00447   escapeNormalPiece(state, targets[0], moves, 
00448                     (last_move.ptype() != PAWN)
00449                     && (eval::Ptype_Eval_Table.value(targets[0].ptype())
00450                         <= eval::Ptype_Eval_Table.value(KNIGHT)));
00451   if (targets.size() > 1)
00452     escapeNormalPiece(state, targets[1], moves, 
00453                       (last_move.ptype() != PAWN)
00454                       && (eval::Ptype_Eval_Table.value(targets[1].ptype())
00455                           <= eval::Ptype_Eval_Table.value(KNIGHT)));
00456 }
00457 
00458 template <osl::Player P>
00459 bool osl::search::QuiescenceGenerator<P>::
00460 escapeByMoveOnly(const NumEffectState& state, Piece piece, MoveVector& moves)
00461 {
00462   assert(piece.isOnBoardByOwner<P>());
00463 
00464   MoveVector all_moves;
00465   GeneratePieceOnBoard::generate(state.turn(),state,piece,all_moves);
00466    
00467   const Player Opponent = PlayerTraits<P>::opponent;
00468   const Square from = piece.square();
00469   
00470   const bool consider_shadowing
00471     = state.hasEffectByPtype<LANCE>(Opponent, from)
00472     || state.hasEffectByPtype<ROOK>(Opponent, from)
00473     || state.hasEffectByPtype<BISHOP>(Opponent, from);
00474   const bool is_major = isMajor(piece.ptype());
00475   const bool chase_danger
00476     = (! state.hasEffectAt(P, from)
00477        && (state.hasMultipleEffectAt(alt(P), from)
00478            || AdditionalEffect::hasEffect(state, from, alt(P))));
00479   BOOST_FOREACH(Move m, all_moves)
00480   {
00481     assert(m.from() == piece.square());
00482     if (m.isCapture())
00483       continue;
00484     const Square to = m.to();
00485     const bool safe_position
00486       = (consider_shadowing
00487          ? (! state.hasEffectByWithRemove<Opponent>(to, from))
00488          : (! state.hasEffectAt<Opponent>(to)));
00489     if (safe_position)
00490     {
00491       if (! is_major || ! chase_danger)
00492         return true;
00493       if (! to.canPromote<Opponent>())
00494         return true; // 自陣以外も対象にする場合は QuiescenceSearch も調整
00495       if ((to - from) != Board_Table.getShortOffset(Offset32(to, from)))
00496         return true;            // 二歩以上逃げられれば良し
00497     }
00498     moves.push_back(m);
00499   }
00500   return false;
00501 }
00502 
00503 template <osl::Player P>
00504 void osl::search::QuiescenceGenerator<P>::
00505 check(const NumEffectState& state, PieceMask pins, MoveVector& moves,
00506       bool no_liberty)
00507 {
00508   Square8 sendoffs;
00509   const Square king_position = state.kingSquare(alt(P));
00510   effect_util::SendOffSquare::find<P>(state, king_position, sendoffs);
00511   check(state, pins, no_liberty, sendoffs, moves);
00512 }
00513 
00514 
00515 template <osl::Player P>
00516 void osl::search::QuiescenceGenerator<P>::
00517 check(const NumEffectState& state, PieceMask pins, bool no_liberty, 
00518       const Square8& sendoffs, MoveVector& moves)
00519 {
00520   using namespace move_action;
00521   MoveVector all_moves;
00522   const Square king_position = state.kingSquare(alt(P));
00523   move_generator::GenerateAddEffectWithEffect::generate<true>
00524     (P, state, king_position, all_moves);
00525 
00526   MoveVector merginal_moves;
00527   BOOST_FOREACH(Move m, all_moves)
00528   {
00529     // 取る手,成る手は重複
00530     assert(! ShouldPromoteCut::canIgnoreAndNotDrop<P>(m));
00531     if (m.isPromotion())
00532       continue;
00533     const Square to = m.to();
00534     const Ptype captured = m.capturePtype();
00535     
00536     if ((captured != PTYPE_EMPTY)
00537         && (eval::Ptype_Eval_Table.value(captured)
00538             >= eval::PtypeEvalTraits<KNIGHT>::val))
00539       continue;
00540     const bool is_open
00541       = (! m.isDrop())
00542       && state.hasEffectAt<P>(m.from())
00543       && (state.hasEffectByPtype<LANCE>(P, m.from())
00544           || state.hasEffectByPtype<BISHOP>(P, m.from())
00545           || state.hasEffectByPtype<ROOK>(P, m.from()))
00546       && ! state.hasEffectIf(m.ptypeO(), m.to(), king_position);
00547     if (! is_open)
00548     {
00549       if ((m.ptype() != PAWN) && (m.ptype() != KNIGHT))
00550       {
00551         // 歩の前は読まない
00552         const Square front_position
00553           = to + DirectionPlayerTraits<U,P>::offset();
00554         const Piece front_piece = state.pieceAt(front_position);
00555         if (front_piece.ptypeO() == newPtypeO(alt(P),PAWN))
00556           continue;
00557       }
00558       if (! sendoffs.isMember(to))
00559       {
00560         const int defense = state.countEffect(alt(P),to, pins);
00561         int offense = state.countEffect(P,to) + no_liberty;
00562         const bool may_effective = offense && (! sendoffs.empty());
00563         if (m.isDrop())
00564           ++offense;
00565         if (defense >= offense)
00566           offense += AdditionalEffect::count2(state, to, P);
00567         if (defense >= offense)
00568           offense += ShadowEffect::count2(state, to, P);
00569         if (m.ptype() == KNIGHT)
00570         {
00571           const Square front_position
00572             = to + DirectionPlayerTraits<U,P>::offset();
00573           if (state.hasEffectAt<P>(front_position))
00574             offense+=1;         // pin もしくは空いた場所に何か打てるかも
00575         }
00576         if (defense > offense)
00577         {
00578           const bool side_attack
00579             = (king_position.x() == 1 || king_position.x() == 9)
00580             && m.ptype() == PAWN;
00581           if (! side_attack)
00582             continue;           // 乱暴な王手は指さない
00583         }
00584         else if (defense == offense)
00585         {
00586           if ((unpromote(m.ptype()) == PAWN)
00587               || state.hasEffectByPtype<PAWN>(P, to)
00588               || state.hasEffectByPtype<LANCE>(P, to))
00589             moves.push_back(m);
00590           else if (may_effective)
00591             merginal_moves.push_back(m);
00592           continue;
00593         }
00594       }
00595     }
00596     if (m.isDrop() && (m.ptype() == PAWN)
00597         && to.canPromote<P>())
00598     {
00599       // 垂れ歩
00600       const Square back_position
00601         = to + DirectionPlayerTraits<D,P>::offset();
00602       if (state.pieceOnBoard(back_position).isEmpty())
00603         moves.push_back(Move(back_position, PAWN, P));
00604     }
00605     moves.push_back(m);
00606   }
00607   if (moves.size() < 3)
00608     moves.push_back(merginal_moves.begin(), merginal_moves.end());
00609 }
00610 
00611 template <osl::Player P>
00612 void osl::search::QuiescenceGenerator<P>::
00613 promote(const NumEffectState& state, PieceMask pins, MoveVector& moves)
00614 {
00615   using namespace move_action;
00616   MoveVector all_moves;
00617   move_generator::Promote<P>::generate(state, all_moves);
00618 
00619   BOOST_FOREACH(Move m, all_moves)
00620   {
00621     const Square to = m.to();
00622     const int defense = state.countEffect(alt(P),to, pins);
00623     int offense = state.countEffect(P,to);
00624     if (defense >= offense)
00625       offense += AdditionalEffect::count2(state, to, P);
00626     if (m.ptype() == PPAWN
00627         && defense && offense + 1 >= defense)
00628     {
00629       // 歩が成れる時は追加利きをつけてみる?
00630       if (m.ptype() == PPAWN)
00631       {
00632         // 飛車が横に動く
00633         for (int i = PtypeTraits<ROOK>::indexMin;
00634              i < PtypeTraits<ROOK>::indexLimit; ++i)
00635         {
00636           const Piece rook = state.pieceOf(i);
00637           if (! rook.isOnBoardByOwner<P>() || rook.ptype() == PROOK
00638               || rook.square().template canPromote<P>())
00639             continue;
00640           const Square mid(m.from().x(), rook.square().y());
00641           if (state.pieceOnBoard(mid).isEmpty()
00642               && state.isEmptyBetween(m.from(), mid)
00643               && state.isEmptyBetween(rook.square(), mid))
00644           {
00645             const Move m(rook.square(), mid, ROOK, PTYPE_EMPTY, false, P);
00646             moves.push_back(m);
00647           }
00648         }
00649         if (state.hasPieceOnStand<LANCE>(P))
00650           move_generator::AdditionalLance<P>::generate(state, m.from(), moves);
00651         // あとは桂馬くらい?
00652       }
00653     }
00654     if (defense > offense)
00655     {
00656       continue;     // 成りではあまり乱暴な手は指さない
00657     }
00658     if ((defense == offense)
00659         && (m.ptype() != PPAWN))
00660       continue;
00661 
00662     moves.push_back(m);
00663   }
00664 }
00665 
00666 template <osl::Player P>
00667 void osl::search::QuiescenceGenerator<P>::
00668 attackKing8(const NumEffectState& state, PieceMask pins, MoveVector& moves) 
00669 {
00670   using namespace move_action;
00671   MoveVector all_moves;
00672 
00673   MoveVector not8;
00674   MoveVector not_drop;
00675   MoveVector major_drop;
00676   move_generator::AddEffect8<P>::generate(state, all_moves);
00677 
00678   const Square king_position = state.kingSquare(alt(P));
00679   const int king_x = king_position.x();
00680   BOOST_FOREACH(Move m, all_moves)
00681   {
00682     // 取る手,成る手は重複
00683     assert(! ShouldPromoteCut::canIgnoreAndNotDrop<P>(m));
00684     assert(! m.isPromotion());
00685     const Square to = m.to();
00686 #ifndef NDEBUG
00687     const Ptype captured = m.capturePtype();
00688     assert(captured==PTYPE_EMPTY);
00689 #endif    
00690 
00691     const Ptype ptype = m.ptype();
00692 
00693     const int defense = state.countEffect(alt(P),to,pins);
00694     int offense = state.countEffect(P,to) + (m.isDrop() ? 1 : 0);
00695     if (defense >= offense)
00696       offense += AdditionalEffect::count2(state, to, P);
00697     if (ptype == PAWN)
00698     {
00699       const Square head = to + DirectionPlayerTraits<U,P>::offset();
00700       if (state.hasEffectAt<P>(head))
00701         ++offense;
00702     }
00703     if (defense > offense)
00704       continue;
00705     if (defense == offense)
00706     {
00707       if (ptype != PAWN)
00708         continue;
00709     }
00710     if (isMajor(ptype))
00711     {
00712       if (defense == 0)
00713       {
00714         // 大駒は利きのあるところにはいかない TODO: kingのみ許可?
00715         if (isPromoted(ptype) && to.x() == king_x 
00716             && abs(to.y() - king_position.y()) <= 2)
00717           moves.push_back(m);
00718         else if (m.isDrop())
00719           major_drop.push_back(m);
00720         else
00721           not_drop.push_back(m);
00722       }
00723       continue;
00724     } 
00725     if (Ptype_Table.getMoveMask(m.ptype()) == PtypeTraits<GOLD>::moveMask)
00726     {
00727       const int y = to.y();
00728       if (((P == BLACK) && (y == 1))
00729           || ((P == WHITE) && (y == 9)))
00730         continue;               // 1段目の金類
00731     }
00732     // 歩の前は読まない TODO: 桂馬だけ許す?
00733     if (ptype != PAWN)
00734     {
00735       if (state.hasEffectByPtype<PAWN>(alt(P), to))
00736         continue;
00737       if (state.hasEffectByPtype<LANCE>(alt(P), to))
00738       {
00739         not_drop.push_back(m);
00740         continue;
00741       }
00742     }
00743     if (! Neighboring8::isNeighboring8(king_position, to))
00744       not8.push_back(m);
00745     else if (! m.isDrop())
00746       not_drop.push_back(m);
00747     else
00748       moves.push_back(m);
00749   }
00750   const size_t minimum_moves
00751     = (king_position.squareForBlack<P>().y() == 1) ? 3 : 2;
00752   for (MoveVector::const_iterator p=not8.begin();
00753        (p!=not8.end()) && (moves.size() <= minimum_moves); ++p)
00754   {
00755     moves.push_back(*p);
00756   }
00757   for (MoveVector::const_iterator p=not_drop.begin();
00758        (p!=not_drop.end()) && (moves.size() <= minimum_moves); ++p)
00759   {
00760     moves.push_back(*p);
00761   }
00762   for (MoveVector::const_iterator p=major_drop.begin();
00763        (p!=major_drop.end()) && (moves.size() <= minimum_moves); ++p)
00764   {
00765     moves.push_back(*p);
00766   }
00767 }
00768 
00769 template <osl::Player P>
00770 void osl::search::QuiescenceGenerator<P>::
00771 attackToPinned(const NumEffectState& state, PieceMask pins, MoveVector& moves)
00772 {
00773   using namespace move_action;
00774   MoveVector all_moves;
00775   move_generator::AttackToPinned<P>::generate(state, all_moves);
00776   
00777   BOOST_FOREACH(Move m, all_moves)
00778   {
00779     // 取る手,成る手は重複
00780     assert(!ShouldPromoteCut::canIgnoreAndNotDrop<P>(m));
00781     if (m.isPromotion())
00782       continue;
00783     const Square to = m.to();
00784     const Ptype captured = m.capturePtype();
00785     
00786     if (captured != PTYPE_EMPTY)
00787       continue;
00788 
00789     const Ptype ptype = m.ptype();
00790 
00791     const int defense = state.countEffect(alt(P),to,pins);
00792     int offense = state.countEffect(P,to) + (m.isDrop() ? 1 : 0);
00793     if (defense >= offense)
00794       offense += AdditionalEffect::count2(state, to, P);
00795     if (ptype == PAWN)
00796     {
00797       const Square head = to + DirectionPlayerTraits<U,P>::offset();
00798       if (state.hasEffectAt<P>(head))
00799         ++offense;
00800     }
00801     if (defense > offense)
00802       continue;
00803     if (defense == offense)
00804     {
00805       if (ptype != PAWN)
00806         continue;
00807     }
00808     // 歩の前は読まない TODO: 桂馬だけ許す?
00809     if (ptype != PAWN)
00810     {
00811       const Square front_position
00812         = to + DirectionPlayerTraits<U,P>::offset();
00813       const Piece front_piece = state.pieceAt(front_position);
00814       if (front_piece.ptypeO() == newPtypeO(alt(P),PAWN))
00815         continue;
00816     }
00817     moves.push_back(m);
00818   }
00819 }
00820 
00821 template <osl::Player P>
00822 void osl::search::QuiescenceGenerator<P>::
00823 utilizePromoted(const NumEffectState& state, Piece target,
00824                 MoveVector& moves)
00825 {
00826   if (! target.isPromoted())
00827     return;
00828   if (/*isMajor*/
00829       target.ptype() == ROOK
00830       || target.ptype() == BISHOP)
00831     return;
00832 
00833   MoveVector all_moves;
00834   move_generator::GeneratePieceOnBoard::generate(P,state, target, all_moves);
00835 
00836   MoveVector others;
00837   const Player Opponent = PlayerTraits<P>::opponent;
00838   bool has_good_capture = false;
00839   bool may_have_additional = false; // 飛車の前とか
00840   BOOST_FOREACH(Move m, all_moves)
00841   {
00842     assert(m.from() == target.square());
00843     if (m.isCapture())
00844     {
00845       if (m.capturePtype() != PAWN)
00846         has_good_capture =true;
00847       continue;
00848     }
00849     
00850     const Square to = m.to();
00851     int offense = state.countEffect(P, to);
00852     const int defense = state.countEffect(Opponent, to);
00853     const int additional = AdditionalEffect::count2(state, to, P);
00854     if (defense >= offense)
00855     {
00856       offense += additional;
00857       may_have_additional |= (additional > 0);
00858     }
00859     if (defense >= offense)
00860     {
00861       others.push_back(m);
00862       continue;
00863     }
00864     moves.push_back(m);
00865   }
00866   if ((! has_good_capture) && may_have_additional)
00867     moves.push_back(others.begin(), others.end());
00868 }
00869 
00870 template <osl::Player P>
00871 void osl::search::QuiescenceGenerator<P>::
00872 breakThreatmate(const NumEffectState& state, 
00873                 Move threatmate, PieceMask pins, MoveVector& moves)
00874 {
00875   MoveVector all_moves, major_piece, major_sacrifice;
00876   assert(threatmate.isNormal());
00877   const Square target = threatmate.to();
00878 
00879   // defense by add effect
00880   move_generator::GenerateAddEffectWithEffect::generate<false>
00881     (P, state, target, all_moves);
00882 
00883   BOOST_FOREACH(Move m, all_moves)
00884   {
00885     const Ptype ptype = m.ptype();
00886     if (ptype == KING)
00887       continue;                 // KING_WALK will generate
00888     if (! m.isDrop())
00889     {
00890       assert(!ShouldPromoteCut::canIgnoreAndNotDrop<P>(m));
00891       if (m.isPromotion()) 
00892         continue;
00893       if (isMajor(ptype)
00894           && state.hasEffectByPiece(state.pieceOnBoard(m.from()), target))
00895         continue;                       // already have effect
00896     }
00897     const Square to = m.to();
00898     const int me = state.countEffect(P, to) + (m.isDrop() ? 1 : 0);
00899     const int op = state.countEffect(alt(P), to, pins);
00900     if ((me >= 2) || (op == 0))
00901     {
00902       if (isMajor(ptype))
00903       {
00904         if (op)
00905           major_sacrifice.push_back(m);
00906         else 
00907           major_piece.push_back(m);
00908       }
00909       else                      // ! major
00910       {
00911         if (m.isDrop() && (ptype == GOLD || ptype == SILVER)
00912             && (to.x() == 1 || to.x() == 9))
00913           major_piece.push_back(m);
00914         else
00915           moves.push_back(m);
00916       }
00917     }
00918   }
00919   all_moves.clear();
00920   
00921   if (threatmate.isDrop())
00922   {
00923     // 場所を指定して、Drop を作る方法は?
00924     if (state.hasPieceOnStand<PAWN>(P)
00925         && ! state.isPawnMaskSet(P, target.x())
00926         && PtypePlayerTraits<PAWN,P>::canDropTo(target))
00927       moves.push_back(Move(target, PAWN, P));
00928     else if (state.hasPieceOnStand<LANCE>(P)
00929              && PtypePlayerTraits<LANCE,P>::canDropTo(target))
00930       moves.push_back(Move(target, LANCE, P));
00931     else if (state.hasPieceOnStand<KNIGHT>(P)
00932              && PtypePlayerTraits<KNIGHT,P>::canDropTo(target))
00933       moves.push_back(Move(target, KNIGHT, P));
00934     else if (state.hasPieceOnStand<SILVER>(P))
00935       moves.push_back(Move(target, SILVER, P));
00936     else if (state.hasPieceOnStand<GOLD>(P))
00937       moves.push_back(Move(target, GOLD, P));
00938   }
00939   // 長い利きのblock他
00940   BreakThreatmate::findBlockLong(state, threatmate, all_moves);
00941   if (! all_moves.empty()) 
00942   {
00943     Ptype cheapest = PTYPE_EMPTY;
00944     if (state.hasPieceOnStand<PAWN>(P)) cheapest = PAWN;
00945     else if (state.hasPieceOnStand<LANCE>(P)) cheapest = LANCE;
00946     else if (state.hasPieceOnStand<KNIGHT>(P)) cheapest = KNIGHT;
00947     BOOST_FOREACH(Move m, all_moves) {
00948       const int d = state.countEffect(P, m.to()) + m.isDrop();
00949       const int a = state.countEffect(alt(P), m.to());
00950       if (a >= d && ! (d >= 2 && m.ptype() == PAWN))
00951         continue;
00952       if (m.ptype() != cheapest && cheapest != PTYPE_EMPTY && Ptype_Table.canDropTo(P, cheapest, m.to()))
00953         continue;
00954       moves.push_back(m);
00955       break;
00956     }
00957     all_moves.clear();
00958   }
00959   
00960   
00961   const Square king_position = state.kingSquare(P);
00962   // make a space for king
00963   {
00964     for (int i=SHORT8_DIRECTION_MIN; i<=SHORT8_DIRECTION_MAX; ++i)
00965     {
00966       const Piece p = state.pieceAt(Board_Table.nextSquare
00967                                        (P,king_position,Direction(i)));
00968       if (! (p.isPiece() && p.owner() == P))
00969         continue;
00970       if (state.hasEffectAt(alt(P), p.square()))
00971         continue;
00972       move_generator::GeneratePieceOnBoard::generate(P,state, p, all_moves);
00973     }
00974     BOOST_FOREACH(Move m, all_moves)
00975     {
00976       assert(! m.isDrop());
00977       assert(!ShouldPromoteCut::canIgnoreAndNotDrop<P>(m));
00978       if (m.isPromotion())
00979         continue;
00980       const Ptype captured = m.capturePtype();
00981       if ((captured != PTYPE_EMPTY)
00982           && (eval::Ptype_Eval_Table.value(captured)
00983               >= eval::PtypeEvalTraits<KNIGHT>::val))
00984         continue;
00985       moves.push_back(m);
00986     }
00987   }
00988   // defence by add effect: unusual moves
00989   const size_t minimum_moves = 8;
00990   for (MoveVector::const_iterator p=major_piece.begin(); 
00991        p!=major_piece.end() && moves.size() < minimum_moves; ++p)
00992   {
00993     moves.push_back(*p);
00994   }
00995   for (MoveVector::const_iterator p=major_sacrifice.begin(); 
00996        p!=major_sacrifice.end() && moves.size() < minimum_moves; ++p)
00997   {
00998     moves.push_back(*p);
00999   }
01000 }
01001 
01002 template <osl::Player P>
01003 void osl::search::QuiescenceGenerator<P>::
01004 attackGoldWithPawn(const NumEffectState& state, PieceMask pins, 
01005                    MoveVector& moves) 
01006 {
01007   using namespace move_action;
01008 
01009   const bool has_pawn   = state.hasPieceOnStand<PAWN>(P);
01010   const bool has_lance  = state.hasPieceOnStand<LANCE>(P);
01011   const bool has_knight = state.hasPieceOnStand<KNIGHT>(P);
01012   const bool has_silver = state.hasPieceOnStand<SILVER>(P);
01013   for (int i = PtypeTraits<GOLD>::indexMin;
01014        i < PtypeTraits<GOLD>::indexLimit; ++i)
01015   {
01016     const Piece p = state.pieceOf(i);
01017     if (! p.isOnBoardByOwner<PlayerTraits<P>::opponent>())
01018       continue;
01019     const Square head = p.square() + DirectionPlayerTraits<D,P>::offset();
01020     if (state.pieceAt(head).isEmpty())
01021     {
01022       // TODO: ただの歩は利きがはずれる時に許す
01023       const int defense = state.countEffect(alt(P), head, pins);
01024       int attack = state.countEffect(P, head)
01025         + state.hasEffectByPtype<BISHOP>(P, p.square());
01026       if (defense >= attack)
01027         attack += AdditionalEffect::count2(state, head, P);
01028 
01029       // move
01030       if (! head.canPromote<P>()) // 成りはすでに生成されているはず
01031       {
01032         const Square origin = head + DirectionPlayerTraits<D,P>::offset();
01033         if (defense <= attack
01034             || state.hasEffectByPtype<BISHOP>(P, origin)) // open attack
01035         {
01036           const Piece candidate = state.pieceAt(origin);
01037           if (candidate.ptype() == PAWN && candidate.owner() == P)
01038           {
01039             const Move move(origin, head, PAWN, PTYPE_EMPTY, false, P);
01040             moves.push_back(move);
01041             ++attack;           // 歩の利きがある
01042           }
01043         }
01044       }      
01045       // drop
01046       if (defense <= attack)
01047       {
01048         if (has_pawn && !state.template isPawnMaskSet<P>(head.x()))
01049         {
01050           const Move move(head, PAWN, P);
01051           moves.push_back(move);
01052         }
01053         if (has_lance)
01054         {
01055           const Move move(head, LANCE, P);
01056           moves.push_back(move);
01057         }
01058         if (has_silver)
01059         {
01060           const Move move(head, SILVER, P);
01061           moves.push_back(move);
01062         }
01063       }
01064       const bool generate_long_lance = has_lance 
01065         && (! state.hasPieceOnStand<PAWN>(alt(P))
01066             || state.template isPawnMaskSet<PlayerTraits<P>::opponent>(head.x()));
01067       if (generate_long_lance) 
01068       {
01069         for (Square to=head + DirectionPlayerTraits<D,P>::offset(); 
01070              state.pieceAt(to).isEmpty(); 
01071              to+=DirectionPlayerTraits<D,P>::offset())
01072         {
01073           const int defense = state.countEffect(alt(P), to, pins);
01074           const int attack = state.countEffect(P, to);
01075           if (defense > attack)
01076             continue;
01077           const Move move(to, LANCE, P);
01078           moves.push_back(move);
01079         }
01080       }
01081     }
01082     // knight
01083     if (! state.pieceAt(head).isEdge())
01084     {
01085       const Square knight_l = head+DirectionPlayerTraits<DL,P>::offset();
01086       attackWithKnight(state, pins, knight_l, has_knight, moves);
01087       const Square knight_r = head+DirectionPlayerTraits<DR,P>::offset();
01088       attackWithKnight(state, pins, knight_r, has_knight, moves);
01089     }
01090   }
01091 }
01092 
01093 template <osl::Player P>
01094 void osl::search::QuiescenceGenerator<P>::
01095 attackWithKnight(const NumEffectState& state, PieceMask pins, 
01096                      Square attack_from, 
01097                      bool has_knight, MoveVector& moves) 
01098 {
01099   if (state.pieceAt(attack_from) != Piece::EMPTY())
01100     return;
01101   
01102   const int defense = state.countEffect(alt(P), attack_from, pins);
01103   int attack = state.countEffect(P, attack_from);
01104 
01105   if (defense == 1 
01106       && (attack == 1 || (has_knight && attack == 0)))
01107   {
01108     const Piece gold = state.findAttackAt<GOLD>(alt(P), attack_from);
01109     if (gold.ptype() == GOLD)
01110     {
01111       // 取ると敵の金の守りが外れる
01112       const Square guarded
01113         = gold.square()+DirectionPlayerTraits<U,P>::offset();
01114       if (state.pieceAt(guarded).isOnBoardByOwner(alt(P))
01115           && (state.countEffect(alt(P), guarded) 
01116               <= state.countEffect(P, guarded)))
01117         ++attack;
01118     }
01119     // 取ると角道が開く
01120     const Square head = attack_from + DirectionPlayerTraits<U,P>::offset();
01121     const Piece head_piece = state.pieceOnBoard(head);
01122     if (head_piece.isOnBoardByOwner<PlayerTraits<P>::opponent>()) {
01123       if (state.hasEffectByPiece(head_piece, attack_from)
01124           && state.hasEffectByPtype<BISHOP>(P, head))
01125         ++attack;
01126     }
01127   }
01128   
01129   if (defense > attack)
01130     return;
01131   
01132   if (has_knight)
01133   {
01134     const Move drop(attack_from, KNIGHT, P);
01135     moves.push_back(drop);
01136   }
01137 
01138   if (defense < attack)
01139   {
01140     mask_t mask=state.effectSetAt(attack_from).getMask(PtypeFuns<KNIGHT>::indexNum);
01141     mask &= mask_t::makeDirect(PtypeFuns<KNIGHT>::indexMask);
01142     mask &= state.piecesOnBoard(P).getMask(PtypeFuns<KNIGHT>::indexNum);
01143     BOOST_STATIC_ASSERT(PtypeTraits<KNIGHT>::indexLimit < 32);
01144     while (mask.any())
01145     {
01146       const int n = mask.takeOneBit();
01147       const Piece knight = state.pieceOf(n);
01148       if (knight.isPromoted())
01149         continue;
01150       
01151       const Move move(knight.square(), attack_from, KNIGHT, PTYPE_EMPTY, false, P);
01152       assert(state.isAlmostValidMove<false>(move));
01153       moves.push_back(move);
01154     }
01155   }
01156 }
01157 
01158 template <osl::Player P>
01159 void osl::search::QuiescenceGenerator<P>::
01160 attackKnightWithPawn(const NumEffectState& state, PieceMask pins,
01161                      MoveVector& moves) 
01162 {
01163   using namespace move_action;
01164 
01165   const bool has_pawn = state.hasPieceOnStand<PAWN>(P);
01166   for (int i = PtypeTraits<KNIGHT>::indexMin;
01167        i < PtypeTraits<KNIGHT>::indexLimit; ++i)
01168   {
01169     const Piece p = state.pieceOf(i);
01170     if (p.isOnBoard() && p.ptype() == KNIGHT && p.owner() == alt(P))
01171     {
01172       const Square head = p.square()+DirectionPlayerTraits<D,P>::offset();
01173       // ただの歩を許すかどうか...
01174       if (state.pieceAt(head).isEmpty())
01175       {
01176         const int defense = state.countEffect(alt(P), head, pins);
01177         const int offense = state.countEffect(P, head);
01178         if ((defense <= offense)
01179             && (! head.canPromote<P>())) // 成りはすでに生成されているはず
01180         {
01181           const Square origin = head+DirectionPlayerTraits<D,P>::offset();
01182           const Piece candidate = state.pieceAt(origin);
01183           if (candidate.ptype() == PAWN && candidate.owner() == P)
01184           {
01185             const Move move(origin, head, PAWN, PTYPE_EMPTY, false, P);
01186             moves.push_back(move);
01187           }
01188         }
01189         if (has_pawn && !state.template isPawnMaskSet<P>(head.x())
01190             && (defense <= offense+1))
01191         {
01192           const Move move(head, PAWN, P);
01193           moves.push_back(move);
01194         }
01195       }
01196     }
01197   }
01198 }
01199 
01200 template <osl::Player P>
01201 void osl::search::QuiescenceGenerator<P>::
01202 attackSilverWithPawn(const NumEffectState& state, PieceMask pins,
01203                      MoveVector& moves) 
01204 {
01205   using namespace move_action;
01206 
01207   const bool has_pawn   = state.hasPieceOnStand<PAWN>(P);
01208   const bool has_lance  = state.hasPieceOnStand<LANCE>(P);
01209   const bool has_knight = state.hasPieceOnStand<KNIGHT>(P);
01210   const bool has_silver = state.hasPieceOnStand<SILVER>(P);
01211   const Square opponent_king = state.kingSquare(alt(P));
01212   for (int i = PtypeTraits<SILVER>::indexMin;
01213        i < PtypeTraits<SILVER>::indexLimit; ++i)
01214   {
01215     const Piece p = state.pieceOf(i);
01216     if (! p.isOnBoardByOwner<PlayerTraits<P>::opponent>())
01217       continue;
01218 
01219     const Square head = p.square()+DirectionPlayerTraits<D,P>::offset();
01220     if (state.pieceAt(head).isEmpty())
01221     {
01222       const int defense = state.countEffect(alt(P), head, pins);
01223       int attack = state.countEffect(P, head) 
01224         + state.hasEffectByPtype<BISHOP>(P, p.square());
01225       if (defense >= attack)
01226         attack += AdditionalEffect::count2(state, head, P);
01227       const bool near_king 
01228         = Neighboring8Direct::hasEffect(state, p.ptypeO(), p.square(),
01229                                         opponent_king);
01230       if (defense > attack)
01231       {
01232         if (! near_king)
01233           continue;
01234         // TODO: ただの歩は利きがはずれる時に許す
01235       }
01236       if (! head.canPromote<P>()) // 成りはすでに生成されているはず
01237       {
01238         const Square origin = head+DirectionPlayerTraits<D,P>::offset();
01239         const Piece candidate = state.pieceAt(origin);
01240         if (candidate.ptype() == PAWN && candidate.owner() == P)
01241         {
01242           const Move move(origin, head, PAWN, PTYPE_EMPTY, false, P);
01243           moves.push_back(move);
01244         }
01245       }
01246       if (has_pawn && !state.template isPawnMaskSet<P>(head.x()))
01247       {
01248         const Move move(head, PAWN, P);
01249         moves.push_back(move);
01250       }
01251       if (! near_king)
01252         continue;
01253       if (defense <= attack)
01254       {
01255         if (has_lance)
01256         {
01257           const Move move(head, LANCE, P);
01258           moves.push_back(move);
01259         }
01260         if (has_silver)
01261         {
01262           const Move move(head, SILVER, P);
01263           moves.push_back(move);
01264         }
01265       }
01266     }
01267     // knight
01268     if (! state.pieceAt(head).isEdge())
01269     {
01270       const Square knight_l = head+DirectionPlayerTraits<DL,P>::offset();
01271       attackWithKnight(state, pins, knight_l, has_knight, moves);
01272       const Square knight_r = head+DirectionPlayerTraits<DR,P>::offset();
01273       attackWithKnight(state, pins, knight_r, has_knight, moves);
01274     }
01275     // ppawn
01276     const CArray<Square,2> side = {{
01277       p.square() + DirectionTraits<L>::blackOffset(),
01278       p.square() + DirectionTraits<R>::blackOffset(),
01279     }};
01280     BOOST_FOREACH(Square s, side) {
01281       if (! state.pieceAt(s).isEmpty())
01282         continue;
01283       if (state.countEffect(P, s) 
01284           < state.countEffect(alt(P), s))
01285         continue;
01286       MoveVector candidate;
01287       move_generator::GenerateCapture::generate(P,state, s, candidate);
01288 
01289       BOOST_FOREACH(Move m, candidate) {
01290         if (m.isPromotion() 
01291             || state.hasEffectByPiece(state.pieceOnBoard(m.from()),
01292                                       p.square()))
01293           continue;
01294         assert(! ShouldPromoteCut::canIgnoreMove<P>(m));
01295         moves.push_back(m);
01296       }
01297     }
01298   }
01299 }
01300 
01301 template <osl::Player P>
01302 void osl::search::QuiescenceGenerator<P>::
01303 kingWalk(const NumEffectState& state, MoveVector& moves)
01304 {
01305   const Piece my_king = state.kingPiece<P>();
01306   MoveVector all_moves;
01307   move_generator::GeneratePieceOnBoard::generate(P,state, my_king, all_moves);
01308 
01309   BOOST_FOREACH(Move m, all_moves)
01310   {
01311     if (state.hasEffectAt(alt(P), m.to()))
01312       continue;
01313     moves.push_back(m);
01314   }
01315 }
01316 
01317 template <osl::Player P>
01318 void osl::search::QuiescenceGenerator<P>::
01319 escapeKing(const NumEffectState& state, MoveVector& moves) 
01320 {
01321   MoveVector all_moves;
01322   GenerateEscape<P>::generateCheap(state, state.template kingPiece<P>(), all_moves);
01323 
01324   BOOST_FOREACH(Move m, all_moves)
01325   {
01326     const Square to = m.to();
01327     if (m.isDrop())
01328     {
01329       // 焦点以外の中合は読まない
01330       if (! state.hasEffectAt<P>(to))
01331       {
01332         if (! ((m.ptype() == PAWN)
01333                && state.hasMultipleEffectAt(alt(P), to)))
01334           continue;
01335       }
01336     }
01337     else if (m.ptype() != KING)
01338     {
01339       // 焦点以外の中合は読まない
01340       if (! m.isCapture())
01341       {
01342         if (! state.hasMultipleEffectAt(P, to))
01343         {
01344           if (! ((m.ptype() == PAWN)
01345                  && state.hasMultipleEffectAt(alt(P), to)))
01346             continue;
01347         }
01348       }
01349     }
01350     moves.push_back(m);
01351   }
01352 }
01353 
01354 template <osl::Player P>
01355 bool osl::search::QuiescenceGenerator<P>::
01356 escapeKingInTakeBack(const NumEffectState& state, MoveVector& moves,
01357                      bool check_by_lance) 
01358 {
01359   bool has_safe_move = false;
01360   assert(moves.empty());
01361   MoveVector all_moves;
01362   GenerateEscape<P>::generate(state, state.template kingPiece<P>(), all_moves);
01363 
01364   Square last_drop_to = Square::STAND();
01365   MoveVector drops;
01366   BOOST_FOREACH(Move m, all_moves)
01367   {
01368     const Square to = m.to();
01369     if (m.ptype() == KING)
01370     {
01371       // TODO: 何か犠牲があるはず
01372       has_safe_move = true; // KFEND 流: 逃げる場所があれば良しとする
01373       continue;
01374     }
01375     if (m.isCapture())
01376     {
01377       moves.push_back(m);
01378       continue;
01379     }
01380     // 無駄合は読まない
01381     const int attack_count = state.countEffect(alt(P),to);
01382     const int defense_count 
01383       = state.countEffect(P,to) + (m.isDrop() ? 1 : 0);
01384     if (defense_count <= attack_count)
01385       continue;
01386     if ((attack_count == 1) && (! check_by_lance))
01387     {
01388       // 大駒の攻撃に対して自分の利きが充分なら良いとする
01389       has_safe_move = true;
01390       continue;
01391     }
01392 
01393     // 攻方がこれ以上drop の王手をかけないので合駒は1手で詰の判定には充分
01394     // TODO: 一番安い駒にする
01395     if (to != last_drop_to)
01396     {
01397       last_drop_to = to;
01398       drops.push_back(m);
01399     }
01400   }
01401   if (! has_safe_move)
01402     moves.push_back(drops.begin(), drops.end());
01403   return has_safe_move;
01404 }
01405 
01406 template <osl::Player P>
01407 void osl::search::QuiescenceGenerator<P>::
01408 advanceBishop(const NumEffectState& state, MoveVector& moves) 
01409 {
01410   for (int i = PtypeTraits<BISHOP>::indexMin;
01411        i < PtypeTraits<BISHOP>::indexLimit; ++i)
01412   {
01413     const Piece bishop = state.pieceOf(i);
01414     if (! bishop.isOnBoardByOwner<P>())
01415       continue;
01416     if (bishop.ptype() != BISHOP)
01417       continue;
01418     const Square from = bishop.square();
01419     if (state.hasEffectAt<PlayerTraits<P>::opponent>(from))
01420       continue;                 // escape は重複
01421     advanceBishop<UL>(state, from, moves);
01422     advanceBishop<UR>(state, from, moves);
01423   }
01424 }
01425 
01426 template <osl::Player P>
01427 template <osl::Direction DIR>
01428 void osl::search::QuiescenceGenerator<P>::
01429 advanceBishop(const NumEffectState& state, 
01430               const Square from, MoveVector& moves)
01431 {
01432   const Offset offset = DirectionPlayerTraits<DIR,P>::offset();
01433   for (Square to=from+offset;; to+=offset)
01434   {
01435     if (! state.pieceAt(to).isEmpty())
01436       break;            // capture は重複.ついでに盤外判定
01437     if (to.canPromote<P>())
01438       break;            // promote は重複
01439     if (state.hasEffectAt<PlayerTraits<P>::opponent>(to))
01440       continue;
01441     const Move move(from, to, BISHOP, PTYPE_EMPTY, false, P);
01442     assert(state.isAlmostValidMove<false>(move));
01443     moves.push_back(move);
01444   }
01445 }
01446       
01447 template <osl::Player P>
01448 template <class EvalT>
01449 void osl::search::QuiescenceGenerator<P>::
01450 escapeFromLastMove(const NumEffectState& state, Move last_move, MoveVector& moves)
01451 {
01452   if (! last_move.isNormal())
01453     return;
01454   if (last_move.ptype() != PAWN)
01455   {
01456     escapeFromLastMoveOtherThanPawn<EvalT>(state, last_move, moves);
01457     return;
01458   }
01459   const Square attack_from = last_move.to();
01460   const Square attack_to = attack_from+DirectionPlayerTraits<D,P>::offset();
01461   const Piece target = state.pieceOnBoard(attack_to);
01462   if (! target.isOnBoardByOwner<P>())
01463     return;
01464 
01465   using namespace move_action;
01466   MoveVector all_moves;
01467   GenerateEscape<P>::generate(state, target, all_moves);
01468 
01469   BOOST_FOREACH(Move m, all_moves)
01470   {
01471     assert(! m.isDrop());
01472     const Square to = m.to();
01473     // 逃げる時には利きの充分なところへ
01474     const int defense = state.countEffect(P, to);
01475     const int offense = state.countEffect(alt(P), to);
01476     if (offense > defense)
01477       continue;
01478     if (to == attack_from)
01479     {
01480       // 取る手は重複だけど歩の場合は深さによるので入れておく
01481       if (offense == defense)
01482         continue;
01483       assert(m.capturePtype() == PAWN);
01484       assert(! ShouldPromoteCut::canIgnoreMove<P>(m));
01485       moves.push_back(m);
01486       continue;
01487     }
01488     assert(m.from() == attack_to);
01489     if ((offense == defense)
01490         && (m.isCapture()))
01491       continue;
01492 
01493     // TODO: KnightCaptureDepth
01494       assert(! ShouldPromoteCut::canIgnoreMove<P>(m));
01495     if (! m.isPromotion())
01496     {
01497       moves.push_back(m);
01498     }
01499   }
01500 }
01501 
01502 template <osl::Player P>
01503 void osl::search::QuiescenceGenerator<P>::
01504 dropMajorPiece(const NumEffectState& state, MoveVector& moves) 
01505 {
01506   move_generator::SafeDropMajorPiece<P>::generateMoves(state, moves);
01507 }
01508 
01509 template <osl::Player P>
01510 void osl::search::QuiescenceGenerator<P>::
01511 dropMajorPiece3(const NumEffectState& state, MoveVector& moves, const HistoryTable& table) 
01512 {
01513   FixedCapacityVector<Move, 27*2> all;
01514   move_generator::SafeDropMajorPiece<P>::generateMoves(state, all);
01515   FixedCapacityVector<std::pair<int,Move>, 27*2> selected;
01516   BOOST_FOREACH(Move m, all) 
01517     selected.push_back(std::make_pair(table.value(m), m));
01518   std::sort(selected.begin(), selected.end());
01519   for (int i=0; i<std::min(3, (int)selected.size()); ++i)
01520     moves.push_back(selected[selected.size()-1-i].second);
01521 }
01522 
01523 #endif /* QUIESCENCEGENERATOR_TCC */
01524 // ;;; Local Variables:
01525 // ;;; mode:c++
01526 // ;;; c-basic-offset:2
01527 // ;;; End:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines