Go to the documentation of this file.00001
00002
00003 #include "osl/repetitionCounter.h"
00004 #include "osl/hash/hashKey.h"
00005 #include "osl/state/simpleState.h"
00006 #include "osl/effect_util/effectUtil.h"
00007 #include "osl/move_classifier/check_.h"
00008 #include "osl/move_classifier/moveAdaptor.h"
00009 #include "osl/stl/hash_map.h"
00010 #include <boost/foreach.hpp>
00011 #include <iostream>
00012
00013 #if (__GNUC__ < 3 || (__GNUC__ ==3 && __GNUC_MINOR__ < 4) ) && defined(USE_GPL_POOL_ALLOCATOR)
00014 template class osl::__gnu_cxx::__pool_alloc<true,0>;
00015 #endif
00016
00017 typedef osl::RepetitionCounter::list_t list_t;
00018 typedef osl::hash_map<osl::HashKey,list_t> map_t;
00019
00020 struct osl::RepetitionCounter::Table : public map_t
00021 {
00022 };
00023
00024 static const int initial_capacity = 256;
00025
00026 void osl::RepetitionCounter::
00027 clear()
00028 {
00029 table->clear();
00030 continuous_check[0].clear();
00031 continuous_check[1].clear();
00032 hash_history.clear();
00033
00034 continuous_check[0].reserve(initial_capacity);
00035 continuous_check[1].reserve(initial_capacity);
00036
00037 continuous_check[0].push_back(0);
00038 continuous_check[1].push_back(0);
00039 }
00040
00041 osl::RepetitionCounter::
00042 RepetitionCounter() : table(new Table()), hash_history(initial_capacity)
00043 {
00044 clear();
00045 }
00046
00047 osl::RepetitionCounter::
00048 RepetitionCounter(const RepetitionCounter& c)
00049 : continuous_check(c.continuous_check),
00050 hash_history(c.hash_history)
00051 {
00052 if (c.table)
00053 table.reset(new Table(*c.table));
00054 assert(isConsistent());
00055 }
00056
00057
00058 osl::RepetitionCounter::
00059 RepetitionCounter(const NumEffectState& initial)
00060 : table(new Table()), hash_history(initial_capacity)
00061 {
00062 clear();
00063 const HashKey key(initial);
00064 push(key, initial);
00065 }
00066
00067 osl::RepetitionCounter::
00068 ~RepetitionCounter()
00069 {
00070 }
00071
00072 void osl::RepetitionCounter::
00073 push(const HashKey& new_key, bool is_check)
00074 {
00075 const Player last_turn = alt(new_key.turn());
00076 if (is_check)
00077 {
00078 continuous_check[last_turn].push_back(checkCount(last_turn)+1);
00079 }
00080 else
00081 {
00082 continuous_check[last_turn].push_back(0);
00083 }
00084
00085 const Table::iterator p=table->find(new_key);
00086 if (p == table->end())
00087 {
00088 (*table)[new_key].push_front(order());
00089 }
00090 else
00091 {
00092 list_t& l = p->second;
00093 l.push_front(order());
00094 }
00095 hash_history.push(new_key);
00096 }
00097
00098 void osl::RepetitionCounter::
00099 push(const HashKey& key, const NumEffectState& state)
00100 {
00101 const bool is_check = state.inCheck();
00102 push(key, is_check);
00103 }
00104
00105 void osl::RepetitionCounter::
00106 push(const NumEffectState& state)
00107 {
00108 push(HashKey(state), state);
00109 }
00110
00111 void osl::RepetitionCounter::
00112 push(const NumEffectState& state, Move move)
00113 {
00114 assert(move.isValidOrPass());
00115 assert(state.turn() == move.player());
00116
00117 HashKey key(state);
00118 key = key.newHashWithMove(move);
00119
00120
00121 using namespace move_classifier;
00122 const bool is_check
00123 = (!move.isPass()) && PlayerMoveAdaptor<Check>::isMember(state, move);
00124 push(key, is_check);
00125 }
00126
00127 void osl::RepetitionCounter::
00128 pop()
00129 {
00130 assert(order());
00131 assert(hash_history.size()>0);
00132 const HashKey last_key = hash_history.top();
00133 hash_history.pop();
00134
00135 const Player last_turn = alt(last_key.turn());
00136 assert(! continuous_check[last_turn].empty());
00137 continuous_check[last_turn].pop_back();
00138
00139 const Table::iterator p=table->find(last_key);
00140 assert(p != table->end());
00141
00142 #ifndef NDEBUG
00143 const list_t::iterator q = p->second.begin();
00144 assert(q != p->second.end());
00145 assert(*q == order());
00146 #endif
00147 p->second.pop_front();
00148 if (p->second.empty())
00149 table->erase(p);
00150 }
00151
00152 int osl::RepetitionCounter::
00153 getLastMove(const HashKey& key) const
00154 {
00155 const Table::const_iterator p=table->find(key);
00156 if (p == table->end())
00157 return -1;
00158 return p->second.front();
00159 }
00160 int osl::RepetitionCounter::
00161 getFirstMove(const HashKey& key) const
00162 {
00163 const Table::const_iterator p=table->find(key);
00164 if (p == table->end())
00165 return -1;
00166 list_t::const_iterator q = p->second.begin();
00167 assert(q != p->second.end());
00168 int result = *q++;
00169 while (q != p->second.end())
00170 result = *q++;
00171 return result;
00172 }
00173
00174 const osl::Sennichite osl::RepetitionCounter::
00175 isSennichite(const NumEffectState& state, Move move) const
00176 {
00177 HashKey key(state);
00178 key = key.newHashWithMove(move);
00179 const Table::const_iterator p=table->find(key);
00180 if (p == table->end())
00181 return Sennichite::NORMAL();
00182
00183
00184 if (p->second.size() < 3)
00185 return Sennichite::NORMAL();
00186 return isAlmostSennichite(key);
00187 }
00188
00189 const std::pair<osl::Sennichite,int> osl::RepetitionCounter::
00190 distanceToSennichite(const HashKey& key) const
00191 {
00192 const Table::const_iterator p=table->find(key);
00193 if (p == table->end())
00194 return std::make_pair(Sennichite::NORMAL(), 0);
00195 return std::make_pair(isAlmostSennichite(key), p->second.size());
00196 }
00197
00198 unsigned int osl::RepetitionCounter::
00199 countRepetition(const HashKey& key) const
00200 {
00201 const Table::const_iterator p=table->find(key);
00202 if (p == table->end())
00203 return 0;
00204 return p->second.size();
00205 }
00206
00207 const list_t osl::RepetitionCounter::
00208 getRepetitions(const HashKey& key) const
00209 {
00210 Table::const_iterator p=table->find(key);
00211 if (p == table->end())
00212 return list_t();
00213 return p->second;
00214 }
00215
00216 #ifndef MINIMAL
00217 void osl::RepetitionCounter::
00218 printMatches(const HashKey& key) const
00219 {
00220 Table::const_iterator p=table->find(key);
00221 if (p == table->end())
00222 return;
00223 BOOST_FOREACH(int q, p->second)
00224 {
00225 std::cerr << q << " ";
00226 }
00227 std::cerr << "\n";
00228 }
00229
00230 bool osl::RepetitionCounter::
00231 isConsistent() const
00232 {
00233 HashKeyStack history = hash_history;
00234 Table table(*this->table);
00235 CArray<osl::vector<int>, 2> continuous_check = this->continuous_check;
00236 while (history.empty())
00237 {
00238 const HashKey last_key = history.top();
00239 history.pop();
00240
00241 const Player last_turn = alt(last_key.turn());
00242 assert(! continuous_check[last_turn].empty());
00243 continuous_check[last_turn].pop_back();
00244
00245 const Table::iterator p=table.find(last_key);
00246 if (p == table.end())
00247 {
00248 std::cerr << "oops, " << this << "\n";
00249 return false;
00250 }
00251 assert(p != table.end());
00252
00253 #ifndef NDEBUG
00254 const list_t::iterator q = p->second.begin();
00255 assert(q != p->second.end());
00256 assert(*q == order());
00257 #endif
00258 p->second.pop_front();
00259 if (p->second.empty())
00260 table.erase(p);
00261 }
00262 return true;
00263 }
00264
00265 bool osl::RepetitionCounter::maybeEqual(const RepetitionCounter& l, const RepetitionCounter& r)
00266 {
00267 #if ! (__GNUC__ >= 4 && __GNUC_MINOR__ >=3)
00268
00269 if (*l.table != *r.table)
00270 return false;
00271 #endif
00272 if (l.continuous_check[0] != r.continuous_check[0])
00273 return false;
00274 if (l.continuous_check[1] != r.continuous_check[1])
00275 return false;
00276 return l.hash_history == r.hash_history;
00277 }
00278 #endif
00279
00280
00281
00282
00283
00284
00285