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