00001
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);
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
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);
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
00076 if(!state.pieceAt(to).isEmpty()) return false;
00077 Square pos1=to-offset;
00078
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
00123
00124 template<Player P,bool setBestMove>
00125 bool hasCheckmateMoveKnight(NumEffectState const& state, Square target,
00126 King8Info canMoveMask,Move& bestMove)
00127 {
00128
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
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
00185 if(setBestMove)
00186 bestMove=Move(drop,ptype,P);
00187 return true;
00188 tryNext:;
00189 }
00190 return false;
00191 }
00192 }
00193 }
00194 }
00195
00196
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
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
00230
00231
00232
00233
00234
00235
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
00247
00248
00249
00250
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
00273
00274
00275
00276 if(p.square()==target-Offset(2*dx,0) &&
00277 state.hasEffectByPiece(p1,pos))
00278 return false;
00279 }
00280 }
00281 }
00282 }
00283 }
00284 }
00285
00286
00287
00288
00289
00290
00291
00292
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
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){
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 || 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
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
00449
00450
00451
00452
00453