00001 //---------------------------------------------------------------------------- 00002 /** @file GoStaticSafetySolver.cpp 00003 See GoStaticSafetySolver.h. 00004 */ 00005 //---------------------------------------------------------------------------- 00006 00007 #include "SgSystem.h" 00008 #include "GoStaticSafetySolver.h" 00009 00010 #include "GoBlock.h" 00011 #include "GoChain.h" 00012 #include "GoSafetyUtil.h" 00013 #include "SgDebug.h" 00014 00015 using GoSafetyUtil::AddToSafe; 00016 00017 //---------------------------------------------------------------------------- 00018 00019 GoStaticSafetySolver::GoStaticSafetySolver(const GoBoard& board, 00020 GoRegionBoard* regions) 00021 : m_board(board), 00022 m_allocRegion(! regions) 00023 { 00024 if (regions) 00025 m_regions = regions; 00026 else 00027 m_regions = new GoRegionBoard(board); 00028 } 00029 00030 GoStaticSafetySolver::~GoStaticSafetySolver() 00031 { 00032 if (m_allocRegion) 00033 delete m_regions; 00034 // else m_regions belongs to the user, so leave it. 00035 } 00036 00037 bool GoStaticSafetySolver::RegionHealthyForBlock(const GoRegion& r, 00038 const GoBlock& b) const 00039 { 00040 return b.AllEmptyAreLiberties(r.Points()); 00041 } 00042 00043 bool GoStaticSafetySolver::UpToDate() const 00044 { 00045 return Regions()->UpToDate(); 00046 } 00047 00048 void GoStaticSafetySolver::GenBlocksRegions() 00049 { 00050 if (UpToDate()) 00051 Regions()->ReInitializeBlocksRegions(); 00052 else 00053 { 00054 Regions()->GenBlocksRegions(); 00055 } 00056 } 00057 00058 00059 void GoStaticSafetySolver::FindHealthy() 00060 { 00061 if (Regions()->ComputedHealthy()) 00062 return; 00063 for (SgBWIterator it; it; ++it) 00064 { 00065 SgBlackWhite color(*it); 00066 for (SgVectorIteratorOf<GoRegion> 00067 it(Regions()->AllRegions(color)); it; ++it) 00068 { 00069 GoRegion* r = *it; 00070 for (SgVectorIteratorOf<GoBlock> it2(r->Blocks()); it2; ++it2) 00071 { 00072 if (RegionHealthyForBlock(*r, **it2)) // virtual call 00073 { 00074 (*it2)->AddHealthy(r); 00075 } 00076 } 00077 } 00078 } 00079 Regions()->SetComputedHealthy(); 00080 } 00081 00082 void GoStaticSafetySolver::TestAdjacent(SgVectorOf<GoRegion>* regions, 00083 const SgVectorOf<GoBlock>& blocks) const 00084 { 00085 SgVectorOf<GoRegion> newregions; 00086 for (SgVectorIteratorOf<GoRegion> it(*regions); it; ++it) 00087 if ((*it)->IsSurrounded(blocks)) 00088 newregions.PushBack(*it); 00089 *regions = newregions; 00090 } 00091 00092 void GoStaticSafetySolver::TestAlive(SgVectorOf<GoBlock>* blocks, 00093 SgBWSet* safe, 00094 SgBlackWhite color) 00095 { 00096 SgVectorOf<GoRegion> regions(Regions()->AllRegions(color)); 00097 SgVectorOf<GoBlock> toDelete; 00098 00099 bool changed = true; 00100 while (changed) 00101 { 00102 TestAdjacent(®ions, *blocks); 00103 toDelete.Clear(); 00104 for (SgVectorIteratorOf<GoBlock> it(*blocks); it; ++it) 00105 { 00106 const SgVectorOf<GoRegion>& br = (*it)->Healthy(); 00107 00108 bool has2 = br.MinLength(2); 00109 if (has2) 00110 { 00111 int nuRegions = 0; 00112 for (SgVectorIteratorOf<GoRegion> it(br); it; ++it) 00113 { 00114 if (regions.Contains(*it)) 00115 { 00116 ++nuRegions; 00117 if (nuRegions >= 2) 00118 break; 00119 } 00120 } 00121 has2 = (nuRegions >= 2); 00122 } 00123 if (! has2) 00124 toDelete.PushBack(*it); 00125 } 00126 00127 changed = toDelete.NonEmpty(); 00128 if (changed) 00129 { 00130 for (SgVectorIteratorOf<GoBlock> it(toDelete); it; ++it) 00131 { 00132 bool found = blocks->Exclude(*it); 00133 SG_DEBUG_ONLY(found); 00134 SG_ASSERT(found); 00135 } 00136 } 00137 } 00138 00139 if (blocks->NonEmpty()) // found safe blocks 00140 { 00141 SgPointSet blockPoints; 00142 for (SgVectorIteratorOf<GoBlock> it(*blocks); it; ++it) 00143 { 00144 blockPoints |= (*it)->Stones(); 00145 (*it)->SetToSafe(); 00146 } 00147 00148 color = blocks->Front()->Color(); 00149 AddToSafe(m_board, blockPoints, color, safe, 00150 "TestAlive-Blocks", 0, false); 00151 00152 for (SgVectorIteratorOf<GoRegion> it(regions); it; ++it) 00153 if ((*it)->HealthyForSomeBlock(*blocks)) 00154 { 00155 (*it)->SetToSafe(); 00156 AddToSafe(m_board, (*it)->Points(), color, safe, 00157 "TestAlive-Region", 0, false); 00158 } 00159 } 00160 } 00161 00162 void GoStaticSafetySolver::FindClosure(SgVectorOf<GoBlock>* blocks) const 00163 { 00164 SgVectorOf<GoBlock> toTest(*blocks); 00165 while (toTest.NonEmpty()) 00166 { 00167 const GoBlock* b = toTest.Back(); 00168 toTest.PopBack(); 00169 for (SgVectorIteratorOf<GoRegion> it(b->Healthy()); it; ++it) 00170 { 00171 const GoRegion* r = *it; 00172 for (SgVectorIteratorOf<GoBlock> it(r->Blocks()); it; ++it) 00173 { 00174 const GoBlock* b2 = *it; 00175 if (! blocks->Contains(b2) && b2->ContainsHealthy(r)) 00176 { 00177 blocks->PushBack(b2); 00178 toTest.PushBack(b2); 00179 } 00180 } 00181 } 00182 } 00183 } 00184 00185 void GoStaticSafetySolver::FindTestSets( 00186 SgVectorOf<SgVectorOf<GoBlock> >* sets, 00187 SgBlackWhite color) const 00188 { 00189 SG_ASSERT(sets->IsEmpty()); 00190 SgVectorOf<GoBlock> doneSoFar; 00191 for (SgVectorIteratorOf<GoBlock> 00192 it(Regions()->AllBlocks(color)); it; ++it) 00193 { 00194 GoBlock* block = *it; 00195 if (! doneSoFar.Contains(block)) 00196 { 00197 SgVectorOf<GoBlock>* blocks = new SgVectorOf<GoBlock>; 00198 blocks->PushBack(block); 00199 00200 FindClosure(blocks); 00201 doneSoFar.PushBackList(*blocks); 00202 sets->PushBack(blocks); 00203 } 00204 } 00205 } 00206 00207 void GoStaticSafetySolver::FindSafePoints(SgBWSet* safe) 00208 { 00209 GenBlocksRegions(); // find all blocks and regions on whole board 00210 FindHealthy(); // find healthy regions of blocks 00211 00212 for (SgBWIterator it; it; ++it) 00213 { 00214 SgBlackWhite color(*it); 00215 SgVectorOf<SgVectorOf<GoBlock> > sets; 00216 // find maximal sets for aliveness testing 00217 FindTestSets(&sets, color); 00218 00219 for (SgVectorIteratorOf<SgVectorOf<GoBlock> > it(sets); it; ++it) 00220 { TestAlive(*it, safe, color); 00221 // find safe subset within each maximal set 00222 delete *it; 00223 } 00224 } 00225 00226 Regions()->SetComputedFlagForAll(GO_REGION_SAFE); 00227 } 00228