00001
00002
00003
00004
00005
00006
00007
00008
00009 #ifndef SG_SEARCH_H
00010 #define SG_SEARCH_H
00011
00012 #include "SgBlackWhite.h"
00013 #include "SgHash.h"
00014 #include "SgMove.h"
00015 #include "SgSearchStatistics.h"
00016 #include "SgSearchTracer.h"
00017 #include "SgStack.h"
00018 #include "SgTimer.h"
00019 #include "SgVector.h"
00020
00021 template <class DATA> class SgHashTable;
00022 class SgNode;
00023 class SgProbCut;
00024 class SgSearchControl;
00025
00026
00027
00028
00029
00030
00031 class SgKiller
00032 {
00033 public:
00034 SgKiller();
00035
00036 void MarkKiller(SgMove killer);
00037
00038 void Clear();
00039
00040 SgMove GetKiller1() const;
00041
00042 SgMove GetKiller2() const;
00043
00044 private:
00045 SgMove m_killer1;
00046
00047 SgMove m_killer2;
00048
00049 int m_count1;
00050
00051 int m_count2;
00052 };
00053
00054 inline SgKiller::SgKiller()
00055 : m_killer1(SG_NULLMOVE),
00056 m_killer2(SG_NULLMOVE),
00057 m_count1(0),
00058 m_count2(0)
00059 {
00060 }
00061
00062 inline SgMove SgKiller::GetKiller1() const
00063 {
00064 return m_killer1;
00065 }
00066
00067 inline SgMove SgKiller::GetKiller2() const
00068 {
00069 return m_killer2;
00070 }
00071
00072
00073
00074
00075 class SgSearchHashData
00076 {
00077 public:
00078 SgSearchHashData();
00079
00080 SgSearchHashData(int depth, signed value, SgMove bestMove,
00081 bool isOnlyUpperBound = false,
00082 bool isOnlyLowerBound = false,
00083 bool isExactValue = false);
00084
00085 ~SgSearchHashData();
00086
00087 int Depth() const;
00088
00089 int Value() const;
00090
00091 SgMove BestMove() const;
00092
00093 bool IsOnlyUpperBound() const;
00094
00095 bool IsOnlyLowerBound() const;
00096
00097 void AdjustBounds(int* lower, int* upper);
00098
00099 bool IsBetterThan(const SgSearchHashData& data) const;
00100
00101 bool IsValid() const;
00102
00103 bool IsExactValue() const;
00104
00105 void Invalidate();
00106
00107 void AgeData();
00108
00109 private:
00110 unsigned m_depth : 12;
00111
00112 unsigned m_isUpperBound : 1;
00113
00114 unsigned m_isLowerBound : 1;
00115
00116 unsigned m_isValid : 1;
00117
00118 unsigned m_isExactValue : 1;
00119
00120 signed m_value : 16;
00121
00122 SgMove m_bestMove;
00123 };
00124
00125 typedef SgHashTable<SgSearchHashData> SgSearchHashTable;
00126
00127 inline SgSearchHashData::SgSearchHashData()
00128 : m_depth(0),
00129 m_isUpperBound(false),
00130 m_isLowerBound(false),
00131 m_isValid(false),
00132 m_isExactValue(false),
00133 m_value(-1),
00134 m_bestMove(SG_NULLMOVE)
00135 { }
00136
00137 inline SgSearchHashData::SgSearchHashData(int depth, signed value,
00138 SgMove bestMove,
00139 bool isOnlyUpperBound,
00140 bool isOnlyLowerBound,
00141 bool isExactValue)
00142 :
00143 m_depth(depth & ((1 << 12) - 1)),
00144 m_isUpperBound(isOnlyUpperBound),
00145 m_isLowerBound(isOnlyLowerBound),
00146 m_isValid(true),
00147 m_isExactValue(isExactValue),
00148
00149 m_value((short int)(value) & (short int)((1 << 16) - 1)),
00150 m_bestMove(bestMove)
00151 {
00152
00153 SG_ASSERT(m_value == value);
00154 }
00155
00156 inline SgSearchHashData::~SgSearchHashData()
00157 {
00158 }
00159
00160 inline int SgSearchHashData::Depth() const
00161 {
00162 return static_cast<int> (m_depth);
00163 }
00164
00165 inline int SgSearchHashData::Value() const
00166 {
00167 return static_cast<int> (m_value);
00168 }
00169
00170 inline SgMove SgSearchHashData::BestMove() const
00171 {
00172 return m_bestMove;
00173 }
00174
00175 inline bool SgSearchHashData::IsOnlyUpperBound() const
00176 {
00177 return m_isUpperBound != 0;
00178 }
00179
00180 inline bool SgSearchHashData::IsOnlyLowerBound() const
00181 {
00182 return m_isLowerBound != 0;
00183 }
00184
00185 inline void SgSearchHashData::AdjustBounds(int* lower, int* upper)
00186 {
00187 if (IsOnlyUpperBound())
00188 *upper = std::min(*upper, Value());
00189 else if (IsOnlyLowerBound())
00190 *lower = std::max(*lower, Value());
00191 else
00192 {
00193 *lower = Value();
00194 *upper = Value();
00195 }
00196 }
00197
00198 inline bool SgSearchHashData::IsValid() const
00199 {
00200 return m_isValid;
00201 }
00202
00203 inline bool SgSearchHashData::IsExactValue() const
00204 {
00205 return m_isExactValue;
00206 }
00207
00208 inline void SgSearchHashData::Invalidate()
00209 {
00210 m_isValid = false;
00211 }
00212
00213 inline void SgSearchHashData::AgeData()
00214 {
00215 m_depth = 0;
00216 }
00217
00218
00219 namespace SgSearchLimit {
00220 static const int MAX_DEPTH = 256;
00221 }
00222
00223 typedef SgStack<SgMove, SgSearchLimit::MAX_DEPTH> SgSearchStack;
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239 class SgSearch
00240 {
00241 public:
00242
00243
00244
00245
00246
00247 static const int DEPTH_UNIT = 100;
00248
00249
00250 static const int MAX_DEPTH = 256;
00251
00252
00253
00254
00255 static const int SG_INFINITY;
00256
00257
00258
00259 SgSearch(SgSearchHashTable* hash);
00260
00261 virtual ~SgSearch();
00262
00263
00264
00265
00266
00267
00268 virtual bool CheckDepthLimitReached() const = 0;
00269
00270 const SgSearchHashTable* HashTable() const;
00271
00272 void SetHashTable(SgSearchHashTable* hashtable);
00273
00274 const SgSearchControl* SearchControl() const;
00275
00276
00277
00278
00279 void SetSearchControl(SgSearchControl* control);
00280
00281
00282
00283
00284 void SetProbCut(SgProbCut* probcut);
00285
00286
00287 virtual std::string MoveString(SgMove move) const = 0;
00288
00289 virtual void SetToPlay(SgBlackWhite toPlay) = 0;
00290
00291
00292
00293 virtual void OnStartSearch();
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304 int DepthFirstSearch(int depthLimit, int boundLo, int boundHi,
00305 SgVector<SgMove>* sequence, bool clearHash = true,
00306 SgNode* traceNode = 0);
00307
00308
00309 int DepthFirstSearch(int depthLimit, SgVector<SgMove>* sequence,
00310 bool clearHash = true, SgNode* traceNode = 0);
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320 int IteratedSearch(int depthMin, int depthMax, int boundLo,
00321 int boundHi, SgVector<SgMove>* sequence,
00322 bool clearHash = true, SgNode* traceNode = 0);
00323
00324
00325
00326 int IteratedSearch(int depthMin, int depthMax, SgVector<SgMove>* sequence,
00327 bool clearHash = true, SgNode* traceNode = 0);
00328
00329
00330
00331 int IteratedSearchDepthLimit() const;
00332
00333
00334
00335
00336 virtual void StartOfDepth(int depthLimit);
00337
00338
00339 bool Aborted() const;
00340
00341
00342
00343
00344
00345 void SetAbortSearch(bool fAborted = true);
00346
00347 void SetScout(bool flag = true);
00348
00349 void SetKillers(bool flag = true);
00350
00351 void SetOpponentBest(bool flag = true);
00352
00353 void SetNullMove(bool flag = true);
00354
00355 void SetNullMoveDepth(int depth);
00356
00357
00358 void GetStatistics(SgSearchStatistics* stat);
00359
00360 const SgSearchStatistics& Statistics() const
00361 {
00362 return m_stat;
00363 }
00364
00365
00366
00367 void StartTime();
00368
00369
00370
00371 void StopTime();
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385 virtual void Generate(SgVector<SgMove>* moves, int depth) = 0;
00386
00387
00388
00389
00390
00391
00392
00393 virtual int Evaluate(bool* isExact, int depth) = 0;
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404 virtual bool Execute(SgMove move, int* delta, int depth) = 0;
00405
00406
00407 virtual void TakeBack() = 0;
00408
00409
00410 virtual SgBlackWhite GetToPlay() const = 0;
00411
00412
00413
00414
00415 virtual bool AbortSearch();
00416
00417
00418 virtual SgHashCode GetHashCode() const = 0;
00419
00420
00421
00422 int CurrentDepth() const;
00423
00424
00425
00426
00427
00428 SgMove PrevMove() const;
00429
00430
00431
00432
00433 SgMove PrevMove2() const;
00434
00435
00436 virtual bool EndOfGame() const = 0;
00437
00438
00439
00440
00441 void InitSearch(int startDepth = 0);
00442
00443
00444 bool TraceIsOn() const;
00445
00446
00447 virtual void CreateTracer();
00448
00449
00450 void SetTracer(SgSearchTracer* tracer);
00451
00452 SgSearchTracer* Tracer() const;
00453
00454 void SetAbortFrequency(int value);
00455
00456
00457
00458 int SearchEngine(int depth, int alpha, int beta, SgSearchStack& stack,
00459 bool* isExactValue, bool lastNullMove = false);
00460
00461 private:
00462
00463 SgSearchHashTable* m_hash;
00464
00465
00466 SgSearchTracer* m_tracer;
00467
00468
00469 int m_currentDepth;
00470
00471 int m_depthLimit;
00472
00473
00474 SgVector<SgMove> m_moveStack;
00475
00476 bool m_useScout;
00477
00478 bool m_useKillers;
00479
00480
00481 bool m_useOpponentBest;
00482
00483
00484 bool m_useNullMove;
00485
00486
00487 int m_nullMoveDepth;
00488
00489
00490 bool m_aborted;
00491
00492
00493 bool m_foundNewBest;
00494
00495
00496 bool m_reachedDepthLimit;
00497
00498 SgSearchStatistics m_stat;
00499
00500 SgTimer m_timer;
00501
00502 int m_timerLevel;
00503
00504
00505 int m_prevValue;
00506
00507
00508 SgVector<SgMove> m_prevSequence;
00509
00510 static const int MAX_KILLER_DEPTH = 10;
00511
00512
00513 SgArray<SgKiller,MAX_KILLER_DEPTH + 1> m_killers;
00514
00515 SgSearchControl* m_control;
00516
00517 SgProbCut* m_probcut;
00518
00519 int m_abortFrequency;
00520
00521
00522 int DFS(int startDepth, int depthLimit, int boundLo, int boundHi,
00523 SgVector<SgMove>* sequence, bool* isExactValue);
00524
00525
00526 bool LookupHash(SgSearchHashData& data) const;
00527
00528 bool NullMovePrune(int depth, int delta, int beta);
00529
00530
00531 void StoreHash(int depth, int value, SgMove move, bool isUpperBound,
00532 bool isLowerBound, bool isExact);
00533
00534
00535 void AddSequenceToHash(const SgVector<SgMove>& sequence, int depth);
00536
00537
00538 int CallEvaluate(int depth, bool* isExact);
00539
00540
00541 bool CallExecute(SgMove move, int* delta, int depth);
00542
00543
00544 void CallGenerate(SgVector<SgMove>* moves, int depth);
00545
00546
00547 void CallTakeBack();
00548
00549 bool TryMove(SgMove move, const SgVector<SgMove>& specialMoves,
00550 const int depth,
00551 const int alpha, const int beta,
00552 int& loValue, int& hiValue,
00553 SgSearchStack& stack,
00554 bool& allExact,
00555 bool& isCutoff);
00556
00557 bool TrySpecialMove(SgMove move, SgVector<SgMove>& specialMoves,
00558 const int depth,
00559 const int alpha, const int beta,
00560 int& loValue, int& hiValue,
00561 SgSearchStack& stack,
00562 bool& allExact,
00563 bool& isCutoff);
00564
00565
00566 SgSearch(const SgSearch&);
00567
00568
00569 SgSearch& operator=(const SgSearch&);
00570 };
00571
00572 inline bool SgSearch::Aborted() const
00573 {
00574 return m_aborted;
00575 }
00576
00577 inline int SgSearch::CurrentDepth() const
00578 {
00579 return m_currentDepth;
00580 }
00581
00582 inline int SgSearch::DepthFirstSearch(int depthLimit,
00583 SgVector<SgMove>* sequence,
00584 bool clearHash, SgNode* traceNode)
00585 {
00586 return DepthFirstSearch(depthLimit, -SG_INFINITY, SG_INFINITY, sequence,
00587 clearHash, traceNode);
00588 }
00589
00590 inline const SgSearchHashTable* SgSearch::HashTable() const
00591 {
00592 return m_hash;
00593 }
00594
00595 inline void SgSearch::SetHashTable(SgSearchHashTable* hashtable)
00596 {
00597 m_hash = hashtable;
00598 }
00599
00600 inline int SgSearch::IteratedSearchDepthLimit() const
00601 {
00602 return m_depthLimit;
00603 }
00604
00605 inline int SgSearch::IteratedSearch(int depthMin, int depthMax,
00606 SgVector<SgMove>* sequence,
00607 bool clearHash,
00608 SgNode* traceNode)
00609 {
00610 return IteratedSearch(depthMin, depthMax, -SG_INFINITY, SG_INFINITY,
00611 sequence, clearHash, traceNode);
00612 }
00613
00614 inline SgMove SgSearch::PrevMove() const
00615 {
00616 return m_moveStack.Back();
00617 }
00618
00619 inline SgMove SgSearch::PrevMove2() const
00620 {
00621 return m_moveStack.TopNth(2);
00622 }
00623
00624 inline const SgSearchControl* SgSearch::SearchControl() const
00625 {
00626 return m_control;
00627 }
00628
00629 inline void SgSearch::SetAbortFrequency(int value)
00630 {
00631 m_abortFrequency = value;
00632 }
00633
00634 inline void SgSearch::SetAbortSearch(bool fAborted)
00635 {
00636 m_aborted = fAborted;
00637 }
00638
00639 inline void SgSearch::SetKillers(bool flag)
00640 {
00641 m_useKillers = flag;
00642 }
00643
00644 inline void SgSearch::SetNullMove(bool flag)
00645 {
00646 m_useNullMove = flag;
00647 }
00648
00649 inline void SgSearch::SetNullMoveDepth(int depth)
00650 {
00651 m_nullMoveDepth = depth;
00652 }
00653
00654 inline void SgSearch::SetOpponentBest(bool flag)
00655 {
00656 m_useOpponentBest = flag;
00657 }
00658
00659 inline void SgSearch::SetScout(bool flag)
00660 {
00661 m_useScout = flag;
00662 }
00663
00664 inline void SgSearch::SetTracer(SgSearchTracer* tracer)
00665 {
00666
00667
00668 SG_ASSERT(! m_tracer || ! tracer);
00669 m_tracer = tracer;
00670 }
00671
00672 inline SgSearchTracer* SgSearch::Tracer() const
00673 {
00674 return m_tracer;
00675 }
00676
00677
00678
00679 #endif // SG_SEARCH_H