immediateCheckmate.tcc
Go to the documentation of this file.
00001 /* immediateCheckmate.tcc
00002  */
00003 #ifndef OSL_CHECKMATE_IMMEDIATE_CHECKMATE_TCC
00004 #define OSL_CHECKMATE_IMMEDIATE_CHECKMATE_TCC
00005 #include "osl/checkmate/immediateCheckmate.h"
00006 #include "osl/checkmate/immediateCheckmateTable.h"
00007 #include "osl/move_classifier/kingOpenMove.h"
00008 #include "osl/effect_util/effectUtil.h"
00009 #include "osl/effect_util/additionalEffect.h"
00010 #include "osl/directionTraits.h"
00011 #include "osl/pieceTable.h"
00012 #include "osl/misc/bitOp.h"
00013 #include "osl/misc/mask.h"
00014 
00015 namespace osl
00016 {
00017   namespace checkmate
00018   {
00019     namespace detail {
00020       using osl::misc::BitOp;
00021       template<Player P>
00022       bool blockingVerticalAttack(NumEffectState const& state,Square pos)
00023       {
00024         PieceMask effect=state.effectSetAt(pos)&
00025           state.effectSetAt(pos+DirectionPlayerTraits<U,P>::offset());
00026         mask_t mask=effect.getMask(1);  // longは常に1
00027         mask&=(state.piecesOnBoard(P).getMask(1)<<8);
00028         if((mask&mask_t::makeDirect(PtypeFuns<LANCE>::indexMask<<8)).none()){
00029           mask&=mask_t::makeDirect(PtypeFuns<ROOK>::indexMask<<8);
00030           while(mask.any()){
00031             int num=mask.takeOneBit()+NumBitmapEffect::longToNumOffset;
00032             Square from=state.pieceOf(num).square();
00033             assert(from.isOnBoard());
00034             if(from.isU<P>(pos)) goto found;
00035           }
00036           return false;
00037         found:;
00038         }
00039         const Offset offset=DirectionPlayerTraits<U,P>::offset();
00040         pos+=offset;
00041         const Player altP=PlayerTraits<P>::opponent;
00042         for(int i=0;i<3;i++,pos+=offset){
00043           Piece p=state.pieceAt(pos);
00044           if(p.canMoveOn<altP>()){ // 自分の駒か空白
00045             if(state.countEffect(P,pos)==1) return true;
00046             if(!p.isEmpty()) return false;
00047           }
00048           else return false;
00049         }
00050         return false;
00051       }
00052       template<Player P>
00053       bool
00054 #ifdef __GNUC__
00055         __attribute__ ((pure))
00056 #endif
00057       blockingDiagonalAttack(NumEffectState const& state,Square pos,Square target,
00058                              King8Info canMoveMask)
00059       {
00060         const Player altP=PlayerTraits<P>::opponent;
00061         Square to=target-DirectionPlayerTraits<U,P>::offset();
00062         // Uに相手の駒がある
00063         if((canMoveMask.uint64Value()&(0x10000<<U))==0) return false;
00064         PieceMask effect=state.effectSetAt(to)&state.effectSetAt(pos);
00065         mask_t mask=effect.getMask(1);  // longは常に1
00066         mask&=(state.piecesOnBoard(P).getMask(1)<<8);
00067         mask&=mask_t::makeDirect(PtypeFuns<BISHOP>::indexMask<<8);
00068         while(mask.any()){
00069           int num=mask.takeOneBit()+NumBitmapEffect::longToNumOffset;
00070           Square from=state.pieceOf(num).square();
00071           assert(from.isOnBoard());
00072           Offset offset=Board_Table.getShort8OffsetUnsafe(to,from);
00073           if(to+offset != pos) continue;
00074           if(state.countEffect(P,to)==1) return true;
00075           // Uがspaceだと絡んでくる
00076           if(!state.pieceAt(to).isEmpty()) return false;
00077           Square pos1=to-offset;
00078           // BISHOPの利き一つで止めていた
00079           Piece p=state.pieceAt(pos1);
00080           if(p.canMoveOn<altP>() &&
00081              state.countEffect(P,pos1)==1){
00082             return true;
00083           }
00084         }
00085         return false;
00086       }
00087       template<Player P,bool canDrop,bool setBestMove>
00088       bool hasKnightCheckmate(NumEffectState const& state, 
00089                               Square target, 
00090                               Square pos,
00091                               King8Info canMoveMask,
00092                               Move& bestMove, mask_t mask1)
00093       {
00094         if(!pos.isOnBoard()) return false;
00095         const Player altP=PlayerTraits<P>::opponent;
00096         Piece p=state.pieceAt(pos);
00097         if(p.canMoveOn<P>() && 
00098            !state.hasEffectByNotPinned(altP,pos)
00099           ){
00100           mask_t mask=state.effectSetAt(pos).getMask<KNIGHT>()&mask1;
00101           if(mask.any()){
00102             if(blockingVerticalAttack<P>(state,pos) ||
00103                blockingDiagonalAttack<P>(state,pos,target,canMoveMask)) return false;
00104             if(setBestMove){
00105               int num=mask.takeOneBit()+(PtypeFuns<KNIGHT>::indexNum<<5);
00106               Piece p1=state.pieceOf(num);
00107               Square from=p1.square();
00108               bestMove=Move(from,pos,KNIGHT,p.ptype(),false,P);
00109             }
00110             return true;
00111           }
00112           else if(canDrop && p.isEmpty()){
00113             if(blockingVerticalAttack<P>(state,pos) ||
00114                blockingDiagonalAttack<P>(state,pos,target,canMoveMask)) return false;
00115             if(setBestMove)
00116               bestMove=Move(pos,KNIGHT,P);
00117             return true;
00118           }
00119         }
00120         return false;
00121       }
00122       // KNIGHT
00123       // KNIGHTのdropは利きを遮ることはない
00124       template<Player P,bool setBestMove>
00125       bool hasCheckmateMoveKnight(NumEffectState const& state, Square target, 
00126                                   King8Info canMoveMask,Move& bestMove)
00127       {
00128         // 8近傍に移動できる時は桂馬の一手詰めはない
00129         if((canMoveMask.uint64Value()&0xff00)!=0) return false;
00130         mask_t mask=mask_t::makeDirect(PtypeFuns<KNIGHT>::indexMask);
00131         mask&=state.piecesOnBoard(P).getMask<KNIGHT>();
00132         mask&= ~state.promotedPieces().getMask<KNIGHT>();
00133         mask&= ~state.pinOrOpen(P).getMask<KNIGHT>();
00134         if(state.hasPieceOnStand<KNIGHT>(P)){
00135           Square pos=target-DirectionPlayerTraits<UUR,P>::offset();
00136           if(hasKnightCheckmate<P,true,setBestMove>(state,target,pos,canMoveMask,bestMove,mask))
00137             return true;
00138           pos=target-DirectionPlayerTraits<UUL,P>::offset();
00139           return hasKnightCheckmate<P,true,setBestMove>(state,target,pos,canMoveMask,bestMove,mask);
00140         }
00141         else{
00142           Square pos=target-DirectionPlayerTraits<UUR,P>::offset();
00143           if(hasKnightCheckmate<P,false,setBestMove>(state,target,pos,canMoveMask,bestMove,mask))
00144             return true;
00145           pos=target-DirectionPlayerTraits<UUL,P>::offset();
00146           return hasKnightCheckmate<P,false,setBestMove>(state,target,pos,canMoveMask,bestMove,mask);
00147         }
00148         return false;
00149       }
00150       template<Player P,bool setBestMove>
00151       bool slowCheckDrop(NumEffectState const& state,Square target,
00152                          Ptype ptype,King8Info canMoveMask,Move& bestMove)
00153       {
00154         unsigned int dropMask=(canMoveMask.uint64Value()&0xff)
00155           &Immediate_Checkmate_Table.ptypeDropMask(ptype,canMoveMask);
00156         // dropMaskが0ならここに来ない
00157         assert(dropMask!=0);
00158         while(dropMask!=0){
00159           int i=BitOp::takeOneBit(dropMask);
00160           Direction d=static_cast<Direction>(i);
00161           unsigned int blockingMask=Immediate_Checkmate_Table.blockingMask(ptype,d) &
00162             (canMoveMask.uint64Value()>>16);
00163           Square drop=target-Board_Table.getOffset<P>(d);
00164           if(blockingMask!=0){
00165             NumBitmapEffect effect=state.effectSetAt(drop);
00166             mask_t longEffect=effect.getMask(1)&NumBitmapEffect::longEffectMask();
00167             longEffect&=(state.piecesOnBoard(P).getMask(1)<<8);
00168             if(longEffect.any()){
00169               do{
00170                 int j=BitOp::takeOneBit(blockingMask);
00171                 Direction d1=static_cast<Direction>(j);
00172                 Square pos=target-Board_Table.getOffset<P>(d1);
00173                 NumBitmapEffect effect1=state.effectSetAt(pos);
00174                 if(effect1.countEffect(P)>1) continue;
00175                 mask_t longEffect1=effect1.getMask(1)&longEffect;
00176                 if(!longEffect1.any()) continue;
00177                 //
00178                 int num=longEffect1.takeOneBit()+NumBitmapEffect::longToNumOffset;
00179                 if(Board_Table.isBetween(drop,state.pieceOf(num).square(),pos))
00180                   goto tryNext;
00181               }while(blockingMask!=0);
00182             }
00183           }
00184           // blockingMaskの点がすべてOKならOK
00185           if(setBestMove)
00186             bestMove=Move(drop,ptype,P);
00187           return true;
00188         tryNext:;
00189         }
00190         return false;
00191       }
00192     } // detail
00193   } // checkmate
00194 } // osl
00195 
00196 // not KNIGHT
00197 template<osl::Player P,bool setBestMove>
00198 bool osl::checkmate::ImmediateCheckmate::
00199 hasCheckmateDrop(NumEffectState const& state, Square target,
00200                  King8Info canMoveMask,Move& bestMove)
00201 {
00202   typedef misc::GeneralMask<unsigned short> mask_t;
00203   mask_t dropPtypeMask=mask_t::makeDirect(Immediate_Checkmate_Table.dropPtypeMask(canMoveMask));
00204   while(dropPtypeMask.any()){
00205     Ptype ptype=static_cast<Ptype>(dropPtypeMask.takeOneBit()+PTYPE_BASIC_MIN);
00206     if(state.hasPieceOnStand(P,ptype) &&
00207        detail::slowCheckDrop<P,setBestMove>(state,target,ptype,canMoveMask,
00208                                             bestMove))
00209       return true;
00210   }
00211   return false;
00212 }
00213 
00214 template<osl::Player P,bool setBestMove>
00215 bool osl::checkmate::ImmediateCheckmate::
00216 slowHasCheckmateMoveDirPiece(NumEffectState const& state, Square target,
00217                              King8Info canMoveMask,Direction d,Square pos,Piece p,Ptype ptype,Move& bestMove){
00218   const Player altP=PlayerTraits<P>::opponent;
00219   // ptypeがPROOKの時は,更なるチェックが必要
00220   if(ptype==PROOK){
00221     int dx=target.x()-pos.x();
00222     int dy=target.y()-pos.y();
00223     if(abs(dx)==1 && abs(dy)==1){
00224       {
00225         Square pos1=pos+Offset(dx,0);
00226         Piece p1=state.pieceAt(pos1);
00227         if(!p1.isEmpty()){
00228           {
00229             //  * -OU *
00230             // (A)(B)(D)
00231             //  * (C) *
00232             // (E) *  *
00233             // +RY (C) -> (A), (E) -> (A)
00234             // -?? - (B)
00235             // (D) - 竜以外の利きなし 
00236             Square pos2=pos+Offset(2*dx,0);
00237             if(state.pieceAt(pos2).template canMoveOn<altP>()){
00238               NumBitmapEffect effect2=state.effectSetAt(pos2);
00239               if(effect2.countEffect(P)==0 ||
00240                  (effect2.countEffect(P)==1 &&
00241                   effect2.test(p.number())))
00242                 return false;
00243             }
00244           }
00245           {
00246             //  * -OU *
00247             // (A)(B) *
00248             //  * (C) *
00249             // +RY (C) -> (A)
00250             // -?? - (B)竜でpinされているが実はAへの利き持つ
00251             if(p.square()==target-Offset(0,2*dy) &&
00252                state.hasEffectByPiece(p1,pos))
00253               return false;
00254           }
00255         }
00256       }
00257       {
00258         Square pos1=pos+Offset(0,dy);
00259         Piece p1=state.pieceAt(pos1);
00260         if(!p1.isEmpty()){
00261           Square pos2=pos+Offset(0,2*dy);
00262           {
00263             if(state.pieceAt(pos2).template canMoveOn<altP>()){
00264               NumBitmapEffect effect2=state.effectSetAt(pos2);
00265               if(effect2.countEffect(P)==0 ||
00266                  (effect2.countEffect(P)==1 &&
00267                   effect2.test(p.number())))
00268                 return false;
00269 
00270             }
00271             {
00272               // (C)(B)-OU
00273               //  * (A) *
00274               // +RY (C) -> (A)
00275               // -?? - (B)竜でpinされているが実はAへの利き持つ
00276               if(p.square()==target-Offset(2*dx,0) &&
00277                  state.hasEffectByPiece(p1,pos))
00278                 return false;
00279             }
00280           }
00281         }
00282       }
00283     }
00284   }
00285   // 元々2つの利きがあったマスが,
00286   // block & 自分の利きの除去で利きがなくなることはあるか?
00287   // -> ある.
00288   // +KA  *   *
00289   //  *  (A) +KI
00290   //  *  -OU (B)
00291   //  *   *   *
00292   // で金がAに移動して王手をかけると,Bの利きが2から0になる.
00293   mask_t mask=mask_t::makeDirect((canMoveMask.uint64Value()>>16)&Immediate_Checkmate_Table.noEffectMask(ptype,d));
00294   if(mask.any()){
00295     int num=p.number();
00296     NumBitmapEffect effect2=state.effectSetAt(pos);
00297     effect2.reset(num+8);
00298     mask_t longEffect2=effect2.getMask(1)&NumBitmapEffect::longEffectMask();
00299     longEffect2&=(state.piecesOnBoard(P).getMask(1)<<8);
00300     do {
00301       Direction d1=static_cast<Direction>(mask.takeOneBit());
00302       Square pos1=target-Board_Table.getOffset<P>(d1);
00303       NumBitmapEffect effect1=state.effectSetAt(pos1);
00304       int count=effect1.countEffect(P);
00305       // 自分の利きの除去
00306       if(effect1.test(num)) count--;
00307       if(count==0) return false;
00308       // blockしている利きの除去
00309       mask_t longEffect1=effect1.getMask(1)&longEffect2;
00310       while(longEffect1.any()){
00311         int num1=longEffect1.takeOneBit()+NumBitmapEffect::longToNumOffset;
00312         if(Board_Table.isBetween(pos,state.pieceOf(num1).square(),pos1))
00313           count--;
00314         if(count==0) return false;
00315       }
00316     } while (mask.any());
00317   }
00318   // 自殺手でないことのチェックを入れる
00319   if(move_classifier::KingOpenMove<P>::isMember(state,ptype,p.square(),pos)) return false;
00320   if(setBestMove){
00321     bestMove=Move(p.square(),pos,ptype,
00322                   state.pieceAt(pos).ptype(),
00323                   ptype!=p.ptype(),P);
00324   }
00325   return true;
00326 }
00327 
00328 template<osl::Player P,bool setBestMove>
00329 bool osl::checkmate::ImmediateCheckmate::
00330 hasCheckmateMoveDirPiece(NumEffectState const& state, Square target,
00331                          King8Info canMoveMask,Direction d,Square pos,Piece p,Move& bestMove){
00332   Square from=p.square();
00333   Ptype ptype=p.ptype();
00334   // 相手の利きが伸びてしまって移動後も利きがついてくる可能性
00335   {
00336     const Player altP=PlayerTraits<P>::opponent;
00337     Direction d1=Board_Table.getShort8Unsafe<P>(from,pos);
00338     if(d1!=DIRECTION_INVALID_VALUE){ // not knight move
00339       int num=state.longEffectNumTable()[p.number()][P==BLACK ? d1 : inverse(d1)];
00340       if(num != EMPTY_NUM && state.pieceOf(num).isOnBoardByOwner<altP>())
00341         return false;
00342     }
00343   }
00344   if(canPromote(ptype) &&
00345      (from.canPromote<P>() || pos.canPromote<P>())){
00346     Ptype pptype=promote(ptype);
00347     if((((canMoveMask.uint64Value()>>8)|0x100)&
00348         Immediate_Checkmate_Table.noEffectMask(pptype,d))==0){
00349       if(slowHasCheckmateMoveDirPiece<P,setBestMove>(state,target,canMoveMask,d,pos,p,pptype,bestMove)) return true;
00350     }
00351     if (ptype==PAWN || /*basic because canpromote*/isMajorBasic(ptype)) 
00352       return false;
00353   }
00354   if((((canMoveMask.uint64Value()>>8)|0x100)&
00355       Immediate_Checkmate_Table.noEffectMask(ptype,d))==0){
00356     if(slowHasCheckmateMoveDirPiece<P,setBestMove>(state,target,canMoveMask,d,pos,p,ptype,bestMove)) return true;
00357   }
00358   return false;
00359 }
00360 
00361 template<osl::Player P,bool setBestMove>
00362 bool osl::checkmate::ImmediateCheckmate::
00363 hasCheckmateMoveDir(NumEffectState const& state, Square target,
00364                     King8Info canMoveMask,Direction d,Move& bestMove){
00365   Square pos=target-Board_Table.getOffset<P>(d);
00366   if(state.countEffect(P,pos)<2 &&
00367      !effect_util::AdditionalEffect::hasEffect(state,pos,P)) return false;
00368   PieceMask pieceMask=state.piecesOnBoard(P)&state.effectSetAt(pos);
00369   assert(pos.isOnBoard());
00370   // 玉で王手をかけない
00371   pieceMask.reset(KingTraits<P>::index);
00372   for(int i=0;i<=PieceMask::numToIndex(40);i++){
00373     mask_t mask=pieceMask.getMask(i);
00374     while (mask.any()){
00375       const int num=mask.takeOneBit()+i*32;
00376       if(hasCheckmateMoveDirPiece<P,setBestMove>(state,target,canMoveMask,d,pos,state.pieceOf(num),bestMove)) return true;
00377     }
00378   }
00379   return false;
00380 }
00381 
00382 // not KNIGHT
00383 template<osl::Player P,bool setBestMove>
00384 bool osl::checkmate::ImmediateCheckmate::
00385 hasCheckmateMove(NumEffectState const& state, Square target,
00386                  King8Info canMoveMask,Move& bestMove)
00387 {
00388   assert(! state.inCheck());
00389   typedef misc::GeneralMask<unsigned int> mask_t;
00390   mask_t mask2=mask_t::makeDirect((canMoveMask.uint64Value()>>24)&0xff);
00391   while(mask2.any()){
00392     Direction d=static_cast<Direction>(mask2.takeOneBit());
00393     if(hasCheckmateMoveDir<P,setBestMove>(state,target,canMoveMask,d,bestMove)) return true;
00394   }
00395   return false;
00396 }
00397 
00398 template<osl::Player P>
00399 bool osl::checkmate::ImmediateCheckmate::
00400 hasCheckmateMove(NumEffectState const& state, King8Info canMoveMask)
00401 {
00402   const Player altP=PlayerTraits<P>::opponent;
00403   const Square target=state.kingSquare(altP);
00404   assert(target.isOnBoard());
00405   // 相手からの王手がかかっていない
00406   Move dummy;
00407   if(hasCheckmateMove<P,false>(state,target,canMoveMask,dummy)) return true;
00408   if(detail::hasCheckmateMoveKnight<P,false>(state,target,canMoveMask,dummy)) return true;
00409   return hasCheckmateDrop<P,false>(state,target,canMoveMask,dummy);
00410 }
00411 
00412 template<osl::Player P>
00413 bool osl::checkmate::ImmediateCheckmate::
00414 hasCheckmateMove(NumEffectState const& state)
00415 {
00416   const Player altP=PlayerTraits<P>::opponent;
00417 #ifndef NDEBUG
00418   const Square target=state.kingSquare(altP);
00419 #endif
00420   assert(target.isOnBoard());
00421   King8Info canMoveMask(state.Iking8Info(altP));
00422   return hasCheckmateMove<P>(state, canMoveMask);
00423 }
00424 
00425 template<osl::Player P>
00426 bool osl::checkmate::ImmediateCheckmate::
00427 hasCheckmateMove(NumEffectState const& state, King8Info canMoveMask,
00428                  Square target, Move& bestMove)
00429 {
00430   assert(! state.inCheck());
00431   assert(target.isOnBoard());
00432 
00433   if(hasCheckmateMove<P,true>(state,target,canMoveMask,bestMove)) return true;
00434   if(detail::hasCheckmateMoveKnight<P,true>(state,target,canMoveMask,bestMove)) return true;
00435   return  hasCheckmateDrop<P,true>(state,target,canMoveMask,bestMove);
00436 }
00437 
00438 template<osl::Player P>
00439 bool osl::checkmate::ImmediateCheckmate::
00440 hasCheckmateMove(NumEffectState const& state,Move& bestMove)
00441 {
00442   const Player altP=PlayerTraits<P>::opponent;
00443   const Square target=state.kingSquare(altP);
00444   King8Info canMoveMask(state.Iking8Info(altP));
00445   return hasCheckmateMove<P>(state, canMoveMask, target, bestMove);
00446 }
00447 
00448 #endif /* OSL_CHECKMATE_IMMEDIATE_CHECKMATE_TCC */
00449 // ;;; Local Variables:
00450 // ;;; mode:c++
00451 // ;;; c-basic-offset:2
00452 // ;;; End:
00453 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines