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