HexUctPolicy.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include "Hex.hpp"
00012 #include "Misc.hpp"
00013 #include "PatternState.hpp"
00014 #include "HexUctPolicy.hpp"
00015
00016 #include <boost/filesystem/path.hpp>
00017
00018 using namespace benzene;
00019
00020
00021
00022 namespace
00023 {
00024
00025
00026
00027
00028 template<typename T>
00029 void ShuffleVector(std::vector<T>& v, SgRandom& random)
00030 {
00031 for (int i = static_cast<int>(v.size() - 1); i > 0; --i)
00032 {
00033 int j = random.Int(i+1);
00034 std::swap(v[i], v[j]);
00035 }
00036 }
00037
00038
00039 bool PercentChance(int percent, SgRandom& random)
00040 {
00041 if (percent >= 100)
00042 return true;
00043 unsigned int threshold = random.PercentageThreshold(percent);
00044 return random.RandomEvent(threshold);
00045 }
00046
00047 }
00048
00049
00050
00051 HexUctPolicyConfig::HexUctPolicyConfig()
00052 : patternHeuristic(true),
00053 responseHeuristic(false),
00054 pattern_update_radius(1),
00055 pattern_check_percent(100),
00056 response_threshold(100)
00057 {
00058 }
00059
00060
00061
00062 HexUctSharedPolicy::HexUctSharedPolicy()
00063 : m_config()
00064 {
00065 LogFine() << "--- HexUctSharedPolicy\n";
00066 LoadPatterns();
00067 }
00068
00069 HexUctSharedPolicy::~HexUctSharedPolicy()
00070 {
00071 }
00072
00073 void HexUctSharedPolicy::LoadPatterns()
00074 {
00075 using namespace boost::filesystem;
00076 path p = path(ABS_TOP_SRCDIR) / "share" / "mohex-patterns.txt";
00077 p.normalize();
00078 LoadPlayPatterns(p.native_file_string());
00079 }
00080
00081 void HexUctSharedPolicy::LoadPlayPatterns(const std::string& filename)
00082 {
00083 std::vector<Pattern> patterns;
00084 Pattern::LoadPatternsFromFile(filename.c_str(), patterns);
00085 LogInfo() << "HexUctSharedPolicy: Read " << patterns.size()
00086 << " patterns from '" << filename << "'.\n";
00087
00088
00089 HexAssert(m_patterns[BLACK].empty());
00090
00091 for (std::size_t i = 0; i < patterns.size(); ++i) {
00092 Pattern p = patterns[i];
00093 switch(p.getType()) {
00094 case Pattern::MOHEX:
00095 m_patterns[BLACK].push_back(p);
00096 p.flipColors();
00097 m_patterns[WHITE].push_back(p);
00098 break;
00099 default:
00100 LogWarning() << "Pattern type = " << p.getType() << '\n';
00101 HexAssert(false);
00102 }
00103 }
00104
00105 for (BWIterator color; color; ++color)
00106 m_hash_patterns[*color].hash(m_patterns[*color]);
00107 }
00108
00109
00110
00111 HexUctPolicy::HexUctPolicy(const HexUctSharedPolicy* shared)
00112 : m_shared(shared)
00113 #if COLLECT_PATTERN_STATISTICS
00114 , m_statistics()
00115 #endif
00116 {
00117 }
00118
00119 HexUctPolicy::~HexUctPolicy()
00120 {
00121 }
00122
00123
00124
00125
00126 void HexUctPolicy::InitializeForSearch()
00127 {
00128 for (int i = 0; i < BITSETSIZE; ++i)
00129 {
00130 m_response[BLACK][i].clear();
00131 m_response[WHITE][i].clear();
00132 }
00133 }
00134
00135 void HexUctPolicy::InitializeForRollout(const StoneBoard& brd)
00136 {
00137 BitsetUtil::BitsetToVector(brd.GetEmpty(), m_moves);
00138 ShuffleVector(m_moves, m_random);
00139 }
00140
00141 HexPoint HexUctPolicy::GenerateMove(PatternState& pastate,
00142 HexColor toPlay,
00143 HexPoint lastMove)
00144 {
00145 HexPoint move = INVALID_POINT;
00146 bool pattern_move = false;
00147 const HexUctPolicyConfig& config = m_shared->Config();
00148 #if COLLECT_PATTERN_STATISTICS
00149 HexUctPolicyStatistics& stats = m_statistics;
00150 #endif
00151
00152
00153 if (config.patternHeuristic
00154 && PercentChance(config.pattern_check_percent, m_random))
00155 {
00156 move = GeneratePatternMove(pastate, toPlay, lastMove);
00157 }
00158
00159 if (move == INVALID_POINT
00160 && config.responseHeuristic)
00161 {
00162 move = GenerateResponseMove(toPlay, lastMove, pastate.Board());
00163 }
00164
00165
00166 if (move == INVALID_POINT)
00167 {
00168 #if COLLECT_PATTERN_STATISTICS
00169 stats.random_moves++;
00170 #endif
00171 move = GenerateRandomMove(pastate.Board());
00172 }
00173 else
00174 {
00175 pattern_move = true;
00176 #if COLLECT_PATTERN_STATISTICS
00177 stats.pattern_moves++;
00178 #endif
00179 }
00180
00181 HexAssert(pastate.Board().IsEmpty(move));
00182 #if COLLECT_PATTERN_STATISTICS
00183 stats.total_moves++;
00184 #endif
00185 return move;
00186 }
00187
00188 #if COLLECT_PATTERN_STATISTICS
00189 std::string HexUctPolicy::DumpStatistics()
00190 {
00191 std::ostringstream os;
00192
00193 os << std::endl;
00194 os << "Pattern statistics:" << std::endl;
00195 os << std::setw(12) << "Name" << " "
00196 << std::setw(10) << "Black" << " "
00197 << std::setw(10) << "White" << " "
00198 << std::setw(10) << "Black" << " "
00199 << std::setw(10) << "White" << std::endl;
00200
00201 os << " ------------------------------------------------------"
00202 << std::endl;
00203
00204 HexUctPolicyStatistics& stats = Statistics();
00205 for (unsigned i=0; i<m_patterns[BLACK].size(); ++i) {
00206 os << std::setw(12) << m_patterns[BLACK][i].getName() << ": "
00207 << std::setw(10) << stats.pattern_counts[BLACK]
00208 [&m_patterns[BLACK][i]] << " "
00209 << std::setw(10) << stats.pattern_counts[WHITE]
00210 [&m_patterns[WHITE][i]] << " "
00211 << std::setw(10) << stats.pattern_picked[BLACK]
00212 [&m_patterns[BLACK][i]] << " "
00213 << std::setw(10) << stats.pattern_picked[WHITE]
00214 [&m_patterns[WHITE][i]]
00215 << std::endl;
00216 }
00217
00218 os << " ------------------------------------------------------"
00219 << std::endl;
00220
00221 os << std::endl;
00222 os << std::setw(12) << "Pattern" << ": "
00223 << std::setw(10) << stats.pattern_moves << " "
00224 << std::setw(10) << std::setprecision(3) <<
00225 stats.pattern_moves*100.0/stats.total_moves << "%"
00226 << std::endl;
00227 os << std::setw(12) << "Random" << ": "
00228 << std::setw(10) << stats.random_moves << " "
00229 << std::setw(10) << std::setprecision(3) <<
00230 stats.random_moves*100.0/stats.total_moves << "%"
00231 << std::endl;
00232 os << std::setw(12) << "Total" << ": "
00233 << std::setw(10) << stats.total_moves << std::endl;
00234
00235 os << std::endl;
00236
00237 return os.str();
00238 }
00239 #endif
00240
00241
00242
00243 HexPoint HexUctPolicy::GenerateResponseMove(HexColor toPlay, HexPoint lastMove,
00244 const StoneBoard& brd)
00245 {
00246 std::size_t num = m_response[toPlay][lastMove].size();
00247 if (num > m_shared->Config().response_threshold)
00248 {
00249 HexPoint move = m_response[toPlay][lastMove][m_random.Int(num)];
00250 if (brd.IsEmpty(move))
00251 return move;
00252 }
00253 return INVALID_POINT;
00254 }
00255
00256
00257 HexPoint HexUctPolicy::GenerateRandomMove(const StoneBoard& brd)
00258 {
00259 HexPoint ret = INVALID_POINT;
00260 while (true)
00261 {
00262 HexAssert(!m_moves.empty());
00263 ret = m_moves.back();
00264 m_moves.pop_back();
00265 if (brd.IsEmpty(ret))
00266 break;
00267 }
00268 return ret;
00269 }
00270
00271
00272
00273
00274 HexPoint HexUctPolicy::PickRandomPatternMove(const PatternState& pastate,
00275 const HashedPatternSet& patterns,
00276 HexColor toPlay,
00277 HexPoint lastMove)
00278 {
00279 UNUSED(toPlay);
00280
00281 if (lastMove == INVALID_POINT)
00282 return INVALID_POINT;
00283
00284 int num = 0;
00285 int patternIndex[MAX_VOTES];
00286 HexPoint patternMoves[MAX_VOTES];
00287
00288 PatternHits hits;
00289 pastate.MatchOnCell(patterns, lastMove, PatternState::MATCH_ALL, hits);
00290
00291 for (unsigned i = 0; i < hits.size(); ++i)
00292 {
00293 #if COLLECT_PATTERN_STATISTICS
00294
00295 m_shared->Statistics().pattern_counts[toPlay][hits[i].pattern()]++;
00296 #endif
00297
00298
00299 for (int j = 0; j < hits[i].pattern()->getWeight(); ++j)
00300 {
00301 patternIndex[num] = i;
00302 patternMoves[num] = hits[i].moves1()[0];
00303 num++;
00304 HexAssert(num < MAX_VOTES);
00305 }
00306 }
00307
00308
00309 if (num == 0)
00310 return INVALID_POINT;
00311
00312
00313 int i = m_random.Int(num);
00314
00315 #if COLLECT_PATTERN_STATISTICS
00316 m_shared->Statistics().pattern_picked
00317 [toPlay][hits[patternIndex[i]].pattern()]++;
00318 #endif
00319
00320 return patternMoves[i];
00321 }
00322
00323
00324 HexPoint HexUctPolicy::GeneratePatternMove(const PatternState& pastate,
00325 HexColor toPlay,
00326 HexPoint lastMove)
00327 {
00328 return PickRandomPatternMove(pastate, m_shared->PlayPatterns(toPlay),
00329 toPlay, lastMove);
00330 }
00331
00332