Main   Namespaces   Classes   Hierarchy   Annotated   Files   Compound   Global   Pages  

BoardUtils.cpp

Go to the documentation of this file.
00001 //----------------------------------------------------------------------------
00002 /** @file BoardUtils.cpp
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 /** Initialize the miai pattern. */
00030 void InitializeOppMiai()
00031 {
00032     if (g_BoardUtilsDecompsInitialized) return;
00033 
00034     LogFine() << "--InitializeOppMiai" << '\n';
00035 
00036     //
00037     // Miai between groups of opposite color.
00038     // W is marked; so if you use this pattern on the black members of 
00039     // group, it will tell you the white groups that are adjacent to it. 
00040     // Used in the decomposition stuff. 
00041     //
00042     //               . W  
00043     //              * .                        [oppmiai/0]
00044     // 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
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 /** @todo Is it possible to speed this up? */
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 } // namespace
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     // If game is over or decided, don't do any work.
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     /** Compute neighbouring groups of opposite color.
00314 
00315         @note Assumes that edges that touch are adjacent. See
00316         ConstBoard for more details. 
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     // The two color edges are in the list. If no other groups are, then quit.
00329     HexAssert(adjTo.size() >= 2);
00330     if (adjTo.size() == 2) 
00331     {
00332     captured.reset();
00333     return false;
00334     }
00335     
00336     // Compute graph representing board from color's perspective.
00337     PointToBitset graphNbs;
00338     GraphUtils::ComputeDigraph(brd.GetGroups(), color, graphNbs);
00339     
00340     // Find (ordered) pairs of color groups that are VC-connected and have at
00341     // least two adjacent opponent groups in common.
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         // This is such a pair, so at least one of the two is not an edge.
00349         // Find which color edges are not equal to either of these groups.
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         // Find the set of empty cells bounded by these two groups.
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         // If the pair has a VC confined to these cells, then we have
00367         // a decomposition - return it.
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     // No combinatorial decomposition with a VC was found.
00379     captured.reset();
00380     return false;
00381 }
00382 
00383 bool BoardUtils::FindSplittingDecomposition(const HexBoard& brd,
00384                         HexColor color,
00385                         HexPoint& group)
00386 {
00387     // compute nbrs of color edges
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     // @note must & with getCells() because we want non-edge groups;
00397     // this assumes that edges are always captains. 
00398     bitset_t adjToBothEdges = adjto1 & adjto2 & brd.Const().GetCells();
00399 
00400     // if there is a group adjacent to both opponent edges, return it.
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 //----------------------------------------------------------------------------


6 Jan 2011 Doxygen 1.6.3