00001 //---------------------------------------------------------------------------- 00002 /** @file SgSortedMoves.h 00003 Sorted table of moves. 00004 00005 Move tables are used to store a small number of best moves. They 00006 have the usual operations Insert, Delete, etc. */ 00007 //---------------------------------------------------------------------------- 00008 00009 #ifndef SG_SORTEDMOVES_H 00010 #define SG_SORTEDMOVES_H 00011 00012 #include <iostream> 00013 #include "SgRandom.h" 00014 #include "SgVector.h" 00015 00016 //---------------------------------------------------------------------------- 00017 00018 /** Small array with moves sorted by their value */ 00019 template<typename MOVE, typename VALUE, int SIZE> 00020 class SgSortedMoves 00021 { 00022 public: 00023 /** check move table before and after each operation */ 00024 static const bool CHECKMOVES = SG_CHECK; 00025 00026 explicit SgSortedMoves(int maxNuMoves); 00027 00028 /** */ 00029 void CheckOverflow() {m_checkOverflow = true;} 00030 00031 /** */ 00032 void Clear(); 00033 00034 /** delete all but one of equal-valued moves */ 00035 void DeleteEqual(); 00036 00037 /** Delete move at index. 00038 Shift remaining moves forward and adjust lower bound if necessary. */ 00039 void Delete(int index); 00040 00041 /** Insert move with given value in table. 00042 Update m_nuMoves, m_lowerBound of table if necessary. */ 00043 void Insert(const MOVE& move, VALUE value); 00044 00045 /** */ 00046 bool GetMove(const MOVE& move, VALUE &value, int &index) const; 00047 00048 /** */ 00049 void GetMoves(SgVector<MOVE>* moves) const; 00050 00051 /** If move in table: increase its value. otherwise insert (move,value) */ 00052 void SetMinValue(const MOVE& move, VALUE value); 00053 00054 /** */ 00055 void SetMove(int i, const MOVE& move) 00056 { 00057 AssertIndexRange(i); 00058 m_move[i] = move; 00059 } 00060 00061 /** */ 00062 void SetValue(int i, VALUE value) 00063 { 00064 AssertIndexRange(i); 00065 m_value[i] = value; 00066 } 00067 00068 /** Adjust number of moves: throw out all moves whose value has become 00069 less than the value of m_move[m_maxNuMoves - 1] */ 00070 void SetMaxMoves(int nu); // adjust all other values too 00071 00072 /** Limit number of moves */ 00073 void SetMaxNuMoves(int max); 00074 00075 /** Lower bound for accepting moves */ 00076 void SetLowerBound(VALUE bound) {m_lowerBound = bound;}; 00077 00078 /** See m_initLowerBound */ 00079 void SetInitLowerBound(VALUE bound) {m_initLowerBound = bound;}; 00080 00081 /** */ 00082 int LowerBound() const {return m_lowerBound;} 00083 00084 /** */ 00085 int NuMoves() const {return m_nuMoves;} 00086 00087 /** */ 00088 int MaxNuMoves() const {return m_maxNuMoves;} 00089 00090 /** Get move at given index i */ 00091 const MOVE& Move(int i) const {AssertIndexRange(i); return m_move[i];} 00092 00093 /** The best move is sorted first in the table */ 00094 const MOVE& BestMove() const {return Move(0);} 00095 00096 /** */ 00097 VALUE Value(int i) const {AssertIndexRange(i); return m_value[i];} 00098 00099 /** */ 00100 VALUE BestValue() const 00101 { 00102 SG_ASSERT(m_nuMoves > 0); 00103 return m_value[0]; 00104 } 00105 00106 /** */ 00107 void DecNuMoves() 00108 { 00109 SG_ASSERT(m_nuMoves > 0); 00110 --m_nuMoves; 00111 } 00112 00113 /** Assert i is an index within the table */ 00114 void AssertIndexRange(int i) const 00115 { 00116 SG_DEBUG_ONLY(i); 00117 SG_ASSERTRANGE(i, 0, m_nuMoves - 1); 00118 } 00119 00120 /** randomly shuffle all the moves of equal value. */ 00121 void Shuffle(); 00122 00123 private: 00124 /** */ 00125 int m_maxNuMoves; 00126 00127 /** */ 00128 int m_nuMoves; 00129 00130 /** Lower bound for accepting moves */ 00131 VALUE m_lowerBound; 00132 00133 /** Initial value of m_lowerBound after a Clear() */ 00134 VALUE m_initLowerBound; 00135 00136 /** */ 00137 bool m_checkOverflow; 00138 00139 /** */ 00140 bool m_considerEqual; 00141 00142 /** */ 00143 MOVE m_move[SIZE]; 00144 00145 /** */ 00146 VALUE m_value[SIZE]; 00147 00148 /** */ 00149 void CheckMoves() const; 00150 00151 /** Randomly shuffle all moves in interval. They must be of equal value */ 00152 void ShuffleInterval(int from, int to); 00153 }; 00154 00155 template<typename MOVE, typename VALUE, int SIZE> 00156 SgSortedMoves<MOVE, VALUE, SIZE>::SgSortedMoves(int maxNuMoves) 00157 : m_maxNuMoves(maxNuMoves), 00158 m_checkOverflow(false), 00159 m_considerEqual(true) 00160 { 00161 SG_ASSERT(maxNuMoves <= SIZE); 00162 Clear(); 00163 } 00164 00165 template<typename MOVE, typename VALUE, int SIZE> 00166 void SgSortedMoves<MOVE, VALUE, SIZE>::Clear() 00167 { 00168 m_initLowerBound = INT_MIN; 00169 SG_ASSERT(m_maxNuMoves >= 1); 00170 m_lowerBound = m_initLowerBound; 00171 m_nuMoves = 0; 00172 } 00173 00174 template<typename MOVE, typename VALUE, int SIZE> 00175 void SgSortedMoves<MOVE, VALUE, SIZE>::Delete(int index) 00176 { 00177 if (CHECKMOVES) 00178 CheckMoves(); 00179 SG_ASSERT(index < m_nuMoves); 00180 00181 --m_nuMoves; 00182 for (int k = index; k <= m_nuMoves - 1; ++k) 00183 { 00184 m_move[k] = m_move[k + 1]; 00185 m_value[k] = m_value[k + 1]; 00186 } 00187 00188 if (m_nuMoves >= m_maxNuMoves) 00189 m_lowerBound = m_value[m_maxNuMoves - 1]; 00190 else 00191 m_lowerBound = m_initLowerBound; 00192 00193 if (CHECKMOVES) 00194 CheckMoves(); 00195 } 00196 00197 template<typename MOVE, typename VALUE, int SIZE> 00198 void SgSortedMoves<MOVE, VALUE, SIZE>::DeleteEqual() 00199 { 00200 for (int j = m_nuMoves - 2; j >= 0; --j) 00201 { 00202 for (int i = m_nuMoves - 1; i >= j + 1; --i) 00203 { 00204 if (m_value[i] == m_value[j]) 00205 { 00206 Delete(SgRandom::Global().Int(2) ? j : i); 00207 /* */ return; /* */ 00208 } 00209 } 00210 } 00211 // must exit through return in the for loop above 00212 SG_ASSERT(false); 00213 } 00214 00215 template<typename MOVE, typename VALUE, int SIZE> 00216 void SgSortedMoves<MOVE, VALUE, SIZE>::CheckMoves() const 00217 { 00218 SG_ASSERT(m_maxNuMoves <= SIZE); // Index[0..MAX - 1] 00219 SG_ASSERT(m_nuMoves <= SIZE); 00220 00221 for (int i = 0; i < m_nuMoves - 1; ++i) 00222 SG_ASSERT(m_value[i] >= m_value[i + 1]); 00223 for (int i = m_maxNuMoves; i < m_nuMoves; ++i) 00224 SG_ASSERT(m_value[i] == m_value[m_maxNuMoves - 1]); 00225 00226 SG_ASSERT((m_nuMoves == 0) || (m_value[m_nuMoves - 1] >= m_lowerBound)); 00227 } 00228 00229 template<typename MOVE, typename VALUE, int SIZE> 00230 void SgSortedMoves<MOVE, VALUE, SIZE>::Insert(const MOVE& m, VALUE val) 00231 { 00232 if (CHECKMOVES) 00233 CheckMoves(); 00234 00235 if (val < m_lowerBound) 00236 /* */ return; /* */ 00237 // must leave 1 free element as scratch space 00238 int i = 0; 00239 while (i < m_nuMoves && m_value[i] > val) 00240 ++i; 00241 int maxMoves = m_nuMoves; 00242 if (maxMoves >= SIZE) 00243 { 00244 if (m_checkOverflow) 00245 { 00246 SG_ASSERT(false); 00247 } 00248 maxMoves = SIZE - 1; 00249 } 00250 else 00251 ++m_nuMoves; 00252 00253 for (int j = maxMoves; j >= i + 1; --j) 00254 { 00255 m_move[j] = m_move[j - 1]; 00256 m_value[j] = m_value[j - 1]; 00257 } 00258 00259 m_move[i] = m; 00260 m_value[i] = val; 00261 00262 // throw out all m_move's whose minValue has become 00263 // less than the minValue of m_move[m_maxNuMoves - 1] 00264 if (m_nuMoves >= m_maxNuMoves) 00265 m_lowerBound = std::max(m_lowerBound, m_value[m_maxNuMoves - 1]); 00266 00267 if (m_nuMoves > m_maxNuMoves) 00268 // throw out the Max-weakest moves 00269 while ( m_value[m_nuMoves - 1] < m_lowerBound 00270 || ( m_nuMoves > m_maxNuMoves 00271 && ! m_considerEqual 00272 && m_value[m_nuMoves - 1] == m_lowerBound 00273 ) 00274 ) 00275 --m_nuMoves; // same effect as: Delete(m_nuMoves - 1); 00276 00277 if (CHECKMOVES) 00278 CheckMoves(); 00279 } 00280 00281 template<typename MOVE, typename VALUE, int SIZE> 00282 bool SgSortedMoves<MOVE, VALUE, SIZE>::GetMove(const MOVE& move, 00283 VALUE &value, int &index) const 00284 { 00285 for (int i = 0; i <= m_nuMoves - 1 ; ++i) 00286 if (m_move[i] == move) 00287 { 00288 value = m_value[i]; 00289 index = i; 00290 return true; 00291 } 00292 return false; 00293 } 00294 00295 template<typename MOVE, typename VALUE, int SIZE> 00296 void SgSortedMoves<MOVE, VALUE, SIZE>::ShuffleInterval(int from, int to) 00297 { 00298 AssertIndexRange(from); 00299 AssertIndexRange(to); 00300 SG_ASSERT(m_value[from] == m_value[to]); 00301 00302 for (; to > from; --to) 00303 {// put random element in [from..to] into to 00304 int i = from + SgRandom::Global().Int(to - from + 1); 00305 SG_ASSERT(m_value[i] == m_value[to]); 00306 MOVE t = m_move[i]; 00307 m_move[i] = m_move[to]; 00308 m_move[to] = t; 00309 } 00310 } 00311 00312 template<typename MOVE, typename VALUE, int SIZE> 00313 void SgSortedMoves<MOVE, VALUE, SIZE>::Shuffle() 00314 { 00315 for (int i = 0; i < m_nuMoves; ++i) 00316 { 00317 int val = m_value[i]; 00318 int j; 00319 for (j = i + 1; j < m_nuMoves && (val == m_value[j]); ++j) 00320 { } 00321 if (j > i + 1) 00322 ShuffleInterval(i, j - 1); 00323 } 00324 } 00325 00326 template<typename MOVE, typename VALUE, int SIZE> 00327 void SgSortedMoves<MOVE, VALUE, SIZE>::GetMoves(SgVector<MOVE>* moves) const 00328 { 00329 for (int i = 0; i < m_nuMoves; ++i) 00330 moves->PushBack(m_move[i]); 00331 } 00332 00333 template<typename MOVE, typename VALUE, int SIZE> 00334 void SgSortedMoves<MOVE, VALUE, SIZE>::SetMinValue(const MOVE& move, 00335 VALUE val) 00336 { 00337 VALUE oldValue; 00338 int index; 00339 bool insert = true; 00340 00341 if (GetMove(move, oldValue, index)) 00342 { 00343 if (val > oldValue) 00344 Delete(index); 00345 else 00346 insert = false; 00347 } 00348 if (insert) 00349 Insert(move, val); 00350 } 00351 00352 template<typename MOVE, typename VALUE, int SIZE> 00353 void SgSortedMoves<MOVE, VALUE, SIZE>::SetMaxNuMoves(int max) 00354 { 00355 SG_ASSERT(max >= 1); 00356 SG_ASSERT(max <= SIZE); 00357 m_maxNuMoves = max; 00358 } 00359 00360 template<typename MOVE, typename VALUE, int SIZE> 00361 void SgSortedMoves<MOVE, VALUE, SIZE>::SetMaxMoves(int nu) 00362 { 00363 SetMaxNuMoves(nu); 00364 00365 if ( m_nuMoves >= m_maxNuMoves 00366 && m_value[m_maxNuMoves - 1] > m_lowerBound 00367 ) 00368 m_lowerBound = m_value[m_maxNuMoves - 1]; 00369 if (m_nuMoves > m_maxNuMoves) 00370 { 00371 // throw out weakest moves 00372 while ( m_value[m_nuMoves - 1] < m_lowerBound 00373 || ( m_nuMoves > m_maxNuMoves 00374 && ! m_considerEqual 00375 && m_value[m_nuMoves - 1] == m_lowerBound 00376 ) 00377 ) 00378 --m_nuMoves; // same as: Delete(m_nuMoves - 1); 00379 } 00380 } 00381 00382 //---------------------------------------------------------------------------- 00383 00384 /** write all moves in the table and their values */ 00385 template<typename MOVE, typename VALUE, int SIZE> 00386 std::ostream& operator<<(std::ostream& str, 00387 const SgSortedMoves<MOVE, VALUE, SIZE>& m) 00388 { 00389 if (m.NuMoves() == 0) 00390 str << "none\n"; 00391 else 00392 { 00393 str << m.NuMoves() << " (Moves, Values): "; 00394 for (int i = 0; i < m.NuMoves(); ++i) 00395 { 00396 str << '(' 00397 << m.Move(i) << ", " 00398 << m.Value(i) 00399 << ')'; 00400 } 00401 str << '\n'; 00402 } 00403 return str; 00404 } 00405 00406 //---------------------------------------------------------------------------- 00407 00408 #endif // SG_SORTEDMOVES_H