00001
00002
00003 #ifndef OSL_CHECKMATE_FIXED_DEPTH_SERCHER_TCC
00004 #define OSL_CHECKMATE_FIXED_DEPTH_SERCHER_TCC
00005 #include "osl/checkmate/fixedDepthSearcher.h"
00006 #include "osl/checkmate/immediateCheckmate.h"
00007 #include "osl/checkmate/proofPieces.h"
00008 #include "osl/checkmate/proofNumberTable.h"
00009 #include "osl/state/numEffectState.h"
00010 #include "osl/container/moveVector.h"
00011 #include "osl/move_action/store.h"
00012 #include "osl/move_action/count.h"
00013 #include "osl/move_generator/addEffectWithEffect.h"
00014 #include "osl/move_generator/escape_.h"
00015 #include "osl/move_classifier/check_.h"
00016 #include "osl/effect_util/effectUtil.h"
00017 #include "osl/apply_move/applyMove.h"
00018 #include "osl/neighboring8.h"
00019 #include "osl/stat/ratio.h"
00020 #include <boost/foreach.hpp>
00021
00022 namespace osl
00023 {
00024 namespace checkmate
00025 {
00026 template<Player P, bool SetPieces>
00027 struct FixedAttackHelper{
00028 FixedDepthSearcher &searcher;
00029 Move move;
00030 int depth;
00031 ProofDisproof& pdp;
00032 PieceStand& pieces;
00033 FixedAttackHelper(FixedDepthSearcher &s,int d,ProofDisproof& p,
00034 PieceStand& pi)
00035 : searcher(s), depth(d), pdp(p), pieces(pi)
00036 {
00037 }
00038 void operator()(Position)
00039 {
00040 assert(move.isNormal());
00041 pdp=searcher.defense<P,SetPieces>(move,depth-1,pieces);
00042 }
00043 };
00047 template<Player P, bool SetPieces, bool MayUnsafe=false>
00048 struct FixedDefenseHelper{
00049 FixedDepthSearcher &searcher;
00050 int depth;
00051 ProofDisproof& pdp;
00052 PieceStand& pieces;
00053 Move best_move;
00054 FixedDefenseHelper(FixedDepthSearcher &s,int d,ProofDisproof& p,
00055 PieceStand& pi)
00056 : searcher(s), depth(d), pdp(p), pieces(pi)
00057 {
00058 }
00059 void operator()(Position)
00060 {
00061 if (MayUnsafe)
00062 pdp=searcher.attackMayUnsafe<P,SetPieces,false>(depth-1, best_move, pieces);
00063 else
00064 pdp=searcher.attack<P,SetPieces,false>(depth-1, best_move, pieces);
00065 }
00066 };
00067 }
00068 }
00069
00070 template <osl::Player P, bool SetPieces, bool HasGuide>
00071 const osl::checkmate::ProofDisproof
00072 osl::checkmate::FixedDepthSearcher::
00073 attackMayUnsafe(int depth, Move& best_move, PieceStand& proof_pieces)
00074 {
00075 assert(state->getTurn() == P);
00076 const Position target_king
00077 = state->template getKingPosition<PlayerTraits<P>::opponent>();
00078 if (state->hasEffectBy<P>(target_king))
00079 return ProofDisproof::NoEscape();
00080 return attack<P,SetPieces,HasGuide>(depth, best_move, proof_pieces);
00081 }
00082
00083 template <osl::Player P, bool SetPieces, bool HasGuide>
00084 const osl::checkmate::ProofDisproof
00085 osl::checkmate::FixedDepthSearcher::
00086 attack(int depth, Move& best_move, PieceStand& proof_pieces)
00087 {
00088 assert(state->getTurn() == P);
00089 assert ((! HasGuide)
00090 || (state->isAlmostValidMove(best_move)
00091 && move_classifier::
00092 Check<P>::isMember(*state, best_move.ptype(), best_move.from(),
00093 best_move.to())));
00094 addCount();
00095 const Position target_king
00096 = state->template getKingPosition<PlayerTraits<P>::opponent>();
00097 assert(! state->hasEffectBy<P>(target_king));
00098 const King8Info info(state->Iking8Info(alt(P)));
00099 if ((! state->inCheck())
00100 && ImmediateCheckmate::hasCheckmateMove<P>(*state, info, target_king,
00101 best_move))
00102 {
00103 if (SetPieces)
00104 {
00105 proof_pieces = PieceStand();
00106 if (best_move.isDrop())
00107 proof_pieces.add(best_move.ptype());
00108 }
00109 return ProofDisproof::Checkmate();
00110 }
00111 if (depth <= 0)
00112 {
00113 const King8Info info_modified
00114 = Edge_Table.resetEdgeFromLiberty(alt(P), target_king, info);
00115 return Proof_Number_Table.attackEstimation(*state, P, info_modified, target_king);
00116 }
00117
00118 ProofDisproof pdp;
00119 typedef FixedAttackHelper<P,SetPieces> helper_t;
00120 helper_t helper(*this,depth,pdp,proof_pieces);
00121 int minProof = ProofDisproof::PROOF_MAX;
00122 int sumDisproof=0;
00123 if (HasGuide)
00124 {
00125 helper.move=best_move;
00126 ApplyMove<P>::doUndoMove(*state,best_move,helper);
00127 if (pdp.isCheckmateSuccess())
00128 {
00129 if (SetPieces)
00130 proof_pieces = ProofPieces::attack(proof_pieces, best_move, stand(P));
00131 return ProofDisproof::Checkmate();
00132 }
00133 minProof = pdp.proof();
00134 sumDisproof += pdp.disproof();
00135 }
00136
00137 const Position targetKing
00138 = state->template getKingPosition<PlayerTraits<P>::opponent>();
00139 MoveVector moves;
00140 bool has_pawn_checkmate=false;
00141 move_generator::GenerateAddEffectWithEffect::generate<true>
00142 (P,*state,targetKing,moves,has_pawn_checkmate);
00143
00144 if (moves.size()==0){
00145 if(has_pawn_checkmate)
00146 return ProofDisproof::PawnCheckmate();
00147 else
00148 return ProofDisproof::NoCheckmate();
00149 }
00150 if(has_pawn_checkmate)
00151 minProof=std::min(minProof,(int)ProofDisproof::PAWN_CHECK_MATE_PROOF);
00152 BOOST_FOREACH(Move move, moves) {
00153 if (HasGuide && move == best_move)
00154 continue;
00155 helper.move=move;
00156 ApplyMove<P>::doUndoMove(*state,move,helper);
00157 int proof=pdp.proof();
00158 if (proof<minProof){
00159 if (proof==0){
00160 best_move=move;
00161 if (SetPieces)
00162 {
00163 proof_pieces = ProofPieces::attack(proof_pieces, best_move, stand(P));
00164 }
00165 return ProofDisproof::Checkmate();
00166 }
00167 minProof=proof;
00168 }
00169 sumDisproof+=pdp.disproof();
00170 }
00171
00172 return ProofDisproof(minProof,sumDisproof);
00173 }
00174
00175 template <osl::Player P, bool SetPieces>
00176 inline
00177 const osl::checkmate::ProofDisproof
00178 osl::checkmate::FixedDepthSearcher::
00179 defenseEstimation(Move last_move, PieceStand& proof_pieces,
00180 Piece attacker_piece, Position target_position) const
00181 {
00182 assert(state->getTurn() == alt(P));
00183 const Player Opponent = PlayerTraits<P>::opponent;
00184 int count=King8Info(state->Iking8Info(Opponent)).libertyCount();
00185
00186 if (attacker_piece.isEmpty())
00187 {
00188 if (count>0){
00189 return ProofDisproof(count,1);
00190 }
00191 return ProofDisproof::NoEscape();
00192 }
00193 const Position attack_from=attacker_piece.position();
00194 count += state->countEffect(alt(P), attack_from);
00195 if (Neighboring8::isNeighboring8(attack_from, target_position))
00196 --count;
00197 const EffectContent effect
00198 = Ptype_Table.getEffect(attacker_piece.ptypeO(),
00199 attack_from, target_position);
00200 if (! effect.hasUnblockableEffect())
00201 {
00202
00203
00204 ++count;
00205 }
00206
00207 if (count==0){
00208 if (last_move.isValid() && last_move.isDrop() && last_move.ptype()==PAWN)
00209 return ProofDisproof::PawnCheckmate();
00210 if (SetPieces)
00211 {
00212 proof_pieces = ProofPieces::leaf(*state, P, stand(P));
00213 }
00214 return ProofDisproof::NoEscape();
00215 }
00216 return ProofDisproof(count, 1);
00217 }
00218
00219 template <osl::Player Defense>
00220 void osl::checkmate::FixedDepthSearcher::
00221 generateBlockingWhenLiberty0(Piece defense_king, Position attack_from,
00222 MoveVector& moves) const
00223 {
00224 assert(state->getKingPiece(Defense) == defense_king);
00225 using namespace move_generator;
00226 using namespace move_action;
00227 MoveVector all_moves;
00228 {
00229 Store store(all_moves);
00230 Escape<Store>::
00231 generateBlockingKing<Defense,false>(*state, defense_king, attack_from,store);
00232 }
00233
00234 BOOST_FOREACH(Move move, all_moves)
00235 {
00236 if (move.isDrop())
00237 {
00238 if (! state->hasEffectBy<Defense>(move.to()))
00239 continue;
00240 }
00241 else
00242 {
00243
00244 if (! Neighboring8::isNeighboring8(move.from(), defense_king.position()))
00245 {
00246 if (! state->hasMultipleEffectBy(Defense, move.to()))
00247 continue;
00248 }
00249 }
00250 moves.push_back(move);
00251 }
00252 }
00253
00254 template <osl::Player Defense> inline
00255 int osl::checkmate::FixedDepthSearcher::
00256 blockEstimation(Position , Position ) const
00257 {
00258
00259 return 1;
00260 }
00261
00262 template <osl::Player P, bool SetPieces>
00263 const osl::checkmate::ProofDisproof
00264 osl::checkmate::FixedDepthSearcher::
00265 defense(Move last_move, int depth, PieceStand& proof_pieces)
00266 {
00267 assert(state->getTurn() == alt(P));
00268 addCount();
00269 const Player Defense = PlayerTraits<P>::opponent;
00270 const Position attackerKing
00271 = state->template getKingPosition<P>();
00275 if (attackerKing.isOnBoard() && state->hasEffectBy<Defense>(attackerKing))
00276 return ProofDisproof::NoCheckmate();
00277 const Piece target_king
00278 = state->template getKingPiece<Defense>();
00279 const Position target_position = target_king.position();
00280 assert(state->hasEffectBy<P>(target_position));
00281 Piece attacker_piece;
00282 state->template findCheckPiece<Defense>(attacker_piece);
00283 if (depth <= 0)
00284 {
00285 return defenseEstimation<P, SetPieces>
00286 (last_move, proof_pieces, attacker_piece, target_position);
00287 }
00288
00289 assert(depth > 0);
00290 MoveVector moves;
00291 bool blockable_check = false;
00292 int nonblock_moves;
00293 {
00294 using namespace move_generator;
00295 using namespace move_action;
00296 if (attacker_piece.isEmpty()) {
00297 move_action::Store store(moves);
00298 Escape<Store>::template
00299 generateEscape<Defense,KING>(*state,target_king,store);
00300 nonblock_moves = moves.size();
00301 }
00302 else {
00303 const Position attack_from=attacker_piece.position();
00304 {
00305 move_action::Store store(moves);
00306 Escape<Store>::
00307 generateCaptureKing<Defense>(*state, target_king, attack_from, store);
00308 }
00309 const int num_captures = moves.size();
00310 {
00311 move_action::Store store(moves);
00312 Escape<Store>::template
00313 generateEscape<Defense,KING>(*state, target_king, store);
00314 }
00315 nonblock_moves = moves.size();
00316 blockable_check =
00317 ! effect_util::UnblockableCheck::isMember(alt(P), *state);
00318 if ((depth <= 1) && num_captures && (nonblock_moves > 2))
00319 {
00320 if (nonblock_moves > 3)
00321 {
00322 const int block_estimate = blockable_check
00323 ? blockEstimation<Defense>(attack_from, target_position)
00324 : 0;
00325 return ProofDisproof(nonblock_moves + block_estimate, 1);
00326 }
00327 }
00328 if (moves.empty())
00329 generateBlockingWhenLiberty0<Defense>(target_king, attack_from, moves);
00330 }
00331 }
00332 const size_t initial_moves = moves.size();
00333 if (moves.empty() && !blockable_check) {
00334 if (last_move.isValid() && last_move.isDrop() && last_move.ptype()==PAWN)
00335 return ProofDisproof::PawnCheckmate();
00336 if (SetPieces)
00337 {
00338 proof_pieces = ProofPieces::leaf(*state, P, stand(P));
00339 }
00340 return ProofDisproof::NoEscape();
00341 }
00342 const bool cut_candidate = (depth <= 1)
00343 && (nonblock_moves - (state->hasPieceOnStand<GOLD>(P)
00344 || state->hasPieceOnStand<SILVER>(P)) > 4);
00345 if (cut_candidate)
00346 return ProofDisproof(nonblock_moves, 1);
00347
00348 typedef FixedDefenseHelper<P,SetPieces> helper_t;
00349 if (SetPieces)
00350 proof_pieces = PieceStand();
00351 PieceStand child_proof;
00352 ProofDisproof pdp;
00353 helper_t helper(*this, depth, pdp, child_proof);
00354 int minDisproof = ProofDisproof::DISPROOF_MAX;
00355 int sumProof = 0;
00356 size_t i=0;
00357 start_examine:
00358 for (;i<moves.size();i++){
00359 ApplyMove<PlayerTraits<P>::opponent>::doUndoMove(*state,moves[i],helper);
00360 const int disproof=pdp.disproof();
00361 if (disproof<minDisproof){
00362 if (disproof==0)
00363 {
00364 return pdp;
00365 }
00366 minDisproof=disproof;
00367 }
00368 sumProof+=pdp.proof();
00369 if (sumProof == 0)
00370 {
00371 if (SetPieces)
00372 proof_pieces = proof_pieces.max(child_proof);
00373 }
00374 else
00375 {
00376 if (i+1 < moves.size())
00377 {
00378 minDisproof = 1;
00379 if ((int)i < nonblock_moves)
00380 sumProof += nonblock_moves - (i+1);
00381 if (blockable_check)
00382 ++sumProof;
00383 }
00384 return ProofDisproof(sumProof,minDisproof);
00385 }
00386 }
00387 if ((sumProof == 0) && blockable_check
00388 && (moves.size() == initial_moves))
00389 {
00390 using namespace move_generator;
00391 using namespace move_action;
00392 const Position attack_from=attacker_piece.position();
00393 {
00394 move_action::Store store(moves);
00395 Escape<Store>::
00396 generateBlockingKing<Defense,false>(*state, target_king, attack_from,store);
00397 }
00398 if ((int)moves.size() > nonblock_moves)
00399 goto start_examine;
00400 if (moves.empty()) {
00401 assert(! (last_move.isValid() && last_move.isDrop() && last_move.ptype()==PAWN));
00402 if (SetPieces)
00403 proof_pieces = ProofPieces::leaf(*state, P, stand(P));
00404 return ProofDisproof::NoEscape();
00405 }
00406 }
00407
00408 if (SetPieces && (sumProof == 0) && blockable_check)
00409 {
00410 ProofPiecesUtil::addMonopolizedPieces(*state, P, stand(P), proof_pieces);
00411 }
00412
00413
00414 return ProofDisproof(sumProof,minDisproof);
00415 }
00416
00417 template <osl::Player P>
00418 const osl::checkmate::ProofDisproof
00419 osl::checkmate::FixedDepthSearcher::
00420 hasEscapeByMove(Move next_move, int depth, Move& check_move,
00421 PieceStand& proof_pieces)
00422 {
00423 typedef FixedDefenseHelper<P,true,true> helper_t;
00424 proof_pieces = PieceStand();
00425 ProofDisproof pdp;
00426 helper_t helper(*this, depth+1, pdp, proof_pieces);
00427 ApplyMove<PlayerTraits<P>::opponent>::doUndoMove(*state,next_move,helper);
00428 check_move = helper.best_move;
00429 return pdp;
00430 }
00431
00432 template <osl::Player P>
00433 const osl::checkmate::ProofDisproof
00434 osl::checkmate::FixedDepthSearcher::
00435 hasEscapeByMove(Move next_move, int depth)
00436 {
00437 typedef FixedDefenseHelper<P,false,true> helper_t;
00438 PieceStand proof_pieces;
00439 ProofDisproof pdp;
00440 helper_t helper(*this, depth+1, pdp, proof_pieces);
00441 ApplyMove<PlayerTraits<P>::opponent>::doUndoMove(*state,next_move,helper);
00442 return pdp;
00443 }
00444
00445 template <osl::Player P>
00446 const osl::checkmate::ProofDisproof
00447 osl::checkmate::FixedDepthSearcher::
00448 hasCheckmateWithGuide(int depth, Move& guide, PieceStand& proof_pieces)
00449 {
00450 assert(guide.isNormal());
00451 if (! guide.isDrop())
00452 {
00453 const Piece p=state->getPieceOnBoard(guide.to());
00454 if (!p.isPtype<KING>())
00455 guide=guide.newCapture(p);
00456 }
00457 if (state->template isAlmostValidMove<false>(guide)
00458 && move_classifier::Check<P>
00459 ::isMember(*state, guide.ptype(), guide.from(), guide.to()))
00460 return attack<P,true,true>(depth, guide, proof_pieces);
00461 return attack<P,true,false>(depth, guide, proof_pieces);
00462 }
00463
00464 #endif
00465
00466
00467
00468