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