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 //----------------------------------------------------------------------------