00001
00002
00003 #ifndef _SEARCHBASE_H
00004 #define _SEARCHBASE_H
00005
00006 #include "osl/search/searchRecorder.h"
00007 #include "osl/search/searchTable.h"
00008 #include "osl/search/realizationProbability.h"
00009 #include "osl/search/simpleHashRecord.h"
00010 #include "osl/search/searchWindow.h"
00011 #include "osl/search/fixedEval.h"
00012 #include "osl/hash/hashCollision.h"
00013 #include "osl/hash/hashKey.h"
00014 #include "osl/state/numEffectState.h"
00015 #include <cassert>
00016 namespace osl
00017 {
00018 namespace search
00019 {
00020 class SimpleHashTable;
00021
00026 template<typename Eval,
00027 typename Table, typename Recorder, typename Probabilities>
00028 struct SearchBase : protected FixedEval
00029 {
00030
00031 typedef Eval eval_t;
00032
00033 typedef Probabilities Probabilities_t;
00034 protected:
00035 Recorder& recorder;
00036 Table *table;
00037 public:
00038 SearchBase(Recorder& r, Table *t)
00039 : recorder(r), table(t)
00040 {
00041 assert(table);
00042 assert(winThreshold(BLACK) > eval_t::infty());
00043 }
00044 virtual ~SearchBase() {}
00045 virtual bool abort(Move) const { return false; }
00046
00055 bool validTableMove(const NumEffectState& state,
00056 const MoveLogProb& move, int limit) const
00057 {
00058 if ((limit < move.getLogProb()) || (! move.validMove()))
00059 return false;
00060 if (move.getMove().isPass())
00061 return false;
00062 const bool valid
00063 = ((move.getMove().player() == state.getTurn())
00064 && state.isAlmostValidMove<false>(move.getMove()));
00065 if (! valid)
00066 {
00067
00068 recorder.recordInvalidMoveInTable(state, move, limit);
00069 throw hash::HashCollision();
00070 }
00071 return valid;
00072 }
00073
00074 void recordLowerBound(Player P,
00075 SimpleHashRecord *record, int limit,
00076 const SearchMove& best_move, int val) const
00077 {
00078 assert(limit >= 0);
00079 recorder.tableStoreLowerBound(P, best_move.moveLogProb(), val, limit);
00080 if (best_move.validMove())
00081 {
00082
00083 if (! (isWinValue(P, val) || isWinValue(alt(P), val)
00084 || (val == drawValue()) || best_move.getMove().isPass()
00085 || table->minimumRecordLimit() >= 0))
00086 {
00087 assert(best_move.record || abort(best_move.getMove()));
00088 }
00089 MoveLogProb store_move = best_move.moveLogProb();
00090 store_move.setLogProbAtLeast(Probabilities::TableMove);
00091 record->setLowerBound(P, limit,
00092 SearchMove(store_move, best_move.record), val);
00093 }
00094 else
00095 {
00096 record->setLowerBound(P, limit, best_move, val);
00097 }
00098 }
00099 void recordUpperBound(Player P,
00100 SimpleHashRecord *record, int limit,
00101 const SearchMove& best_move, int val) const
00102 {
00103 assert(limit >= 0);
00104 recorder.tableStoreUpperBound(P, best_move.moveLogProb(), val, limit);
00105
00106 if (best_move.validMove())
00107 {
00108 if (! (isWinValue(P, val) || isWinValue(alt(P), val)
00109 || (val == drawValue()) || best_move.getMove().isPass()
00110 || table->minimumRecordLimit() >= 0))
00111 assert(best_move.record || abort(best_move.getMove()));
00112 MoveLogProb store_move = best_move.moveLogProb();
00113 store_move.setLogProbAtLeast(Probabilities::TableMove);
00114 record->setUpperBound(P, limit,
00115 SearchMove(store_move, best_move.record), val);
00116 }
00117 else
00118 {
00119 record->setUpperBound(P, limit, best_move, val);
00120 }
00121 }
00122 private:
00123 void recordCheckmateResult(Player P, SimpleHashRecord *record,
00124 int val, Move move) const
00125 {
00126 assert(isWinValue(P,val) || isWinValue(alt(P),val));
00127 const int limit = SearchTable::CheckmateSpecialDepth;
00128 const MoveLogProb best_move(move, 101);
00129 recorder.tableStoreLowerBound(P, best_move, val, limit);
00130 recorder.tableStoreUpperBound(P, best_move, val, limit);
00131 record->setAbsoluteValue(best_move.getMove(), val,
00132 SearchTable::CheckmateSpecialDepth);
00133 }
00134 public:
00136 void recordWinByCheckmate(Player P, SimpleHashRecord *record,
00137 Move check_move) const
00138 {
00139 assert(record);
00140 recordCheckmateResult(P, record, winByCheckmate(P), check_move);
00141 }
00143 void recordLoseByCheckmate(Player P, SimpleHashRecord *record) const
00144 {
00145 assert(record);
00146 recordCheckmateResult(P, record, winByCheckmate(alt(P)), Move::INVALID());
00147 }
00148
00149 using FixedEval::isWinValue;
00150 using FixedEval::winByCheckmate;
00151 using FixedEval::winByFoul;
00152 using FixedEval::winByLoop;
00153 using FixedEval::minusInfty;
00154 using FixedEval::drawValue;
00155
00156 };
00157 }
00158 }
00159
00160
00161 #endif
00162
00163
00164
00165