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