00001
00002
00003 #ifndef _DISPROOFORACLE_H
00004 #define _DISPROOFORACLE_H
00005
00006 #include "osl/checkmate/checkHashRecord.h"
00007 #include "osl/checkmate/checkAssert.h"
00008 #include "osl/pathEncoding.h"
00009
00010 #include <cstddef>
00011 namespace osl
00012 {
00013 namespace checkmate
00014 {
00015 template <Player Attacker>
00016 struct DisproofOracleAttack;
00017
00022 template <Player Attacker>
00023 struct DisproofOracleDefense
00024 {
00025 const CheckHashRecord *guide;
00026 const CheckHashRecord *next_guide;
00027 PathEncoding path;
00028 Move best_move;
00029 DisproofOracleDefense(CheckHashRecord *g, const PathEncoding& p)
00030 : guide(g), next_guide(0), path(p), best_move(Move::INVALID())
00031 {
00032 if (guide)
00033 {
00034 if (guide->hasBestMove()
00035 && guide->getBestMove()->record
00036 && guide->getBestMove()->record->proofDisproof().isCheckmateFail())
00037 {
00038 next_guide = guide->getBestMove()->record;
00039 best_move = guide->getBestMove()->move;
00040 if (! guide->proofDisproof().isCheckmateFail())
00041 {
00042 g->setDisproofPiecesDefense(alt(Attacker));
00043 g->propagateNoCheckmate<Attacker>(g->getBestMove()->record->proofDisproof());
00044 }
00045 }
00046 else
00047 {
00048 if (const TwinEntry *loop = guide->findLoopInList(path))
00049 {
00050 next_guide = loop->move.record;
00051 best_move = loop->move.move;
00052 }
00053 else
00054 {
00055 setValidTwins();
00056 }
00057 }
00058 check_assert((guide->proofDisproof().isCheckmateFail()
00059 && guide->hasBestMove()
00060 && (guide->getBestMove()->move.player()==alt(Attacker)))
00061 || (guide->findLoopInList(path))
00062 || (guide->proofDisproof() == ProofDisproof::NoEscape())
00063 || (guide->dump(), 0));
00064 }
00065 }
00066 explicit DisproofOracleDefense(CheckHashRecord *g)
00067 : guide(g), next_guide(0), path(alt(Attacker)), best_move(Move::INVALID())
00068 {
00069 if (guide)
00070 {
00071 if (guide->hasBestMove() && guide->getBestMove()->record)
00072 {
00073 if (guide->getBestMove()->record->proofDisproof().isCheckmateFail())
00074 {
00075 next_guide = guide->getBestMove()->record;
00076 best_move = guide->getBestMove()->move;
00077 if (! guide->proofDisproof().isCheckmateFail())
00078 {
00079 g->setDisproofPiecesDefense(alt(Attacker));
00080 g->propagateNoCheckmate<Attacker>(g->getBestMove()->record->proofDisproof());
00081 }
00082 }
00083 else if (! guide->bestMove->record->twins.empty())
00084 {
00085 next_guide = guide->getBestMove()->record;
00086 best_move = guide->getBestMove()->move;
00087 path = guide->bestMove->record->twins.begin()->path;
00088 path.popMove(guide->bestMove->move);
00089 }
00090 }
00091 if ((! next_guide) && (! guide->twins.empty()))
00092 {
00093 setValidTwins();
00094 }
00095 check_assert((! guide->hasBestMove())
00096 || guide->getBestMove()->move.player()==alt(Attacker));
00097 check_assert((guide->hasBestMove()
00098 && (guide->getBestMove()->record->proofDisproof().isCheckmateFail()
00099 || (guide->getBestMove()->findLoopInList(path))))
00100 || (guide->findLoopInList(path))
00101 || (guide->proofDisproof() == ProofDisproof::NoEscape())
00102 || (guide->dump(), 0));
00103 }
00104 }
00105 private:
00106 void setValidTwins()
00107 {
00108 for (TwinList::const_iterator p=guide->twins.begin();
00109 p!=guide->twins.end(); ++p)
00110 {
00111 if (best_move.isInvalid())
00112 {
00113 assert(! best_move.isPass());
00114 path = p->path;
00115 best_move = p->move.move;
00116 next_guide = p->move.record;
00117 if (next_guide)
00118 break;
00119 }
00120 }
00121 }
00122 public:
00123 Move oracle()
00124 {
00125 check_assert(guide && next_guide);
00126 return best_move;
00127 }
00128 inline DisproofOracleAttack<Attacker> expandOracle() const;
00129 bool isValid() const { return guide; }
00130 };
00131
00136 template <Player Attacker>
00137 struct DisproofOracleAttack
00138 {
00139 const CheckHashRecord *guide;
00140 PathEncoding path;
00141 DisproofOracleAttack(const CheckHashRecord *g, const PathEncoding& p)
00142 : guide(g), path(p)
00143 {
00144 if (guide && (! guide->proofDisproof().isCheckmateFail())
00145 && (! guide->findLoopInList(path)))
00146 {
00147 if (! guide->twins.empty())
00148 path = guide->twins.begin()->path;
00149 else
00150 guide = 0;
00151
00152
00153 }
00154 check_assert((!guide)
00155 || guide->proofDisproof().isCheckmateFail()
00156 || guide->findLoopInList(path)
00157 || (g->dump(), 0));
00158 }
00159 DisproofOracleAttack(const CheckHashRecord *g)
00160 : guide(g), path(Attacker)
00161 {
00162 if (guide && (! guide->proofDisproof().isCheckmateFail())
00163 && (! guide->twins.empty()))
00164 {
00165 path = guide->twins.begin()->path;
00166 }
00167 check_assert((!guide)
00168 || guide->proofDisproof().isCheckmateFail()
00169 || guide->findLoopInList(path)
00170 || (g->dump(), 0));
00171 }
00172 bool invalidNextOracle(const CheckMove& move) const
00173 {
00174 if (! move.record)
00175 return true;
00176 const ProofDisproof& pdp = move.record->proofDisproof();
00177 return (! pdp.isCheckmateFail())
00178 && (! (guide->bestResultInSolved == ProofDisproof::PawnCheckmate()
00179 && (pdp == ProofDisproof::NoEscape())))
00180 && move.record->twins.empty();
00181 }
00182 DisproofOracleDefense<Attacker> makeOracle(const CheckMove& move) const
00183 {
00184 check_assert(move.record);
00185 #ifndef NDEBUG
00186 const ProofDisproof& pdp = move.record->proofDisproof();
00187 #endif
00188 const PathEncoding new_path(path, move.move);
00189 check_assert((! move.record->twins.empty())
00190 || (pdp.isCheckmateFail() && move.record->hasBestMove())
00191 || (move.record->proofDisproof() == ProofDisproof::NoEscape())
00192 || (guide->dump(), 0));
00193 return DisproofOracleDefense<Attacker>(move.record, new_path);
00194 }
00195
00197 DisproofOracleDefense<Attacker> expandOracle(Move attack) const
00198 {
00199 check_assert(guide);
00200 check_assert(guide->proofDisproof().isCheckmateFail()
00201 || guide->findLoopInList(path));
00202 check_assert(attack.player() == Attacker);
00203 const CheckMoveList& moves
00204 = (guide->finalByDominance()
00205 ? guide->finalByDominance()->moves
00206 : guide->moves);
00207 for (CheckMoveList::const_iterator p=moves.begin();
00208 p!=moves.end(); ++p)
00209 {
00210 if (p->move == attack)
00211 {
00212 if (invalidNextOracle(*p))
00213 goto not_found;
00214 return makeOracle(*p);
00215 }
00216 }
00217 {
00218
00219 const Position from = attack.from();
00220 const Position to = attack.to();
00221 const Ptype ptype = attack.ptype();
00222 if (from.isPieceStand())
00223 {
00224
00225 for (CheckMoveList::const_iterator p=moves.begin();
00226 p!=moves.end(); ++p)
00227 {
00228 if (! p->move.isDrop())
00229 continue;
00230 if (p->move.to() == to)
00231 {
00232 if (! invalidNextOracle(*p))
00233 return makeOracle(*p);
00234 }
00235 else if (p->move.ptype() == ptype)
00236 {
00237
00238
00239 if (! invalidNextOracle(*p))
00240 return makeOracle(*p);
00241 }
00242 }
00243 }
00244 else
00245 {
00246
00247 const CheckMove *ignorePtype = 0;
00248 for (CheckMoveList::const_iterator p=moves.begin();
00249 p!=moves.end(); ++p)
00250 {
00251 if ((p->move.to() != to) || invalidNextOracle(*p))
00252 continue;
00253 if (unpromote(p->move.ptype()) == unpromote(ptype))
00254 return makeOracle(*p);
00255 ignorePtype = &*p;
00256 }
00257 if (ignorePtype)
00258 return makeOracle(*ignorePtype);
00259 }
00260 }
00261 not_found:
00262 return DisproofOracleDefense<Attacker>(0,PathEncoding());
00263 }
00264 bool isValid() const { return guide; }
00265 };
00266
00267 template <Player Attacker>
00268 inline DisproofOracleAttack<Attacker>
00269 DisproofOracleDefense<Attacker>::expandOracle() const
00270 {
00271 PathEncoding new_path = path;
00272 new_path.pushMove(best_move);
00273 return DisproofOracleAttack<Attacker>(next_guide, new_path);
00274 }
00275 }
00276 }
00277
00278 #endif
00279
00280
00281
00282