00001
00002
00003 #include "osl/checkmate/proofTreeDepthDfpn.h"
00004 #include "osl/checkmate/dfpn.h"
00005 #include "osl/checkmate/dfpnRecord.h"
00006 #include "osl/checkmate/fixedDepthSearcher.h"
00007 #include "osl/checkmate/fixedDepthSearcher.tcc"
00008 #include "osl/container/moveVector.h"
00009 #include "osl/stl/hash_map.h"
00010 #include "osl/stl/slist.h"
00011 #include <boost/foreach.hpp>
00016 struct osl::checkmate::ProofTreeDepthDfpn::Table
00017 {
00018 boost::scoped_array<NumEffectState> state;
00019 typedef osl::hash_map<HashKey, std::pair<int, Move> > map_t;
00020 typedef std::pair<const HashKey, std::pair<int, Move> > entry_t;
00021 typedef slist<const entry_t*> list_t;
00022 typedef hash_map<BoardKey, list_t> index_t;
00023 map_t depth_table;
00024 index_t depth_index;
00025 const DfpnTable& table;
00026 Table(const DfpnTable& t) : state(new NumEffectState[t.maxDepth()]), table(t)
00027 {
00028 }
00029 void store(const HashKey& key, int depth, Move best_move=Move())
00030 {
00031 depth_table[key] = std::make_pair(depth, best_move);
00032 const entry_t& e = *depth_table.find(key);
00033 depth_index[key.boardKey()].push_front(&e);
00034 }
00035 bool find(const HashKey& key, int& depth, Move& best_move) const
00036 {
00037 map_t::const_iterator p=depth_table.find(key);
00038 if (p == depth_table.end())
00039 return false;
00040 depth = p->second.first;
00041 best_move = p->second.second;
00042 return true;
00043 }
00044 bool expectMoreDepth(Player attack, const HashKey& key, int depth) const
00045 {
00046 index_t::const_iterator p=depth_index.find(key.boardKey());
00047 if (p == depth_index.end())
00048 return true;
00049 BOOST_FOREACH(const entry_t *q, p->second) {
00050 assert(q->first.boardKey() == key.boardKey());
00051 if (attack == BLACK) {
00052 if (q->first.blackStand().isSuperiorOrEqualTo(key.blackStand())) {
00053 if (q->second.first >= depth)
00054 return true;
00055 } else if (key.blackStand().isSuperiorOrEqualTo(q->first.blackStand())) {
00056 if (q->second.first < depth)
00057 return false;
00058 }
00059 }
00060 else {
00061 if (q->first.blackStand().isSuperiorOrEqualTo(key.blackStand())) {
00062 if (q->second.first < depth)
00063 return false;
00064 } else if (key.blackStand().isSuperiorOrEqualTo(q->first.blackStand())) {
00065 if (q->second.first >= depth)
00066 return true;
00067 }
00068 }
00069 }
00070 return true;
00071 }
00072 int maxDepth() const { return table.maxDepth(); }
00073 };
00074
00075 osl::checkmate::
00076 ProofTreeDepthDfpn::ProofTreeDepthDfpn(const DfpnTable& dfpn_table)
00077 : table(new Table(dfpn_table))
00078 {
00079 }
00080
00081 osl::checkmate::
00082 ProofTreeDepthDfpn::~ProofTreeDepthDfpn()
00083 {
00084 }
00085
00086 int osl::checkmate::
00087 ProofTreeDepthDfpn::depth(const HashKey& key, const NumEffectState& state, bool is_or_node) const
00088 {
00089 Move dummy;
00090 table->state[0] = state;
00091 return (is_or_node ? orNode(key, dummy) : andNode(key, dummy));
00092 }
00093
00094 void osl::checkmate::
00095 ProofTreeDepthDfpn::retrievePV
00096 (const state::NumEffectState& src, bool is_or_node,
00097 vector<Move>& pv) const
00098 {
00099 table->state[0] = src;
00100 HashKey key(table->state[0]);
00101 pv.clear();
00102 for (int i=0; i<table->maxDepth(); ++i) {
00103 Move next;
00104 if (is_or_node ^ (i%2))
00105 orNode(key, next);
00106 else
00107 andNode(key, next);
00108 if (! next.isNormal())
00109 return;
00110 pv.push_back(next);
00111 table->state[0].makeMove(next);
00112 key = key.newMakeMove(next);
00113 }
00114 }
00115
00116 int osl::checkmate::
00117 ProofTreeDepthDfpn::orNode(const HashKey& key, Move& best_move, int height) const
00118 {
00119 assert(key == HashKey(table->state[height]));
00120 best_move = Move();
00121 if (height >= table->maxDepth())
00122 return -1;
00123
00124
00125 FixedDepthSearcher fixed_searcher(table->state[height]);
00126 ProofDisproof pdp = fixed_searcher.hasCheckmateMoveOfTurn(0, best_move);
00127 if (pdp.isCheckmateSuccess()) {
00128 table->store(key, 1, best_move);
00129 return 1;
00130 }
00131 pdp = fixed_searcher.hasCheckmateMoveOfTurn(2, best_move);
00132 if (pdp.isCheckmateSuccess()) {
00133 table->store(key, 3, best_move);
00134 return 3;
00135 }
00136
00137 const PieceStand white_stand = PieceStand(WHITE, table->state[height]);
00138 DfpnRecord record = table->table.probe(key, white_stand);
00139 if (! record.proof_disproof.isCheckmateSuccess()) {
00140 table->store(key, 5, Move());
00141 return 5;
00142 }
00143 {
00144 int recorded;
00145 if (table->find(key, recorded, best_move))
00146 return recorded;
00147 }
00148 table->store(key, -1, Move());
00149
00150 if (! record.best_move.isNormal())
00151 {
00152
00153 table->store(key, 1, Move());
00154 }
00155
00156 const HashKey new_key = key.newHashWithMove(record.best_move);
00157 const PieceStand next_white_stand = (table->state[height].turn() == WHITE)
00158 ? white_stand.nextStand(WHITE, record.best_move) : white_stand;
00159 DfpnRecord new_record = table->table.probe(new_key, next_white_stand);
00160 if (! new_record.proof_disproof.isCheckmateSuccess())
00161 new_record = table->table.findProofOracle(new_key, next_white_stand, record.best_move);
00162 if (new_record.proof_disproof.isCheckmateSuccess()) {
00163 table->state[height+1] = table->state[height];
00164 table->state[height+1].makeMove(record.best_move);
00165 Move dummy;
00166 const int depth = andNode(new_key, dummy, height+1);
00167 if (depth >= 0)
00168 {
00169 best_move = record.best_move;
00170 table->store(key, depth+1, best_move);
00171 return depth+1;
00172 }
00173 }
00174 return 0;
00175 }
00176
00177 int osl::checkmate::
00178 ProofTreeDepthDfpn::andNode(const HashKey& key, Move& best_move, int height) const
00179 {
00180 best_move = Move();
00181 if (height >= table->maxDepth())
00182 return -1;
00183 {
00184 int recorded;
00185 if (table->find(key, recorded, best_move))
00186 return recorded;
00187 }
00188 table->store(key, -1, Move());
00189
00190 int result = 0;
00191 boost::scoped_ptr<Dfpn::DfpnMoveVector> moves(new Dfpn::DfpnMoveVector);
00192 if (table->state[height].turn() == BLACK)
00193 Dfpn::generateEscape<WHITE>(table->state[height], true, Square(), *moves);
00194 else
00195 Dfpn::generateEscape<BLACK>(table->state[height], true, Square(), *moves);
00196
00197 for (size_t i=0; i<moves->size(); ++i)
00198 {
00199 const HashKey new_key = key.newHashWithMove((*moves)[i]);
00200 if (i > 0 && ! table->expectMoreDepth(alt((*moves)[i].player()), new_key, result))
00201 continue;
00202 table->state[height+1] = table->state[height];
00203 table->state[height+1].makeMove((*moves)[i]);
00204 Move dummy;
00205 const int depth = orNode(new_key, dummy, height+1);
00206 if (depth < 0) {
00207 return depth;
00208 }
00209 if (result < depth+1) {
00210 result = depth+1;
00211 best_move = (*moves)[i];
00212 }
00213 }
00214
00215 table->store(key, result, best_move);
00216 return result;
00217 }
00218
00219
00220
00221
00222
00223