00001
00002
00003 #ifndef _QUIESCENCERECORD_H
00004 #define _QUIESCENCERECORD_H
00005
00006 #include "osl/search/dualThreatmateState.h"
00007 #include "osl/checkmate/oracleAges.h"
00008 #include "osl/checkmate/king8Info.h"
00009 #include "osl/effect_util/sendOffPosition.h"
00010 #include "osl/ptype.h"
00011 #include "osl/move.h"
00012 #include "osl/container/moveVector.h"
00013 #include "osl/stl/vector.h"
00014 #include <iosfwd>
00015 #ifdef OSL_SMP
00016 # include "osl/misc/lightMutex.h"
00017 #endif
00018
00019 namespace osl
00020 {
00021 namespace search
00022 {
00023 struct QSearchTraits
00024 {
00025 enum {
00027 MaxDepth = 8,
00029 CheckmateSpecialDepth = 127,
00031 HistorySpecialDepth = 126,
00032 };
00033 enum { FirstThreat = 6, SecondThreat = 2 };
00034 enum MoveType {
00035 UNKNOWN, KING_ESCAPE, CAPTURE, PROMOTE, CHECK,
00036 ESCAPE, ATTACK, OTHER,
00037 };
00038 };
00039
00040 struct QuiescenceFlags
00041 {
00042 unsigned int data;
00043 enum Flags {
00048 KING_ESCAPE = KING, PROMOTE = PTYPE_EMPTY, CHECK = PTYPE_EDGE,
00049 DROP = PTYPE_SIZE, ALL_ESCAPE, MAJOR_PIECE_ATTACK, KNIGHT_ATTACK,
00050 GOLDSILVER_ATTACK,
00051 ADVANCE_BISHOP, KING8_ATTACK, ESCAPE_FROM_LAST_MOVE,
00052 PINNED_ATTACK, UTILIZE_PROMOTED, BREAK_THREATMATE, KING_WALK,
00053
00054 LAST_FLAG,
00055 };
00056 QuiescenceFlags() : data(0)
00057 {
00058 }
00059 private:
00060 bool isGenerated(int type) const
00061 {
00062 return data & (1u << type);
00063 }
00064 void recordGeneration(int type)
00065 {
00066 data |= (1u << type);
00067 }
00068 public:
00069 bool isGenerated(Ptype ptype) const
00070 {
00071 return isGenerated(static_cast<int>(ptype));
00072 }
00073 void recordGeneration(Ptype ptype)
00074 {
00075 recordGeneration(static_cast<int>(ptype));
00076 }
00077 bool isGenerated(Flags f) const
00078 {
00079 return isGenerated(static_cast<int>(f));
00080 }
00081 void recordGeneration(Flags f)
00082 {
00083 recordGeneration(static_cast<int>(f));
00084 }
00085 void clear()
00086 {
00087 data = 0;
00088 }
00089 };
00090
00094 struct QuiescenceThreat
00095 {
00096 int value;
00097 Move move;
00098 explicit QuiescenceThreat(int v=0, Move m=Move::INVALID())
00099 : value(v), move(m)
00100 {
00101 }
00102 };
00103
00107 struct QuiescenceRecordBase
00108 {
00109 int upper_bound, lower_bound;
00110 vector<Move> move_cache;
00111 QuiescenceFlags flags;
00112 Move best_move;
00113 int static_value;
00115 QuiescenceThreat threat1, threat2;
00116 int checkmate_nodes;
00117 int threatmate_nodes;
00118 mutable Position8 sendoffs;
00119 mutable King8Info king8info;
00121 char upper_depth, lower_depth, static_value_depth;
00122 char static_value_type;
00123 mutable bool sendoffs_initialized, king8info_initialized;
00124 bool visited;
00125 public:
00130 enum { InitialDepth = -128, };
00131 enum StaticValueType { UNKNOWN, UPPER_BOUND, EXACT };
00132 protected:
00133 QuiescenceRecordBase()
00134 : best_move(Move::INVALID()), checkmate_nodes(0), threatmate_nodes(0),
00135 king8info(0),
00136 upper_depth(InitialDepth), lower_depth(InitialDepth),
00137 static_value_depth(InitialDepth),
00138 static_value_type(UNKNOWN), sendoffs_initialized(false),
00139 king8info_initialized(false), visited(false)
00140 {
00141 }
00142 ~QuiescenceRecordBase() {}
00143 };
00144
00148 class QuiescenceRecord : public QuiescenceRecordBase
00149 {
00150 public:
00151 static const char *toString(StaticValueType);
00152 private:
00153 #ifdef OSL_SMP
00154 typedef osl::misc::LightMutex Mutex;
00155 mutable Mutex mutex;
00156 #endif
00157 public:
00158 DualThreatmateState threatmate;
00160 AttackOracleAges attack_oracle, threatmate_oracle;
00161 QuiescenceRecord()
00162 {
00163 }
00167 QuiescenceRecord(const QuiescenceRecord& src)
00168 : QuiescenceRecordBase(src), threatmate(src.threatmate),
00169 attack_oracle(src.attack_oracle),
00170 threatmate_oracle(src.threatmate_oracle)
00171 {
00172 }
00173 QuiescenceRecord& operator=(const QuiescenceRecord& src)
00174 {
00175 if (this == &src)
00176 return *this;
00177
00178 QuiescenceRecordBase::operator=(src);
00179 threatmate = src.threatmate;
00180 attack_oracle = src.attack_oracle;
00181 threatmate_oracle = src.threatmate_oracle;
00182 return *this;
00183 }
00184
00185 template <Player Turn>
00186 const Position8& sendOffPosition(const NumEffectState& state) const
00187 {
00188 #ifdef OSL_SMP
00189 Mutex::scoped_lock lk(mutex);
00190 #endif
00191 assert(Turn == state.getTurn());
00192 if (! sendoffs_initialized)
00193 {
00194 const Position king_position = state.getKingPosition(alt(Turn));
00195 effect_util::SendOffPosition::find<Turn>(state, king_position,
00196 sendoffs);
00197 sendoffs_initialized = true;
00198 }
00199 return sendoffs;
00200 }
00201 const Position8&
00202 sendOffPosition(Player turn, const NumEffectState& state) const
00203 {
00204 if (turn == BLACK)
00205 return sendOffPosition<BLACK>(state);
00206 else
00207 return sendOffPosition<WHITE>(state);
00208 }
00209 private:
00210 void makeKing8InfoInLock(const NumEffectState& state, PieceMask pins) const
00211 {
00212 if (! king8info_initialized)
00213 {
00214 king8info = King8Info::makeWithPin(state.getTurn(), state, pins);
00215 king8info_initialized = true;
00216 }
00217 }
00218 public:
00219 const King8Info&
00220 king8Info(const NumEffectState& state, const PieceMask& pin) const
00221 {
00222 #ifdef OSL_SMP
00223 Mutex::scoped_lock lk(mutex);
00224 #endif
00225 makeKing8InfoInLock(state, pin);
00226 return king8info;
00227 }
00228
00233 int checkmateNodesLeft(int max)
00234 {
00235 #ifdef OSL_SMP
00236 Mutex::scoped_lock lk(mutex);
00237 #endif
00238 if (max > checkmate_nodes)
00239 {
00240 const int left = max - checkmate_nodes;
00241 checkmate_nodes = max;
00242 return left;
00243 }
00244 return 0;
00245 }
00250 int threatmateNodesLeft(int max)
00251 {
00252 #ifdef OSL_SMP
00253 Mutex::scoped_lock lk(mutex);
00254 #endif
00255 if (max > threatmate_nodes)
00256 {
00257 const int left = max - threatmate_nodes;
00258 threatmate_nodes = max;
00259 return left;
00260 }
00261 return 0;
00262 }
00264 int checkmateNodes() const { return checkmate_nodes; }
00265 int threatmateNodes() const { return threatmate_nodes; }
00266
00267 void setVisited(bool value=true) {
00268 #ifndef OSL_SMP
00269 assert(! (visited && value));
00270 #endif
00271 visited = value;
00272 }
00273 bool isVisited() const { return visited; }
00274 void clear()
00275 {
00276 #ifdef OSL_SMP
00277 Mutex::scoped_lock lk(mutex);
00278 #endif
00279 move_cache.clear();
00280 flags.clear();
00281 upper_depth = lower_depth = static_value_depth = InitialDepth;
00282 }
00283 void setStaticValue(StaticValueType type, int value, int depth,
00284 const QuiescenceThreat& t1=QuiescenceThreat(),
00285 const QuiescenceThreat& t2=QuiescenceThreat())
00286 {
00287 #ifdef OSL_SMP
00288 Mutex::scoped_lock lk(mutex);
00289 #endif
00290 assert((depth <= QSearchTraits::MaxDepth)
00291 || (depth == QSearchTraits::CheckmateSpecialDepth));
00292 assert(value % 2 == 0);
00293 static_value = value;
00294 threat1 = t1;
00295 threat2 = t2;
00296 static_value_type = type;
00297 static_value_depth = depth;
00298 }
00299 void setLowerBound(int depth, int bound, Move best_move)
00300 {
00301 #ifdef OSL_SMP
00302 Mutex::scoped_lock lk(mutex);
00303 #endif
00304 assert((depth <= QSearchTraits::MaxDepth)
00305 || (depth == QSearchTraits::CheckmateSpecialDepth));
00306 if (depth >= lower_depth)
00307 {
00308 this->best_move = best_move;
00309 lower_bound = bound;
00310 lower_depth = depth;
00311 }
00312 }
00313 void setUpperBound(int depth, int bound)
00314 {
00315 #ifdef OSL_SMP
00316 Mutex::scoped_lock lk(mutex);
00317 #endif
00318 assert((depth <= QSearchTraits::MaxDepth)
00319 || (depth == QSearchTraits::CheckmateSpecialDepth));
00320 if (depth >= upper_depth)
00321 {
00322 upper_bound = bound;
00323 upper_depth = depth;
00324 }
00325 }
00326 void setHistoryValue(int value)
00327 {
00328 lower_bound = upper_bound = value;
00329 lower_depth = upper_depth = QSearchTraits::HistorySpecialDepth;
00330 }
00331 void setHistoryValue(Move best_move, int value)
00332 {
00333 #ifdef OSL_SMP
00334 Mutex::scoped_lock lk(mutex);
00335 #endif
00336 this->best_move = best_move;
00337 setHistoryValue(value);
00338 }
00339 private:
00340 void reserveMovesInLock(size_t new_size)
00341 {
00342 move_cache.reserve(move_cache.size()+new_size);
00343 }
00344 public:
00345 void reserveMoves(size_t new_size)
00346 {
00347 #ifdef OSL_SMP
00348 Mutex::scoped_lock lk(mutex);
00349 #endif
00350 reserveMovesInLock(new_size);
00351 }
00352 private:
00353 void addMovesReservedInLock(const MoveVector& new_moves)
00354 {
00355 move_cache.insert(move_cache.end(),
00356 new_moves.begin(), new_moves.end());
00357 }
00358 void addMovesReserved(const MoveVector& new_moves)
00359 {
00360 #ifdef OSL_SMP
00361 Mutex::scoped_lock lk(mutex);
00362 #endif
00363 addMovesReservedInLock(new_moves);
00364 }
00365 void addMovesInLock(const MoveVector& new_moves)
00366 {
00367 reserveMovesInLock(new_moves.size());
00368 addMovesReservedInLock(new_moves);
00369 }
00370 void addMoves(const MoveVector& new_moves)
00371 {
00372 #ifdef OSL_SMP
00373 Mutex::scoped_lock lk(mutex);
00374 #endif
00375 addMovesInLock(new_moves);
00376 }
00377 public:
00378 void addKillerMoves(const MoveVector& new_moves)
00379 {
00380 addMoves(new_moves);
00381 }
00382 void addKillerMovesReserved(const MoveVector& new_moves)
00383 {
00384 assert(move_cache.capacity() >= move_cache.size() + new_moves.size());
00385 addMovesReserved(new_moves);
00386 }
00387 template <class MOVE_TYPE>
00388 void addMoves(MOVE_TYPE type, const MoveVector& new_moves)
00389 {
00390 #ifdef OSL_SMP
00391 Mutex::scoped_lock lk(mutex);
00392 if(flags.isGenerated(type)) return;
00393 #else
00394 assert(! flags.isGenerated(type));
00395 #endif
00396 flags.recordGeneration(type);
00397 addMovesInLock(new_moves);
00398 }
00399
00400 StaticValueType staticValueType() const {
00401 return static_cast<StaticValueType>(static_value_type);
00402 }
00403 bool hasStaticValue() const { return staticValueType() != UNKNOWN; }
00404 int staticValue() const { assert(hasStaticValue()); return static_value; }
00405 int staticValueDepth() const { return static_value_depth; }
00406 int upperDepth() const { return upper_depth; }
00407 int lowerDepth() const { return lower_depth; }
00408 int upperBound() const { return upper_bound; }
00409 int lowerBound() const { return lower_bound; }
00410 const Move bestMove() const { return best_move; }
00411 int moves_size() const {
00412 return move_cache.size();
00413 }
00414 void loadMoves(MoveVector& dst) const{
00415 #ifdef OSL_SMP
00416 Mutex::scoped_lock lk(mutex);
00417 #endif
00418 dst.clear();
00419 dst.push_back(move_cache.begin(),move_cache.end());
00420 }
00421 QuiescenceFlags cacheFlags() const { return flags; }
00422
00423 void dump(std::ostream&) const;
00424 };
00425
00426 }
00427 }
00428
00429 #endif
00430
00431
00432
00433