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[Dfpn::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 };
00073
00074 osl::checkmate::
00075 ProofTreeDepthDfpn::ProofTreeDepthDfpn(const DfpnTable& dfpn_table)
00076 : table(new Table(dfpn_table))
00077 {
00078 }
00079
00080 osl::checkmate::
00081 ProofTreeDepthDfpn::~ProofTreeDepthDfpn()
00082 {
00083 }
00084
00085 int osl::checkmate::
00086 ProofTreeDepthDfpn::depth(const HashKey& key, const NumEffectState& state, bool is_or_node) const
00087 {
00088 Move dummy;
00089 table->state[0] = state;
00090 return (is_or_node ? orNode(key, dummy) : andNode(key, dummy));
00091 }
00092
00093 void osl::checkmate::
00094 ProofTreeDepthDfpn::retrievePV
00095 (const state::NumEffectState& src, bool is_or_node,
00096 vector<Move>& pv) const
00097 {
00098 table->state[0] = src;
00099 HashKey key(table->state[0]);
00100 pv.clear();
00101 for (int i=0; i<Dfpn::MaxDepth; ++i) {
00102 Move next;
00103 if (is_or_node ^ (i%2))
00104 orNode(key, next);
00105 else
00106 andNode(key, next);
00107 if (! next.isNormal())
00108 return;
00109 pv.push_back(next);
00110 table->state[0].makeMove(next);
00111 key = key.newMakeMove(next);
00112 }
00113 }
00114
00115 int osl::checkmate::
00116 ProofTreeDepthDfpn::orNode(const HashKey& key, Move& best_move, int height) const
00117 {
00118 assert(key == HashKey(table->state[height]));
00119 best_move = Move();
00120 if (height >= Dfpn::MaxDepth)
00121 return -1;
00122
00123
00124 FixedDepthSearcher fixed_searcher(table->state[height]);
00125 ProofDisproof pdp = fixed_searcher.hasCheckmateMoveOfTurn(0, best_move);
00126 if (pdp.isCheckmateSuccess()) {
00127 table->store(key, 1, best_move);
00128 return 1;
00129 }
00130 pdp = fixed_searcher.hasCheckmateMoveOfTurn(2, best_move);
00131 if (pdp.isCheckmateSuccess()) {
00132 table->store(key, 3, best_move);
00133 return 3;
00134 }
00135
00136 const PieceStand white_stand = PieceStand(WHITE, table->state[height]);
00137 DfpnRecord record = table->table.probe(key, white_stand);
00138 if (! record.proof_disproof.isCheckmateSuccess()) {
00139 table->store(key, 5, Move());
00140 return 5;
00141 }
00142 {
00143 int recorded;
00144 if (table->find(key, recorded, best_move))
00145 return recorded;
00146 }
00147 table->store(key, -1, Move());
00148
00149 if (! record.best_move.isNormal())
00150 {
00151
00152 table->store(key, 1, Move());
00153 }
00154
00155 const HashKey new_key = key.newHashWithMove(record.best_move);
00156 const PieceStand next_white_stand = (table->state[height].turn() == WHITE)
00157 ? white_stand.nextStand(WHITE, record.best_move) : white_stand;
00158 DfpnRecord new_record = table->table.probe(new_key, next_white_stand);
00159 if (! new_record.proof_disproof.isCheckmateSuccess())
00160 new_record = table->table.findProofOracle(new_key, next_white_stand, record.best_move);
00161 if (new_record.proof_disproof.isCheckmateSuccess()) {
00162 table->state[height+1] = table->state[height];
00163 table->state[height+1].makeMove(record.best_move);
00164 Move dummy;
00165 const int depth = andNode(new_key, dummy, height+1);
00166 if (depth >= 0)
00167 {
00168 best_move = record.best_move;
00169 table->store(key, depth+1, best_move);
00170 return depth+1;
00171 }
00172 }
00173 return 0;
00174 }
00175
00176 int osl::checkmate::
00177 ProofTreeDepthDfpn::andNode(const HashKey& key, Move& best_move, int height) const
00178 {
00179 best_move = Move();
00180 if (height >= Dfpn::MaxDepth)
00181 return -1;
00182 {
00183 int recorded;
00184 if (table->find(key, recorded, best_move))
00185 return recorded;
00186 }
00187 table->store(key, -1, Move());
00188
00189 int result = 0;
00190 boost::scoped_ptr<Dfpn::DfpnMoveVector> moves(new Dfpn::DfpnMoveVector);
00191 if (table->state[height].turn() == BLACK)
00192 Dfpn::generateEscape<WHITE>(table->state[height], true, Square(), *moves);
00193 else
00194 Dfpn::generateEscape<BLACK>(table->state[height], true, Square(), *moves);
00195
00196 for (size_t i=0; i<moves->size(); ++i)
00197 {
00198 const HashKey new_key = key.newHashWithMove((*moves)[i]);
00199 if (i > 0 && ! table->expectMoreDepth(alt((*moves)[i].player()), new_key, result))
00200 continue;
00201 table->state[height+1] = table->state[height];
00202 table->state[height+1].makeMove((*moves)[i]);
00203 Move dummy;
00204 const int depth = orNode(new_key, dummy, height+1);
00205 if (depth < 0) {
00206 return depth;
00207 }
00208 if (result < depth+1) {
00209 result = depth+1;
00210 best_move = (*moves)[i];
00211 }
00212 }
00213
00214 table->store(key, result, best_move);
00215 return result;
00216 }
00217
00218
00219
00220
00221
00222