00001
00002
00003 #ifndef _QUIESCENCERECORD_H
00004 #define _QUIESCENCERECORD_H
00005
00006 #include "osl/search/dualThreatmateState.h"
00007 #include "osl/ptype.h"
00008 #include "osl/move.h"
00009 #include "osl/container/moveVector.h"
00010 #include "osl/stl/vector.h"
00011 #include <iosfwd>
00012 #ifdef OSL_SMP
00013 # include "osl/misc/lightMutex.h"
00014 #endif
00015
00016 namespace osl
00017 {
00018 namespace search
00019 {
00020 struct QSearchTraits
00021 {
00022 enum {
00024 MaxDepth = 8,
00026 CheckmateSpecialDepth = 127,
00028 HistorySpecialDepth = 126,
00029 };
00030 enum { FirstThreat = 6, SecondThreat = 2 };
00031 enum MoveType {
00032 UNKNOWN, KING_ESCAPE, CAPTURE, PROMOTE, CHECK,
00033 ESCAPE, ATTACK, OTHER,
00034 };
00035 };
00036
00040 struct QuiescenceThreat
00041 {
00042 int value;
00043 Move move;
00044 explicit QuiescenceThreat(int v=0, Move m=Move::INVALID())
00045 : value(v), move(m)
00046 {
00047 }
00048 };
00049
00050 struct BestMoves : public CArray<Move,4>
00051 {
00052 BestMoves()
00053 {
00054
00055 }
00056 size_t capacity() const { return size(); }
00057 size_t sizeFilled() const
00058 {
00059 for (size_t i=0; i<capacity(); ++i)
00060 if (! operator[](i).isNormal())
00061 return i;
00062 return capacity();
00063 }
00064 void add(Move m)
00065 {
00066 if (! m.isNormal())
00067 return;
00068 iterator p = std::find(begin(), end(), m);
00069 if (p != end()) {
00070 std::rotate(begin(), p, p+1);
00071 return;
00072 }
00073 size_t size = sizeFilled();
00074 if (size == capacity())
00075 operator[](capacity()-1) = m;
00076 else
00077 operator[](size++) = m;
00078 std::rotate(begin(), begin()+(int)size-1, begin()+(int)size);
00079 }
00080 void clear()
00081 {
00082 fill(Move());
00083 }
00084 void addSecondary(const MoveVector& v)
00085 {
00086 CArray<Move,4> copy = *this;
00087 clear();
00088 size_t size = 0;
00089 if (copy[0].isNormal())
00090 operator[](size++) = copy[0];
00091 for (size_t i=0; i<v.size() && size<capacity(); ++i) {
00092 assert(v[i].isNormal());
00093 if (std::find(begin(), begin()+(int)size, v[i]) == begin()+(int)size)
00094 operator[](size++) = v[i];
00095 }
00096 for (size_t i=1; i<copy.size() && copy[i].isNormal() && size<capacity(); ++i)
00097 if (std::find(begin(), begin()+(int)size, copy[i]) == begin()+(int)size)
00098 operator[](size++) = copy[i];
00099 }
00100 };
00101
00105 struct QuiescenceRecordBase
00106 {
00107 int upper_bound, lower_bound;
00108 BestMoves best_moves;
00110 QuiescenceThreat threat1, threat2;
00111 int static_value;
00112 int checkmate_nodes;
00113 DualThreatmateState threatmate;
00114 int threatmate_nodes;
00116 int8_t upper_depth, lower_depth, static_value_depth;
00117 public:
00122 enum { InitialDepth = -128, };
00123 enum StaticValueType { UNKNOWN, UPPER_BOUND, EXACT };
00124 protected:
00125 QuiescenceRecordBase()
00126 : checkmate_nodes(0), threatmate_nodes(0),
00127 upper_depth(InitialDepth), lower_depth(InitialDepth),
00128 static_value_depth(InitialDepth)
00129 {
00130 }
00131 ~QuiescenceRecordBase() {}
00132 };
00133 class SimpleHashRecord;
00137 class QuiescenceRecord : public QuiescenceRecordBase
00138 {
00139 public:
00140 static const char *toString(StaticValueType);
00141 private:
00142 #ifdef OSL_SMP
00143 typedef osl::misc::LightMutexChar Mutex;
00144 mutable Mutex mutex;
00145 #endif
00146 public:
00147 QuiescenceRecord()
00148 {
00149 }
00153 QuiescenceRecord(const QuiescenceRecord& src)
00154 : QuiescenceRecordBase(src)
00155 {
00156 }
00157 QuiescenceRecord& operator=(const QuiescenceRecord& src)
00158 {
00159 if (this == &src)
00160 return *this;
00161
00162 QuiescenceRecordBase::operator=(src);
00163 return *this;
00164 }
00165
00166 template <Player Turn>
00167 const Square8 sendOffSquare(const NumEffectState& state) const
00168 {
00169 #ifdef OSL_SMP
00170 SCOPED_LOCK_CHAR(lk,mutex);
00171 #endif
00172 assert(Turn == state.turn());
00173 Square8 ret;
00174 const Square king_position = state.kingSquare(alt(Turn));
00175 if (threatmate.sendoffs == SendOffSquare::invalidData())
00176 threatmate.sendoffs = SendOffSquare::find<Turn>(state, king_position, ret);
00177 else
00178 SendOffSquare::unpack(threatmate.sendoffs, king_position, ret);
00179 return ret;
00180 }
00181 const Square8
00182 sendOffSquare(Player turn, const NumEffectState& state) const
00183 {
00184 if (turn == BLACK)
00185 return sendOffSquare<BLACK>(state);
00186 else
00187 return sendOffSquare<WHITE>(state);
00188 }
00193 int checkmateNodesLeft(int max)
00194 {
00195 #ifdef OSL_SMP
00196 SCOPED_LOCK_CHAR(lk,mutex);
00197 #endif
00198 if (max > checkmate_nodes)
00199 {
00200 const int left = max - checkmate_nodes;
00201 checkmate_nodes = max;
00202 return left;
00203 }
00204 return 0;
00205 }
00210 int threatmateNodesLeft(int max)
00211 {
00212 #ifdef OSL_SMP
00213 SCOPED_LOCK_CHAR(lk,mutex);
00214 #endif
00215 if (max > threatmate_nodes)
00216 {
00217 const int left = max - threatmate_nodes;
00218 threatmate_nodes = max;
00219 return left;
00220 }
00221 return 0;
00222 }
00224 int checkmateNodes() const { return checkmate_nodes; }
00225 int threatmateNodes() const { return threatmate_nodes; }
00226
00227 void clear()
00228 {
00229 #ifdef OSL_SMP
00230 SCOPED_LOCK_CHAR(lk,mutex);
00231 #endif
00232 best_moves.clear();
00233 upper_depth = lower_depth = static_value_depth = InitialDepth;
00234 }
00235 void setStaticValue(StaticValueType type, int value, int depth,
00236 const QuiescenceThreat& t1=QuiescenceThreat(),
00237 const QuiescenceThreat& t2=QuiescenceThreat())
00238 {
00239 #ifdef OSL_SMP
00240 SCOPED_LOCK_CHAR(lk,mutex);
00241 #endif
00242 assert((depth <= QSearchTraits::MaxDepth)
00243 || (depth == QSearchTraits::CheckmateSpecialDepth));
00244 assert(value % 2 == 0);
00245 static_value = value;
00246 threat1 = t1;
00247 threat2 = t2;
00248 static_value_depth = depth;
00249 threatmate.flags.static_value_type = type;
00250 }
00251 public:
00252 void setLowerBound(int depth, int bound, Move best_move)
00253 {
00254 #ifdef OSL_SMP
00255 SCOPED_LOCK_CHAR(lk,mutex);
00256 #endif
00257 assert((depth <= QSearchTraits::MaxDepth)
00258 || (depth == QSearchTraits::CheckmateSpecialDepth));
00259 if (depth >= lower_depth)
00260 {
00261 best_moves.add(best_move);
00262 lower_bound = bound;
00263 lower_depth = depth;
00264 }
00265 }
00266 void setUpperBound(int depth, int bound)
00267 {
00268 #ifdef OSL_SMP
00269 SCOPED_LOCK_CHAR(lk,mutex);
00270 #endif
00271 assert((depth <= QSearchTraits::MaxDepth)
00272 || (depth == QSearchTraits::CheckmateSpecialDepth));
00273 if (depth >= upper_depth)
00274 {
00275 upper_bound = bound;
00276 upper_depth = depth;
00277 }
00278 }
00279 void setHistoryValue(int value)
00280 {
00281 lower_bound = upper_bound = value;
00282 lower_depth = upper_depth = QSearchTraits::HistorySpecialDepth;
00283 }
00284 void setHistoryValue(Move best_move, int value)
00285 {
00286 #ifdef OSL_SMP
00287 SCOPED_LOCK_CHAR(lk,mutex);
00288 #endif
00289 best_moves.add(best_move);
00290 setHistoryValue(value);
00291 }
00292 public:
00293 void addKillerMoves(const MoveVector& new_moves)
00294 {
00295 #ifdef OSL_SMP
00296 SCOPED_LOCK_CHAR(lk,mutex);
00297 #endif
00298 best_moves.addSecondary(new_moves);
00299 }
00300 StaticValueType staticValueType() const {
00301 return static_cast<StaticValueType>(threatmate.flags.static_value_type);
00302 }
00303 bool hasStaticValue() const { return staticValueType() != UNKNOWN; }
00304 bool hasStaticValue(int& value, int& depth, StaticValueType& type) const {
00305 type = staticValueType();
00306 if (type == UNKNOWN)
00307 return false;
00308 #ifdef OSL_SMP
00309 SCOPED_LOCK_CHAR(lk,mutex);
00310 #endif
00311 type = staticValueType();
00312 value = static_value;
00313 depth = static_value_depth;
00314 return type != UNKNOWN;
00315 }
00316 int staticValue() const { assert(hasStaticValue()); return static_value; }
00317 int staticValueDepth() const { return static_value_depth; }
00318 int upperDepth() const { return upper_depth; }
00319 int lowerDepth() const { return lower_depth; }
00320 int upperBound() const { return upper_bound; }
00321 int lowerBound() const { return lower_bound; }
00322 const Move bestMove() const { return best_moves[0]; }
00323 int movesEmpty() const { return ! best_moves[1].isNormal(); }
00324 int movesSizeLessThan(size_t n) const {
00325 return best_moves.capacity() < n || ! best_moves[n-1].isNormal();
00326 }
00327 int moves_size() const {
00328 return std::max(0, (int)best_moves.sizeFilled()-1);
00329 }
00330 void loadMoves(MoveVector& dst) const{
00331 #ifdef OSL_SMP
00332 SCOPED_LOCK_CHAR(lk,mutex);
00333 #endif
00334 dst.clear();
00335 for (size_t i=1; i<best_moves.capacity() && best_moves[i].isNormal(); ++i)
00336 dst.push_back(best_moves[i]);
00337 }
00338 void dump(std::ostream&) const;
00339 const QuiescenceThreat staticThreat(int index) const
00340 {
00341 return (index == 0) ? threat1 : threat2;
00342 }
00343 void updateThreatmate(Player turn, const DualThreatmateState *parent, bool in_check)
00344 {
00345 #ifdef OSL_SMP
00346 SCOPED_LOCK_CHAR(lk,mutex);
00347 #endif
00348 threatmate.updateInLock(turn, parent, in_check);
00349 }
00350 friend class SimpleHashRecord;
00351 };
00352
00353 }
00354 }
00355
00356 #endif
00357
00358
00359
00360