00001
00002
00003
00004
00005
00006 #include "SgSystem.h"
00007 #include "SgRandom.h"
00008
00009 #include "BoardUtils.hpp"
00010 #include "BitsetIterator.hpp"
00011 #include "VCSet.hpp"
00012 #include "GraphUtils.hpp"
00013 #include "HexBoard.hpp"
00014 #include "Pattern.hpp"
00015 #include "HashedPatternSet.hpp"
00016
00017 using namespace benzene;
00018
00019
00020
00021 namespace {
00022
00023
00024
00025 bool g_BoardUtilsDecompsInitialized = false;
00026 std::vector<Pattern> g_oppmiai[BLACK_AND_WHITE];
00027 HashedPatternSet g_hash_oppmiai[BLACK_AND_WHITE];
00028
00029
00030 void InitializeOppMiai()
00031 {
00032 if (g_BoardUtilsDecompsInitialized) return;
00033
00034 LogFine() << "--InitializeOppMiai" << '\n';
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045 std::string oppmiai = "m:5,0,4,4,0;1,0,0,0,0;0,0,0,0,0;0,0,0,0,0;0,0,0,0,0;0,0,0,0,0;1";
00046
00047 Pattern pattern;
00048 if (!pattern.unserialize(oppmiai)) {
00049 HexAssert(false);
00050 }
00051 pattern.setName("oppmiai");
00052
00053 g_oppmiai[BLACK].push_back(pattern);
00054 pattern.flipColors();
00055 g_oppmiai[WHITE].push_back(pattern);
00056
00057 for (BWIterator c; c; ++c)
00058 g_hash_oppmiai[*c].hash(g_oppmiai[*c]);
00059 }
00060
00061
00062 void ComputeAdjacentByMiai(const HexBoard& brd, PointToBitset& adjByMiai)
00063 {
00064 HexAssert(g_BoardUtilsDecompsInitialized);
00065
00066 adjByMiai.clear();
00067 for (BWIterator color; color; ++color)
00068 {
00069 for (BitsetIterator p(brd.GetPosition().GetColor(*color)
00070 & brd.GetPosition().Const().GetCells());
00071 p; ++p)
00072 {
00073 PatternHits hits;
00074 brd.GetPatternState().MatchOnCell(g_hash_oppmiai[*color], *p,
00075 PatternState::MATCH_ALL, hits);
00076 HexPoint cp = brd.GetGroups().CaptainOf(*p);
00077 for (unsigned j=0; j<hits.size(); ++j)
00078 {
00079 HexPoint cj = brd.GetGroups().CaptainOf(hits[j].moves1()[0]);
00080 adjByMiai[cj].set(cp);
00081 adjByMiai[cp].set(cj);
00082 }
00083 }
00084 }
00085 }
00086
00087 }
00088
00089
00090
00091 HexPoint BoardUtils::CoordsToPoint(const ConstBoard& brd, int x, int y)
00092 {
00093 if (x <= -2 || x > brd.Width()) return INVALID_POINT;
00094 if (y <= -2 || y > brd.Height()) return INVALID_POINT;
00095 if ((x == -1 || x == brd.Width()) &&
00096 (y == -1 || y == brd.Height())) return INVALID_POINT;
00097
00098 if (y == -1) return NORTH;
00099 if (y == brd.Height()) return SOUTH;
00100 if (x == -1) return WEST;
00101 if (x == brd.Width()) return EAST;
00102
00103 return HexPointUtil::coordsToPoint(x, y);
00104 }
00105
00106 HexPoint BoardUtils::PointInDir(const ConstBoard& brd,
00107 HexPoint point, HexDirection dir)
00108 {
00109 if (HexPointUtil::isEdge(point))
00110 return point;
00111
00112 int x, y;
00113 HexAssert(HexPointUtil::isInteriorCell(point));
00114 HexPointUtil::pointToCoords(point, x, y);
00115 x += HexPointUtil::DeltaX(dir);
00116 y += HexPointUtil::DeltaY(dir);
00117 return BoardUtils::CoordsToPoint(brd, x, y);
00118 }
00119
00120 HexPoint BoardUtils::Rotate(const ConstBoard& brd, HexPoint p)
00121 {
00122 HexAssert(brd.IsValid(p));
00123
00124 if (!brd.IsLocation(p)) return p;
00125 if (HexPointUtil::isEdge(p)) return HexPointUtil::oppositeEdge(p);
00126
00127 int x, y;
00128 HexPointUtil::pointToCoords(p, x, y);
00129 return HexPointUtil::coordsToPoint(brd.Width()-1-x, brd.Height()-1-y);
00130 }
00131
00132 HexPoint BoardUtils::Mirror(const ConstBoard& brd, HexPoint p)
00133 {
00134 HexAssert(brd.IsValid(p));
00135 HexAssert(brd.Width() == brd.Height());
00136
00137 if (!brd.IsLocation(p)) return p;
00138
00139 if (HexPointUtil::isEdge(p)) {
00140 if (HexPointUtil::isColorEdge(p, VERTICAL_COLOR))
00141 return HexPointUtil::rightEdge(p);
00142 else
00143 return HexPointUtil::leftEdge(p);
00144 }
00145
00146 int x, y;
00147 HexPointUtil::pointToCoords(p, x, y);
00148 return HexPointUtil::coordsToPoint(y, x);
00149 }
00150
00151 HexPoint BoardUtils::CenterPoint(const ConstBoard& brd)
00152 {
00153 HexAssert((brd.Width() & 1) && (brd.Height() & 1));
00154 return CenterPointRight(brd);
00155 }
00156
00157 HexPoint BoardUtils::CenterPointRight(const ConstBoard& brd)
00158 {
00159 int x = brd.Width() / 2;
00160 int y = brd.Height() / 2;
00161
00162 if (!(brd.Width() & 1) && !(brd.Height() & 1)) y--;
00163
00164 return HexPointUtil::coordsToPoint(x, y);
00165 }
00166
00167 HexPoint BoardUtils::CenterPointLeft(const ConstBoard& brd)
00168 {
00169 int x = brd.Width() / 2;
00170 int y = brd.Height() / 2;
00171
00172 if (!(brd.Width() & 1)) x--;
00173 if ((brd.Width() & 1) && !(brd.Height() & 1)) y--;
00174
00175 return HexPointUtil::coordsToPoint(x, y);
00176 }
00177
00178 HexPoint BoardUtils::RandomEmptyCell(const StoneBoard& brd)
00179 {
00180 bitset_t moves = brd.GetEmpty() & brd.Const().GetCells();
00181 int count = static_cast<int>(moves.count());
00182 if (count == 0)
00183 return INVALID_POINT;
00184
00185 int randMove = SgRandom::Global().Int(count) + 1;
00186 for (BitsetIterator p(moves); p; ++p)
00187 if (--randMove==0) return *p;
00188
00189 HexAssert(false);
00190 return INVALID_POINT;
00191 }
00192
00193
00194
00195 bitset_t BoardUtils::PackBitset(const ConstBoard& brd,
00196 const bitset_t& in)
00197 {
00198 int j=0;
00199 bitset_t ret;
00200 for (BoardIterator it(brd.Interior()); it; ++it, ++j) {
00201 if (in.test(*it))
00202 ret.set(j);
00203 }
00204 return ret;
00205 }
00206
00207 bitset_t BoardUtils::UnpackBitset(const ConstBoard& brd,
00208 const bitset_t& in)
00209 {
00210 int j=0;
00211 bitset_t ret;
00212 for (BoardIterator it(brd.Interior()); it; ++it, ++j) {
00213 if (in.test(j))
00214 ret.set(*it);
00215 }
00216 return ret;
00217 }
00218
00219 bitset_t BoardUtils::Rotate(const ConstBoard& brd,
00220 const bitset_t& bs)
00221 {
00222 bitset_t ret;
00223 for (BitsetIterator it(bs); it; ++it) {
00224 ret.set(Rotate(brd, *it));
00225 }
00226 return ret;
00227 }
00228
00229 bitset_t BoardUtils::Mirror(const ConstBoard& brd,
00230 const bitset_t& bs)
00231 {
00232 bitset_t ret;
00233 for (BitsetIterator it(bs); it; ++it) {
00234 ret.set(Mirror(brd, *it));
00235 }
00236 return ret;
00237 }
00238
00239 bool BoardUtils::ShiftBitset(const ConstBoard& brd, const bitset_t& bs,
00240 HexDirection dir, bitset_t& out)
00241 {
00242 out.reset();
00243 bool still_inside = true;
00244 for (BitsetIterator p(bs); p; ++p) {
00245 HexPoint s = PointInDir(brd, *p, dir);
00246 if (!HexPointUtil::isEdge(*p) && HexPointUtil::isEdge(s))
00247 still_inside = false;
00248 out.set(s);
00249 }
00250 return still_inside;
00251 }
00252
00253 bool BoardUtils::ConnectedOnBitset(const ConstBoard& brd,
00254 const bitset_t& carrier,
00255 HexPoint p1, HexPoint p2)
00256 {
00257 HexAssert(carrier.test(p1));
00258 HexAssert(carrier.test(p2));
00259 bitset_t seen = ReachableOnBitset(brd, carrier, EMPTY_BITSET, p1);
00260 return seen.test(p2);
00261 }
00262
00263 bitset_t BoardUtils::ReachableOnBitset(const ConstBoard& brd,
00264 const bitset_t& carrier,
00265 const bitset_t& stopset,
00266 HexPoint start)
00267 {
00268 HexAssert(carrier.test(start));
00269 bitset_t seen;
00270 std::queue<HexPoint> q;
00271 q.push(start);
00272 seen.set(start);
00273 while (!q.empty())
00274 {
00275 HexPoint p = q.front();
00276 q.pop();
00277 if (stopset.test(p))
00278 continue;
00279 for (BoardIterator nb(brd.Nbs(p)); nb; ++nb)
00280 {
00281 if (carrier.test(*nb) && !seen.test(*nb))
00282 {
00283 q.push(*nb);
00284 seen.set(*nb);
00285 }
00286 }
00287 }
00288 return seen;
00289 }
00290
00291
00292
00293 void BoardUtils::InitializeDecompositions()
00294 {
00295 InitializeOppMiai();
00296 g_BoardUtilsDecompsInitialized = true;
00297 }
00298
00299 bool BoardUtils::FindCombinatorialDecomposition(const HexBoard& brd,
00300 HexColor color,
00301 bitset_t& captured)
00302 {
00303
00304 HexPoint edge1 = HexPointUtil::colorEdge1(color);
00305 HexPoint edge2 = HexPointUtil::colorEdge2(color);
00306 const VCSet& cons = brd.Cons(color);
00307 if (brd.GetGroups().IsGameOver() || cons.Exists(edge1, edge2, VC::FULL))
00308 {
00309 captured.reset();
00310 return false;
00311 }
00312
00313
00314
00315
00316
00317
00318 PointToBitset adjTo;
00319 PointToBitset adjByMiai;
00320 ComputeAdjacentByMiai(brd, adjByMiai);
00321 for (GroupIterator g(brd.GetGroups(), color); g; ++g)
00322 {
00323 bitset_t opptNbs = adjByMiai[g->Captain()]
00324 | (g->Nbs() & brd.GetPosition().GetColor(!color));
00325 if (opptNbs.count() >= 2)
00326 adjTo[g->Captain()] = opptNbs;
00327 }
00328
00329 HexAssert(adjTo.size() >= 2);
00330 if (adjTo.size() == 2)
00331 {
00332 captured.reset();
00333 return false;
00334 }
00335
00336
00337 PointToBitset graphNbs;
00338 GraphUtils::ComputeDigraph(brd.GetGroups(), color, graphNbs);
00339
00340
00341
00342 PointToBitset::iterator g1, g2;
00343 for (g1 = adjTo.begin(); g1 != adjTo.end(); ++g1) {
00344 for (g2 = adjTo.begin(); g2 != g1; ++g2) {
00345 if ((g1->second & g2->second).count() < 2) continue;
00346 if (!cons.Exists(g1->first, g2->first, VC::FULL)) continue;
00347
00348
00349
00350 HexAssert(!HexPointUtil::isEdge(g1->first) ||
00351 !HexPointUtil::isEdge(g2->first));
00352 bool edge1Free = (g1->first != edge1 && g2->first != edge1);
00353 bool edge2Free = (g1->first != edge2 && g2->first != edge2);
00354
00355
00356 bitset_t stopSet = graphNbs[g1->first] | graphNbs[g2->first];
00357 bitset_t decompArea;
00358 decompArea.reset();
00359 if (edge1Free)
00360 decompArea |= GraphUtils::BFS(edge1, graphNbs, stopSet);
00361 if (edge2Free)
00362 decompArea |= GraphUtils::BFS(edge2, graphNbs, stopSet);
00363 decompArea.flip();
00364 decompArea &= brd.GetPosition().GetEmpty();
00365
00366
00367
00368 const VCList& vl = cons.GetList(VC::FULL, g1->first, g2->first);
00369 for (VCList::const_iterator vi=vl.begin(); vi!=vl.end(); ++vi) {
00370 if (BitsetUtil::IsSubsetOf(vi->carrier(), decompArea)) {
00371 captured = vi->carrier();
00372 return true;
00373 }
00374 }
00375 }
00376 }
00377
00378
00379 captured.reset();
00380 return false;
00381 }
00382
00383 bool BoardUtils::FindSplittingDecomposition(const HexBoard& brd,
00384 HexColor color,
00385 HexPoint& group)
00386 {
00387
00388 PointToBitset adjByMiai;
00389 ComputeAdjacentByMiai(brd, adjByMiai);
00390 const Groups& groups = brd.GetGroups();
00391 HexPoint edge1 = HexPointUtil::colorEdge1(!color);
00392 HexPoint edge2 = HexPointUtil::colorEdge2(!color);
00393 bitset_t adjto1 = adjByMiai[edge1] | groups.Nbs(edge1, color);
00394 bitset_t adjto2 = adjByMiai[edge2] | groups.Nbs(edge2, color);
00395
00396
00397
00398 bitset_t adjToBothEdges = adjto1 & adjto2 & brd.Const().GetCells();
00399
00400
00401 if (adjToBothEdges.any())
00402 {
00403 group = groups.CaptainOf(static_cast<HexPoint>
00404 (BitsetUtil::FirstSetBit(adjToBothEdges)));
00405 return true;
00406 }
00407 return false;
00408 }
00409
00410
00411
00412 std::string BoardUtils::GuiDumpOutsideConsiderSet(const StoneBoard& brd,
00413 const bitset_t& consider,
00414 const bitset_t& remove)
00415 {
00416 std::ostringstream os;
00417 bitset_t outside = brd.GetEmpty() - (remove | consider);
00418 for (BitsetIterator p(outside); p; ++p)
00419 os << " " << *p << " x";
00420 return os.str();
00421 }
00422
00423