00001
00002
00003 #ifndef _SEARCH_SIMPLEHASHRECORD_H
00004 #define _SEARCH_SIMPLEHASHRECORD_H
00005
00006 #include "osl/search/quiescenceRecord.h"
00007 #include "osl/search/searchTable.h"
00008 #include "osl/search/searchMoveSet.h"
00009 #include "osl/search/searchMove.h"
00010 #include "osl/checkmate/oracleAges.h"
00011 #include "osl/eval/evalTraits.h"
00012 #include "osl/category/categoryFlags.h"
00013 #ifdef OSL_SMP
00014 # include "osl/misc/lightMutex.h"
00015 #endif
00016 #include <cassert>
00017
00018 namespace osl
00019 {
00020 namespace search
00021 {
00025 struct SimpleHashRecordBase
00026 {
00027 signed short upper_limit;
00028 signed short lower_limit;
00029 int upper_bound;
00030 int lower_bound;
00031 SearchMove best_move;
00033 SearchMoveSet move_cache;
00035 unsigned int search_nodes;
00037 category::CategoryFlags used_categories;
00039 signed short limit_of_moves;
00040 SimpleHashRecordBase()
00041 : upper_limit(-1), lower_limit(-1), search_nodes(0), limit_of_moves(-1)
00042 {
00043 }
00044 };
00048 class SimpleHashRecord : private SimpleHashRecordBase
00049 {
00050 #ifdef OSL_SMP
00051 typedef osl::misc::LightMutex Mutex;
00052 mutable Mutex mutex;
00053 #endif
00054 public:
00056 QuiescenceRecord qrecord;
00057 bool is_king_in_check;
00058
00059 SimpleHashRecord() : is_king_in_check(false)
00060 {
00061 }
00065 SimpleHashRecord(const SimpleHashRecord& src)
00066 : SimpleHashRecordBase(src), qrecord(src.qrecord),
00067 is_king_in_check(src.is_king_in_check)
00068 {
00069 }
00070 SimpleHashRecord& operator=(const SimpleHashRecord& src)
00071 {
00072 if (this == &src)
00073 return *this;
00074
00075 SimpleHashRecordBase::operator=(src);
00076 qrecord = src.qrecord;
00077 is_king_in_check = src.is_king_in_check;
00078 return *this;
00079 }
00080 void addNodeCount(size_t diff)
00081 {
00082 search_nodes += diff;
00083 }
00084 void setSumNodeCountOfChildren();
00085 size_t sumOfNodeCountOfChildren() const;
00086 category::CategoryFlags& prepareGenerate(int new_limit, int margin)
00087 {
00088 #ifdef OSL_SMP
00089 Mutex::scoped_lock lk(mutex);
00090 #endif
00091 if (limit_of_moves + margin < new_limit)
00092 {
00093 used_categories.clear();
00094 limit_of_moves = new_limit;
00095 }
00096 return used_categories;
00097 }
00098
00102 void setAbsoluteValue(Move best_move, int value, int limit)
00103 {
00104 #ifdef OSL_SMP
00105 Mutex::scoped_lock lk(mutex);
00106 #endif
00107 lower_limit = limit;
00108 lower_bound = value;
00109 upper_limit = limit;
00110 upper_bound = value;
00111 this->best_move = SearchMove(MoveLogProb(best_move, value));
00112 }
00113 void setBestMove(SearchMove m)
00114 {
00115
00116 #ifdef OSL_SMP
00117 if (best_move.validMove() && ! m.record)
00118 return;
00119 #else
00120 assert(! best_move.validMove()
00121 || (best_move.getMove() == m.getMove() && m.record));
00122 #endif
00123 best_move = m;
00124 }
00125 void setAbsoluteValue(MoveLogProb best_move, int value, int limit)
00126 {
00127 #ifdef OSL_SMP
00128 Mutex::scoped_lock lk(mutex);
00129 #endif
00130 lower_limit = limit;
00131 lower_bound = value;
00132 upper_limit = limit;
00133 upper_bound = value;
00134 this->best_move = SearchMove(best_move);
00135 }
00136
00142 void setLowerBound(Player P, int limit, const SearchMove& best_move,
00143 int value)
00144 {
00145 #ifdef OSL_SMP
00146 Mutex::scoped_lock lk(mutex);
00147 #endif
00148 assert((value % 2) == 0);
00149 assert(limit >= 0);
00150 if (limit < lower_limit)
00151 return;
00152 if (best_move.validMove()
00153 && ((! this->best_move.moveLogProb().validMove())
00154 || (limit > lower_limit)
00155 || eval::betterThan(P, value, lower_bound)))
00156 {
00157 this->best_move= best_move;
00158 }
00159 lower_bound = value;
00160 lower_limit = limit;
00161 if (hasUpperBound(0))
00162 makeConsistent<true>(P);
00163 }
00164
00170 void setUpperBound(Player P, int limit, const SearchMove& best_move,
00171 int value)
00172 {
00173 #ifdef OSL_SMP
00174 Mutex::scoped_lock lk(mutex);
00175 #endif
00176 assert((value % 2) == 0);
00177 assert(limit >= 0);
00178 if (limit < upper_limit)
00179 return;
00180 if (best_move.validMove()
00181 && (! this->best_move.moveLogProb().validMove()))
00182 {
00183
00184 this->best_move= best_move;
00185 }
00186 upper_bound = value;
00187 upper_limit = limit;
00188 if (hasLowerBound(0))
00189 makeConsistent<false>(P);
00190 }
00191 private:
00197 template <bool PreferLowerBound>
00198 void makeConsistent(Player P)
00199 {
00200 assert(hasLowerBound(0) && hasUpperBound(0));
00201 if (! eval::betterThan(P, lower_bound, upper_bound))
00202 return;
00203 if ((upper_limit < lower_limit)
00204 || (PreferLowerBound && (upper_limit == lower_limit)))
00205 {
00206 upper_bound = lower_bound;
00207 assert((upper_bound % 2) == 0);
00208 }
00209 else
00210 {
00211 lower_bound = upper_bound;
00212 assert((lower_bound % 2) == 0);
00213 }
00214 }
00215 public:
00217 int upperLimit() const { return upper_limit; }
00219 int upperBound() const { return upper_bound; }
00221 int lowerLimit() const { return lower_limit; }
00223 int lowerBound() const { return lower_bound; }
00225 int checkmateNodes() const { return qrecord.checkmate_nodes; }
00226 int threatmateNodes() const { return qrecord.threatmate_nodes; }
00227 const SearchMove bestMove() const {
00228 #ifdef OSL_SMP
00229 Mutex::scoped_lock lk(mutex);
00230 #endif
00231 return best_move;
00232 }
00233 SearchMoveSet& moves() { return move_cache; }
00234 const SearchMoveSet& moves() const { return move_cache; }
00235
00236 bool hasUpperBound(int limit) const
00237 {
00238 return (upperLimit() >= limit);
00239 }
00240 bool hasLowerBound(int limit) const
00241 {
00242 return (lowerLimit() >= limit);
00243 }
00244 bool hasAbsoluteUpperBound(Player p, int limit) const
00245 {
00246 return (p == BLACK) ? hasUpperBound(limit) : hasLowerBound(limit);
00247 }
00248 bool hasAbsoluteLowerBound(Player p, int limit) const
00249 {
00250 return (p == BLACK) ? hasLowerBound(limit) : hasUpperBound(limit);
00251 }
00252 int absoluteUpperBound(Player p) const
00253 {
00254 return (p == BLACK) ? upperBound() : lowerBound();
00255 }
00256 int absoluteLowerBound(Player p) const
00257 {
00258 return (p == BLACK) ? lowerBound() : upperBound();
00259 }
00260 void resetValue()
00261 {
00262 #ifdef OSL_SMP
00263 Mutex::scoped_lock lk(mutex);
00264 #endif
00265 lower_limit = -1;
00266 upper_limit = -1;
00267 }
00269 template <Player P>
00270 bool hasGreaterLowerBound(int limit, int threshold, int& val) const
00271 {
00272 #ifdef OSL_SMP
00273 Mutex::scoped_lock lk(mutex);
00274 #endif
00275 if ((lowerLimit() < limit)
00276 || (EvalTraits<P>::betterThan(threshold, lowerBound())))
00277 return false;
00278 val = lowerBound();
00279 return true;
00280 }
00282 template <Player P>
00283 bool hasLesserUpperBound(int limit, int threshold, int& val) const
00284 {
00285 #ifdef OSL_SMP
00286 Mutex::scoped_lock lk(mutex);
00287 #endif
00288 if ((upperLimit() < limit)
00289 || (EvalTraits<P>::betterThan(upperBound(), threshold)))
00290 return false;
00291 val = upperBound();
00292 return true;
00293 }
00294
00295 const DualThreatmateState& threatmate() const { return qrecord.threatmate; }
00296 DualThreatmateState& threatmate() { return qrecord.threatmate; }
00297
00298 void dump(std::ostream&) const;
00299
00301 void copyFrom(const SimpleHashRecord&);
00303 void fixBestMove();
00304
00305 size_t nodeCount() const { return search_nodes; }
00306 double nodeRatio(Move) const;
00307 void dumpNodeCount(std::ostream& os, size_t) const;
00308 };
00309 }
00310
00311 using search::SimpleHashRecord;
00312 }
00313
00314
00315 #endif
00316
00317
00318
00319