00001
00002
00003 #ifndef OSL_DFPN_H
00004 #define OSL_DFPN_H
00005 #include "osl/checkmate/proofDisproof.h"
00006 #include "osl/checkmate/checkMoveVector.h"
00007 #include "osl/state/numEffectState.h"
00008 #include "osl/container/moveVector.h"
00009 #include "osl/hash/hashKey.h"
00010 #include "osl/stl/vector.h"
00011 #include "osl/pathEncoding.h"
00012 #include "osl/config.h"
00013 #include <boost/scoped_array.hpp>
00014 #include <boost/scoped_ptr.hpp>
00015 #include <boost/noncopyable.hpp>
00016
00017 #ifdef OSL_SMP
00018 # ifndef OSL_DFPN_SMP
00019 # define OSL_DFPN_SMP
00020 # endif
00021 #endif
00022
00023 #ifdef OSL_DFPN_SMP
00024 # include "osl/misc/lightMutex.h"
00025 # include <boost/thread/mutex.hpp>
00026 #endif
00027
00028 namespace osl
00029 {
00030 namespace checkmate
00031 {
00032 class DfpnRecord;
00034 class DfpnTable
00035 {
00036 struct Table;
00037 struct List;
00038 boost::scoped_array<Table> table;
00039 size_t total_size;
00040 int dfpn_max_depth;
00041 size_t growth_limit, gc_threshold;
00042 public:
00043 DfpnTable(Player attack);
00044 DfpnTable();
00045 ~DfpnTable();
00046 template <Player Attack>
00047 const DfpnRecord probe(const HashKey& key, PieceStand white) const;
00048 const DfpnRecord probe(const HashKey& key, PieceStand white) const;
00049 size_t estimateNodeCount(const HashKey& key, bool dominance_max=false) const;
00050 template <Player Attack>
00051 const DfpnRecord findProofOracle(const HashKey& key, PieceStand white, Move last_move=Move()) const;
00052 const DfpnRecord findProofOracle(const HashKey& key, PieceStand white, Move last_move=Move()) const;
00053 template <Player Attack>
00054 void showProofOracles(const HashKey& key, PieceStand white, Move last_move=Move()) const;
00055 size_t
00056 #ifdef __GNUC__
00057 __attribute__ ((pure))
00058 #endif
00059 size() const;
00060 void showStats() const;
00061
00062 void setAttack(Player);
00063 void setWorking(const HashKey& key, const DfpnRecord& value, int thread_id);
00064 void leaveWorking(const HashKey& key, int thread_id);
00065 void store(const HashKey& key, DfpnRecord& value, int leaving_thread_id=-1);
00066 void addDag(const HashKey& key, DfpnRecord& value);
00067 void clear();
00068 size_t totalSize() { return total_size; }
00069 Player attack() const;
00070
00071 void setMaxDepth(int);
00072 int maxDepth() const;
00073
00074 void testTable();
00075 size_t smallTreeGC(size_t threshold=10);
00077 void setGrowthLimit(size_t new_limit);
00078 size_t growthLimit() const { return growth_limit; }
00079 bool runGC();
00080 private:
00081 #ifdef OSL_DFPN_SMP
00082 typedef osl::misc::LightMutex Mutex;
00083 # ifdef USE_TBB_HASH
00084 static const int DIVSIZE=1;
00085 # else
00086 static const int DIVSIZE=256;
00087 mutable CArray<Mutex,DIVSIZE> mutex;
00088 # endif
00089
00090
00091 LightMutex root_mutex;
00092 #else
00093 static const int DIVSIZE=1;
00094 #endif
00095 static int keyToIndex(const HashKey& key)
00096 {
00097 unsigned long val=key.signature();
00098 return (val>>24)%DIVSIZE;
00099 }
00100 template <Player Attack>
00101 List *find(const HashKey& key, int subindex);
00102 template <Player Attack>
00103 const List *find(const HashKey& key, int subindex) const;
00104 const List *find(const HashKey& key, int subindex) const;
00105 };
00107 class DfpnPathTable;
00109 class DfpnShared;
00111 class Dfpn : boost::noncopyable
00112 {
00113 public:
00114 enum { DfpnMaxUniqMoves = CheckOrEscapeMaxUniqMoves };
00115 typedef CheckMoveVector DfpnMoveVector;
00116 typedef DfpnTable table_t;
00117 private:
00118 DfpnTable *table;
00119 struct NodeBase;
00120 struct Node;
00121 struct Tree;
00122 boost::scoped_ptr<Tree> tree;
00123 boost::scoped_ptr<DfpnPathTable> path_table;
00124 size_t node_count;
00125 size_t node_count_limit;
00126 DfpnShared *parallel_shared;
00127 int thread_id;
00128 bool blocking_verify;
00129 public:
00130 Dfpn();
00131 ~Dfpn();
00132 void setTable(DfpnTable *new_table);
00133 void setIllegal(const HashKey& key, PieceStand white);
00134 void setBlockingVerify(bool enable=true) { blocking_verify = enable; }
00135 void setParallel(int id, DfpnShared *s)
00136 {
00137 if (s)
00138 assert(id >= 0);
00139 thread_id = id;
00140 parallel_shared = s;
00141 }
00142 const ProofDisproof
00143 hasCheckmateMove(const NumEffectState& state, const HashKey& key,
00144 const PathEncoding& path, size_t limit, Move& best_move,
00145 Move last_move=Move::INVALID(), vector<Move> *pv=0);
00146 const ProofDisproof
00147 hasCheckmateMove(const NumEffectState& state, const HashKey& key,
00148 const PathEncoding& path, size_t limit, Move& best_move, PieceStand& proof,
00149 Move last_move=Move::INVALID(), vector<Move> *pv=0);
00150 const ProofDisproof
00151 hasEscapeMove(const NumEffectState& state,
00152 const HashKey& key, const PathEncoding& path,
00153 size_t limit, Move last_move);
00154
00155 size_t nodeCount() const { return node_count; }
00156 const DfpnTable& currentTable() const { return *table; }
00157 void analyze(const PathEncoding& path,
00158 const NumEffectState& state, const vector<Move>& moves) const;
00159 void clear();
00160
00161
00162 template <Player P> void attack();
00163 template <Player P> void defense();
00164 template <Player P> struct CallAttack;
00165 template <Player P> struct CallDefense;
00166 struct DepthLimitReached {};
00167
00168 struct ProofOracle;
00169 template <Player P, bool UseTable> void proofOracleAttack(const ProofOracle& oracle, int proof_limit);
00170 template <Player P, bool UseTable> void proofOracleDefense(const ProofOracle& oracle, int proof_limit);
00171 template <Player P, bool UseTable> struct CallProofOracleAttack;
00172 template <Player P, bool UseTable> struct CallProofOracleDefense;
00174 template <Player P> void blockingSimulation(int seed, const ProofOracle&);
00175 template <Player P> void grandParentSimulation(int cur_move, const Node& gparent, int gp_move);
00176 private:
00177 template <bool UseTable>
00178 const ProofDisproof
00179 tryProofMain(const NumEffectState& state, const HashKey& key,
00180 const PathEncoding& path, const ProofOracle&, size_t oracle_id, Move& best_move,
00181 Move last_move);
00182 public:
00183 const ProofDisproof
00184 tryProof(const NumEffectState& state, const HashKey& key,
00185 const PathEncoding& path, const ProofOracle&, size_t oracle_id, Move& best_move,
00186 Move last_move=Move::INVALID());
00187 const ProofDisproof
00188 tryProofLight(const NumEffectState& state, const HashKey& key,
00189 const PathEncoding& path, const ProofOracle&, size_t oracle_id, Move& best_move,
00190 Move last_move=Move::INVALID());
00191
00192
00193 int distance(const HashKey&) const;
00195 template <Player P>
00196 static void generateCheck(const NumEffectState&, DfpnMoveVector&, bool&);
00198 template <Player P>
00199 static void generateEscape(const NumEffectState&, bool need_full_width,
00200 Square grand_parent_delay_last_to, DfpnMoveVector&);
00202 bool grandParentSimulationSuitable() const;
00203 template <Player Turn>
00204 static void sort(const NumEffectState&, DfpnMoveVector&);
00205 private:
00206 void findDagSource();
00207 void findDagSource(const HashKey& terminal_key,
00208 DfpnRecord& terminal_record,
00209 PieceStand terminal_stand, int offset=0);
00210 };
00211
00212 }
00213 }
00214
00215 struct osl::checkmate::Dfpn::ProofOracle
00216 {
00217 HashKey key;
00218 PieceStand white_stand;
00219 ProofOracle(const HashKey& k, PieceStand w) : key(k), white_stand(w)
00220 {
00221 }
00222 const ProofOracle newOracle(Player P, Move move) const
00223 {
00224 assert(P == move.player());
00225 return ProofOracle(key.newHashWithMove(move),
00226 (P == WHITE) ? white_stand.nextStand(P, move) : white_stand);
00227 }
00228 bool traceable(Player P, Move move) const
00229 {
00230 assert(P == move.player());
00231 if (! move.isDrop())
00232 return true;
00233 if (P == BLACK) {
00234 if (key.blackStand().get(move.ptype()) == 0)
00235 return false;
00236 }
00237 else {
00238 if (white_stand.get(move.ptype()) == 0)
00239 return false;
00240 }
00241 return true;
00242 }
00243 };
00244
00245 #endif
00246
00247
00248
00249