Index   Main   Namespaces   Classes   Hierarchy   Annotated   Files   Compound   Global   Pages  

GoRegionUtil.cpp

Go to the documentation of this file.
00001 //----------------------------------------------------------------------------
00002 /** @file GoRegionUtil.cpp
00003     See GoRegionUtil.h.
00004 */
00005 //----------------------------------------------------------------------------
00006 
00007 #include "SgSystem.h"
00008 #include "GoRegionUtil.h"
00009 
00010 #include "GoBoard.h"
00011 #include "GoBoardUtil.h"
00012 #include "GoEyeUtil.h"
00013 #include "SgVector.h"
00014 #include "SgPointSet.h"
00015 
00016 //----------------------------------------------------------------------------
00017 
00018 namespace {
00019 
00020 /** Special case of single boundary block */
00021 bool Has2IntersectionPoints(const GoBoard& board, const SgPointSet& region, 
00022                             const SgPoint boundaryAnchor)
00023 {
00024     int nuIPs = 0;
00025     for (GoBoard::LibertyIterator it(board, boundaryAnchor); it; ++it)
00026     {
00027         if (  region.Contains(*it)
00028            && GoEyeUtil::IsSplitPt(*it, region)
00029            && ++nuIPs >= 2
00030            )
00031             return true;
00032     }
00033     return false;
00034 }
00035 
00036 /** Do liberties of boundary blocks contain 2 intersection points? */
00037 bool Has2IntersectionPoints(const GoBoard& board, const SgPointSet& region, 
00038                             const SgVector<SgPoint>& boundaryAnchors)
00039 {
00040     if (boundaryAnchors.IsLength(1)) // single block
00041         return Has2IntersectionPoints(board, region, boundaryAnchors.Back());
00042     else // compute joint liberties of all blocks in region.
00043     {
00044         SgVector<SgPoint> sharedLibs;
00045         for (GoBoard::LibertyIterator it(board, boundaryAnchors.Front()); it;
00046              ++it)
00047             if (region.Contains(*it))
00048                 sharedLibs.PushBack(*it);
00049 
00050         if (sharedLibs.MaxLength(1))
00051             return false;
00052         bool first = true;
00053         for (SgVectorIterator<SgPoint> it(boundaryAnchors); it; ++it)
00054         {
00055             if (first) // we already have the liberties of first block.
00056                 first = false;
00057             else // keep those sharedLibs that are libs of block
00058             {
00059                 SgVector<SgPoint> newShared;
00060                 const SgPoint block = *it;
00061                 for (GoBoard::LibertyIterator it(board, block); it; ++it)
00062                     if (sharedLibs.Contains(*it))
00063                         newShared.PushBack(*it);
00064                 if (newShared.MaxLength(1))
00065                     return false;
00066                 else
00067                     newShared.SwapWith(&sharedLibs);
00068             }
00069         }
00070         
00071         // now we have at least two shared libs, check if at least two are
00072         // split points that divide the area into two eyes.
00073         int nuIPs = 0;
00074         for (SgVectorIterator<SgPoint> it(sharedLibs); it; ++it)
00075         {
00076             if (  GoEyeUtil::IsSplitPt(*it, region)
00077                && ++nuIPs >= 2
00078                )
00079                     /* */ return true; /* */
00080         }
00081         return false;
00082     }
00083 }
00084 
00085 /** Is p adjacent to all blocks represented by anchors?
00086     GoRegion has an identical function taking a list of GoBlock's.
00087 */
00088 inline bool IsAdjacentToAll(const GoBoard& board, SgPoint p,
00089                             const SgVector<SgPoint>& anchors)
00090 {
00091     for (SgVectorIterator<SgPoint> it(anchors); it; ++it)
00092         if (! board.IsLibertyOfBlock(p, *it))
00093             return false;
00094     return true;
00095 }
00096 
00097 /** A simple test if the 2-vital search has produced a two-eyed group.
00098     @todo To be replaced by incremental region code, which will recognize the
00099     eye regions.
00100     Right now, test only for special cases, not even Benson.
00101         1. single block 2 eyes
00102         2. simple check for 2 blocks
00103 */
00104 bool TwoSeparateEyes(const GoBoard& bd, const SgPointSet& pts,
00105                      const SgPointSet& boundary, SgBlackWhite color)
00106 {
00107     SG_ASSERT((pts & bd.AllEmpty()).SubsetOf(boundary.Border(bd.Size())));
00108     
00109     if (pts.Disjoint(bd.All(color)) && ! pts.IsConnected())
00110     {
00111         if (GoRegionUtil::IsSingleBlock(bd, boundary, color))
00112             return true;
00113         else
00114         {
00115             const SgPointSet area = pts & bd.AllEmpty();
00116             if (area.MinSetSize(2))
00117             {
00118                 for (SgSetIterator it(area); it; ++it)
00119                     if (bd.IsLegal(*it, SgOppBW(color)))
00120                         return false;
00121                 return true;
00122             }
00123         }
00124     }
00125     return false;
00126 }
00127 
00128 } // namespace
00129 
00130 //----------------------------------------------------------------------------
00131 
00132 void GoRegionUtil::FindCurrentAnchors(const GoBoard& board,
00133                                       const SgVector<SgPoint>& origAnchors,
00134                                       SgVector<SgPoint>* currentAnchors)
00135 {
00136     SG_ASSERT(currentAnchors->IsEmpty());
00137     for (SgVectorIterator<SgPoint> it(origAnchors); it; ++it)
00138         currentAnchors->Insert(board.Anchor(*it));
00139 }
00140 
00141 bool GoRegionUtil::Has2IPorEyes(const GoBoard& board, const SgPointSet& pts,
00142                                 SgBlackWhite color,
00143                                 const SgVector<SgPoint>& boundaryAnchors)
00144 {
00145     return     Has2IntersectionPoints(board, pts, boundaryAnchors) 
00146             || (  boundaryAnchors.IsLength(1) 
00147                && pts.Disjoint(board.All(color)) 
00148                && ! pts.IsConnected()
00149                );
00150 }
00151 
00152 bool GoRegionUtil::Has2SureLiberties(const GoBoard& board,
00153                                      const SgPointSet& pts,
00154                                      SgBlackWhite color,
00155                                      const SgVector<SgPoint>& boundaryAnchors)
00156 {
00157     const int size = board.Size();
00158     SgPointSet boundary(pts.Border(size));
00159     if (! boundary.SubsetOf(board.All(color)))
00160     {
00161         return false; // no result of open area
00162     }
00163     else
00164     {
00165         boundary -= board.AllEmpty();
00166         SG_ASSERT(boundary.SubsetOf(board.All(color)));
00167     }
00168     // Cond 1: all empty points are in liberties of some boundary block
00169     // Cond 2: two intersection points
00170     
00171     if (  (pts & board.AllEmpty()).SubsetOf(boundary.Border(size))
00172        && (  Has2IntersectionPoints(board, pts, boundaryAnchors)
00173           || TwoSeparateEyes(board, pts, boundary, color)
00174           )
00175        )
00176         /* */ return true; /* */
00177     
00178     return false;
00179 }
00180 
00181 bool GoRegionUtil::IsSingleBlock(const GoBoard& board, const SgPointSet& pts,
00182                                  SgBlackWhite color)
00183 {
00184     SG_DEBUG_ONLY(color);
00185     // exception for completely empty board. @todo catch this elsewhere???
00186     SG_ASSERT(pts.NonEmpty()
00187               || board.TotalNumEmpty() == board.Size() * board.Size());
00188     
00189     SgPoint firstAnchor(SG_NULLPOINT);
00190     for (SgSetIterator it(pts); it; ++it)
00191     {
00192         SG_ASSERT(board.IsColor(*it, color));
00193         const SgPoint anchor = board.Anchor(*it);
00194         if (anchor != firstAnchor)
00195         {
00196             if (firstAnchor == SG_NULLPOINT)
00197                 firstAnchor = anchor;
00198             else
00199                 return false;
00200         }
00201     }
00202     return true;
00203 }
00204 
00205 bool GoRegionUtil::IsSmallRegion(const GoBoard& board, const SgPointSet& pts,
00206                                  SgBlackWhite opp)
00207 {
00208     const int size = board.Size();
00209     return pts.Kernel(size).SubsetOf(board.All(opp));
00210 }
00211 
00212 bool GoRegionUtil::StaticIs1VitalAndConnected(const GoBoard& board,
00213                                               const SgPointSet& pts,
00214                                               SgBlackWhite color)
00215 {
00216     // type 1:small region with two connection points for all blocks
00217     SgVector<SgPoint> anchors;
00218     GoBoardUtil::BlocksAdjacentToPoints(board, pts, color, &anchors);
00219     
00220     bool is1Vital = false;
00221     
00222     if (IsSmallRegion(board, pts, SgOppBW(color)))
00223     {
00224         if (anchors.MaxLength(1)) // single block, connected.
00225             /* */ return true; /* */
00226         else if (anchors.MinLength(5)) 
00227         // no way so many blocks can be connected.
00228             return false;
00229             
00230         int nuConn = 0;
00231         for (SgSetIterator it(pts); it; ++it)
00232         {
00233             const SgPoint p(*it);
00234             if (board.IsEmpty(p) && IsAdjacentToAll(board, p, anchors))
00235             {   // test if boundary stones can be connected by playing p
00236                 if (++nuConn >= 2)
00237                 {
00238                     is1Vital = true;
00239                     break;
00240                 }
00241             }
00242         }
00243     }
00244     return is1Vital;    
00245 }
00246 
00247 //----------------------------------------------------------------------------


17 Jun 2010 Doxygen 1.4.7