searchState2.h
Go to the documentation of this file.
00001 /* searchState2.h
00002  */
00003 #ifndef OSL_SEARCHSTATE2_H
00004 #define OSL_SEARCHSTATE2_H
00005 
00006 #include "osl/search/killerMoveTable.h"
00007 #include "osl/search/bigramKillerMove.h"
00008 #include "osl/search/historyTable.h"
00009 #include "osl/search/firstMoveThreatmate.h"
00010 #include "osl/search/simpleHashRecord.h"
00011 #include "osl/checkmate/dualDfpn.h"
00012 #include "osl/checkmate/fixedDepthSearcher.h"
00013 #include "osl/effect_util/neighboring8Direct.h"
00014 #include "osl/state/numEffectState.h"
00015 #include "osl/hash/hashKey.h"
00016 #include "osl/repetitionCounter.h"
00017 #include "osl/container/moveStack.h"
00018 #include "osl/misc/fixedCapacityVector.h"
00019 #include "osl/misc/align16New.h"
00020 
00021 #include <boost/shared_ptr.hpp>
00022 #include <boost/utility.hpp>
00023 
00024 namespace osl
00025 {
00026   namespace search
00027   {
00032     class RecordStack2
00033     {
00034       static const int SEARCH_DEPTH_MAX = 64;
00035       FixedCapacityVector<SimpleHashRecord*, SEARCH_DEPTH_MAX> data;
00036     public:
00037       RecordStack2();
00038       void clear();
00039       void push(SimpleHashRecord *r) { data.push_back(r); }
00040       void pop() { assert(size() > 1); data.pop_back(); }
00041 
00042       SimpleHashRecord* lastRecord(unsigned int n=0) const
00043       {
00044         assert(size() > n);
00045         return data[size()-1-n];
00046       }
00047       SimpleHashRecord* rootRecord() const
00048       {
00049         assert(! empty());
00050         return data[0];
00051       }
00052       void setRootRecord(SimpleHashRecord *root) { data[0] = root; }
00053       void setLastRecord(SimpleHashRecord *r) { 
00054         assert(size() > 0);     // 1 for root
00055         data[size()-1] = r;
00056       }
00057 
00058       size_t size() const { return data.size(); }
00059       bool empty() const { return data.empty(); }
00060       bool hasLastRecord(unsigned int n=0) const
00061       {
00062         return size() > n;
00063       }
00064 
00065       void dump() const;
00066     };
00067 
00068     class Worker;
00072     struct SearchState2Shared : boost::noncopyable
00073     {
00074       BigramKillerMove bigram_killers;
00075       KillerMoveTable killer_moves;
00076       HistoryTable history_table;
00077 
00078       SearchState2Shared();
00079       ~SearchState2Shared();
00080     };
00081 #define search_assert(x) assert(((x) || (SearchState2Core::abort())))
00082 #define search_assert2(x, m) assert(((x) || (SearchState2Core::abort(m))))
00083     struct AlphaBeta2ParallelCommon;
00086     class SearchState2Core
00087 #if OSL_WORDSIZE == 32
00088       : public misc::Align16New
00089 #endif
00090     {
00091       friend struct AlphaBeta2ParallelCommon;
00092     public:
00093       enum { MaxDepth = 64 };
00094       typedef DualDfpn checkmate_t;
00095     protected:
00096       NumEffectState current_state, root_state;
00097       checkmate_t* checkmate_searcher;
00098 #ifdef OSL_SMP
00099     public:
00100       void setCheckmateSearcher(checkmate_t *new_checkmate) {
00101         checkmate_searcher = new_checkmate;
00102       }
00103     private:
00104 #endif
00105       PathEncoding current_path;
00106       MoveStack move_history;
00107       int root_depth;
00108     protected:
00109       RecordStack2 record_stack;
00110       RepetitionCounter repetition_counter;
00111       boost::shared_ptr<SearchState2Shared> shared;
00112     public:
00113       typedef FixedCapacityVector<Move,MaxDepth> PVVector;
00114     protected:
00115       CArray<PVVector,MaxDepth> pv;
00116       enum NodeType { PvNode = 0, AllNode = 1, CutNode = -1, };
00117       CArray<NodeType,MaxDepth> node_type;
00118     public:
00120       volatile bool stop_tree;
00121 #ifndef MINIMAL
00122       static CArray<int, MaxDepth> depth_node_count_quiesce;
00123 #endif
00124       SearchState2Core(const NumEffectState& s, checkmate_t& checker);
00125       virtual ~SearchState2Core();
00126       int curDepth() const { return history().size() - root_depth; }
00127 
00134       virtual void setState(const NumEffectState& s);
00135       void setHistory(const MoveStack& h);
00136       bool hasLastRecord(unsigned int n=0) const
00137       {
00138         return record_stack.hasLastRecord(n);
00139       }
00140       SimpleHashRecord* lastRecord(unsigned int n=0) 
00141       {
00142         return record_stack.lastRecord(n); 
00143       }
00144       const SimpleHashRecord* lastRecord(unsigned int n=0) const
00145       {
00146         return record_stack.lastRecord(n); 
00147       }
00148       SimpleHashRecord *rootRecord()
00149       {
00150         return record_stack.rootRecord();
00151       }
00152       void setCurrentRecord(SimpleHashRecord *r)
00153       {
00154         search_assert((int)record_stack.size() == curDepth()+1);
00155         record_stack.setLastRecord(r);
00156       }
00157       void setRootRecord(SimpleHashRecord *root)
00158       {
00159         search_assert(record_stack.size() == 1);
00160         search_assert(curDepth() == 0);
00161         record_stack.setRootRecord(root); 
00162       }
00163 
00164       // killer move
00165       void setKillerMove(Move best_move)
00166       {
00167         if (best_move.isPass())
00168           return;
00169         shared->killer_moves.setMove(curDepth(), best_move);
00170         const Move last_move = lastMove();
00171         if (! last_move.isInvalid()) {
00172           search_assert(best_move.player() != last_move.player());
00173           shared->bigram_killers.setMove(last_move, best_move);
00174         }
00175       }
00176       void getBigramKillerMoves(MoveVector& moves) const
00177       {
00178         shared->bigram_killers.getMove(state(), lastMove(), moves);
00179 #ifdef TRI_PLY_BIGRAM_KILLERS
00180         if (move_history.hasLastMove(3))
00181           shared->bigram_killers.getMove(state(), lastMove(3), moves);
00182 #endif
00183       }
00184       void getKillerMoves(MoveVector& moves) const
00185       {
00186         getBigramKillerMoves(moves);
00187         shared->killer_moves.getMove(state(), curDepth(), moves);
00188       }
00189       const BigramKillerMove& bigramKillerMove() const { 
00190         return shared->bigram_killers;
00191       }
00192       void setBigramKillerMove(const BigramKillerMove& killers);
00193       HistoryTable& historyTable() { return shared->history_table; }
00194       const HistoryTable& historyTable() const { return shared->history_table; }
00195       // doUndo
00196       void pushPass()
00197       {
00198         const Move pass = Move::PASS(current_state.turn());
00199         current_state.changeTurn();
00200         current_path.pushMove(pass);
00201         move_history.push(pass);
00202       }
00203       void popPass()
00204       {
00205         const Move pass = Move::PASS(alt(current_state.turn()));
00206         current_state.changeTurn();
00207         current_path.popMove(pass);
00208         move_history.pop();
00209       }
00210     private:
00214       void pushBeforeApply(Move move)
00215       {
00216         move_history.push(move);
00217         record_stack.push(0);
00218         assert(curDepth() > 0);
00219         node_type[curDepth()] = static_cast<NodeType>(-node_type[curDepth()-1]);
00220       }
00221       struct Updator
00222       {
00223         const HashKey& new_hash;
00224         SearchState2Core *state;
00225         Updator(const HashKey& h, SearchState2Core *s)
00226           : new_hash(h), state(s)
00227         {
00228         }
00229         void update()
00230         {
00231           state->updateRepetitionCounterAfterMove(new_hash);
00232         }
00233       };
00234       template <class Function>
00235       struct UpdateWrapper : public Updator
00236       {
00237         Function& function;
00238         UpdateWrapper(const HashKey& h, SearchState2Core *s, Function& f)
00239           : Updator(h, s), function(f)
00240         {
00241         }
00242         void operator()(Square to)
00243         {
00244           update();
00245           function(to);
00246         }
00247       };
00248       friend struct Updator;
00252       void updateRepetitionCounterAfterMove(const HashKey& new_hash)
00253       {
00254         repetition_counter.push(new_hash, current_state);
00255       }
00259       void popAfterApply()
00260       {
00261         record_stack.pop();
00262         repetition_counter.pop();
00263         move_history.pop();
00264       }
00265 #ifndef NDEBUG
00266       void makeMoveHook(Move);
00267 #endif
00268     public:
00272       template <Player P, class Function>
00273       void doUndoMoveOrPass(const HashKey& new_hash,
00274                             Move move, Function& f)
00275       {
00276         pushBeforeApply(move);
00277         UpdateWrapper<Function> wrapper(new_hash, this, f);
00278         current_path.pushMove(move);
00279         current_state.makeUnmakeMove(Player2Type<P>(), move, wrapper);
00280         current_path.popMove(move);
00281         popAfterApply();
00282       }
00283       void makeMove(Move move)  // for debug
00284       {
00285         HashKey new_hash = currentHash().newHashWithMove(move);
00286         pushBeforeApply(move);
00287         current_state.makeMove(move);
00288         updateRepetitionCounterAfterMove(new_hash);
00289       }
00290       
00291       const Move lastMove(int i=1) const { return move_history.lastMove(i); }
00292       const MoveStack& history() const { return move_history; }
00293       const RecordStack2& recordHistory() const { return record_stack; }
00294       const PathEncoding& path() const { return current_path; }
00295       const NumEffectState& state() const { return current_state; }
00296       const NumEffectState& rootState() const { return root_state; }
00297       void restoreRootState();
00298       const checkmate_t& checkmateSearcher() const { return *checkmate_searcher; }
00299       const RepetitionCounter& repetitionCounter() const { 
00300         return repetition_counter;
00301       }
00302       const HashKey& currentHash() const
00303       {
00304         return repetition_counter.history().top();
00305       }
00306 
00310       template <Player P, class Function>
00311       void doUndoMoveLight(Move move, Function& f)
00312       {
00313         current_path.pushMove(move);
00314         current_state.makeUnmakeMove(Player2Type<P>(), move, f);
00315         current_path.popMove(move);
00316       }
00317 
00318       template <Player P>
00319       bool isLosingState(int node_limit)
00320       {
00321         search_assert(P == path().turn());
00322         const bool lose = 
00323           checkmate_searcher->isLosingState<P>
00324           (node_limit, current_state, currentHash(), path(), lastMove());
00325         return lose;
00326       }
00327     public:
00328       template <Player P>
00329       static bool isWinningState(checkmate_t& search, NumEffectState& state,
00330                                  const HashKey& key, PathEncoding path,
00331                                  int node_limit, Move& checkmate_move, 
00332                                  Move last_move, bool
00333 #ifdef OSL_DFPN_SMP_SEARCH
00334  parallel
00335 #endif
00336                                  =false
00337         )
00338       {
00339         assert(P == path.turn());
00340 #ifdef OSL_DFPN_SMP_SEARCH
00341         if (parallel)
00342           return search.isWinningStateParallel<P>
00343             (node_limit, state, key, path, checkmate_move, last_move);
00344 #endif
00345         const bool win = search.isWinningState<P>
00346           (node_limit, state, key, path, checkmate_move, last_move);
00347         return win;
00348       }
00349       static bool isWinningState(checkmate_t& search, NumEffectState& state,
00350                                  const HashKey& key, PathEncoding path,
00351                                  int node_limit, Move& checkmate_move, 
00352                                  Move last_move, bool parallel=false)
00353       {
00354         if (state.turn() == BLACK)
00355           return isWinningState<BLACK>
00356             (search, state, key, path, node_limit, checkmate_move, last_move, parallel);
00357         else
00358           return isWinningState<WHITE>
00359             (search, state, key, path, node_limit, checkmate_move, last_move, parallel);
00360       }
00361       template <Player P>
00362       bool isWinningState(int node_limit, Move& checkmate_move, bool parallel=false)
00363       {
00364         search_assert(P == path().turn());
00365         return isWinningState<P>(*checkmate_searcher, current_state, currentHash(),
00366                                  path(), node_limit, checkmate_move, lastMove(), parallel);
00367       }
00369       template <Player P>
00370       bool isWinningStateShort(int depth, Move& checkmate_move)
00371       {
00372         checkmate::FixedDepthSearcher searcher(current_state);
00373         const ProofDisproof pdp=searcher.hasCheckmateMove<P>(depth, checkmate_move);
00374         return pdp.isCheckmateSuccess();
00375       }
00379       template <Player P>
00380       bool isThreatmateState(int node_limit, Move& threatmate_move, bool 
00381 #ifdef OSL_DFPN_SMP_SEARCH
00382                              parallel
00383 #endif
00384                              =false)
00385       {
00386         search_assert(P == path().turn());
00387         current_state.changeTurn();
00388         HashKey threatmate_hash = currentHash();
00389         threatmate_hash.changeTurn();
00390         const PathEncoding threatmate_path(current_state.turn());
00391         const Player Opponent = PlayerTraits<P>::opponent;
00392         bool threatmate;
00393 #ifdef OSL_DFPN_SMP_SEARCH
00394         if (parallel)
00395           threatmate = checkmate_searcher->template isWinningStateParallel<Opponent>
00396             (node_limit, current_state, 
00397              threatmate_hash, threatmate_path, threatmate_move, Move::PASS(P));
00398         else
00399 #endif
00400         threatmate
00401           = checkmate_searcher->template isWinningState<Opponent>
00402           (node_limit, current_state, 
00403            threatmate_hash, threatmate_path, threatmate_move, Move::PASS(P));
00404         current_state.changeTurn();
00405         return threatmate;
00406       }
00407       template <Player P>
00408       bool isThreatmateStateShort(int depth, Move& threatmate_move)
00409       {
00410         search_assert(P == path().turn());
00411         current_state.changeTurn();
00412 
00413         const Player Opponent = PlayerTraits<P>::opponent;
00414 
00415         checkmate::FixedDepthSearcher searcher(current_state);
00416         const ProofDisproof pdp
00417           = searcher.hasCheckmateMove<Opponent>(depth, threatmate_move);
00418 
00419         current_state.changeTurn();
00420         return pdp.isCheckmateSuccess();
00421       }
00422       bool abort() const;
00423       virtual bool abort(Move) const;
00424 
00425       bool tryThreatmate() const 
00426       {
00427         const Move last_move = lastMove();
00428         if (! last_move.isNormal())
00429           return false;
00430         const Square king = state().kingSquare(state().turn());
00431         if (curDepth() == 1)
00432           return FirstMoveThreatmate::isMember(last_move, king);
00433         return Neighboring8Direct::hasEffect
00434           (state(), last_move.ptypeO(), last_move.to(), king);
00435 
00436       }
00437 
00438       void makePV(Move m) 
00439       {
00440         const int depth = curDepth();
00441         makePV(pv[depth], m, pv[depth+1]);
00442       }
00443       void initPV() 
00444       {
00445         const int depth = curDepth();
00446         pv[depth].clear();
00447       }
00448       void makePV(PVVector& parent, Move m, PVVector& pv) const;
00450       int
00451 #ifdef __GNUC__
00452         __attribute__ ((pure))
00453 #endif
00454       countCheckAfterThreatmate(Player turn, int depth=1) const
00455       {
00456         assert(((depth % 2) && state().turn() == turn)
00457                || ((depth % 2) == 0 && state().turn() != turn));
00458         int result = 0;
00459         for (int i=depth;; i+=2) {
00460           if (! hasLastRecord(i) || ! lastRecord(i))
00461             break;
00462           if (lastRecord(i)->qrecord.threatmate.status(turn).status()
00463               != ThreatmateState::CHECK_AFTER_THREATMATE)
00464             break;
00465           ++result;
00466         }
00467         return result;
00468       }
00469       int countCheckAfterThreatmateSacrifice(Player turn, int depth=1) const
00470       {
00471         assert(((depth % 2) && state().turn() == turn)
00472                || ((depth % 2) == 0 && state().turn() != turn));
00473         assert(depth > 0);
00474         int result = 0;
00475         for (int i=depth;; i+=2) {
00476           if (! hasLastRecord(i) || ! lastRecord(i))
00477             break;
00478           if (lastRecord(i)->qrecord.threatmate.status(turn).status()
00479               != ThreatmateState::CHECK_AFTER_THREATMATE)
00480             break;
00481           if (lastMove(i-1).isCapture())
00482             ++result;
00483         }
00484         return result;
00485       }
00486     };
00487 
00488 #undef search_assert    
00489 #undef search_assert2
00490 #define search_assert(x) assert((x) || SearchState2Core::abort())
00491 #define search_assert2(x, m) assert((x) || SearchState2Core::abort(m))
00492 
00495     class SearchState2 : public SearchState2Core
00496     {
00497     public:
00499       static const int ReSearchLimitMargin = 80;
00500     protected:
00501       int root_limit;
00502       int cur_limit;
00503     public:
00504       SearchState2(const NumEffectState& s, checkmate_t& checker);
00505       virtual ~SearchState2();
00506 
00507       void setState(const NumEffectState& s);
00508       void setKillerMove(Move best_move)
00509       {
00510         if (best_move.isPass())
00511           return;
00512         SearchState2Core::setKillerMove(best_move);
00513       }
00514       
00515       int curLimit() const { return cur_limit; }
00516 
00517       bool abort(Move) const;
00518 
00519     protected:
00523       void setRoot(int limit)
00524       {
00525         root_limit = limit;
00526         cur_limit = limit;
00527       }
00528       void addLimit(int limit) { cur_limit += limit; search_assert(cur_limit >= 0); }
00529       void subLimit(int limit) { cur_limit -= limit; search_assert(cur_limit >= 0); }
00530 
00534       int countSacrificeCheck2(int history_max) const;
00536       void checkPointSearchAllMoves();
00537     };
00538   } // namespace search
00539 } // namespace osl
00540 
00541 #undef search_assert
00542 #undef search_assert2
00543 
00544 #endif /* OSL_SEARCHSTATE2_H */
00545 // ;;; Local Variables:
00546 // ;;; mode:c++
00547 // ;;; c-basic-offset:2
00548 // ;;; End:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines