00001 //---------------------------------------------------------------------------- 00002 /** @file GoSafetySolver.cpp 00003 See GoSafetySolver.h. */ 00004 //---------------------------------------------------------------------------- 00005 00006 #include "SgSystem.h" 00007 #include "GoSafetySolver.h" 00008 00009 #include "GoBlock.h" 00010 #include "GoChain.h" 00011 #include "GoSafetyUtil.h" 00012 #include "SgConnCompIterator.h" 00013 00014 //---------------------------------------------------------------------------- 00015 00016 namespace { 00017 00018 const bool DEBUG_MERGE_CHAINS = false; 00019 const bool DEBUG_SAFETY_SOLVER = false; 00020 00021 bool HaveSharedUnsafe(const SgVectorOf<GoBlock>& list1, 00022 const SgVectorOf<GoBlock>& list2) 00023 { 00024 for (SgVectorIteratorOf<GoBlock> it(list1); it; ++it) 00025 if (! (*it)->IsSafe() && list2.Contains(*it)) 00026 return true; 00027 return false; 00028 } 00029 00030 } // namespace 00031 00032 void GoSafetySolver::FindHealthy() 00033 { 00034 for (SgBWIterator it; it; ++it) 00035 { 00036 SgBlackWhite color(*it); 00037 for (SgVectorIteratorOf<GoRegion> 00038 it(Regions()->AllRegions(color)); it; ++it) 00039 (*it)->ComputeFlag(GO_REGION_STATIC_1VITAL); 00040 } 00041 00042 // used to just call GoStaticSafetySolver::FindHealthy() here, 00043 // but that works with GoBlock's and now we use GoChain's. 00044 // Code is duplicated though. Can maybe use a template function. 00045 00046 for (SgBWIterator it; it; ++it) 00047 { 00048 SgBlackWhite color(*it); 00049 for (SgVectorIteratorOf<GoRegion> 00050 it(Regions()->AllRegions(color)); it; ++it) 00051 { 00052 GoRegion* r = *it; 00053 for (SgVectorIteratorOf<GoChain> it2(r->Chains()); it2; ++it2) 00054 { 00055 if (RegionHealthyForBlock(*r, **it2)) // virtual call 00056 (*it2)->AddHealthy(r); 00057 } } } } 00058 00059 void GoSafetySolver::FindClosure(SgVectorOf<GoBlock>* blocks) const 00060 { 00061 SgVectorOf<GoBlock> toTest(*blocks); 00062 while (toTest.NonEmpty()) 00063 { 00064 const GoBlock* b = toTest.Back(); 00065 toTest.PopBack(); 00066 for (SgVectorIteratorOf<GoRegion> it(b->Healthy()); it; ++it) 00067 { GoRegion* r = *it; 00068 for (SgVectorIteratorOf<GoChain> it(r->Chains()); it; ++it) 00069 { GoBlock* b2 = *it; 00070 if (! blocks->Contains(b2)) 00071 //if (! blocks->Contains(b2) && b2->ContainsHealthy(r)) 00072 { 00073 blocks->PushBack(b2); 00074 toTest.PushBack(b2); 00075 } } } } } 00076 00077 void GoSafetySolver::FindTestSets(SgVectorOf<SgVectorOf<GoBlock> >* sets, 00078 SgBlackWhite color) const 00079 { 00080 SG_ASSERT(sets->IsEmpty()); 00081 SgVectorOf<GoBlock> doneSoFar; 00082 for (SgVectorIteratorOf<GoChain> 00083 it(Regions()->AllChains(color)); it; ++it) 00084 { 00085 GoBlock* block = *it; 00086 if (! doneSoFar.Contains(block)) 00087 { 00088 SgVectorOf<GoBlock>* blocks = new SgVectorOf<GoBlock>; 00089 blocks->PushBack(block); 00090 00091 FindClosure(blocks); 00092 doneSoFar.PushBackList(*blocks); 00093 sets->PushBack(blocks); 00094 } 00095 } 00096 } 00097 00098 bool GoSafetySolver::RegionHealthyForBlock(const GoRegion& r, 00099 const GoBlock& b) const 00100 { 00101 return GoStaticSafetySolver::RegionHealthyForBlock(r, b) 00102 || r.GetFlag(GO_REGION_STATIC_1VITAL); 00103 } 00104 00105 00106 void GoSafetySolver::Test2Vital(GoRegion* r, SgBWSet* safe) 00107 { 00108 if (r->ComputeAndGetFlag(GO_REGION_STATIC_2V)) 00109 GoSafetyUtil::AddToSafe(Board(), r->Points(), r->Color(), 00110 safe, "2-vital:", 0, true); 00111 } 00112 00113 void GoSafetySolver::Find2VitalAreas(SgBWSet* safe) 00114 { 00115 for (SgBWIterator it; it; ++it) 00116 { 00117 SgBlackWhite color(*it); 00118 for (SgVectorIteratorOf<GoRegion> 00119 it(Regions()->AllRegions(color)); it; ++it) 00120 if ( (*it)->Points().Disjoint((*safe)[SG_BLACK]) 00121 && (*it)->Points().Disjoint((*safe)[SG_WHITE]) 00122 ) 00123 { 00124 Test2Vital(*it, safe); 00125 safe->AssertDisjoint(); 00126 } 00127 } 00128 } 00129 00130 00131 void GoSafetySolver::FindSurroundedSafeAreas(SgBWSet* safe, 00132 SgBlackWhite color) 00133 { 00134 // AR keep this always up to date earlier. 00135 Regions()->SetSafeFlags(*safe); 00136 00137 // try to find single regions that become safe. 00138 while (FindSurroundedSingleRegion(safe, color)) 00139 { } 00140 while (FindSurroundedRegionPair(safe, color)) 00141 // if found new pair, re-run single region algorithm - it is faster 00142 while (FindSurroundedSingleRegion(safe, color)) 00143 { } 00144 } 00145 00146 bool GoSafetySolver::FindSafePair(SgBWSet* safe, 00147 SgBlackWhite color, 00148 const SgPointSet& anySafe, 00149 const GoRegion* r1) 00150 { 00151 for (SgVectorIteratorOf<GoRegion> 00152 it(Regions()->AllRegions(color)); it; ++it) 00153 { 00154 const GoRegion* r2 = *it; 00155 if ( r2 != r1 00156 && ! r2->Points().Overlaps(anySafe) 00157 && HaveSharedUnsafe(r1->Blocks(), r2->Blocks()) 00158 ) 00159 { 00160 const SgPointSet unionSet(r1->Points() | r2->Points()); 00161 if (GoSafetyUtil::IsTerritory(Board(), unionSet, 00162 (*safe)[color], color)) 00163 { 00164 GoSafetyUtil::AddToSafe(Board(), unionSet, color, safe, 00165 "surr-safe-2", 0, true); 00166 Regions()->SetSafeFlags(*safe); 00167 safe->AssertDisjoint(); 00168 return true; 00169 } 00170 } 00171 } 00172 return false; 00173 } 00174 00175 bool GoSafetySolver::FindSurroundedRegionPair(SgBWSet* safe, 00176 SgBlackWhite color) 00177 { 00178 SgPointSet anySafe(safe->Both()); 00179 for (SgVectorIteratorOf<GoRegion> 00180 it(Regions()->AllRegions(color)); it; ++it) 00181 { 00182 GoRegion* r1 = *it; 00183 if ( ! r1->GetFlag(GO_REGION_SAFE) 00184 && r1->SomeBlockIsSafe() 00185 && ! r1->Points().Overlaps(anySafe) 00186 && FindSafePair(safe, color, anySafe, r1) 00187 ) 00188 return true; 00189 } 00190 return false; 00191 } 00192 00193 bool GoSafetySolver::FindSurroundedSingleRegion(SgBWSet* safe, 00194 SgBlackWhite color) 00195 { 00196 SgPointSet anySafe(safe->Both()); 00197 for (SgVectorIteratorOf<GoRegion> 00198 it(Regions()->AllRegions(color)); it; ++it) 00199 { 00200 GoRegion* r = *it; 00201 if ( ! r->GetFlag(GO_REGION_SAFE) 00202 && r->SomeBlockIsSafe() 00203 && ! r->Points().Overlaps(anySafe) 00204 && GoSafetyUtil::ExtendedIsTerritory(Board(), Regions(), 00205 r->PointsPlusInteriorBlocks(), 00206 (*safe)[color], 00207 color) 00208 ) 00209 { 00210 GoSafetyUtil::AddToSafe(Board(), r->Points(), color, safe, 00211 "surr-safe-1", 0, true); 00212 Regions()->SetSafeFlags(*safe); 00213 return true; 00214 } 00215 } 00216 return false; 00217 } 00218 00219 void GoSafetySolver::FindSafePoints(SgBWSet* safe) 00220 { 00221 GoStaticSafetySolver::FindSafePoints(safe); 00222 safe->AssertDisjoint(); 00223 if (DEBUG_SAFETY_SOLVER) 00224 GoSafetyUtil::WriteStatistics("Base Solver", Regions(), safe); 00225 00226 // find areas big enough for two eyes 00227 Find2VitalAreas(safe); 00228 safe->AssertDisjoint(); 00229 if (DEBUG_SAFETY_SOLVER) 00230 GoSafetyUtil::WriteStatistics("2Vital", Regions(), safe); 00231 00232 // GoStaticSafetySolver::FindSafePoints(safe); 00233 //called again before 030505, 00234 // but now double-counts healthy regions for chains. Must change to 00235 // set a computedHealthy flag 00236 // safe->AssertDisjoint(); 00237 00238 // find areas small enough that opponent cannot make two eyes 00239 for (SgBWIterator it; it; ++it) 00240 { 00241 FindSurroundedSafeAreas(safe, *it); 00242 safe->AssertDisjoint(); 00243 } 00244 00245 if (DEBUG_SAFETY_SOLVER) 00246 GoSafetyUtil::WriteStatistics("SurroundedSafe-Final", 00247 Regions(), safe); 00248 } 00249 00250 void GoSafetySolver::Merge(GoChain* c1, GoChain* c2, 00251 GoRegion* r, bool bySearch) 00252 { 00253 SG_ASSERT(! r->GetFlag(GO_REGION_USED_FOR_MERGE)); 00254 r->SetFlag(GO_REGION_USED_FOR_MERGE, true); 00255 00256 GoChainCondition* c = 0; 00257 if (bySearch) 00258 c = new GoChainCondition(GO_CHAIN_BY_SEARCH); 00259 else 00260 { 00261 SgPoint lib1, lib2; 00262 r->Find2FreeLibs(c1, c2, &lib1, &lib2); 00263 c = new GoChainCondition(GO_CHAIN_TWO_LIBERTIES_IN_REGION, 00264 lib1, lib2); 00265 } 00266 00267 GoChain* m = new GoChain(c1, c2, c); 00268 00269 SgBlackWhite color = c1->Color(); 00270 bool found = Regions()->AllChains(color).Exclude(c1); 00271 SG_ASSERT(found); 00272 found = Regions()->AllChains(color).Exclude(c2); 00273 SG_ASSERT(found); 00274 Regions()->AllChains(color).Include(m); 00275 SG_ASSERT(Regions()->AllChains(color).UniqueElements()); 00276 00277 for (SgVectorIteratorOf<GoRegion> 00278 it(Regions()->AllRegions(color)); it; ++it) 00279 { 00280 GoRegion* r = *it; 00281 bool replace1 = r->ReplaceChain(c1, m); 00282 bool replace2 = r->ReplaceChain(c2, m); 00283 if (replace1 || replace2) 00284 { 00285 r->ReInitialize(); 00286 r->ComputeFlag(GO_REGION_STATIC_1VITAL); 00287 } 00288 } 00289 00290 if (DEBUG_MERGE_CHAINS) 00291 { 00292 SgDebug() << "\nmerge:"; 00293 c1->WriteID(SgDebug()); 00294 SgDebug() << " + "; 00295 c2->WriteID(SgDebug()); 00296 SgDebug() << " = "; 00297 m->WriteID(SgDebug()); 00298 SgDebug() << '\n'; 00299 } 00300 00301 delete c1; 00302 delete c2; 00303 } 00304 00305 void GoSafetySolver::GenBlocksRegions() 00306 { 00307 if (UpToDate()) 00308 /* */ return; /* */ 00309 00310 GoStaticSafetySolver::GenBlocksRegions(); 00311 00312 Regions()->GenChains(); 00313 00314 // merge blocks adjacent to 1-vital with 2 conn. points 00315 for (SgBWIterator it; it; ++it) 00316 { 00317 SgBlackWhite color(*it); 00318 for (SgVectorIteratorOf<GoRegion> 00319 it(Regions()->AllRegions(color)); it; ++it) 00320 { 00321 GoRegion* r = *it; 00322 r->ComputeFlag(GO_REGION_STATIC_1VITAL); 00323 } 00324 00325 bool changed = true; 00326 while (changed) 00327 { changed = false; 00328 for (SgVectorIteratorOf<GoRegion> 00329 it(Regions()->AllRegions(color)); it; ++it) 00330 { GoRegion* r = *it; 00331 if ( r->GetFlag(GO_REGION_STATIC_1VC) 00332 && r->Chains().IsLength(2) 00333 && r->Has2Conn() 00334 // || r->Safe2Cuts(Board()) changed from && to || 00335 // @todo does not work if blocks are already chains??? 00336 // must explicitly keep chain libs info. 00337 ) 00338 // easy case of only 2 chains 00339 { 00340 GoChain* c1 = r->Chains().Front(); 00341 GoChain* c2 = r->Chains().Back(); 00342 Merge(c1, c2, r, false); // false = not by search 00343 changed = true; 00344 break; // to leave iteration 00345 } 00346 else if ( r->GetFlag(GO_REGION_STATIC_1VITAL) 00347 && r->GetFlag(GO_REGION_CORRIDOR) 00348 && ! r->GetFlag(GO_REGION_USED_FOR_MERGE) 00349 ) 00350 { 00351 GoChain* c1 = 0; 00352 GoChain* c2 = 0; 00353 if (r->Find2Mergable(&c1, &c2)) 00354 { 00355 Merge(c1, c2, r, false); 00356 changed = true; 00357 break; // to leave iteration 00358 } } } } } 00359 00360 m_code = Board().GetHashCode(); 00361 } 00362