proofTreeDepthDfpn.cc
Go to the documentation of this file.
00001 /* proofTreeDepthDfpn.cc
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   // always test ImmediateCheckmate since users do not want to see redundant solutions
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()); // XXX
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     // XXX // ImmediateCheckmate
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;       // and node で指手がなくて詰 => 逃げられない
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;             // loop found
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 // ;;; Local Variables:
00220 // ;;; mode:c++
00221 // ;;; c-basic-offset:2
00222 // ;;; End:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines