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