00001
00002
00003
00004
00005 #include "BitsetIterator.hpp"
00006 #include "BoardUtils.hpp"
00007 #include "PatternState.hpp"
00008
00009 using namespace benzene;
00010
00011
00012
00013 const PatternMatcherData* PatternMatcherData::Get(const ConstBoard* brd)
00014 {
00015 static std::vector<const PatternMatcherData*> data;
00016 for (std::size_t i=0; i<data.size(); ++i)
00017 {
00018 if (*brd == *data[i]->brd)
00019 return data[i];
00020 }
00021
00022 LogFine() << "Data does not exist. Creating..." << '\n';
00023
00024 data.push_back(new PatternMatcherData(brd));
00025 return data.back();
00026 }
00027
00028 PatternMatcherData::PatternMatcherData(const ConstBoard* brd)
00029 : brd(brd)
00030 {
00031 Initialize();
00032 }
00033
00034
00035 void PatternMatcherData::Initialize()
00036 {
00037 LogFine() << "PatternMatcherData::Initialize "
00038 << "(" << brd->Width() << " x " << brd->Height() <<")" << '\n';
00039
00040 memset(played_in_slice, 0, sizeof(played_in_slice));
00041 memset(played_in_godel, 0, sizeof(played_in_godel));
00042 memset(played_in_edge, 0, sizeof(played_in_edge));
00043 memset(inverse_slice_godel, 0, sizeof(inverse_slice_godel));
00044
00045 for (BoardIterator ip1=brd->Interior(); ip1; ++ip1)
00046 {
00047 int x, y;
00048 HexPoint p1 = *ip1;
00049 HexPointUtil::pointToCoords(p1, x, y);
00050
00051 for (int s=0; s<Pattern::NUM_SLICES; s++)
00052 {
00053 int fwd = s;
00054 int lft = (s + 2) % NUM_DIRECTIONS;
00055
00056 int x1 = x + HexPointUtil::DeltaX(fwd);
00057 int y1 = y + HexPointUtil::DeltaY(fwd);
00058
00059 for (int i=1, g=0; i<=Pattern::MAX_EXTENSION; i++)
00060 {
00061 int x2 = x1;
00062 int y2 = y1;
00063 for (int j=0; j<i; j++)
00064 {
00065
00066 if (x2 == -1 && y2 == brd->Height())
00067 {
00068
00069 played_in_edge[p1][SOUTH - FIRST_EDGE][s]
00070 |= (1 << g);
00071 played_in_edge[p1][WEST - FIRST_EDGE][s]
00072 |= (1 << g);
00073 }
00074
00075 else if (x2 == brd->Width() && y2 == -1)
00076 {
00077
00078 played_in_edge[p1][NORTH - FIRST_EDGE][s]
00079 |= (1 << g);
00080 played_in_edge[p1][EAST - FIRST_EDGE][s]
00081 |= (1 << g);
00082 }
00083 else
00084 {
00085
00086 HexPoint p2
00087 = BoardUtils::CoordsToPoint(*brd, x2, y2);
00088
00089 if (p2 != INVALID_POINT)
00090 {
00091 if (HexPointUtil::isEdge(p2))
00092 {
00093 played_in_edge[p1][p2 - FIRST_EDGE][s]
00094 |= (1 << g);
00095 }
00096 else
00097 {
00098 played_in_slice[p1][p2] = s;
00099 played_in_godel[p1][p2] = (1 << g);
00100 }
00101 inverse_slice_godel[p1][s][g] = p2;
00102 }
00103 }
00104
00105 x2 += HexPointUtil::DeltaX(lft);
00106 y2 += HexPointUtil::DeltaY(lft);
00107 g++;
00108 }
00109 x1 += HexPointUtil::DeltaX(fwd);
00110 y1 += HexPointUtil::DeltaY(fwd);
00111 }
00112 }
00113 }
00114 }
00115
00116 HexPoint PatternMatcherData::GetRotatedMove(HexPoint cell, int slice,
00117 int bit, int angle) const
00118 {
00119 slice = (slice + 6 - angle) % Pattern::NUM_SLICES;
00120 return inverse_slice_godel[cell][slice][bit];
00121 }
00122
00123
00124
00125 PatternState::PatternState(StoneBoard& brd)
00126 : m_brd(brd),
00127 m_data(PatternMatcherData::Get(&m_brd.Const())),
00128 m_update_radius(Pattern::MAX_EXTENSION)
00129 {
00130 ClearGodels();
00131 }
00132
00133 PatternState::~PatternState()
00134 {
00135 }
00136
00137
00138
00139 void PatternState::UpdateRingGodel(HexPoint cell)
00140 {
00141 HexAssert(m_brd.Const().IsCell(cell));
00142 HexColor color = m_brd.GetColor(cell);
00143 HexAssert(HexColorUtil::isBlackWhite(color));
00144
00145
00146
00147
00148 HexAssert(Pattern::NUM_SLICES == 6);
00149 for (int opp_slice = 3, slice = 0; slice < Pattern::NUM_SLICES; ++slice)
00150 {
00151 HexPoint p = m_data->inverse_slice_godel[cell][slice][0];
00152 m_ring_godel[p].AddColorToSlice(opp_slice, color);
00153 m_ring_godel[p].RemoveColorFromSlice(opp_slice, EMPTY);
00154 if (++opp_slice == Pattern::NUM_SLICES) opp_slice = 0;
00155 }
00156 }
00157
00158 void PatternState::Update(HexPoint cell)
00159 {
00160 if (HexPointUtil::isSwap(cell))
00161 return;
00162
00163 HexAssert(m_brd.Const().IsLocation(cell));
00164
00165 int r = m_update_radius;
00166 HexColor color = m_brd.GetColor(cell);
00167 HexAssert(HexColorUtil::isBlackWhite(color));
00168
00169 if (HexPointUtil::isEdge(cell))
00170 goto handleEdge;
00171
00172 for (BoardIterator p = m_brd.Const().Nbs(cell, r); p; ++p)
00173 {
00174 int slice = m_data->played_in_slice[*p][cell];
00175 int godel = m_data->played_in_godel[*p][cell];
00176 m_slice_godel[*p][color][slice] |= godel;
00177
00178
00179 if (godel == 1)
00180 {
00181 m_ring_godel[*p].AddColorToSlice(slice, color);
00182 m_ring_godel[*p].RemoveColorFromSlice(slice, EMPTY);
00183 }
00184 }
00185 return;
00186
00187 handleEdge:
00188
00189 int edge = cell - FIRST_EDGE;
00190 for (BoardIterator p = m_brd.Const().Nbs(cell, r); p; ++p)
00191 {
00192 for (int slice = 0; slice < Pattern::NUM_SLICES; ++slice)
00193 {
00194 int godel = m_data->played_in_edge[*p][edge][slice];
00195 m_slice_godel[*p][color][slice] |= godel;
00196
00197
00198
00199
00200 if ((godel & 1) == 1)
00201 {
00202 m_ring_godel[*p].AddColorToSlice(slice, color);
00203 m_ring_godel[*p].RemoveColorFromSlice(slice, EMPTY);
00204 }
00205 }
00206 }
00207 }
00208
00209 void PatternState::Update(const bitset_t& changed)
00210 {
00211 for (BitsetIterator p(changed); p; ++p)
00212 {
00213 HexAssert(m_brd.IsOccupied(*p));
00214 Update(*p);
00215 }
00216 }
00217
00218 void PatternState::Update()
00219 {
00220 ClearGodels();
00221 for (BitsetIterator p(m_brd.GetBlack() | m_brd.GetWhite()); p; ++p)
00222 Update(*p);
00223 }
00224
00225 void PatternState::ClearGodels()
00226 {
00227 memset(m_slice_godel, 0, sizeof(m_slice_godel));
00228 for (BoardIterator p(m_brd.Const().Interior()); p; ++p)
00229 m_ring_godel[*p].SetEmpty();
00230 }
00231
00232 void PatternState::CopyState(const PatternState& other)
00233 {
00234 HexAssert(m_brd.Const() == other.m_brd.Const());
00235 m_update_radius = other.m_update_radius;
00236 memcpy(m_slice_godel, other.m_slice_godel, sizeof(m_slice_godel));
00237 memcpy(m_ring_godel, other.m_ring_godel, sizeof(m_ring_godel));
00238 }
00239
00240
00241
00242 void PatternState::MatchOnCell(const HashedPatternSet& patset,
00243 HexPoint cell, MatchMode mode,
00244 PatternHits& hits) const
00245 {
00246 const RingGodel& ring_godel = m_ring_godel[cell];
00247 const RotatedPatternList& rlist = patset.ListForGodel(ring_godel);
00248 RotatedPatternList::const_iterator it = rlist.begin();
00249 for (; it != rlist.end(); ++it)
00250 {
00251 std::vector<HexPoint> moves1, moves2;
00252 if (CheckRotatedPattern(cell, *it, moves1, moves2))
00253 {
00254 hits.push_back(PatternHit(it->pattern(), moves1, moves2));
00255 if (mode == STOP_AT_FIRST_HIT)
00256 break;
00257 }
00258 }
00259 }
00260
00261 bitset_t PatternState::MatchOnBoard(const bitset_t& consider,
00262 const HashedPatternSet& patset,
00263 MatchMode mode,
00264 std::vector<PatternHits>& hits) const
00265 {
00266 bitset_t ret;
00267 bitset_t lookat = consider & Board().Const().GetCells();
00268 for (BitsetIterator p(lookat); p; ++p)
00269 {
00270 MatchOnCell(patset, *p, mode, hits[*p]);
00271 if (!hits[*p].empty())
00272 ret.set(*p);
00273 }
00274 return ret;
00275 }
00276
00277 bitset_t PatternState::MatchOnBoard(const bitset_t& consider,
00278 const HashedPatternSet& patset) const
00279 {
00280 bitset_t ret;
00281 bitset_t lookat = consider & Board().Const().GetCells();
00282 for (BitsetIterator p(lookat); p; ++p)
00283 {
00284 PatternHits hits;
00285 MatchOnCell(patset, *p, STOP_AT_FIRST_HIT, hits);
00286 if (!hits.empty())
00287 ret.set(*p);
00288 }
00289 return ret;
00290 }
00291
00292
00293
00294
00295
00296 bool PatternState::CheckRotatedPattern(HexPoint cell,
00297 const RotatedPattern& rotpat,
00298 std::vector<HexPoint>& moves1,
00299 std::vector<HexPoint>& moves2) const
00300 {
00301 HexAssert(m_brd.Const().IsCell(cell));
00302
00303 m_statistics.pattern_checks++;
00304
00305 bool matches = CheckRingGodel(cell, rotpat);
00306
00307 const Pattern* pattern = rotpat.pattern();
00308 if (matches && pattern->extension() > 1)
00309 matches = CheckRotatedSlices(cell, rotpat);
00310
00311 if (matches)
00312 {
00313 if (pattern->getFlags() & Pattern::HAS_MOVES1)
00314 {
00315 for (unsigned i = 0; i < pattern->getMoves1().size(); ++i)
00316 {
00317 int slice = pattern->getMoves1()[i].first;
00318 int bit = pattern->getMoves1()[i].second;
00319 moves1.push_back(m_data->GetRotatedMove(cell, slice, bit,
00320 rotpat.angle()));
00321 }
00322 }
00323
00324 if (pattern->getFlags() & Pattern::HAS_MOVES2)
00325 {
00326 for (unsigned i = 0; i < pattern->getMoves2().size(); ++i)
00327 {
00328 int slice = pattern->getMoves2()[i].first;
00329 int bit = pattern->getMoves2()[i].second;
00330 moves2.push_back(m_data->GetRotatedMove(cell, slice, bit,
00331 rotpat.angle()));
00332 }
00333 }
00334 return true;
00335 }
00336 return false;
00337 }
00338
00339
00340 bool PatternState::CheckRotatedSlices(HexPoint cell,
00341 const RotatedPattern& rotpat) const
00342 {
00343 return CheckRotatedSlices(cell, *rotpat.pattern(), rotpat.angle());
00344 }
00345
00346
00347
00348 bool PatternState::CheckRotatedSlices(HexPoint cell, const Pattern& pattern,
00349 int angle) const
00350 {
00351 const int *gb = m_slice_godel[cell][BLACK];
00352 const int *gw = m_slice_godel[cell][WHITE];
00353 const Pattern::slice_t* pat = pattern.getData();
00354
00355 bool matches = true;
00356 for (int i = 0; matches && i < Pattern::NUM_SLICES; ++i)
00357 {
00358 m_statistics.slice_checks++;
00359
00360 int j = (angle + i) % Pattern::NUM_SLICES;
00361
00362 int black_b = gb[i] & pat[j][Pattern::FEATURE_CELLS];
00363 int white_b = gw[i] & pat[j][Pattern::FEATURE_CELLS];
00364 int empty_b = black_b | white_b;
00365
00366 int black_p = pat[j][Pattern::FEATURE_BLACK];
00367 int white_p = pat[j][Pattern::FEATURE_WHITE];
00368 int empty_p = pat[j][Pattern::FEATURE_CELLS] -
00369 pat[j][Pattern::FEATURE_BLACK] -
00370 pat[j][Pattern::FEATURE_WHITE];
00371
00372
00373
00374
00375
00376
00377
00378
00379 if (empty_b & empty_p)
00380 matches = false;
00381 else if ((black_b & black_p) != black_p)
00382 matches = false;
00383 else if ((white_b & white_p) != white_p)
00384 matches = false;
00385 }
00386 return matches;
00387 }
00388
00389
00390 bool PatternState::CheckRingGodel(HexPoint cell,
00391 const RotatedPattern& rotpat) const
00392 {
00393 return CheckRingGodel(cell, *rotpat.pattern(), rotpat.angle());
00394 }
00395
00396
00397 bool PatternState::CheckRingGodel(HexPoint cell,
00398 const Pattern& pattern, int angle) const
00399 {
00400 m_statistics.ring_checks++;
00401 return pattern.RingGodel(angle).MatchesGodel(m_ring_godel[cell]);
00402 }
00403
00404
00405
00406 void PatternState::ClearPatternCheckStats()
00407 {
00408 m_statistics.pattern_checks = 0;
00409 m_statistics.ring_checks = 0;
00410 m_statistics.slice_checks = 0;
00411 }
00412
00413 std::string PatternState::DumpPatternCheckStats() const
00414 {
00415 std::ostringstream os;
00416 os << std::endl;
00417 os << " Patterns Checked: " << m_statistics.pattern_checks << '\n';
00418 os << " Ring Godels Checked: " << m_statistics.ring_checks << '\n';
00419 os << " Slices Checked: " << m_statistics.slice_checks << '\n';
00420 os << " Avg Rings Per Check: "
00421 << std::setprecision(4)
00422 << static_cast<double>(m_statistics.ring_checks)
00423 / static_cast<double>(m_statistics.pattern_checks) << '\n';
00424 os << "Avg Slices Per Check: "
00425 << std::setprecision(4)
00426 << static_cast<double>(m_statistics.slice_checks)
00427 / static_cast<double>(m_statistics.pattern_checks) << '\n';
00428 return os.str();
00429 }
00430
00431