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