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 #ifndef NDEBUG
00278         makeMoveHook(move);
00279 #endif
00280         UpdateWrapper<Function> wrapper(new_hash, this, f);
00281         current_path.pushMove(move);
00282         current_state.makeUnmakeMove(Player2Type<P>(), move, wrapper);
00283         current_path.popMove(move);
00284         popAfterApply();
00285       }
00286       void makeMove(Move move)  // for debug
00287       {
00288         HashKey new_hash = currentHash().newHashWithMove(move);
00289         pushBeforeApply(move);
00290         current_state.makeMove(move);
00291         updateRepetitionCounterAfterMove(new_hash);
00292       }
00293       
00294       const Move lastMove(int i=1) const { return move_history.lastMove(i); }
00295       const MoveStack& history() const { return move_history; }
00296       const RecordStack2& recordHistory() const { return record_stack; }
00297       const PathEncoding& path() const { return current_path; }
00298       const NumEffectState& state() const { return current_state; }
00299       const NumEffectState& rootState() const { return root_state; }
00300       void restoreRootState();
00301       const checkmate_t& checkmateSearcher() const { return *checkmate_searcher; }
00302       const RepetitionCounter& repetitionCounter() const { 
00303         return repetition_counter;
00304       }
00305       const HashKey& currentHash() const
00306       {
00307         return repetition_counter.history().top();
00308       }
00309 
00313       template <Player P, class Function>
00314       void doUndoMoveLight(Move move, Function& f)
00315       {
00316         current_path.pushMove(move);
00317         current_state.makeUnmakeMove(Player2Type<P>(), move, f);
00318         current_path.popMove(move);
00319       }
00320 
00321       template <Player P>
00322       bool isLosingState(int node_limit)
00323       {
00324         search_assert(P == path().turn());
00325         const bool lose = 
00326           checkmate_searcher->isLosingState<P>
00327           (node_limit, current_state, currentHash(), path(), lastMove());
00328         return lose;
00329       }
00330     public:
00331       template <Player P>
00332       static bool isWinningState(checkmate_t& search, NumEffectState& state,
00333                                  const HashKey& key, PathEncoding path,
00334                                  int node_limit, Move& checkmate_move, 
00335                                  Move last_move, bool
00336 #ifdef OSL_DFPN_SMP_SEARCH
00337  parallel
00338 #endif
00339                                  =false
00340         )
00341       {
00342         assert(P == path.turn());
00343 #ifdef OSL_DFPN_SMP_SEARCH
00344         if (parallel)
00345           return search.isWinningStateParallel<P>
00346             (node_limit, state, key, path, checkmate_move, last_move);
00347 #endif
00348         const bool win = search.isWinningState<P>
00349           (node_limit, state, key, path, checkmate_move, last_move);
00350         return win;
00351       }
00352       static bool isWinningState(checkmate_t& search, NumEffectState& state,
00353                                  const HashKey& key, PathEncoding path,
00354                                  int node_limit, Move& checkmate_move, 
00355                                  Move last_move, bool parallel=false)
00356       {
00357         if (state.turn() == BLACK)
00358           return isWinningState<BLACK>
00359             (search, state, key, path, node_limit, checkmate_move, last_move, parallel);
00360         else
00361           return isWinningState<WHITE>
00362             (search, state, key, path, node_limit, checkmate_move, last_move, parallel);
00363       }
00364       template <Player P>
00365       bool isWinningState(int node_limit, Move& checkmate_move, bool parallel=false)
00366       {
00367         search_assert(P == path().turn());
00368         return isWinningState<P>(*checkmate_searcher, current_state, currentHash(),
00369                                  path(), node_limit, checkmate_move, lastMove(), parallel);
00370       }
00372       template <Player P>
00373       bool isWinningStateShort(int depth, Move& checkmate_move)
00374       {
00375         checkmate::FixedDepthSearcher searcher(current_state);
00376         const ProofDisproof pdp=searcher.hasCheckmateMove<P>(depth, checkmate_move);
00377         return pdp.isCheckmateSuccess();
00378       }
00382       template <Player P>
00383       bool isThreatmateState(int node_limit, Move& threatmate_move, bool 
00384 #ifdef OSL_DFPN_SMP_SEARCH
00385                              parallel
00386 #endif
00387                              =false)
00388       {
00389         search_assert(P == path().turn());
00390         current_state.changeTurn();
00391         HashKey threatmate_hash = currentHash();
00392         threatmate_hash.changeTurn();
00393         const PathEncoding threatmate_path(current_state.turn());
00394         const Player Opponent = PlayerTraits<P>::opponent;
00395         bool threatmate;
00396 #ifdef OSL_DFPN_SMP_SEARCH
00397         if (parallel)
00398           threatmate = checkmate_searcher->template isWinningStateParallel<Opponent>
00399             (node_limit, current_state, 
00400              threatmate_hash, threatmate_path, threatmate_move, Move::PASS(P));
00401         else
00402 #endif
00403         threatmate
00404           = checkmate_searcher->template isWinningState<Opponent>
00405           (node_limit, current_state, 
00406            threatmate_hash, threatmate_path, threatmate_move, Move::PASS(P));
00407         current_state.changeTurn();
00408         return threatmate;
00409       }
00410       template <Player P>
00411       bool isThreatmateStateShort(int depth, Move& threatmate_move)
00412       {
00413         search_assert(P == path().turn());
00414         current_state.changeTurn();
00415 
00416         const Player Opponent = PlayerTraits<P>::opponent;
00417 
00418         checkmate::FixedDepthSearcher searcher(current_state);
00419         const ProofDisproof pdp
00420           = searcher.hasCheckmateMove<Opponent>(depth, threatmate_move);
00421 
00422         current_state.changeTurn();
00423         return pdp.isCheckmateSuccess();
00424       }
00425       bool abort() const;
00426       virtual bool abort(Move) const;
00427 
00428       bool tryThreatmate() const 
00429       {
00430         const Move last_move = lastMove();
00431         if (! last_move.isNormal())
00432           return false;
00433         const Square king = state().kingSquare(state().turn());
00434         if (curDepth() == 1)
00435           return FirstMoveThreatmate::isMember(last_move, king);
00436         return Neighboring8Direct::hasEffect
00437           (state(), last_move.ptypeO(), last_move.to(), king);
00438 
00439       }
00440 
00441       void makePV(Move m) 
00442       {
00443         const int depth = curDepth();
00444         makePV(pv[depth], m, pv[depth+1]);
00445       }
00446       void initPV() 
00447       {
00448         const int depth = curDepth();
00449         pv[depth].clear();
00450       }
00451       void makePV(PVVector& parent, Move m, PVVector& pv) const;
00453       int
00454 #ifdef __GNUC__
00455         __attribute__ ((pure))
00456 #endif
00457       countCheckAfterThreatmate(Player turn, int depth=1) const
00458       {
00459         assert(((depth % 2) && state().turn() == turn)
00460                || ((depth % 2) == 0 && state().turn() != turn));
00461         int result = 0;
00462         for (int i=depth;; i+=2) {
00463           if (! hasLastRecord(i) || ! lastRecord(i))
00464             break;
00465           if (lastRecord(i)->qrecord.threatmate.status(turn).status()
00466               != ThreatmateState::CHECK_AFTER_THREATMATE)
00467             break;
00468           ++result;
00469         }
00470         return result;
00471       }
00472       int countCheckAfterThreatmateSacrifice(Player turn, int depth=1) const
00473       {
00474         assert(((depth % 2) && state().turn() == turn)
00475                || ((depth % 2) == 0 && state().turn() != turn));
00476         assert(depth > 0);
00477         int result = 0;
00478         for (int i=depth;; i+=2) {
00479           if (! hasLastRecord(i) || ! lastRecord(i))
00480             break;
00481           if (lastRecord(i)->qrecord.threatmate.status(turn).status()
00482               != ThreatmateState::CHECK_AFTER_THREATMATE)
00483             break;
00484           if (lastMove(i-1).isCapture())
00485             ++result;
00486         }
00487         return result;
00488       }
00489     };
00490 
00491 #undef search_assert    
00492 #undef search_assert2
00493 #define search_assert(x) assert((x) || SearchState2Core::abort())
00494 #define search_assert2(x, m) assert((x) || SearchState2Core::abort(m))
00495 
00498     class SearchState2 : public SearchState2Core
00499     {
00500     public:
00502       static const int ReSearchLimitMargin = 80;
00503     protected:
00504       int root_limit;
00505       int cur_limit;
00506     public:
00507       SearchState2(const NumEffectState& s, checkmate_t& checker);
00508       virtual ~SearchState2();
00509 
00510       void setState(const NumEffectState& s);
00511       void setKillerMove(Move best_move)
00512       {
00513         if (best_move.isPass())
00514           return;
00515         SearchState2Core::setKillerMove(best_move);
00516       }
00517       
00518       int curLimit() const { return cur_limit; }
00519 
00520       bool abort(Move) const;
00521 
00522     protected:
00526       void setRoot(int limit)
00527       {
00528         root_limit = limit;
00529         cur_limit = limit;
00530       }
00531       void addLimit(int limit) { cur_limit += limit; search_assert(cur_limit >= 0); }
00532       void subLimit(int limit) { cur_limit -= limit; search_assert(cur_limit >= 0); }
00533 
00537       int countSacrificeCheck2(int history_max) const;
00539       void checkPointSearchAllMoves();
00540     };
00541   } // namespace search
00542 } // namespace osl
00543 
00544 #undef search_assert
00545 #undef search_assert2
00546 
00547 #endif /* OSL_SEARCHSTATE2_H */
00548 // ;;; Local Variables:
00549 // ;;; mode:c++
00550 // ;;; c-basic-offset:2
00551 // ;;; End:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines