immediateCheckmate.tcc Source File

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
immediateCheckmate.tcc
Go to the documentation of this file.
1 /* immediateCheckmate.tcc
2 */
3 #ifndef OSL_CHECKMATE_IMMEDIATE_CHECKMATE_TCC
4 #define OSL_CHECKMATE_IMMEDIATE_CHECKMATE_TCC
5 #include "osl/checkmate/immediateCheckmate.h"
6 #include "osl/checkmate/immediateCheckmateTable.h"
7 #include "osl/move_classifier/kingOpenMove.h"
8 #include "osl/effect_util/effectUtil.h"
9 #include "osl/effect_util/additionalEffect.h"
10 #include "osl/directionTraits.h"
11 #include "osl/pieceTable.h"
12 #include "osl/misc/bitOp.h"
13 #include "osl/misc/mask.h"
14
15 namespace osl
16 {
17 namespace checkmate
18 {
19 namespace detail {
20 using osl::misc::BitOp;
21 template<Player P>
22 bool blockingVerticalAttack(NumEffectState const& state,Square pos)
23 {
24 PieceMask effect=state.effectSetAt(pos)&
25 state.effectSetAt(pos+DirectionPlayerTraits<U,P>::offset());
26 mask_t mask=effect.getMask(1); // longは常に1
27 mask&=(state.piecesOnBoard(P).getMask(1)<<8);
28 if((mask&mask_t::makeDirect(PtypeFuns<LANCE>::indexMask<<8)).none()){
29 mask&=mask_t::makeDirect(PtypeFuns<ROOK>::indexMask<<8);
30 while(mask.any()){
31 int num=mask.takeOneBit()+NumBitmapEffect::longToNumOffset;
32 Square from=state.pieceOf(num).square();
33 assert(from.isOnBoard());
34 if(from.isU<P>(pos)) goto found;
35 }
36 return false;
37 found:;
38 }
39 const Offset offset=DirectionPlayerTraits<U,P>::offset();
40 pos+=offset;
41 const Player altP=PlayerTraits<P>::opponent;
42 for(int i=0;i<3;i++,pos+=offset){
43 Piece p=state.pieceAt(pos);
44 if(p.canMoveOn<altP>()){ // 自分の駒か空白
45 if(state.countEffect(P,pos)==1) return true;
46 if(!p.isEmpty()) return false;
47 }
48 else return false;
49 }
50 return false;
51 }
52 template<Player P>
53 bool
54 #ifdef __GNUC__
55 __attribute__ ((pure))
56 #endif
57 blockingDiagonalAttack(NumEffectState const& state,Square pos,Square target,
58 King8Info canMoveMask)
59 {
60 const Player altP=PlayerTraits<P>::opponent;
61 Square to=target-DirectionPlayerTraits<U,P>::offset();
62 // Uに相手の駒がある
63 if((canMoveMask.uint64Value()&(0x10000<<U))==0) return false;
64 PieceMask effect=state.effectSetAt(to)&state.effectSetAt(pos);
65 mask_t mask=effect.getMask(1); // longは常に1
66 mask&=(state.piecesOnBoard(P).getMask(1)<<8);
67 mask&=mask_t::makeDirect(PtypeFuns<BISHOP>::indexMask<<8);
68 while(mask.any()){
69 int num=mask.takeOneBit()+NumBitmapEffect::longToNumOffset;
70 Square from=state.pieceOf(num).square();
71 assert(from.isOnBoard());
72 Offset offset=Board_Table.getShort8OffsetUnsafe(to,from);
73 if(to+offset != pos) continue;
74 if(state.countEffect(P,to)==1) return true;
75 // Uがspaceだと絡んでくる
76 if(!state.pieceAt(to).isEmpty()) return false;
77 Square pos1=to-offset;
78 // BISHOPの利き一つで止めていた
79 Piece p=state.pieceAt(pos1);
80 if(p.canMoveOn<altP>() &&
81 state.countEffect(P,pos1)==1){
82 return true;
83 }
84 }
85 return false;
86 }
87 template<Player P,bool canDrop,bool setBestMove>
88 bool hasKnightCheckmate(NumEffectState const& state,
89 Square target,
90 Square pos,
91 King8Info canMoveMask,
92 Move& bestMove, mask_t mask1)
93 {
94 if(!pos.isOnBoard()) return false;
95 const Player altP=PlayerTraits<P>::opponent;
96 Piece p=state.pieceAt(pos);
97 if(p.canMoveOn<P>() &&
98 !state.hasEffectByNotPinned(altP,pos)
99 ){
100 mask_t mask=state.effectSetAt(pos).getMask<KNIGHT>()&mask1;
101 if(mask.any()){
102 if(blockingVerticalAttack<P>(state,pos) ||
103 blockingDiagonalAttack<P>(state,pos,target,canMoveMask)) return false;
104 if(setBestMove){
105 int num=mask.takeOneBit()+(PtypeFuns<KNIGHT>::indexNum<<5);
106 Piece p1=state.pieceOf(num);
107 Square from=p1.square();
108 bestMove=Move(from,pos,KNIGHT,p.ptype(),false,P);
109 }
110 return true;
111 }
112 else if(canDrop && p.isEmpty()){
113 if(blockingVerticalAttack<P>(state,pos) ||
114 blockingDiagonalAttack<P>(state,pos,target,canMoveMask)) return false;
115 if(setBestMove)
116 bestMove=Move(pos,KNIGHT,P);
117 return true;
118 }
119 }
120 return false;
121 }
122 // KNIGHT
123 // KNIGHTのdropは利きを遮ることはない
124 template<Player P,bool setBestMove>
125 bool hasCheckmateMoveKnight(NumEffectState const& state, Square target,
126 King8Info canMoveMask,Move& bestMove)
127 {
128 // 8近傍に移動できる時は桂馬の一手詰めはない
129 if((canMoveMask.uint64Value()&0xff00)!=0) return false;
130 mask_t mask=mask_t::makeDirect(PtypeFuns<KNIGHT>::indexMask);
131 mask&=state.piecesOnBoard(P).getMask<KNIGHT>();
132 mask&= ~state.promotedPieces().getMask<KNIGHT>();
133 mask&= ~state.pinOrOpen(P).getMask<KNIGHT>();
134 if(state.hasPieceOnStand<KNIGHT>(P)){
135 Square pos=target-DirectionPlayerTraits<UUR,P>::offset();
136 if(hasKnightCheckmate<P,true,setBestMove>(state,target,pos,canMoveMask,bestMove,mask))
137 return true;
138 pos=target-DirectionPlayerTraits<UUL,P>::offset();
139 return hasKnightCheckmate<P,true,setBestMove>(state,target,pos,canMoveMask,bestMove,mask);
140 }
141 else{
142 Square pos=target-DirectionPlayerTraits<UUR,P>::offset();
143 if(hasKnightCheckmate<P,false,setBestMove>(state,target,pos,canMoveMask,bestMove,mask))
144 return true;
145 pos=target-DirectionPlayerTraits<UUL,P>::offset();
146 return hasKnightCheckmate<P,false,setBestMove>(state,target,pos,canMoveMask,bestMove,mask);
147 }
148 return false;
149 }
150 template<Player P,bool setBestMove>
151 bool slowCheckDrop(NumEffectState const& state,Square target,
152 Ptype ptype,King8Info canMoveMask,Move& bestMove)
153 {
154 unsigned int dropMask=(canMoveMask.uint64Value()&0xff)
155 &Immediate_Checkmate_Table.ptypeDropMask(ptype,canMoveMask);
156 // dropMaskが0ならここに来ない
157 assert(dropMask!=0);
158 while(dropMask!=0){
159 int i=BitOp::takeOneBit(dropMask);
160 Direction d=static_cast<Direction>(i);
161 unsigned int blockingMask=Immediate_Checkmate_Table.blockingMask(ptype,d) &
162 (canMoveMask.uint64Value()>>16);
163 Square drop=target-Board_Table.getOffset<P>(d);
164 if(blockingMask!=0){
165 NumBitmapEffect effect=state.effectSetAt(drop);
166 mask_t longEffect=effect.getMask(1)&NumBitmapEffect::longEffectMask();
167 longEffect&=(state.piecesOnBoard(P).getMask(1)<<8);
168 if(longEffect.any()){
169 do{
170 int j=BitOp::takeOneBit(blockingMask);
171 Direction d1=static_cast<Direction>(j);
172 Square pos=target-Board_Table.getOffset<P>(d1);
173 NumBitmapEffect effect1=state.effectSetAt(pos);
174 if(effect1.countEffect(P)>1) continue;
175 mask_t longEffect1=effect1.getMask(1)&longEffect;
176 if(!longEffect1.any()) continue;
177 //
178 int num=longEffect1.takeOneBit()+NumBitmapEffect::longToNumOffset;
179 if(Board_Table.isBetween(drop,state.pieceOf(num).square(),pos))
180 goto tryNext;
181 }while(blockingMask!=0);
182 }
183 }
184 // blockingMaskの点がすべてOKならOK
185 if(setBestMove)
186 bestMove=Move(drop,ptype,P);
187 return true;
188 tryNext:;
189 }
190 return false;
191 }
192 } // detail
193 } // checkmate
194 } // osl
195
196 // not KNIGHT
197 template<osl::Player P,bool setBestMove>
198 bool osl::checkmate::ImmediateCheckmate::
199 hasCheckmateDrop(NumEffectState const& state, Square target,
200 King8Info canMoveMask,Move& bestMove)
201 {
202 typedef misc::GeneralMask<unsigned short> mask_t;
203 mask_t dropPtypeMask=mask_t::makeDirect(Immediate_Checkmate_Table.dropPtypeMask(canMoveMask));
204 while(dropPtypeMask.any()){
205 Ptype ptype=static_cast<Ptype>(dropPtypeMask.takeOneBit()+PTYPE_BASIC_MIN);
206 if(state.hasPieceOnStand(P,ptype) &&
207 detail::slowCheckDrop<P,setBestMove>(state,target,ptype,canMoveMask,
208 bestMove))
209 return true;
210 }
211 return false;
212 }
213
214 template<osl::Player P,bool setBestMove>
215 bool osl::checkmate::ImmediateCheckmate::
216 slowHasCheckmateMoveDirPiece(NumEffectState const& state, Square target,
217 King8Info canMoveMask,Direction d,Square pos,Piece p,Ptype ptype,Move& bestMove){
218 const Player altP=PlayerTraits<P>::opponent;
219 // ptypeがPROOKの時は，更なるチェックが必要
220 if(ptype==PROOK){
221 int dx=target.x()-pos.x();
222 int dy=target.y()-pos.y();
223 if(abs(dx)==1 && abs(dy)==1){
224 {
225 Square pos1=pos+Offset(dx,0);
226 Piece p1=state.pieceAt(pos1);
227 if(!p1.isEmpty()){
228 {
229 // * -OU *
230 // (A)(B)(D)
231 // * (C) *
232 // (E) * *
233 // +RY (C) -> (A), (E) -> (A)
234 // -?? - (B)
235 // (D) - 竜以外の利きなし
236 Square pos2=pos+Offset(2*dx,0);
237 if(state.pieceAt(pos2).template canMoveOn<altP>()){
238 NumBitmapEffect effect2=state.effectSetAt(pos2);
239 if(effect2.countEffect(P)==0 ||
240 (effect2.countEffect(P)==1 &&
241 effect2.test(p.number())))
242 return false;
243 }
244 }
245 {
246 // * -OU *
247 // (A)(B) *
248 // * (C) *
249 // +RY (C) -> (A)
250 // -?? - (B)竜でpinされているが実はAへの利き持つ
251 if(p.square()==target-Offset(0,2*dy) &&
252 state.hasEffectByPiece(p1,pos))
253 return false;
254 }
255 }
256 }
257 {
258 Square pos1=pos+Offset(0,dy);
259 Piece p1=state.pieceAt(pos1);
260 if(!p1.isEmpty()){
261 Square pos2=pos+Offset(0,2*dy);
262 {
263 if(state.pieceAt(pos2).template canMoveOn<altP>()){
264 NumBitmapEffect effect2=state.effectSetAt(pos2);
265 if(effect2.countEffect(P)==0 ||
266 (effect2.countEffect(P)==1 &&
267 effect2.test(p.number())))
268 return false;
269
270 }
271 {
272 // (C)(B)-OU
273 // * (A) *
274 // +RY (C) -> (A)
275 // -?? - (B)竜でpinされているが実はAへの利き持つ
276 if(p.square()==target-Offset(2*dx,0) &&
277 state.hasEffectByPiece(p1,pos))
278 return false;
279 }
280 }
281 }
282 }
283 }
284 }
285 // 元々2つの利きがあったマスが，
286 // block & 自分の利きの除去で利きがなくなることはあるか?
287 // -> ある．
288 // +KA * *
289 // * (A) +KI
290 // * -OU (B)
291 // * * *
292 // で金がAに移動して王手をかけると，Bの利きが2から0になる．
293 mask_t mask=mask_t::makeDirect((canMoveMask.uint64Value()>>16)&Immediate_Checkmate_Table.noEffectMask(ptype,d));
294 if(mask.any()){
295 int num=p.number();
296 NumBitmapEffect effect2=state.effectSetAt(pos);
297 effect2.reset(num+8);
298 mask_t longEffect2=effect2.getMask(1)&NumBitmapEffect::longEffectMask();
299 longEffect2&=(state.piecesOnBoard(P).getMask(1)<<8);
300 do {
301 Direction d1=static_cast<Direction>(mask.takeOneBit());
302 Square pos1=target-Board_Table.getOffset<P>(d1);
303 NumBitmapEffect effect1=state.effectSetAt(pos1);
304 int count=effect1.countEffect(P);
305 // 自分の利きの除去
306 if(effect1.test(num)) count--;
307 if(count==0) return false;
308 // blockしている利きの除去
309 mask_t longEffect1=effect1.getMask(1)&longEffect2;
310 while(longEffect1.any()){
311 int num1=longEffect1.takeOneBit()+NumBitmapEffect::longToNumOffset;
312 if(Board_Table.isBetween(pos,state.pieceOf(num1).square(),pos1))
313 count--;
314 if(count==0) return false;
315 }
316 } while (mask.any());
317 }
318 // 自殺手でないことのチェックを入れる
319 if(move_classifier::KingOpenMove<P>::isMember(state,ptype,p.square(),pos)) return false;
320 if(setBestMove){
321 bestMove=Move(p.square(),pos,ptype,
322 state.pieceAt(pos).ptype(),
323 ptype!=p.ptype(),P);
324 }
325 return true;
326 }
327
328 template<osl::Player P,bool setBestMove>
329 bool osl::checkmate::ImmediateCheckmate::
330 hasCheckmateMoveDirPiece(NumEffectState const& state, Square target,
331 King8Info canMoveMask,Direction d,Square pos,Piece p,Move& bestMove){
332 Square from=p.square();
333 Ptype ptype=p.ptype();
334 // 相手の利きが伸びてしまって移動後も利きがついてくる可能性
335 {
336 const Player altP=PlayerTraits<P>::opponent;
337 Direction d1=Board_Table.getShort8Unsafe<P>(from,pos);
338 if(d1!=DIRECTION_INVALID_VALUE){ // not knight move
339 int num=state.longEffectNumTable()[p.number()][P==BLACK ? d1 : inverse(d1)];
340 if(num != EMPTY_NUM && state.pieceOf(num).isOnBoardByOwner<altP>())
341 return false;
342 }
343 }
344 if(canPromote(ptype) &&
345 (from.canPromote<P>() || pos.canPromote<P>())){
346 Ptype pptype=promote(ptype);
347 if((((canMoveMask.uint64Value()>>8)|0x100)&
348 Immediate_Checkmate_Table.noEffectMask(pptype,d))==0){
349 if(slowHasCheckmateMoveDirPiece<P,setBestMove>(state,target,canMoveMask,d,pos,p,pptype,bestMove)) return true;
350 }
351 if (ptype==PAWN || /*basic because canpromote*/isMajorBasic(ptype))
352 return false;
353 }
354 if((((canMoveMask.uint64Value()>>8)|0x100)&
355 Immediate_Checkmate_Table.noEffectMask(ptype,d))==0){
356 if(slowHasCheckmateMoveDirPiece<P,setBestMove>(state,target,canMoveMask,d,pos,p,ptype,bestMove)) return true;
357 }
358 return false;
359 }
360
361 template<osl::Player P,bool setBestMove>
362 bool osl::checkmate::ImmediateCheckmate::
363 hasCheckmateMoveDir(NumEffectState const& state, Square target,
364 King8Info canMoveMask,Direction d,Move& bestMove){
365 Square pos=target-Board_Table.getOffset<P>(d);
366 if(state.countEffect(P,pos)<2 &&
367 !effect_util::AdditionalEffect::hasEffect(state,pos,P)) return false;
368 PieceMask pieceMask=state.piecesOnBoard(P)&state.effectSetAt(pos);
369 assert(pos.isOnBoard());
370 // 玉で王手をかけない
371 pieceMask.reset(KingTraits<P>::index);
372 for(int i=0;i<=PieceMask::numToIndex(40);i++){
373 mask_t mask=pieceMask.getMask(i);
374 while (mask.any()){
375 const int num=mask.takeOneBit()+i*32;
376 if(hasCheckmateMoveDirPiece<P,setBestMove>(state,target,canMoveMask,d,pos,state.pieceOf(num),bestMove)) return true;
377 }
378 }
379 return false;
380 }
381
382 // not KNIGHT
383 template<osl::Player P,bool setBestMove>
384 bool osl::checkmate::ImmediateCheckmate::
385 hasCheckmateMove(NumEffectState const& state, Square target,
386 King8Info canMoveMask,Move& bestMove)
387 {
388 assert(! state.inCheck());
389 typedef misc::GeneralMask<unsigned int> mask_t;
390 mask_t mask2=mask_t::makeDirect((canMoveMask.uint64Value()>>24)&0xff);
391 while(mask2.any()){
392 Direction d=static_cast<Direction>(mask2.takeOneBit());
393 if(hasCheckmateMoveDir<P,setBestMove>(state,target,canMoveMask,d,bestMove)) return true;
394 }
395 return false;
396 }
397
398 template<osl::Player P>
399 bool osl::checkmate::ImmediateCheckmate::
400 hasCheckmateMove(NumEffectState const& state, King8Info canMoveMask)
401 {
402 const Player altP=PlayerTraits<P>::opponent;
403 const Square target=state.kingSquare(altP);
404 assert(target.isOnBoard());
405 // 相手からの王手がかかっていない
406 Move dummy;
407 if(hasCheckmateMove<P,false>(state,target,canMoveMask,dummy)) return true;
408 if(detail::hasCheckmateMoveKnight<P,false>(state,target,canMoveMask,dummy)) return true;
409 return hasCheckmateDrop<P,false>(state,target,canMoveMask,dummy);
410 }
411
412 template<osl::Player P>
413 bool osl::checkmate::ImmediateCheckmate::
414 hasCheckmateMove(NumEffectState const& state)
415 {
416 const Player altP=PlayerTraits<P>::opponent;
417 #ifndef NDEBUG
418 const Square target=state.kingSquare(altP);
419 #endif
420 assert(target.isOnBoard());
421 King8Info canMoveMask(state.Iking8Info(altP));
422 return hasCheckmateMove<P>(state, canMoveMask);
423 }
424
425 template<osl::Player P>
426 bool osl::checkmate::ImmediateCheckmate::
427 hasCheckmateMove(NumEffectState const& state, King8Info canMoveMask,
428 Square target, Move& bestMove)
429 {
430 assert(! state.inCheck());
431 assert(target.isOnBoard());
432
433 if(hasCheckmateMove<P,true>(state,target,canMoveMask,bestMove)) return true;
434 if(detail::hasCheckmateMoveKnight<P,true>(state,target,canMoveMask,bestMove)) return true;
435 return hasCheckmateDrop<P,true>(state,target,canMoveMask,bestMove);
436 }
437
438 template<osl::Player P>
439 bool osl::checkmate::ImmediateCheckmate::
440 hasCheckmateMove(NumEffectState const& state,Move& bestMove)
441 {
442 const Player altP=PlayerTraits<P>::opponent;
443 const Square target=state.kingSquare(altP);
444 King8Info canMoveMask(state.Iking8Info(altP));
445 return hasCheckmateMove<P>(state, canMoveMask, target, bestMove);
446 }
447
448 #endif /* OSL_CHECKMATE_IMMEDIATE_CHECKMATE_TCC */
449 // ;;; Local Variables:
450 // ;;; mode:c++
451 // ;;; c-basic-offset:2
452 // ;;; End:
453