00001
00002
00003 #ifndef OSL_ALPHA_BETA2_H
00004 #define OSL_ALPHA_BETA2_H
00005
00006 #include "osl/search/realizationProbability.h"
00007 #include "osl/search/searchBase.h"
00008 #include "osl/search/searchState2.h"
00009 #include "osl/search/searchRecorder.h"
00010 #include "osl/search/passCounter.h"
00011 #include "osl/search/killerMoveTable.h"
00012 #include "osl/search/searchTimer.h"
00013 #include "osl/eval/evalTraits.h"
00014 #include "osl/eval/ml/openMidEndingEval.h"
00015 #include "osl/eval/progressEval.h"
00016 #include "osl/container/moveStack.h"
00017 #include "osl/container/moveLogProbVector.h"
00018 #include "osl/stat/average.h"
00019 #include "osl/oslConfig.h"
00020 #include <boost/scoped_array.hpp>
00021 #include <boost/noncopyable.hpp>
00022 #include <iosfwd>
00023
00024 namespace osl
00025 {
00026 namespace search
00027 {
00028 class SimpleHashRecord;
00029 class SimpleHashTable;
00030 class MoveGenerator;
00031 struct MoveWithComment;
00032
00033 class AlphaBeta2Window
00034 {
00035 CArray<int,2> values;
00036 public:
00037 explicit AlphaBeta2Window(int a=0) { values.fill(a); }
00038 AlphaBeta2Window(int a, int b)
00039 {
00040 values[0] = a;
00041 values[1] = b;
00042 }
00043 AlphaBeta2Window(Player P, int a=0, int b=0)
00044 {
00045 alpha(P) = a;
00046 beta(P) = b;
00047 }
00048 int& alpha(Player P) { return values[P]; }
00049 int& beta(Player P) { return values[alt(P)]; }
00050
00051 int alpha(Player P) const { return values[P]; }
00052 int beta(Player P) const { return values[alt(P)]; }
00053 bool isConsistent() const {
00054 return eval::notLessThan(BLACK, beta(BLACK), alpha(BLACK));
00055 }
00056 bool null() const { return values[0] == values[1]; }
00057 bool operator==(const AlphaBeta2Window& r) const
00058 {
00059 return values == r.values;
00060 }
00061 };
00062
00066 template <class EvalT>
00067 struct AlphaBeta2Common
00068 #if OSL_WORDSIZE == 32
00069 : public misc::Align16New
00070 #endif
00071 {
00072 static int rootLimitBias()
00073 {
00074 return 0;
00075 }
00076 static int leafLimit()
00077 {
00078 static int value = 300 + rootLimitBias();
00079 return value;
00080 }
00081
00082 enum { MaxDepth = SearchState2Core::MaxDepth };
00083 EvalT eval;
00084 PassCounter pass_count;
00085 enum MoveType { INITIAL, HASH=INITIAL, TACTICAL, KILLER, PASS, ALL, FINISH };
00087 CArray<MoveType, MaxDepth> move_type;
00088 CArray<bool, MaxDepth> in_pv;
00089 typedef FixedCapacityVector<Move,4> killer_t;
00090 CArray<killer_t, MaxDepth> killers;
00091 const MoveVector *root_ignore_moves;
00092 bool prediction_for_speculative_search;
00094 int multi_pv;
00095
00096 explicit AlphaBeta2Common(const NumEffectState& s)
00097 : eval(s), root_ignore_moves(0), prediction_for_speculative_search(false),
00098 multi_pv(0)
00099 {
00100 in_pv[0] = true;
00101 }
00102 };
00103 struct RootPV
00104 {
00105 SearchState2::PVVector pv;
00106 int depth, eval;
00107 RootPV(int root_limit, const SearchState2::PVVector &p, int v)
00108 : pv(p), depth(root_limit), eval(v)
00109 {
00110 }
00111 };
00112 struct AlphaBeta2SharedRoot
00113 {
00115 vector<int> root_values, root_values_for_iteration;
00116 vector<Move> best_move_for_iteration;
00118 vector<RootPV> last_pv;
00120 Move last_root_move;
00122 int last_root_value_update;
00123 AlphaBeta2SharedRoot() : last_root_value_update(0)
00124 {
00125 }
00126 void showLastPv(int limit) const;
00127 int sameBestMoves() const
00128 {
00129 int ret = 0;
00130 for (int i=best_move_for_iteration.size()-2; i>=0; --i, ++ret)
00131 if (best_move_for_iteration[i] != best_move_for_iteration[i+1])
00132 break;
00133 return ret;
00134 }
00135 };
00136
00137 template <class EvalT> struct AlphaBeta2Parallel;
00141 template <class EvalT>
00142 class AlphaBeta2Tree
00143 : public SearchBase<EvalT,SimpleHashTable,CountRecorder,RealizationProbability>,
00144 public SearchState2, public SearchTimer, protected AlphaBeta2Common<EvalT>, boost::noncopyable
00145 {
00146 public:
00147 typedef EvalT eval_t;
00148 typedef AlphaBeta2Common<EvalT> common_t;
00149 enum { MaxDepth = SearchState2Core::MaxDepth };
00150 protected:
00152 size_t node_count;
00153 FixedCapacityVector<MoveGenerator*, MaxDepth> generators;
00154 stat::Average mpn, mpn_cut, alpha_update, last_alpha_update;
00155 stat::Average ext, ext_limit;
00156 boost::shared_ptr<AlphaBeta2Parallel<EvalT> > shared;
00157 boost::shared_ptr<AlphaBeta2SharedRoot> shared_root;
00158 protected:
00159 static CArray<int, SearchState2Core::MaxDepth> depth_node_count;
00160 AlphaBeta2Tree(const NumEffectState& s, checkmate_t& checker,
00161 SimpleHashTable *t, CountRecorder&);
00162
00163 AlphaBeta2Tree(const AlphaBeta2Tree& src, AlphaBeta2Parallel<EvalT> *);
00164 ~AlphaBeta2Tree();
00165 private:
00166 void throwStop();
00167 public:
00168 struct BetaCut {};
00169 bool stopping() const
00170 {
00171 return stop_tree || SearchTimer::stopping();
00172 }
00173 void testStop() {
00174 throwIfNoMoreTime(this->recorder.allNodeCount());
00175 if (stop_tree)
00176 throw BetaCut();
00177 }
00178 public:
00179 typedef AlphaBeta2Window Window;
00180 size_t nodeCount() const { return node_count; }
00181 static int rootAlpha(Player P, int last_value, Progress16 progress);
00182 static int stableThreshold(Player P, int last_value);
00183
00184 template <Player P>
00185 const MoveLogProb nextMove();
00186 protected:
00187 void updateRootPV(Player P, std::ostream&, int, Move);
00188 void addMultiPV(Player P, int, Move);
00189 bool isStable(Player P, int new_value) const;
00190 void showFailLow(int result, Move m) const;
00191 private:
00192 void showPV(std::ostream&, int, Move, char stable) const;
00193 public:
00194 template <Player P> struct NextMove;
00195 friend struct NextMove<BLACK>;
00196 friend struct NextMove<WHITE>;
00197 template <Player P> struct NextQMove;
00198 friend struct NextQMove<BLACK>;
00199 friend struct NextQMove<WHITE>;
00200 protected:
00209 template <Player P>
00210 int alphaBetaSearch(const MoveLogProb& move, Window window,
00211 bool in_pv);
00212 template <Player P>
00213 int alphaBetaSearchAfterMove(const MoveLogProb& move,
00214 Window window, bool in_pv);
00215 template <Player P> int quiesce(Window);
00216 template <Player P> int quiesceStable(Window);
00217 template <Player P> int quiesceExp(Window);
00218
00219 template <Player P>
00220 int searchAllMoves(SimpleHashRecord*, Window w);
00221 template <Player P>
00222 int searchAllMoves(Move m, int limit_consumption,
00223 SimpleHashRecord*, Window w);
00224
00226 template <Player P>
00227 bool tryCheckmate(SimpleHashRecord *record, bool in_pv, Move& checkmate_move);
00229 template <Player P>
00230 bool tryCheckmateAgain(SimpleHashRecord *record, Move& checkmate_move,
00231 int node_count,
00232 int best_value);
00233
00235 template <Player P>
00236 void testThreatmate(SimpleHashRecord *record, bool in_pv);
00237
00239 template <Player P>
00240 void examineMovesRoot(const MoveLogProbVector&, size_t, Window,
00241 MoveLogProb&, int&);
00242
00243 template <Player P> int quiesceRoot(Window, int depth_left, Move& best_move, DualThreatmateState);
00244 template <Player P> int quiesce(Window, int depth_left, DualThreatmateState);
00245 template <Player P>
00246 bool quiesceWithMove(Move, Window&, int, Move&, int&, const DualThreatmateState&);
00247
00248 void updateCheckmateCount();
00249 bool tryPass(SimpleHashRecord *record, Player P) const;
00250 MoveGenerator& makeGenerator();
00251 static MoveGenerator *alloc();
00252 static void dealloc(MoveGenerator *);
00253 #ifdef OSL_SMP
00254 public:
00255 friend struct AlphaBeta2Parallel<EvalT>;
00256 struct NodeProperty;
00257 template <Player P> struct SearchJob;
00258 struct SearchJobData;
00259 struct Shared;
00260 friend struct Shared;
00261 friend struct SearchJob<BLACK>;
00262 friend struct SearchJob<WHITE>;
00263 protected:
00264 template <Player P>
00265 void examineMovesRootPar(const MoveLogProbVector&, size_t, Window,
00266 MoveLogProb&, int&);
00267 void examineMovesRootPar(int tree_id);
00268 template <Player P>
00269 void testMoveRoot(int tree_id, const MoveLogProb&);
00270
00271 template <Player P>
00272 bool examineMovesOther(Window& w, MoveLogProb& best_move, int& best_value,
00273 int& tried_moves, int& alpha_update, int& last_alpha_update);
00274 void examineMovesOther(int tree_id);
00275 template <Player P>
00276 bool testMoveOther(int tree_id, const MoveLogProb&, size_t index, bool in_pv);
00277 #endif
00278 };
00279
00283 template <class EvalT>
00284 class AlphaBeta2
00285 : public AlphaBeta2Tree<EvalT>
00286 {
00287 public:
00288 typedef AlphaBeta2Tree<EvalT> base_t;
00289 typedef typename base_t::checkmate_t checkmate_t;
00290 typedef typename base_t::Window Window;
00291 public:
00292 AlphaBeta2(const NumEffectState& s, checkmate_t& checker,
00293 SimpleHashTable *t, CountRecorder&);
00294 ~AlphaBeta2();
00295
00302 template <Player P>
00303 int alphaBetaSearchRoot(Window window, MoveLogProb& best_move,
00304 int limit);
00305 static const Window fullWindow(Player P)
00306 {
00307 return Window(P, base_t::winThreshold(alt(P)), base_t::winThreshold(P));
00308 }
00309 int alphaBetaSearchRoot(Window window, MoveLogProb& best_move, int limit)
00310 {
00311 const Player P = this->state().turn();
00312 if (P == BLACK)
00313 return alphaBetaSearchRoot<BLACK>(window, best_move, limit);
00314 else
00315 return alphaBetaSearchRoot<WHITE>(window, best_move, limit);
00316 }
00317 int alphaBetaSearchRoot(MoveLogProb& best_move, int limit);
00318
00322 Move computeBestMoveIteratively(int limit,
00323 const int step=100,
00324 int initialLimit=600,
00325 size_t nodeLimit=1600000,
00326 const TimeAssigned& assign=TimeAssigned(MilliSeconds::Interval(60*1000)),
00327 MoveWithComment *additional_info=0);
00328 bool isReasonableMove(Move move, int pawn_sacrifice=1);
00329 void setRootIgnoreMoves(const MoveVector *rim, bool prediction)
00330 {
00331 assert(!prediction || rim);
00332 this->root_ignore_moves = rim;
00333 this->prediction_for_speculative_search = prediction;
00334 }
00335
00336 static void showNodeDepth(std::ostream&);
00337 static void clearNodeDepth();
00338 void enableMultiPV(unsigned int width) { this->multi_pv = width; }
00339 const AlphaBeta2SharedRoot sharedRootInfo() const { return *(this->shared_root); }
00340 public:
00341 void setRoot(int limit);
00342 void makeMove(Move);
00343 private:
00344 enum PVCheckmateStatus {
00345 PVStable, PVThreatmateNotRecord, PVThreatmate, PVCheckmate,
00346 };
00347 PVCheckmateStatus findCheckmateInPV(int verify_node, CArray<bool,2>& king_in_threat);
00348 };
00349
00350 }
00351 typedef search::AlphaBeta2<eval::ProgressEval> AlphaBeta2ProgressEval;
00352 typedef search::AlphaBeta2<eval::ml::OpenMidEndingEval> AlphaBeta2OpenMidEndingEval;
00353 }
00354
00355 #endif
00356
00357
00358
00359