00001
00002
00003 #include "osl/ntesuki/oracleProverLight.h"
00004 #include "osl/ntesuki/ntesukiRecord.h"
00005 #include "osl/ntesuki/ntesukiMoveGenerator.h"
00006 #include "osl/checkmate/fixedDepthSearcher.h"
00007 #include "osl/checkmate/fixedDepthSearcher.tcc"
00008 #include "osl/move_classifier/safeMove.h"
00009 #include "osl/apply_move/applyMoveWithPath.h"
00010 #include "osl/checkmate/immediateCheckmate.h"
00011 #include "osl/effect_util/effectUtil.h"
00012 #ifdef NDEBUG
00013 # include "osl/ntesuki/ntesukiMove.tcc"
00014 # include "osl/ntesuki/ntesukiRecord.tcc"
00015
00016 #endif
00017
00018 using namespace osl;
00019 using namespace osl::ntesuki;
00020
00021
00022
00023 template <class Searcher, Player P>
00024 class
00025 OracleProverLight::
00026 AttackHelper
00027 {
00028 Searcher* searcher;
00029 const NtesukiRecord *record_orig;
00030 unsigned int pass_left;
00031 public:
00032 bool result;
00033
00034 AttackHelper(Searcher* searcher,
00035 const NtesukiRecord* record_orig,
00036 unsigned int pass_left)
00037 : searcher(searcher), record_orig(record_orig), pass_left(pass_left)
00038 {}
00039
00040 void operator()(Position p)
00041 {
00042 const Player O = PlayerTraits<P>::opponent;
00043 result = (*searcher).template defense<O>(record_orig, pass_left);
00044 }
00045 };
00046
00047 template <class Searcher, Player P>
00048 class OracleProverLight::
00049 DefenseHelper
00050 {
00051 Searcher* searcher;
00052 const NtesukiRecord *record_orig;
00053 unsigned int pass_left;
00054
00055 public:
00056 bool result;
00057
00058 DefenseHelper(Searcher* searcher,
00059 const NtesukiRecord* record_orig,
00060 unsigned int pass_left)
00061 : searcher(searcher), record_orig(record_orig), pass_left(pass_left)
00062 {}
00063
00064 void operator()(Position p)
00065 {
00066 const Player O = PlayerTraits<P>::opponent;
00067 result = (*searcher).template attack<O>(record_orig, pass_left);
00068 }
00069 };
00070
00071
00072
00073
00074
00075 template <Player P>
00076 static bool
00077 is_safe_move(const osl::ntesuki::OracleProverLight::state_t state,
00078 const osl::Move& m,
00079 int pass_left)
00080 {
00081 if (!m.isValid()) return false;
00082 if (!state.isValidMove(m, false)) return false;
00083 if (m.isDrop()) return true;
00084 return move_classifier::SafeMove<P>::isMember(state, m.ptype(), m.from(), m.to());
00085 }
00086
00087
00088 template <Player P>
00089 static osl::Move
00090 adjustMove(const osl::ntesuki::OracleProverLight::state_t state,
00091 osl::Move candidate)
00092 {
00093 if (! candidate.isDrop())
00094 {
00095 const osl::Ptype existing = state.getPieceOnBoard(candidate.to()).ptype();
00096 candidate.setCapturePtype(existing);
00097 }
00098 return candidate;
00099 }
00100
00101
00102
00103
00104
00105
00106 template <Player P>
00107 bool
00108 OracleProverLight::
00109 attack(const NtesukiRecord* record_orig,
00110 const unsigned int pass_left)
00111 {
00112 const Player attacker = P;
00113 ntesuki_assert(P == state.getTurn());
00114
00115 if (!record_orig ||
00116 !record_orig->getValue<attacker>(pass_left)
00117 .isCheckmateSuccess() ||
00118 !record_orig->getBestMove<attacker>(pass_left).isValid())
00119 {
00120 return false;
00121 }
00122
00123 Move check_move;
00124 FixedDepthSearcher fixed_searcher(state);
00125
00126 if (!EffectUtil::isKingInCheck(P, state) &&
00127 fixed_searcher.hasCheckmateMove<P>(NtesukiRecord::fixed_search_depth,
00128 check_move).isCheckmateSuccess())
00129 {
00130
00131 return true;
00132 }
00133
00134
00135 const NtesukiMove best_move_orig = record_orig->getBestMove<attacker>(pass_left);
00136 if (best_move_orig.isImmediateCheckmate())
00137 {
00138 return false;
00139 }
00140
00141
00142 if ((pass_left > 0) &&
00143 record_orig->getValue<attacker>(pass_left - 1).isCheckmateSuccess())
00144 {
00145 return attack<P>(record_orig, pass_left - 1);
00146 }
00147
00148 const Move move = adjustMove<P>(state, best_move_orig.getMove());
00149
00150
00151 if (!is_safe_move<P>(state, move, pass_left))
00152 {
00153 return false;
00154 }
00155 const bool move_is_check = (move_classifier::PlayerMoveAdaptor<move_classifier::Check>::
00156 isMember(state, move));
00157
00158 if(0 == pass_left && !move_is_check)
00159 {
00160 return false;
00161 }
00162
00163
00164 if (best_move_orig.isCheck() != move_is_check)
00165 {
00166 return false;
00167 }
00168
00169
00170 const NtesukiRecord* record_child_orig = table.findWithMoveConst(record_orig,
00171 best_move_orig);
00172 if (!record_child_orig)
00173 {
00174
00175 return false;
00176 }
00177
00178
00179 AttackHelper<OracleProverLight, P> helper(this,
00180 record_child_orig,
00181 pass_left);
00182 TRY_DFPN;
00183 ApplyMoveWithPath<P>::doUndoMove(state, path, move, helper);
00184 CATCH_DFPN;
00185
00186 return helper.result;
00187 }
00188
00189
00190 template <Player P>
00191 bool OracleProverLight::
00192 defense(const NtesukiRecord* record_orig,
00193 const unsigned int pass_left)
00194 {
00195 const Player attacker = PlayerTraits<P>::opponent;
00196
00197 ntesuki_assert(P == state.getTurn());
00198 if (!record_orig ||
00199 !record_orig->getValue<attacker>(pass_left)
00200 .isCheckmateSuccess())
00201 {
00202 return false;
00203 }
00204
00205
00206 if (EffectUtil::isKingInCheck(attacker, state))
00207 {
00208 return false;
00209 }
00210
00211
00212 if ((pass_left == 0) &&
00213 !EffectUtil::isKingInCheck(P, state))
00214 {
00215 return false;
00216 }
00217
00218
00219 if (pass_left > 0 &&
00220 record_orig->getValue<attacker>(pass_left - 1).isCheckmateSuccess())
00221 {
00222 return defense<P>(record_orig, pass_left - 1);
00223 }
00224
00225
00226 NtesukiMoveList moves;
00227 mg->generateSlow(P, state, moves);
00228 if (moves.empty()) return true;
00229
00230
00231 for (NtesukiMoveList::iterator move_it = moves.begin();
00232 move_it != moves.end(); move_it++)
00233 {
00234 NtesukiMove& move = *move_it;
00235 if (isscheme != NtesukiRecord::normal_is &&
00236 isscheme != NtesukiRecord::delay_is &&
00237 move.isCheck() && pass_left > 0) continue;
00238
00239 ntesuki_assert(move.isPass() || move.isNormal());
00240
00241 const NtesukiRecord *record_child_orig = table.findWithMoveConst(record_orig, move);
00242 if (!record_child_orig ||
00243 !record_child_orig->getValue<attacker>(pass_left).isCheckmateSuccess())
00244 {
00245 return false;
00246 }
00247
00248 int pass_left_child = pass_left;
00249 if (move.isPass()) --pass_left_child;
00250 DefenseHelper<OracleProverLight, P> helper(this, record_child_orig, pass_left_child);
00251 TRY_DFPN;
00252 ApplyMoveWithPath<P>::doUndoMoveOrPass(state, path, move.getMove(), helper);
00253 CATCH_DFPN;
00254 if (false == helper.result) return false;
00255 }
00256
00257 return true;
00258 }
00259
00260
00261
00262 template <Player P>
00263 bool
00264 OracleProverLight::
00265 startFromAttack(NtesukiRecord* record,
00266 const NtesukiRecord* record_orig,
00267 const unsigned int pass_left)
00268 {
00269 const Player attacker = P;
00270 if (!record || !record_orig) return false;
00271
00272 if (!record->getPieceStand<attacker>().isSuperiorOrEqualTo
00273 (record_orig->getPDPieces<attacker>(pass_left)))
00274 {
00275 return false;
00276 }
00277
00278 ntesuki_assert(record_orig->getValue<attacker>(pass_left).isCheckmateSuccess());
00279
00280 if (attack<P>(record_orig, pass_left))
00281 {
00282 #ifndef NDEBUG
00283 const NtesukiMove m = (record_orig->getBestMove<attacker>(pass_left));
00284 ntesuki_assert(m.isValid());
00285 ntesuki_assert(!m.isImmediateCheckmate());
00286 #endif
00287
00288 TRY_DFPN;
00289 const PieceStand ps = record->getPieceStand<attacker>();
00290 record->setResult<attacker>(pass_left, ProofDisproof::Checkmate(),
00291 record_orig->getBestMove<attacker>(pass_left),
00292 true, &ps);
00293 CATCH_DFPN;
00294 return true;
00295 }
00296 return false;
00297 }
00298
00299 template <Player P>
00300 bool
00301 OracleProverLight::
00302 startFromDefense(NtesukiRecord* record,
00303 const NtesukiRecord* record_orig,
00304 const unsigned int pass_left)
00305 {
00306 const Player attacker = PlayerTraits<P>::opponent;
00307 if (!record || !record_orig) return false;
00308
00309 if (!record->getPieceStand<attacker>().isSuperiorOrEqualTo
00310 (record_orig->getPDPieces<attacker>(pass_left)))
00311 {
00312 return false;
00313 }
00314
00315 ntesuki_assert(record_orig->getValue<attacker>(pass_left).isCheckmateSuccess());
00316
00317 if (defense<P>(record_orig, pass_left))
00318 {
00319 TRY_DFPN;
00320 const PieceStand ps = record->getPieceStand<attacker>();
00321 record->setResult<attacker>(pass_left, ProofDisproof::Checkmate(),
00322 record_orig->getBestMove<attacker>(pass_left),
00323 true, &ps);
00324 CATCH_DFPN;
00325 return true;
00326 }
00327 return false;
00328 }
00329
00330
00331
00332
00333