All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
quiescenceGenerator.tcc
Go to the documentation of this file.
1 /* quiescenceGenerator.tcc
2  */
3 #ifndef QUIESCENCEGENERATOR_TCC
4 #define QUIESCENCEGENERATOR_TCC
5 
14 #include "osl/effect_util/pin.h"
17 #include "osl/neighboring8.h"
18 
19 template <osl::Player P>
20 template <osl::Ptype PTYPE, bool has_dont_capture>
22 capture(const NumEffectState& state, MoveVector& moves, Piece dont_capture)
23 {
24  mask_t pieces = state.effectedMask(P).template selectBit<PTYPE>()
25  & state.piecesOnBoard(alt(P)).getMask(PtypeFuns<PTYPE>::indexNum);
26 
27  if (has_dont_capture && dont_capture.isPiece() && (dont_capture.ptype() == PTYPE))
28  {
29  while (pieces.any()) {
30  const Piece target = state.pieceOf(pieces.takeOneBit()+PtypeFuns<PTYPE>::indexNum*32);
31  if (target != dont_capture)
32  capture(state, target.square(), moves);
33  }
34  }
35  else
36  {
37  while (pieces.any()) {
38  const Piece target = state.pieceOf(pieces.takeOneBit()+PtypeFuns<PTYPE>::indexNum*32);
39  capture(state, target.square(), moves);
40  }
41  }
42  if (((PTYPE == KNIGHT) || (PTYPE == BISHOP))
43  && state.hasPieceOnStand<LANCE>(P))
44  {
45  // 歩で駒を取る手がある場合は,追加利きをつける
46 
47  // NOTE: MoveVector はpush_backしてもiteratorをinvalidate
48  // しないという仕様に依存
49  MoveVector::const_iterator original_end = moves.end();
50  for (MoveVector::const_iterator p=moves.begin(); p!=original_end; ++p)
51  {
52  const Square from = p->from();
53  if ((p->oldPtype() == PAWN)
54  && (state.hasEffectAt<PlayerTraits<P>::opponent>(p->to())))
55  {
57  }
58  }
59  }
60 }
61 
62 template <osl::Player P> inline
64 attackMajorPieceFirstSelection(const NumEffectState& state,
65  PieceMask pins, const MoveVector& all_moves,
66  MoveVector& moves,
67  MoveVector& expensive_drops)
68 {
69  BOOST_FOREACH(Move m, all_moves)
70  {
71  const Square to = m.to();
72  {
73  const int defense = state.countEffect(alt(P),to, pins);
74  int offense = state.countEffect(P,to) + (m.isDrop() ? 1 : 0);
75  if (defense >= offense)
76  offense += AdditionalEffect::count2(state, to, P);
77  if (m.ptype() != PAWN)
78  {
79  if (defense > offense)
80  continue;
81  }
82  else
83  {
84  if (defense && (offense==1))
85  {
86  if (! (state.hasEffectByPtype<ROOK>(alt(P),to)
87  && state.hasEffectByPtype<BISHOP>(alt(P),to)))
88  continue;
89  }
90  }
91  const Ptype ptype = m.ptype();
92  if ((defense >= offense)
93  && (unpromote(ptype) != PAWN))
94  continue;
95  if (ptype != PAWN)
96  {
97  const Square front_position
99  const Piece front_piece = state.pieceAt(front_position);
100  if (front_piece.ptypeO() == newPtypeO(alt(P),PAWN))
101  continue;
102  }
103  if (m.isDrop() && (m.ptype() == PAWN)
104  && to.canPromote<P>())
105  {
106  // 垂れ歩
107  const Square back_position
109  if (state.pieceOnBoard(back_position).isEmpty())
110  moves.push_back(Move(back_position, PAWN, P));
111  }
112  const int ptype_value = eval::Ptype_Eval_Table.value(ptype);
113  const bool is_large_piece
114  = (ptype_value > eval::PtypeEvalTraits<BISHOP>::val);
115  if ((m.isDrop()
116  && (ptype_value > eval::PtypeEvalTraits<KNIGHT>::val))
117  || (is_large_piece && defense))
118  expensive_drops.push_back(m);
119  else
120  moves.push_back(m);
121  }
122  }
123 }
124 
125 template <osl::Player P> inline
127 attackMajorPieceSecondSelection(bool target_has_support,
128  const MoveVector& src,
129  MoveVector& out)
130 {
131  BOOST_FOREACH(Move m, src)
132  {
133  const Ptype ptype = m.ptype();
134  if (target_has_support
135  && (eval::Ptype_Eval_Table.value(ptype)
137  continue;
138 
139  out.push_back(m);
140  }
141 }
142 
143 template <osl::Player P>
145 attackMajorPieceZerothSelection(const NumEffectState& state,
146  const MoveVector& src,
147  Square target,
148  MoveVector& open_out,
149  MoveVector& out)
150 {
151  BOOST_FOREACH(Move m, src)
152  {
153  assert(!ShouldPromoteCut::canIgnoreAndNotDrop<P>(m));
154  const bool is_open
155  = (! m.isDrop())
156  && state.hasEffectAt<P>(m.from())
157  && (state.hasEffectByPtype<LANCE>(P, m.from())
158  || state.hasEffectByPtype<BISHOP>(P, m.from())
159  || state.hasEffectByPtype<ROOK>(P, m.from()))
160  && ! state.hasEffectIf(m.ptypeO(), m.to(), target);
161  // 取る手は重複
162  const bool may_overlap = m.isCaptureOrPromotion();
163  if (is_open)
164  {
165  if (! may_overlap // 取り返される場合はたぶん重複しない
166  || state.hasEffectAt<PlayerTraits<P>::opponent>(m.to()))
167  open_out.push_back(m);
168  }
169  else
170  {
171  if (! may_overlap)
172  out.push_back(m);
173  }
174  }
175 }
176 
177 template <osl::Player P>
179 attackMajorPiece(const NumEffectState& state, PieceMask pins,
180  MoveVector& moves)
181 {
182  using namespace move_action;
183  MoveVector work;
184  MoveVector unsupported, supported;
186  for (int i = PtypeTraits<BISHOP>::indexMin;
187  i < PtypeTraits<ROOK>::indexLimit; i++)
188  {
189  const Piece p = state.pieceOf(i);
191  {
192  const Square target = p.square();
193  assert(isMajor(p.ptype()));
194  const bool unstable_rook = (p.ptype() == ROOK)
195  && (state.pieceAt(target + DirectionPlayerTraits<U, PlayerTraits<P>::opponent>::offset())
196  != Piece::EMPTY()); // 前に進めない
197  work.clear();
198  if (state.hasEffectAt(alt(P), target) && (! unstable_rook))
199  {
200  move_generator::GenerateAddEffectWithEffect::generate<false>
201  (P, state, target, work);
202  attackMajorPieceZerothSelection(state, work, target, moves, supported);
203  }
204  else if (unstable_rook || (! state.hasEffectAt(P, target)))
205  {
206  // ただで取れる時には利きをつけない
207  move_generator::GenerateAddEffectWithEffect::generate<false>
208  (P, state, target, work);
209  attackMajorPieceZerothSelection(state, work, target, moves, unsupported);
210  }
211  }
212  }
213 
214  // first pass
215  MoveVector drops_supported, drops_unsupported;
216  attackMajorPieceFirstSelection(state, pins, unsupported, moves,
217  drops_unsupported);
218  attackMajorPieceFirstSelection(state, pins, supported, moves,
219  drops_supported);
220  // second pass
221  if (moves.size() > 5)
222  return;
223  attackMajorPieceSecondSelection(false, drops_unsupported, moves);
224  if (moves.size() > 5)
225  return;
226  attackMajorPieceSecondSelection(true, drops_supported, moves);
227 }
228 
229 template <osl::Player P>
231 escapeNormalPiece(const NumEffectState& state,
232  Piece escape, MoveVector& moves, bool add_support_only)
233 {
234  assert(escape.ptype() != KING);
235  using namespace move_action;
236  MoveVector all_moves;
237  const Piece attack_piece
238  = state.findCheapAttack(alt(P), escape.square());
239  const int attack_ptype_value
240  = eval::Ptype_Eval_Table.value(unpromote(attack_piece.ptype()));
241  const Square escape_from = escape.square();
242  if (! add_support_only)
243  {
244  GenerateEscape<P>::generateCheap(state, escape, all_moves);
245  BOOST_FOREACH(Move m, all_moves)
246  {
247  const Square to = m.to();
248  if (m.isDrop())
249  {
250  if (! state.hasEffectAt<P>(to))
251  continue; // 中合
252 #ifdef QSEARCH_EXPENSIVE_BLOCK
253  if (eval::Ptype_Eval_Table.value(m.ptype()) > attack_ptype_value)
254  continue;
255 #else
256  if (m.ptype() != PAWN)
257  continue;
258 #endif
259  moves.push_back(m);
260  }
261  else
262  {
263  if (m.from() != escape_from)
264  {
265  // 移動合
266  if (! state.hasMultipleEffectAt(P, to))
267  continue;
268  if (eval::Ptype_Eval_Table.value(m.ptype()) > attack_ptype_value)
269  continue;
270  }
271  // 取る手は重複
272  // TODO: KnightCaptureDepth
273  assert(! ShouldPromoteCut::canIgnoreMove<P>(m));
274  if (! m.isCaptureOrPromotion())
275  {
276  moves.push_back(m);
277  }
278  }
279  }
280  }
281  // 紐をつける
282  if (unpromote(attack_piece.ptype()) == PAWN)
283  return;
284  if ((eval::Ptype_Eval_Table.value(escape.ptype()) - attack_ptype_value)
286  return;
287  if (state.hasEffectAt<P>(escape_from)
288  || (state.countEffect(alt(P), escape_from) != 1))
289  return;
290  all_moves.clear();
291  move_generator::GenerateAddEffectWithEffect::generate<false>
292  (P, state, escape_from, all_moves);
293  const size_t escape_moves = moves.size();
294  MoveVector not_drop;
295  BOOST_FOREACH(Move m, all_moves)
296  {
297  const Square to = m.to();
298  if (m.isDrop())
299  {
300  if (state.hasEffectAt<PlayerTraits<P>::opponent>(to)
301  && (! state.hasEffectAt<P>(to)))
302  continue;
303  // 打つ手は歩か香車だけ
304  if ((m.ptype() != PAWN) && (m.ptype() != LANCE))
305  continue;
306  moves.push_back(m);
307  }
308  else
309  {
310  // 移動
311  const int defense = state.countEffect(P,to);
312  const int offense = state.countEffect(alt(P),to);
313  if (offense >= defense)
314  continue;
315  // 取る手は重複
316  // TODO: KnightCaptureDepth
317  assert(! ShouldPromoteCut::canIgnoreMove<P>(m));
318  if (! m.isCaptureOrPromotion())
319  {
320  moves.push_back(m);
321  }
322  }
323  }
324  // 合わせ角
325  if (state.hasEffectByPtype<BISHOP>(alt(P), escape_from)
326  && state.hasPieceOnStand<BISHOP>(P))
327  {
328  const Piece bishop = state.findAttackAt<BISHOP>(alt(P), escape_from);
329  assert(unpromote(bishop.ptype()) == BISHOP);
330  {
331  Square p = bishop.square();
332  const Offset offset = Board_Table.getShortOffset(Offset32(p,escape_from));
333  p += offset;
334  while (state.pieceAt(p).isEmpty())
335  {
336  if (state.hasEffectAt<P>(p))
337  {
338  moves.push_back(Move(p, BISHOP, P));
339  break;
340  }
341  p += offset;
342  }
343  }
344  }
345 
346  if (escape_moves == moves.size()) // drop not found
347  moves.push_back(not_drop.begin(), not_drop.end());
348 }
349 
350 template <osl::Player P>
352 escapeAll(const NumEffectState& state, MoveVector& moves)
353 {
354  // 逃げるのは大駒か価値の一番高い駒のみ
355  const PieceMask pieces = state.effectedMask(alt(P)) & state.piecesOnBoard(P);
356  bool found_attacked_piece = false;
357  mask_t m = pieces.selectBit<ROOK>();
358  while (m.any())
359  {
360  const Piece p = state.pieceOf(m.takeOneBit()+PtypeFuns<ROOK>::indexNum*32);
361  assert(p.isOnBoardByOwner<P>()
362  && state.hasEffectAt<PlayerTraits<P>::opponent>(p.square()));
363  found_attacked_piece = true;
364  escapeNormalPiece(state, p, moves);
365  }
366  m = pieces.selectBit<BISHOP>();
367  while (m.any())
368  {
369  const Piece p = state.pieceOf(m.takeOneBit()+PtypeFuns<BISHOP>::indexNum*32);
370  assert(p.isOnBoardByOwner<P>()
371  && state.hasEffectAt<PlayerTraits<P>::opponent>(p.square()));
372  found_attacked_piece = true;
373  escapeNormalPiece(state, p, moves);
374  }
375 
376  if (found_attacked_piece)
377  goto finish;
378  m = pieces.selectBit<GOLD>();
379  while (m.any())
380  {
381  const Piece p = state.pieceOf(m.takeOneBit()+PtypeFuns<GOLD>::indexNum*32);
382  assert(p.isOnBoardByOwner<P>()
383  && state.hasEffectAt<PlayerTraits<P>::opponent>(p.square()));
384  escapeNormalPiece(state, p, moves);
385  goto finish;
386  }
387  m = pieces.selectBit<SILVER>();
388  while (m.any())
389  {
390  const Piece p = state.pieceOf(m.takeOneBit()+PtypeFuns<SILVER>::indexNum*32);
391  assert(p.isOnBoardByOwner<P>()
392  && state.hasEffectAt<PlayerTraits<P>::opponent>(p.square()));
393  escapeNormalPiece(state, p, moves);
394  goto finish;
395  }
396  m = pieces.selectBit<KNIGHT>();
397  while (m.any())
398  {
399  // 成桂は逃げない
400  const Piece p = state.pieceOf(m.takeOneBit()+PtypeFuns<KNIGHT>::indexNum*32);
401  assert(p.isOnBoardByOwner<P>()
402  && state.hasEffectAt<PlayerTraits<P>::opponent>(p.square()));
403  escapeNormalPiece(state, p, moves, p.ptype()==PKNIGHT);
404  goto finish;
405  }
406  m = pieces.selectBit<LANCE>();
407  while (m.any())
408  {
409  // 香,成香は逃げない
410  const Piece p = state.pieceOf(m.takeOneBit()+PtypeFuns<LANCE>::indexNum*32);
411  assert(p.isOnBoardByOwner<P>()
412  && state.hasEffectAt<PlayerTraits<P>::opponent>(p.square()));
413  escapeNormalPiece(state, p, moves, true);
414  goto finish;
415  }
416  m = pieces.selectBit<PAWN>();
417  while (m.any())
418  {
419  // 歩,と金は逃げない
420  const Piece p = state.pieceOf(m.takeOneBit()+PtypeFuns<PAWN>::indexNum*32);
421  assert(p.isOnBoardByOwner<P>()
422  && state.hasEffectAt<PlayerTraits<P>::opponent>(p.square()));
423  escapeNormalPiece(state, p, moves, true);
424  goto finish;
425  }
426 finish:
427  return;
428 }
429 
430 template <osl::Player P>
431 template <class EvalT>
433 escapeFromLastMoveOtherThanPawn(const NumEffectState& state, Move last_move,
434  MoveVector& moves)
435 {
436  if (! last_move.isNormal())
437  return;
438  assert(last_move.ptype() != PAWN);
439 
440  PieceVector targets;
441  const Square from = last_move.to();
442  EffectUtil::findThreat<EvalT>(state, from, last_move.ptypeO(), targets);
443  if (targets.empty())
444  return;
445  assert(targets[0].ptype() != KING);
446 
447  escapeNormalPiece(state, targets[0], moves,
448  (last_move.ptype() != PAWN)
449  && (eval::Ptype_Eval_Table.value(targets[0].ptype())
451  if (targets.size() > 1)
452  escapeNormalPiece(state, targets[1], moves,
453  (last_move.ptype() != PAWN)
454  && (eval::Ptype_Eval_Table.value(targets[1].ptype())
456 }
457 
458 template <osl::Player P>
460 escapeByMoveOnly(const NumEffectState& state, Piece piece, MoveVector& moves)
461 {
462  assert(piece.isOnBoardByOwner<P>());
463 
464  MoveVector all_moves;
465  GeneratePieceOnBoard::generate(state.turn(),state,piece,all_moves);
466 
467  const Player Opponent = PlayerTraits<P>::opponent;
468  const Square from = piece.square();
469 
470  const bool consider_shadowing
471  = state.hasEffectByPtype<LANCE>(Opponent, from)
472  || state.hasEffectByPtype<ROOK>(Opponent, from)
473  || state.hasEffectByPtype<BISHOP>(Opponent, from);
474  const bool is_major = isMajor(piece.ptype());
475  const bool chase_danger
476  = (! state.hasEffectAt(P, from)
477  && (state.hasMultipleEffectAt(alt(P), from)
478  || AdditionalEffect::hasEffect(state, from, alt(P))));
479  BOOST_FOREACH(Move m, all_moves)
480  {
481  assert(m.from() == piece.square());
482  if (m.isCapture())
483  continue;
484  const Square to = m.to();
485  const bool safe_position
486  = (consider_shadowing
487  ? (! state.hasEffectByWithRemove<Opponent>(to, from))
488  : (! state.hasEffectAt<Opponent>(to)));
489  if (safe_position)
490  {
491  if (! is_major || ! chase_danger)
492  return true;
493  if (! to.canPromote<Opponent>())
494  return true; // 自陣以外も対象にする場合は QuiescenceSearch も調整
495  if ((to - from) != Board_Table.getShortOffset(Offset32(to, from)))
496  return true; // 二歩以上逃げられれば良し
497  }
498  moves.push_back(m);
499  }
500  return false;
501 }
502 
503 template <osl::Player P>
505 check(const NumEffectState& state, PieceMask pins, MoveVector& moves,
506  bool no_liberty)
507 {
508  Square8 sendoffs;
509  const Square king_position = state.kingSquare(alt(P));
510  effect_util::SendOffSquare::find<P>(state, king_position, sendoffs);
511  check(state, pins, no_liberty, sendoffs, moves);
512 }
513 
514 
515 template <osl::Player P>
517 check(const NumEffectState& state, PieceMask pins, bool no_liberty,
518  const Square8& sendoffs, MoveVector& moves)
519 {
520  using namespace move_action;
521  MoveVector all_moves;
522  const Square king_position = state.kingSquare(alt(P));
523  move_generator::GenerateAddEffectWithEffect::generate<true>
524  (P, state, king_position, all_moves);
525 
526  MoveVector merginal_moves;
527  BOOST_FOREACH(Move m, all_moves)
528  {
529  // 取る手,成る手は重複
530  assert(! ShouldPromoteCut::canIgnoreAndNotDrop<P>(m));
531  if (m.isPromotion())
532  continue;
533  const Square to = m.to();
534  const Ptype captured = m.capturePtype();
535 
536  if ((captured != PTYPE_EMPTY)
537  && (eval::Ptype_Eval_Table.value(captured)
539  continue;
540  const bool is_open
541  = (! m.isDrop())
542  && state.hasEffectAt<P>(m.from())
543  && (state.hasEffectByPtype<LANCE>(P, m.from())
544  || state.hasEffectByPtype<BISHOP>(P, m.from())
545  || state.hasEffectByPtype<ROOK>(P, m.from()))
546  && ! state.hasEffectIf(m.ptypeO(), m.to(), king_position);
547  if (! is_open)
548  {
549  if ((m.ptype() != PAWN) && (m.ptype() != KNIGHT))
550  {
551  // 歩の前は読まない
552  const Square front_position
554  const Piece front_piece = state.pieceAt(front_position);
555  if (front_piece.ptypeO() == newPtypeO(alt(P),PAWN))
556  continue;
557  }
558  if (! sendoffs.isMember(to))
559  {
560  const int defense = state.countEffect(alt(P),to, pins);
561  int offense = state.countEffect(P,to) + no_liberty;
562  const bool may_effective = offense && (! sendoffs.empty());
563  if (m.isDrop())
564  ++offense;
565  if (defense >= offense)
566  offense += AdditionalEffect::count2(state, to, P);
567  if (defense >= offense)
568  offense += ShadowEffect::count2(state, to, P);
569  if (m.ptype() == KNIGHT)
570  {
571  const Square front_position
573  if (state.hasEffectAt<P>(front_position))
574  offense+=1; // pin もしくは空いた場所に何か打てるかも
575  }
576  if (defense > offense)
577  {
578  const bool side_attack
579  = (king_position.x() == 1 || king_position.x() == 9)
580  && m.ptype() == PAWN;
581  if (! side_attack)
582  continue; // 乱暴な王手は指さない
583  }
584  else if (defense == offense)
585  {
586  if ((unpromote(m.ptype()) == PAWN)
587  || state.hasEffectByPtype<PAWN>(P, to)
588  || state.hasEffectByPtype<LANCE>(P, to))
589  moves.push_back(m);
590  else if (may_effective)
591  merginal_moves.push_back(m);
592  continue;
593  }
594  }
595  }
596  if (m.isDrop() && (m.ptype() == PAWN)
597  && to.canPromote<P>())
598  {
599  // 垂れ歩
600  const Square back_position
602  if (state.pieceOnBoard(back_position).isEmpty())
603  moves.push_back(Move(back_position, PAWN, P));
604  }
605  moves.push_back(m);
606  }
607  if (moves.size() < 3)
608  moves.push_back(merginal_moves.begin(), merginal_moves.end());
609 }
610 
611 template <osl::Player P>
613 promote(const NumEffectState& state, PieceMask pins, MoveVector& moves)
614 {
615  using namespace move_action;
616  MoveVector all_moves;
617  move_generator::Promote<P>::generate(state, all_moves);
618 
619  BOOST_FOREACH(Move m, all_moves)
620  {
621  const Square to = m.to();
622  const int defense = state.countEffect(alt(P),to, pins);
623  int offense = state.countEffect(P,to);
624  if (defense >= offense)
625  offense += AdditionalEffect::count2(state, to, P);
626  if (m.ptype() == PPAWN
627  && defense && offense + 1 >= defense)
628  {
629  // 歩が成れる時は追加利きをつけてみる?
630  if (m.ptype() == PPAWN)
631  {
632  // 飛車が横に動く
633  for (int i = PtypeTraits<ROOK>::indexMin;
634  i < PtypeTraits<ROOK>::indexLimit; ++i)
635  {
636  const Piece rook = state.pieceOf(i);
637  if (! rook.isOnBoardByOwner<P>() || rook.ptype() == PROOK
638  || rook.square().template canPromote<P>())
639  continue;
640  const Square mid(m.from().x(), rook.square().y());
641  if (state.pieceOnBoard(mid).isEmpty()
642  && state.isEmptyBetween(m.from(), mid)
643  && state.isEmptyBetween(rook.square(), mid))
644  {
645  const Move m(rook.square(), mid, ROOK, PTYPE_EMPTY, false, P);
646  moves.push_back(m);
647  }
648  }
649  if (state.hasPieceOnStand<LANCE>(P))
651  // あとは桂馬くらい?
652  }
653  }
654  if (defense > offense)
655  {
656  continue; // 成りではあまり乱暴な手は指さない
657  }
658  if ((defense == offense)
659  && (m.ptype() != PPAWN))
660  continue;
661 
662  moves.push_back(m);
663  }
664 }
665 
666 template <osl::Player P>
668 attackKing8(const NumEffectState& state, PieceMask pins, MoveVector& moves)
669 {
670  using namespace move_action;
671  MoveVector all_moves;
672 
673  MoveVector not8;
674  MoveVector not_drop;
675  MoveVector major_drop;
676  move_generator::AddEffect8<P>::generate(state, all_moves);
677 
678  const Square king_position = state.kingSquare(alt(P));
679  const int king_x = king_position.x();
680  BOOST_FOREACH(Move m, all_moves)
681  {
682  // 取る手,成る手は重複
683  assert(! ShouldPromoteCut::canIgnoreAndNotDrop<P>(m));
684  assert(! m.isPromotion());
685  const Square to = m.to();
686 #ifndef NDEBUG
687  const Ptype captured = m.capturePtype();
688  assert(captured==PTYPE_EMPTY);
689 #endif
690 
691  const Ptype ptype = m.ptype();
692 
693  const int defense = state.countEffect(alt(P),to,pins);
694  int offense = state.countEffect(P,to) + (m.isDrop() ? 1 : 0);
695  if (defense >= offense)
696  offense += AdditionalEffect::count2(state, to, P);
697  if (ptype == PAWN)
698  {
699  const Square head = to + DirectionPlayerTraits<U,P>::offset();
700  if (state.hasEffectAt<P>(head))
701  ++offense;
702  }
703  if (defense > offense)
704  continue;
705  if (defense == offense)
706  {
707  if (ptype != PAWN)
708  continue;
709  }
710  if (isMajor(ptype))
711  {
712  if (defense == 0)
713  {
714  // 大駒は利きのあるところにはいかない TODO: kingのみ許可?
715  if (isPromoted(ptype) && to.x() == king_x
716  && abs(to.y() - king_position.y()) <= 2)
717  moves.push_back(m);
718  else if (m.isDrop())
719  major_drop.push_back(m);
720  else
721  not_drop.push_back(m);
722  }
723  continue;
724  }
726  {
727  const int y = to.y();
728  if (((P == BLACK) && (y == 1))
729  || ((P == WHITE) && (y == 9)))
730  continue; // 1段目の金類
731  }
732  // 歩の前は読まない TODO: 桂馬だけ許す?
733  if (ptype != PAWN)
734  {
735  if (state.hasEffectByPtype<PAWN>(alt(P), to))
736  continue;
737  if (state.hasEffectByPtype<LANCE>(alt(P), to))
738  {
739  not_drop.push_back(m);
740  continue;
741  }
742  }
743  if (! Neighboring8::isNeighboring8(king_position, to))
744  not8.push_back(m);
745  else if (! m.isDrop())
746  not_drop.push_back(m);
747  else
748  moves.push_back(m);
749  }
750  const size_t minimum_moves
751  = (king_position.squareForBlack<P>().y() == 1) ? 3 : 2;
752  for (MoveVector::const_iterator p=not8.begin();
753  (p!=not8.end()) && (moves.size() <= minimum_moves); ++p)
754  {
755  moves.push_back(*p);
756  }
757  for (MoveVector::const_iterator p=not_drop.begin();
758  (p!=not_drop.end()) && (moves.size() <= minimum_moves); ++p)
759  {
760  moves.push_back(*p);
761  }
762  for (MoveVector::const_iterator p=major_drop.begin();
763  (p!=major_drop.end()) && (moves.size() <= minimum_moves); ++p)
764  {
765  moves.push_back(*p);
766  }
767 }
768 
769 template <osl::Player P>
771 attackToPinned(const NumEffectState& state, PieceMask pins, MoveVector& moves)
772 {
773  using namespace move_action;
774  MoveVector all_moves;
776 
777  BOOST_FOREACH(Move m, all_moves)
778  {
779  // 取る手,成る手は重複
780  assert(!ShouldPromoteCut::canIgnoreAndNotDrop<P>(m));
781  if (m.isPromotion())
782  continue;
783  const Square to = m.to();
784  const Ptype captured = m.capturePtype();
785 
786  if (captured != PTYPE_EMPTY)
787  continue;
788 
789  const Ptype ptype = m.ptype();
790 
791  const int defense = state.countEffect(alt(P),to,pins);
792  int offense = state.countEffect(P,to) + (m.isDrop() ? 1 : 0);
793  if (defense >= offense)
794  offense += AdditionalEffect::count2(state, to, P);
795  if (ptype == PAWN)
796  {
797  const Square head = to + DirectionPlayerTraits<U,P>::offset();
798  if (state.hasEffectAt<P>(head))
799  ++offense;
800  }
801  if (defense > offense)
802  continue;
803  if (defense == offense)
804  {
805  if (ptype != PAWN)
806  continue;
807  }
808  // 歩の前は読まない TODO: 桂馬だけ許す?
809  if (ptype != PAWN)
810  {
811  const Square front_position
813  const Piece front_piece = state.pieceAt(front_position);
814  if (front_piece.ptypeO() == newPtypeO(alt(P),PAWN))
815  continue;
816  }
817  moves.push_back(m);
818  }
819 }
820 
821 template <osl::Player P>
823 utilizePromoted(const NumEffectState& state, Piece target,
824  MoveVector& moves)
825 {
826  if (! target.isPromoted())
827  return;
828  if (/*isMajor*/
829  target.ptype() == ROOK
830  || target.ptype() == BISHOP)
831  return;
832 
833  MoveVector all_moves;
834  move_generator::GeneratePieceOnBoard::generate(P,state, target, all_moves);
835 
836  MoveVector others;
837  const Player Opponent = PlayerTraits<P>::opponent;
838  bool has_good_capture = false;
839  bool may_have_additional = false; // 飛車の前とか
840  BOOST_FOREACH(Move m, all_moves)
841  {
842  assert(m.from() == target.square());
843  if (m.isCapture())
844  {
845  if (m.capturePtype() != PAWN)
846  has_good_capture =true;
847  continue;
848  }
849 
850  const Square to = m.to();
851  int offense = state.countEffect(P, to);
852  const int defense = state.countEffect(Opponent, to);
853  const int additional = AdditionalEffect::count2(state, to, P);
854  if (defense >= offense)
855  {
856  offense += additional;
857  may_have_additional |= (additional > 0);
858  }
859  if (defense >= offense)
860  {
861  others.push_back(m);
862  continue;
863  }
864  moves.push_back(m);
865  }
866  if ((! has_good_capture) && may_have_additional)
867  moves.push_back(others.begin(), others.end());
868 }
869 
870 template <osl::Player P>
872 breakThreatmate(const NumEffectState& state,
873  Move threatmate, PieceMask pins, MoveVector& moves)
874 {
875  MoveVector all_moves, major_piece, major_sacrifice;
876  assert(threatmate.isNormal());
877  const Square target = threatmate.to();
878 
879  // defense by add effect
880  move_generator::GenerateAddEffectWithEffect::generate<false>
881  (P, state, target, all_moves);
882 
883  BOOST_FOREACH(Move m, all_moves)
884  {
885  const Ptype ptype = m.ptype();
886  if (ptype == KING)
887  continue; // KING_WALK will generate
888  if (! m.isDrop())
889  {
890  assert(!ShouldPromoteCut::canIgnoreAndNotDrop<P>(m));
891  if (m.isPromotion())
892  continue;
893  if (isMajor(ptype)
894  && state.hasEffectByPiece(state.pieceOnBoard(m.from()), target))
895  continue; // already have effect
896  }
897  const Square to = m.to();
898  const int me = state.countEffect(P, to) + (m.isDrop() ? 1 : 0);
899  const int op = state.countEffect(alt(P), to, pins);
900  if ((me >= 2) || (op == 0))
901  {
902  if (isMajor(ptype))
903  {
904  if (op)
905  major_sacrifice.push_back(m);
906  else
907  major_piece.push_back(m);
908  }
909  else // ! major
910  {
911  if (m.isDrop() && (ptype == GOLD || ptype == SILVER)
912  && (to.x() == 1 || to.x() == 9))
913  major_piece.push_back(m);
914  else
915  moves.push_back(m);
916  }
917  }
918  }
919  all_moves.clear();
920 
921  if (threatmate.isDrop())
922  {
923  // 場所を指定して、Drop を作る方法は?
924  if (state.hasPieceOnStand<PAWN>(P)
925  && ! state.isPawnMaskSet(P, target.x())
927  moves.push_back(Move(target, PAWN, P));
928  else if (state.hasPieceOnStand<LANCE>(P)
930  moves.push_back(Move(target, LANCE, P));
931  else if (state.hasPieceOnStand<KNIGHT>(P)
933  moves.push_back(Move(target, KNIGHT, P));
934  else if (state.hasPieceOnStand<SILVER>(P))
935  moves.push_back(Move(target, SILVER, P));
936  else if (state.hasPieceOnStand<GOLD>(P))
937  moves.push_back(Move(target, GOLD, P));
938  }
939  // 長い利きのblock他
940  BreakThreatmate::findBlockLong(state, threatmate, all_moves);
941  if (! all_moves.empty())
942  {
943  Ptype cheapest = PTYPE_EMPTY;
944  if (state.hasPieceOnStand<PAWN>(P)) cheapest = PAWN;
945  else if (state.hasPieceOnStand<LANCE>(P)) cheapest = LANCE;
946  else if (state.hasPieceOnStand<KNIGHT>(P)) cheapest = KNIGHT;
947  BOOST_FOREACH(Move m, all_moves) {
948  const int d = state.countEffect(P, m.to()) + m.isDrop();
949  const int a = state.countEffect(alt(P), m.to());
950  if (a >= d && ! (d >= 2 && m.ptype() == PAWN))
951  continue;
952  if (m.ptype() != cheapest && cheapest != PTYPE_EMPTY && Ptype_Table.canDropTo(P, cheapest, m.to()))
953  continue;
954  moves.push_back(m);
955  break;
956  }
957  all_moves.clear();
958  }
959 
960 
961  const Square king_position = state.kingSquare(P);
962  // make a space for king
963  {
964  for (int i=SHORT8_DIRECTION_MIN; i<=SHORT8_DIRECTION_MAX; ++i)
965  {
966  const Piece p = state.pieceAt(Board_Table.nextSquare
967  (P,king_position,Direction(i)));
968  if (! (p.isPiece() && p.owner() == P))
969  continue;
970  if (state.hasEffectAt(alt(P), p.square()))
971  continue;
972  move_generator::GeneratePieceOnBoard::generate(P,state, p, all_moves);
973  }
974  BOOST_FOREACH(Move m, all_moves)
975  {
976  assert(! m.isDrop());
977  assert(!ShouldPromoteCut::canIgnoreAndNotDrop<P>(m));
978  if (m.isPromotion())
979  continue;
980  const Ptype captured = m.capturePtype();
981  if ((captured != PTYPE_EMPTY)
982  && (eval::Ptype_Eval_Table.value(captured)
984  continue;
985  moves.push_back(m);
986  }
987  }
988  // defence by add effect: unusual moves
989  const size_t minimum_moves = 8;
990  for (MoveVector::const_iterator p=major_piece.begin();
991  p!=major_piece.end() && moves.size() < minimum_moves; ++p)
992  {
993  moves.push_back(*p);
994  }
995  for (MoveVector::const_iterator p=major_sacrifice.begin();
996  p!=major_sacrifice.end() && moves.size() < minimum_moves; ++p)
997  {
998  moves.push_back(*p);
999  }
1000 }
1001 
1002 template <osl::Player P>
1004 attackGoldWithPawn(const NumEffectState& state, PieceMask pins,
1005  MoveVector& moves)
1006 {
1007  using namespace move_action;
1008 
1009  const bool has_pawn = state.hasPieceOnStand<PAWN>(P);
1010  const bool has_lance = state.hasPieceOnStand<LANCE>(P);
1011  const bool has_knight = state.hasPieceOnStand<KNIGHT>(P);
1012  const bool has_silver = state.hasPieceOnStand<SILVER>(P);
1013  for (int i = PtypeTraits<GOLD>::indexMin;
1014  i < PtypeTraits<GOLD>::indexLimit; ++i)
1015  {
1016  const Piece p = state.pieceOf(i);
1018  continue;
1019  const Square head = p.square() + DirectionPlayerTraits<D,P>::offset();
1020  if (state.pieceAt(head).isEmpty())
1021  {
1022  // TODO: ただの歩は利きがはずれる時に許す
1023  const int defense = state.countEffect(alt(P), head, pins);
1024  int attack = state.countEffect(P, head)
1025  + state.hasEffectByPtype<BISHOP>(P, p.square());
1026  if (defense >= attack)
1027  attack += AdditionalEffect::count2(state, head, P);
1028 
1029  // move
1030  if (! head.canPromote<P>()) // 成りはすでに生成されているはず
1031  {
1032  const Square origin = head + DirectionPlayerTraits<D,P>::offset();
1033  if (defense <= attack
1034  || state.hasEffectByPtype<BISHOP>(P, origin)) // open attack
1035  {
1036  const Piece candidate = state.pieceAt(origin);
1037  if (candidate.ptype() == PAWN && candidate.owner() == P)
1038  {
1039  const Move move(origin, head, PAWN, PTYPE_EMPTY, false, P);
1040  moves.push_back(move);
1041  ++attack; // 歩の利きがある
1042  }
1043  }
1044  }
1045  // drop
1046  if (defense <= attack)
1047  {
1048  if (has_pawn && !state.template isPawnMaskSet<P>(head.x()))
1049  {
1050  const Move move(head, PAWN, P);
1051  moves.push_back(move);
1052  }
1053  if (has_lance)
1054  {
1055  const Move move(head, LANCE, P);
1056  moves.push_back(move);
1057  }
1058  if (has_silver)
1059  {
1060  const Move move(head, SILVER, P);
1061  moves.push_back(move);
1062  }
1063  }
1064  const bool generate_long_lance = has_lance
1065  && (! state.hasPieceOnStand<PAWN>(alt(P))
1066  || state.template isPawnMaskSet<PlayerTraits<P>::opponent>(head.x()));
1067  if (generate_long_lance)
1068  {
1069  for (Square to=head + DirectionPlayerTraits<D,P>::offset();
1070  state.pieceAt(to).isEmpty();
1072  {
1073  const int defense = state.countEffect(alt(P), to, pins);
1074  const int attack = state.countEffect(P, to);
1075  if (defense > attack)
1076  continue;
1077  const Move move(to, LANCE, P);
1078  moves.push_back(move);
1079  }
1080  }
1081  }
1082  // knight
1083  if (! state.pieceAt(head).isEdge())
1084  {
1085  const Square knight_l = head+DirectionPlayerTraits<DL,P>::offset();
1086  attackWithKnight(state, pins, knight_l, has_knight, moves);
1087  const Square knight_r = head+DirectionPlayerTraits<DR,P>::offset();
1088  attackWithKnight(state, pins, knight_r, has_knight, moves);
1089  }
1090  }
1091 }
1092 
1093 template <osl::Player P>
1095 attackWithKnight(const NumEffectState& state, PieceMask pins,
1096  Square attack_from,
1097  bool has_knight, MoveVector& moves)
1098 {
1099  if (state.pieceAt(attack_from) != Piece::EMPTY())
1100  return;
1101 
1102  const int defense = state.countEffect(alt(P), attack_from, pins);
1103  int attack = state.countEffect(P, attack_from);
1104 
1105  if (defense == 1
1106  && (attack == 1 || (has_knight && attack == 0)))
1107  {
1108  const Piece gold = state.findAttackAt<GOLD>(alt(P), attack_from);
1109  if (gold.ptype() == GOLD)
1110  {
1111  // 取ると敵の金の守りが外れる
1112  const Square guarded
1114  if (state.pieceAt(guarded).isOnBoardByOwner(alt(P))
1115  && (state.countEffect(alt(P), guarded)
1116  <= state.countEffect(P, guarded)))
1117  ++attack;
1118  }
1119  // 取ると角道が開く
1120  const Square head = attack_from + DirectionPlayerTraits<U,P>::offset();
1121  const Piece head_piece = state.pieceOnBoard(head);
1122  if (head_piece.isOnBoardByOwner<PlayerTraits<P>::opponent>()) {
1123  if (state.hasEffectByPiece(head_piece, attack_from)
1124  && state.hasEffectByPtype<BISHOP>(P, head))
1125  ++attack;
1126  }
1127  }
1128 
1129  if (defense > attack)
1130  return;
1131 
1132  if (has_knight)
1133  {
1134  const Move drop(attack_from, KNIGHT, P);
1135  moves.push_back(drop);
1136  }
1137 
1138  if (defense < attack)
1139  {
1140  mask_t mask=state.effectSetAt(attack_from).getMask(PtypeFuns<KNIGHT>::indexNum);
1141  mask &= mask_t::makeDirect(PtypeFuns<KNIGHT>::indexMask);
1142  mask &= state.piecesOnBoard(P).getMask(PtypeFuns<KNIGHT>::indexNum);
1144  while (mask.any())
1145  {
1146  const int n = mask.takeOneBit();
1147  const Piece knight = state.pieceOf(n);
1148  if (knight.isPromoted())
1149  continue;
1150 
1151  const Move move(knight.square(), attack_from, KNIGHT, PTYPE_EMPTY, false, P);
1152  assert(state.isAlmostValidMove<false>(move));
1153  moves.push_back(move);
1154  }
1155  }
1156 }
1157 
1158 template <osl::Player P>
1160 attackKnightWithPawn(const NumEffectState& state, PieceMask pins,
1161  MoveVector& moves)
1162 {
1163  using namespace move_action;
1164 
1165  const bool has_pawn = state.hasPieceOnStand<PAWN>(P);
1166  for (int i = PtypeTraits<KNIGHT>::indexMin;
1167  i < PtypeTraits<KNIGHT>::indexLimit; ++i)
1168  {
1169  const Piece p = state.pieceOf(i);
1170  if (p.isOnBoard() && p.ptype() == KNIGHT && p.owner() == alt(P))
1171  {
1173  // ただの歩を許すかどうか...
1174  if (state.pieceAt(head).isEmpty())
1175  {
1176  const int defense = state.countEffect(alt(P), head, pins);
1177  const int offense = state.countEffect(P, head);
1178  if ((defense <= offense)
1179  && (! head.canPromote<P>())) // 成りはすでに生成されているはず
1180  {
1181  const Square origin = head+DirectionPlayerTraits<D,P>::offset();
1182  const Piece candidate = state.pieceAt(origin);
1183  if (candidate.ptype() == PAWN && candidate.owner() == P)
1184  {
1185  const Move move(origin, head, PAWN, PTYPE_EMPTY, false, P);
1186  moves.push_back(move);
1187  }
1188  }
1189  if (has_pawn && !state.template isPawnMaskSet<P>(head.x())
1190  && (defense <= offense+1))
1191  {
1192  const Move move(head, PAWN, P);
1193  moves.push_back(move);
1194  }
1195  }
1196  }
1197  }
1198 }
1199 
1200 template <osl::Player P>
1202 attackSilverWithPawn(const NumEffectState& state, PieceMask pins,
1203  MoveVector& moves)
1204 {
1205  using namespace move_action;
1206 
1207  const bool has_pawn = state.hasPieceOnStand<PAWN>(P);
1208  const bool has_lance = state.hasPieceOnStand<LANCE>(P);
1209  const bool has_knight = state.hasPieceOnStand<KNIGHT>(P);
1210  const bool has_silver = state.hasPieceOnStand<SILVER>(P);
1211  const Square opponent_king = state.kingSquare(alt(P));
1212  for (int i = PtypeTraits<SILVER>::indexMin;
1213  i < PtypeTraits<SILVER>::indexLimit; ++i)
1214  {
1215  const Piece p = state.pieceOf(i);
1217  continue;
1218 
1220  if (state.pieceAt(head).isEmpty())
1221  {
1222  const int defense = state.countEffect(alt(P), head, pins);
1223  int attack = state.countEffect(P, head)
1224  + state.hasEffectByPtype<BISHOP>(P, p.square());
1225  if (defense >= attack)
1226  attack += AdditionalEffect::count2(state, head, P);
1227  const bool near_king
1228  = Neighboring8Direct::hasEffect(state, p.ptypeO(), p.square(),
1229  opponent_king);
1230  if (defense > attack)
1231  {
1232  if (! near_king)
1233  continue;
1234  // TODO: ただの歩は利きがはずれる時に許す
1235  }
1236  if (! head.canPromote<P>()) // 成りはすでに生成されているはず
1237  {
1238  const Square origin = head+DirectionPlayerTraits<D,P>::offset();
1239  const Piece candidate = state.pieceAt(origin);
1240  if (candidate.ptype() == PAWN && candidate.owner() == P)
1241  {
1242  const Move move(origin, head, PAWN, PTYPE_EMPTY, false, P);
1243  moves.push_back(move);
1244  }
1245  }
1246  if (has_pawn && !state.template isPawnMaskSet<P>(head.x()))
1247  {
1248  const Move move(head, PAWN, P);
1249  moves.push_back(move);
1250  }
1251  if (! near_king)
1252  continue;
1253  if (defense <= attack)
1254  {
1255  if (has_lance)
1256  {
1257  const Move move(head, LANCE, P);
1258  moves.push_back(move);
1259  }
1260  if (has_silver)
1261  {
1262  const Move move(head, SILVER, P);
1263  moves.push_back(move);
1264  }
1265  }
1266  }
1267  // knight
1268  if (! state.pieceAt(head).isEdge())
1269  {
1270  const Square knight_l = head+DirectionPlayerTraits<DL,P>::offset();
1271  attackWithKnight(state, pins, knight_l, has_knight, moves);
1272  const Square knight_r = head+DirectionPlayerTraits<DR,P>::offset();
1273  attackWithKnight(state, pins, knight_r, has_knight, moves);
1274  }
1275  // ppawn
1276  const CArray<Square,2> side = {{
1279  }};
1280  BOOST_FOREACH(Square s, side) {
1281  if (! state.pieceAt(s).isEmpty())
1282  continue;
1283  if (state.countEffect(P, s)
1284  < state.countEffect(alt(P), s))
1285  continue;
1286  MoveVector candidate;
1287  move_generator::GenerateCapture::generate(P,state, s, candidate);
1288 
1289  BOOST_FOREACH(Move m, candidate) {
1290  if (m.isPromotion()
1291  || state.hasEffectByPiece(state.pieceOnBoard(m.from()),
1292  p.square()))
1293  continue;
1294  assert(! ShouldPromoteCut::canIgnoreMove<P>(m));
1295  moves.push_back(m);
1296  }
1297  }
1298  }
1299 }
1300 
1301 template <osl::Player P>
1303 kingWalk(const NumEffectState& state, MoveVector& moves)
1304 {
1305  const Piece my_king = state.kingPiece<P>();
1306  MoveVector all_moves;
1307  move_generator::GeneratePieceOnBoard::generate(P,state, my_king, all_moves);
1308 
1309  BOOST_FOREACH(Move m, all_moves)
1310  {
1311  if (state.hasEffectAt(alt(P), m.to()))
1312  continue;
1313  moves.push_back(m);
1314  }
1315 }
1316 
1317 template <osl::Player P>
1319 escapeKing(const NumEffectState& state, MoveVector& moves)
1320 {
1321  MoveVector all_moves;
1322  GenerateEscape<P>::generateCheap(state, state.template kingPiece<P>(), all_moves);
1323 
1324  BOOST_FOREACH(Move m, all_moves)
1325  {
1326  const Square to = m.to();
1327  if (m.isDrop())
1328  {
1329  // 焦点以外の中合は読まない
1330  if (! state.hasEffectAt<P>(to))
1331  {
1332  if (! ((m.ptype() == PAWN)
1333  && state.hasMultipleEffectAt(alt(P), to)))
1334  continue;
1335  }
1336  }
1337  else if (m.ptype() != KING)
1338  {
1339  // 焦点以外の中合は読まない
1340  if (! m.isCapture())
1341  {
1342  if (! state.hasMultipleEffectAt(P, to))
1343  {
1344  if (! ((m.ptype() == PAWN)
1345  && state.hasMultipleEffectAt(alt(P), to)))
1346  continue;
1347  }
1348  }
1349  }
1350  moves.push_back(m);
1351  }
1352 }
1353 
1354 template <osl::Player P>
1356 escapeKingInTakeBack(const NumEffectState& state, MoveVector& moves,
1357  bool check_by_lance)
1358 {
1359  bool has_safe_move = false;
1360  assert(moves.empty());
1361  MoveVector all_moves;
1362  GenerateEscape<P>::generate(state, state.template kingPiece<P>(), all_moves);
1363 
1364  Square last_drop_to = Square::STAND();
1365  MoveVector drops;
1366  BOOST_FOREACH(Move m, all_moves)
1367  {
1368  const Square to = m.to();
1369  if (m.ptype() == KING)
1370  {
1371  // TODO: 何か犠牲があるはず
1372  has_safe_move = true; // KFEND 流: 逃げる場所があれば良しとする
1373  continue;
1374  }
1375  if (m.isCapture())
1376  {
1377  moves.push_back(m);
1378  continue;
1379  }
1380  // 無駄合は読まない
1381  const int attack_count = state.countEffect(alt(P),to);
1382  const int defense_count
1383  = state.countEffect(P,to) + (m.isDrop() ? 1 : 0);
1384  if (defense_count <= attack_count)
1385  continue;
1386  if ((attack_count == 1) && (! check_by_lance))
1387  {
1388  // 大駒の攻撃に対して自分の利きが充分なら良いとする
1389  has_safe_move = true;
1390  continue;
1391  }
1392 
1393  // 攻方がこれ以上drop の王手をかけないので合駒は1手で詰の判定には充分
1394  // TODO: 一番安い駒にする
1395  if (to != last_drop_to)
1396  {
1397  last_drop_to = to;
1398  drops.push_back(m);
1399  }
1400  }
1401  if (! has_safe_move)
1402  moves.push_back(drops.begin(), drops.end());
1403  return has_safe_move;
1404 }
1405 
1406 template <osl::Player P>
1408 advanceBishop(const NumEffectState& state, MoveVector& moves)
1409 {
1410  for (int i = PtypeTraits<BISHOP>::indexMin;
1411  i < PtypeTraits<BISHOP>::indexLimit; ++i)
1412  {
1413  const Piece bishop = state.pieceOf(i);
1414  if (! bishop.isOnBoardByOwner<P>())
1415  continue;
1416  if (bishop.ptype() != BISHOP)
1417  continue;
1418  const Square from = bishop.square();
1419  if (state.hasEffectAt<PlayerTraits<P>::opponent>(from))
1420  continue; // escape は重複
1421  advanceBishop<UL>(state, from, moves);
1422  advanceBishop<UR>(state, from, moves);
1423  }
1424 }
1425 
1426 template <osl::Player P>
1427 template <osl::Direction DIR>
1429 advanceBishop(const NumEffectState& state,
1430  const Square from, MoveVector& moves)
1431 {
1433  for (Square to=from+offset;; to+=offset)
1434  {
1435  if (! state.pieceAt(to).isEmpty())
1436  break; // capture は重複.ついでに盤外判定
1437  if (to.canPromote<P>())
1438  break; // promote は重複
1439  if (state.hasEffectAt<PlayerTraits<P>::opponent>(to))
1440  continue;
1441  const Move move(from, to, BISHOP, PTYPE_EMPTY, false, P);
1442  assert(state.isAlmostValidMove<false>(move));
1443  moves.push_back(move);
1444  }
1445 }
1446 
1447 template <osl::Player P>
1448 template <class EvalT>
1450 escapeFromLastMove(const NumEffectState& state, Move last_move, MoveVector& moves)
1451 {
1452  if (! last_move.isNormal())
1453  return;
1454  if (last_move.ptype() != PAWN)
1455  {
1456  escapeFromLastMoveOtherThanPawn<EvalT>(state, last_move, moves);
1457  return;
1458  }
1459  const Square attack_from = last_move.to();
1460  const Square attack_to = attack_from+DirectionPlayerTraits<D,P>::offset();
1461  const Piece target = state.pieceOnBoard(attack_to);
1462  if (! target.isOnBoardByOwner<P>())
1463  return;
1464 
1465  using namespace move_action;
1466  MoveVector all_moves;
1467  GenerateEscape<P>::generate(state, target, all_moves);
1468 
1469  BOOST_FOREACH(Move m, all_moves)
1470  {
1471  assert(! m.isDrop());
1472  const Square to = m.to();
1473  // 逃げる時には利きの充分なところへ
1474  const int defense = state.countEffect(P, to);
1475  const int offense = state.countEffect(alt(P), to);
1476  if (offense > defense)
1477  continue;
1478  if (to == attack_from)
1479  {
1480  // 取る手は重複だけど歩の場合は深さによるので入れておく
1481  if (offense == defense)
1482  continue;
1483  assert(m.capturePtype() == PAWN);
1484  assert(! ShouldPromoteCut::canIgnoreMove<P>(m));
1485  moves.push_back(m);
1486  continue;
1487  }
1488  assert(m.from() == attack_to);
1489  if ((offense == defense)
1490  && (m.isCapture()))
1491  continue;
1492 
1493  // TODO: KnightCaptureDepth
1494  assert(! ShouldPromoteCut::canIgnoreMove<P>(m));
1495  if (! m.isPromotion())
1496  {
1497  moves.push_back(m);
1498  }
1499  }
1500 }
1501 
1502 template <osl::Player P>
1504 dropMajorPiece(const NumEffectState& state, MoveVector& moves)
1505 {
1507 }
1508 
1509 template <osl::Player P>
1511 dropMajorPiece3(const NumEffectState& state, MoveVector& moves, const HistoryTable& table)
1512 {
1513  FixedCapacityVector<Move, 27*2> all;
1515  FixedCapacityVector<std::pair<int,Move>, 27*2> selected;
1516  BOOST_FOREACH(Move m, all)
1517  selected.push_back(std::make_pair(table.value(m), m));
1518  std::sort(selected.begin(), selected.end());
1519  for (int i=0; i<std::min(3, (int)selected.size()); ++i)
1520  moves.push_back(selected[selected.size()-1-i].second);
1521 }
1522 
1523 #endif /* QUIESCENCEGENERATOR_TCC */
1524 // ;;; Local Variables:
1525 // ;;; mode:c++
1526 // ;;; c-basic-offset:2
1527 // ;;; End: