00001
00002
00003 #ifndef SEARCHSTATE2_H
00004 #define 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/apply_move/applyMoveWithPath.h"
00019 #include "osl/misc/fixedCapacityVector.h"
00020 #include "osl/misc/align16New.h"
00021
00022 #include <boost/shared_ptr.hpp>
00023 #include <boost/utility.hpp>
00024
00025 namespace osl
00026 {
00027 namespace search
00028 {
00033 class RecordStack2
00034 {
00035 static const int SEARCH_DEPTH_MAX = 64;
00036 FixedCapacityVector<SimpleHashRecord*, SEARCH_DEPTH_MAX> data;
00037 public:
00038 RecordStack2();
00039 void clear();
00040 void push(SimpleHashRecord *r) { data.push_back(r); }
00041 void pop() { assert(size() > 1); data.pop_back(); }
00042
00043 SimpleHashRecord* lastRecord(unsigned int n=0) const
00044 {
00045 assert(size() > n);
00046 return data[size()-1-n];
00047 }
00048 SimpleHashRecord* rootRecord() const
00049 {
00050 assert(! empty());
00051 return data[0];
00052 }
00053 void setRootRecord(SimpleHashRecord *root) { data[0] = root; }
00054 void setLastRecord(SimpleHashRecord *r) {
00055 assert(size() > 0);
00056 data[size()-1] = r;
00057 }
00058
00059 size_t size() const { return data.size(); }
00060 bool empty() const { return data.empty(); }
00061 bool hasLastRecord(unsigned int n=0) const
00062 {
00063 return size() > n;
00064 }
00065
00066 void dump() const;
00067 };
00068
00069 class Worker;
00073 struct SearchState2Shared : boost::noncopyable
00074 {
00075 BigramKillerMove bigram_killers;
00076 KillerMoveTable killer_moves;
00077 HistoryTable history_table;
00078
00079 SearchState2Shared();
00080 ~SearchState2Shared();
00081 };
00082 #define search_assert(x) assert(((x) || (SearchState2Core::abort())))
00083 #define search_assert2(x, m) assert(((x) || (SearchState2Core::abort(m))))
00084 class AlphaBeta2ParallelCommon;
00087 class SearchState2Core
00088 #if OSL_WORDSIZE == 32
00089 : public misc::Align16New
00090 #endif
00091 {
00092 friend class AlphaBeta2ParallelCommon;
00093 public:
00094 enum { MaxDepth = 64 };
00095 typedef DualDfpn checkmate_t;
00096 protected:
00097 NumEffectState current_state, root_state;
00098 checkmate_t* checkmate_searcher;
00099 #ifdef OSL_SMP
00100 public:
00101 void setCheckmateSearcher(checkmate_t *new_checkmate) {
00102 checkmate_searcher = new_checkmate;
00103 }
00104 private:
00105 #endif
00106 PathEncoding current_path;
00107 MoveStack move_history;
00108 int root_depth;
00109 protected:
00110 RecordStack2 record_stack;
00111 RepetitionCounter repetition_counter;
00112 boost::shared_ptr<SearchState2Shared> shared;
00113 public:
00114 typedef FixedCapacityVector<Move,MaxDepth> PVVector;
00115 protected:
00116 CArray<PVVector,MaxDepth> pv;
00117 enum NodeType { PvNode = 0, AllNode = 1, CutNode = -1, };
00118 CArray<NodeType,MaxDepth> node_type;
00119 public:
00121 volatile bool stop_tree;
00122 #ifndef MINIMAL
00123 static CArray<int, MaxDepth> depth_node_count_quiesce;
00124 #endif
00125 SearchState2Core(const NumEffectState& s, checkmate_t& checker);
00126 virtual ~SearchState2Core();
00127 int curDepth() const { return history().size() - root_depth; }
00128
00135 virtual void setState(const NumEffectState& s);
00136 void setHistory(const MoveStack& h);
00137 bool hasLastRecord(unsigned int n=0) const
00138 {
00139 return record_stack.hasLastRecord(n);
00140 }
00141 SimpleHashRecord* lastRecord(unsigned int n=0)
00142 {
00143 return record_stack.lastRecord(n);
00144 }
00145 const SimpleHashRecord* lastRecord(unsigned int n=0) const
00146 {
00147 return record_stack.lastRecord(n);
00148 }
00149 SimpleHashRecord *rootRecord()
00150 {
00151 return record_stack.rootRecord();
00152 }
00153 void setCurrentRecord(SimpleHashRecord *r)
00154 {
00155 search_assert((int)record_stack.size() == curDepth()+1);
00156 record_stack.setLastRecord(r);
00157 }
00158 void setRootRecord(SimpleHashRecord *root)
00159 {
00160 search_assert(record_stack.size() == 1);
00161 search_assert(curDepth() == 0);
00162 record_stack.setRootRecord(root);
00163 }
00164
00165
00166 void setKillerMove(Move best_move)
00167 {
00168 if (best_move.isPass())
00169 return;
00170 shared->killer_moves.setMove(curDepth(), best_move);
00171 const Move last_move = lastMove();
00172 if (! last_move.isInvalid()) {
00173 search_assert(best_move.player() != last_move.player());
00174 shared->bigram_killers.setMove(last_move, best_move);
00175 }
00176 }
00177 void getBigramKillerMoves(MoveVector& moves) const
00178 {
00179 shared->bigram_killers.getMove(state(), lastMove(), moves);
00180 #ifdef TRI_PLY_BIGRAM_KILLERS
00181 if (move_history.hasLastMove(3))
00182 shared->bigram_killers.getMove(state(), lastMove(3), moves);
00183 #endif
00184 }
00185 void getKillerMoves(MoveVector& moves) const
00186 {
00187 getBigramKillerMoves(moves);
00188 shared->killer_moves.getMove(state(), curDepth(), moves);
00189 }
00190 const BigramKillerMove& bigramKillerMove() const {
00191 return shared->bigram_killers;
00192 }
00193 void setBigramKillerMove(const BigramKillerMove& killers);
00194 HistoryTable& historyTable() { return shared->history_table; }
00195 const HistoryTable& historyTable() const { return shared->history_table; }
00196
00197 void pushPass()
00198 {
00199 const Move pass = Move::PASS(current_state.getTurn());
00200 current_state.changeTurn();
00201 current_path.pushMove(pass);
00202 move_history.push(pass);
00203 }
00204 void popPass()
00205 {
00206 const Move pass = Move::PASS(alt(current_state.getTurn()));
00207 current_state.changeTurn();
00208 current_path.popMove(pass);
00209 move_history.pop();
00210 }
00211 private:
00215 void pushBeforeApply(Move move)
00216 {
00217 move_history.push(move);
00218 record_stack.push(0);
00219 assert(curDepth() > 0);
00220 node_type[curDepth()] = static_cast<NodeType>(-node_type[curDepth()-1]);
00221 }
00222 struct Updator
00223 {
00224 const HashKey& new_hash;
00225 SearchState2Core *state;
00226 Updator(const HashKey& h, SearchState2Core *s)
00227 : new_hash(h), state(s)
00228 {
00229 }
00230 void update()
00231 {
00232 state->updateRepetitionCounterAfterMove(new_hash);
00233 }
00234 };
00235 template <class Function>
00236 struct UpdateWrapper : public Updator
00237 {
00238 Function& function;
00239 UpdateWrapper(const HashKey& h, SearchState2Core *s, Function& f)
00240 : Updator(h, s), function(f)
00241 {
00242 }
00243 void operator()(Position to)
00244 {
00245 update();
00246 function(to);
00247 }
00248 };
00249 friend class Updator;
00253 void updateRepetitionCounterAfterMove(const HashKey& new_hash)
00254 {
00255 repetition_counter.push(new_hash, current_state);
00256 }
00260 void popAfterApply()
00261 {
00262 record_stack.pop();
00263 repetition_counter.pop();
00264 move_history.pop();
00265 }
00266 #ifndef NDEBUG
00267 void makeMoveHook(Move);
00268 #endif
00269 public:
00273 template <Player P, class Function>
00274 void doUndoMoveOrPass(const HashKey& new_hash,
00275 Move move, Function& f)
00276 {
00277 pushBeforeApply(move);
00278 #ifndef NDEBUG
00279 makeMoveHook(move);
00280 #endif
00281 UpdateWrapper<Function> wrapper(new_hash, this, f);
00282 ApplyMoveWithPath<P>::doUndoMoveOrPass(current_state, current_path,
00283 move, wrapper);
00284 popAfterApply();
00285 }
00286 void makeMove(Move move)
00287 {
00288 HashKey new_hash = currentHash().newHashWithMove(move);
00289 pushBeforeApply(move);
00290 ApplyMoveOfTurn::doMove(current_state, 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 ApplyMoveWithPath<P>::doUndoMoveOrPass
00317 (static_cast<NumEffectState&>(current_state), current_path,
00318 move, f);
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.getTurn() == 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.getTurn());
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 Position king = state().getKingPosition(state().getTurn());
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 countCheckAfterThreatmate(Player turn, int depth=1) const
00454 {
00455 assert(((depth % 2) && state().getTurn() == turn)
00456 || ((depth % 2) == 0 && state().getTurn() != turn));
00457 int result = 0;
00458 for (int i=depth;; i+=2) {
00459 if (! hasLastRecord(i) || ! lastRecord(i))
00460 break;
00461 if (lastRecord(i)->qrecord.threatmate.status(turn).status()
00462 != ThreatmateState::CHECK_AFTER_THREATMATE)
00463 break;
00464 ++result;
00465 }
00466 return result;
00467 }
00468 int countCheckAfterThreatmateSacrifice(Player turn, int depth=1) const
00469 {
00470 assert(((depth % 2) && state().getTurn() == turn)
00471 || ((depth % 2) == 0 && state().getTurn() != turn));
00472 assert(depth > 0);
00473 int result = 0;
00474 for (int i=depth;; i+=2) {
00475 if (! hasLastRecord(i) || ! lastRecord(i))
00476 break;
00477 if (lastRecord(i)->qrecord.threatmate.status(turn).status()
00478 != ThreatmateState::CHECK_AFTER_THREATMATE)
00479 break;
00480 if (lastMove(i-1).capturePtype() != PTYPE_EMPTY)
00481 ++result;
00482 }
00483 return result;
00484 }
00485 };
00486
00487 #undef search_assert
00488 #undef search_assert2
00489 #define search_assert(x) assert((x) || SearchState2Core::abort())
00490 #define search_assert2(x, m) assert((x) || SearchState2Core::abort(m))
00491
00494 class SearchState2 : public SearchState2Core
00495 {
00496 public:
00498 static const int ReSearchLimitMargin = 80;
00499 protected:
00500 int root_limit;
00501 int cur_limit;
00502 public:
00503 SearchState2(const NumEffectState& s, checkmate_t& checker);
00504 virtual ~SearchState2();
00505
00506 void setState(const NumEffectState& s);
00507 void setKillerMove(Move best_move)
00508 {
00509 if (best_move.isPass())
00510 return;
00511 SearchState2Core::setKillerMove(best_move);
00512 }
00513
00514 int curLimit() const { return cur_limit; }
00515
00516 bool abort(Move) const;
00517
00518 protected:
00522 void setRoot(int limit)
00523 {
00524 root_limit = limit;
00525 cur_limit = limit;
00526 }
00527 void addLimit(int limit) { cur_limit += limit; search_assert(cur_limit >= 0); }
00528 void subLimit(int limit) { cur_limit -= limit; search_assert(cur_limit >= 0); }
00529
00533 int countSacrificeCheck2(int history_max) const;
00535 void checkPointSearchAllMoves();
00536 };
00537 }
00538 }
00539
00540 #undef search_assert
00541 #undef search_assert2
00542
00543 #endif
00544
00545
00546
00547