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
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  }
40  pos+=offset;
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  {
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());
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;
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)){
136  if(hasKnightCheckmate<P,true,setBestMove>(state,target,pos,canMoveMask,bestMove,mask))
137  return true;
139  return hasKnightCheckmate<P,true,setBestMove>(state,target,pos,canMoveMask,bestMove,mask);
140  }
141  else{
143  if(hasKnightCheckmate<P,false,setBestMove>(state,target,pos,canMoveMask,bestMove,mask))
144  return true;
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>
199 hasCheckmateDrop(NumEffectState const& state, Square target,
200  King8Info canMoveMask,Move& bestMove)
201 {
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>
216 slowHasCheckmateMoveDirPiece(NumEffectState const& state, Square target,
217  King8Info canMoveMask,Direction d,Square pos,Piece p,Ptype ptype,Move& bestMove){
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>
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  {
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)&
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)&
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>
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>
385 hasCheckmateMove(NumEffectState const& state, Square target,
386  King8Info canMoveMask,Move& bestMove)
387 {
388  assert(! state.inCheck());
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>
400 hasCheckmateMove(NumEffectState const& state, King8Info canMoveMask)
401 {
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>
414 hasCheckmateMove(NumEffectState const& state)
415 {
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>
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>
440 hasCheckmateMove(NumEffectState const& state,Move& bestMove)
441 {
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