00001
00002
00003
00004
00005
00006 #include "SgSystem.h"
00007 #include "GoRegion.h"
00008
00009 #include <iostream>
00010 #include <cstdio>
00011 #include "GoBlock.h"
00012 #include "GoBoard.h"
00013 #include "GoChain.h"
00014 #include "GoEyeUtil.h"
00015 #include "GoRegionBoard.h"
00016 #include "GoRegionUtil.h"
00017 #include "GoSafetyUtil.h"
00018 #include "SgConnCompIterator.h"
00019 #include "SgDebug.h"
00020 #include "SgVector.h"
00021 #include "SgNbIterator.h"
00022 #include "SgPointArray.h"
00023 #include "SgStrategy.h"
00024 #include "SgWrite.h"
00025
00026 using GoBoardUtil::ExpandToBlocks;
00027 using GoEyeUtil::IsSplitPt;
00028 using GoEyeUtil::TestNakade;
00029 using GoRegionUtil::IsSmallRegion;
00030 using GoSafetyUtil::Find2BestLibs;
00031 using GoSafetyUtil::Find2Libs;
00032 using GoSafetyUtil::MightMakeLife;
00033
00034
00035
00036 static const bool CHECK = SG_CHECK && true;
00037
00038 static const bool HEAVYCHECK = SG_HEAVYCHECK && CHECK && false;
00039
00040 static const bool WRITEDEBUG = false;
00041
00042
00043
00044 namespace {
00045
00046
00047
00048 inline bool IsAdjacentToAll(const GoBoard& board, SgPoint p,
00049 const SgVectorOf<GoBlock>& blocks)
00050 {
00051 for (SgVectorIteratorOf<GoBlock> it(blocks); it; ++it)
00052 if (! board.IsLibertyOfBlock(p, (*it)->Anchor()))
00053 return false;
00054 return true;
00055 }
00056
00057
00058 inline bool AdjacentToAll(SgPoint p, const SgVector<SgPoint>& points)
00059 {
00060 if (points.IsEmpty())
00061 return true;
00062
00063 for (SgVectorIterator<SgPoint> it(points); it; ++it)
00064 if (! SgPointUtil::AreAdjacent(p, *it))
00065 return false;
00066
00067 return true;
00068 }
00069
00070 }
00071
00072
00073
00074 GoRegion::GoRegion(const GoBoard& board, const SgPointSet& points,
00075 SgBlackWhite color)
00076 : m_bd(board),
00077 m_points(points),
00078 m_color(color),
00079 m_eyes(),
00080 m_vitalPoint(SG_NULLMOVE),
00081 m_1vcDepth(0),
00082 m_miaiStrategy(color)
00083 {
00084 #ifndef NDEBUG
00085 ++s_alloc;
00086 #endif
00087 }
00088
00089
00090 bool GoRegion::StaticIs1VitalAndConnected() const
00091 {
00092
00093
00094 bool is1Vital = false;
00095 if (GetFlag(GO_REGION_SMALL))
00096 {
00097
00098 if (GetFlag(GO_REGION_SINGLE_BLOCK_BOUNDARY))
00099 return true;
00100 else if (m_blocks.MinLength(5))
00101
00102 return false;
00103
00104 int nuConn = 0;
00105 for (SgSetIterator it(Points()); it; ++it)
00106 {
00107 SgPoint p(*it);
00108 if (m_bd.IsEmpty(p) && IsAdjacentToAll(m_bd, p, m_blocks))
00109 {
00110 if (++nuConn >= 2)
00111 {
00112 is1Vital = true;
00113 break;
00114 }
00115 }
00116 }
00117 }
00118 return is1Vital;
00119 }
00120
00121 bool GoRegion::AllEmptyAreLibs() const
00122 {
00123 for (SgSetIterator it(Points()); it; ++it)
00124 {
00125 SgPoint p(*it);
00126 if (m_bd.IsEmpty(p) && ! m_bd.HasNeighbors(p, Color()))
00127 return false;
00128 }
00129 return true;
00130 }
00131
00132 SgVectorOf<GoBlock> GoRegion::InteriorBlocks() const
00133 {
00134 SgVectorOf<GoBlock> interior;
00135 for (SgVectorIteratorOf<GoBlock> it(m_blocks); it; ++it)
00136 if (IsInteriorBlock(*it))
00137 interior.PushBack(*it);
00138 return interior;
00139 }
00140
00141 bool GoRegion::IsInteriorBlock(const GoBlock* block) const
00142 {
00143 SG_ASSERT(m_blocks.Contains(block));
00144 const SgBlackWhite opp = SgOppBW(block->Color());
00145 for (GoBoard::StoneIterator it(m_bd, block->Anchor()); it; ++it)
00146 for (SgNb4Iterator nb(*it); nb; ++nb)
00147 {
00148 const SgPoint p = *nb;
00149 if ( (m_bd.IsEmpty(p) || m_bd.IsColor(p, opp))
00150 && ! m_points.Contains(p))
00151 return false;
00152 }
00153 return true;
00154 }
00155
00156 SgPointSet GoRegion::PointsPlusInteriorBlocks() const
00157 {
00158 SgPointSet area = m_points;
00159 for (SgVectorIteratorOf<GoBlock> it(m_blocks); it; ++it)
00160 if (IsInteriorBlock(*it))
00161 area |= (*it)->Stones();
00162 return area;
00163 }
00164
00165 void GoRegion::InteriorEmpty(SgVector<SgPoint>* interiorEmpty,
00166 int maxNu) const
00167 {
00168 for (SgSetIterator it(Points()); it; ++it)
00169 {
00170 SgPoint p(*it);
00171 if (m_bd.IsEmpty(p) && ! m_bd.HasNeighbors(p, Color()))
00172 {
00173 interiorEmpty->Include(p);
00174 if (--maxNu < 0)
00175 return;
00176 }
00177 }
00178 }
00179
00180 bool GoRegion::Has2SureLibs(SgMiaiStrategy* miaiStrategy) const
00181 {
00182
00183 if (m_blocks.IsEmpty())
00184 return false;
00185
00186 SG_ASSERT(! m_blocks.IsEmpty());
00187 SgVector<SgPoint> interiorEmpty;
00188 InteriorEmpty(&interiorEmpty, 3);
00189 SgMiaiPair ips;
00190 bool result1 = interiorEmpty.MaxLength(2)
00191 && Has2IPs(interiorEmpty, &ips);
00192
00193 if (result1)
00194 {
00195 miaiStrategy->AddPair(ips);
00196 return true;
00197 }
00198
00199
00200
00201 SgVector<SgPoint> usedLibs;
00202 bool result2 = Find2ConnForAllInterior(miaiStrategy, usedLibs)
00203 && Has2IntersectionPoints(usedLibs);
00204 return result2;
00205 }
00206
00207 void GoRegion::InsideLibs(const GoBlock* b, SgVector<SgPoint>* libs) const
00208 {
00209 for (GoBoard::LibertyIterator it(m_bd, b->Anchor()); it; ++it)
00210 if (Points().Contains(*it))
00211 libs->PushBack(*it);
00212 }
00213
00214 bool GoRegion::HasLibForAllBlocks() const
00215 {
00216 for (SgVectorIteratorOf<GoBlock> it(m_blocks); it; ++it)
00217 if (! HasBlockLibs(*it))
00218 return false;
00219 return true;
00220 }
00221
00222 bool GoRegion::HasLibsForAllBlocks(int n) const
00223 {
00224 for (SgVectorIteratorOf<GoBlock> it(m_blocks); it; ++it)
00225 if (! (*it)->IsSafe() && ! HasLibsForBlock(*it, n))
00226 return false;
00227 return true;
00228 }
00229
00230 bool GoRegion::HasBlockLibs(const GoBlock* b) const
00231 {
00232 for (GoBoard::LibertyIterator it(m_bd, b->Anchor()); it; ++it)
00233 if (Points().Contains(*it))
00234 return true;
00235 return false;
00236 }
00237
00238 bool GoRegion::HasLibsForBlock(const GoBlock* b, int n) const
00239 {
00240 int counter = 0;
00241 for (GoBoard::LibertyIterator it(m_bd, b->Anchor()); it; ++it)
00242 if (Points().Contains(*it))
00243 {
00244 if (++counter >= n)
00245 return true;
00246 }
00247 return false;
00248 }
00249
00250 void GoRegion::JointLibs(SgVector<SgPoint>* libs) const
00251 {
00252 GoBlock* first = m_blocks.Front();
00253 if (GetFlag(GO_REGION_SINGLE_BLOCK_BOUNDARY))
00254 {
00255 InsideLibs(first, libs);
00256 return;
00257 }
00258
00259 SG_ASSERT(m_blocks.MinLength(2));
00260 int minLib = INT_MAX;
00261 GoBlock* minB = 0;
00262
00263
00264 for (SgVectorIteratorOf<GoBlock> it(m_blocks); it; ++it)
00265 { int nu = (*it)->NuLiberties();
00266 if (nu < 2)
00267 return;
00268 else if (nu < minLib)
00269 {
00270 minLib = nu;
00271 minB = *it;
00272 }
00273 }
00274 SG_ASSERT(minB != 0);
00275
00276 for (GoBoard::LibertyIterator it(m_bd, minB->Anchor()); it; ++it)
00277 {
00278 SgPoint lib(*it);
00279 if (Points().Contains(lib))
00280 {
00281 bool joint = true;
00282 for (SgVectorIteratorOf<GoBlock> itBlock(m_blocks); itBlock;
00283 ++itBlock)
00284 {
00285 if (! (*itBlock)->HasLiberty(lib))
00286 {
00287 joint = false;
00288 break;
00289 }
00290 }
00291 if (joint)
00292 libs->PushBack(*it);
00293 }
00294 }
00295 }
00296
00297 bool GoRegion::Has2IPs(const SgVector<SgPoint>& interiorEmpty,
00298 SgMiaiPair* ips) const
00299 {
00300 SgVector<SgPoint> jointLibs;
00301 JointLibs(&jointLibs);
00302 if (jointLibs.MinLength(2))
00303 {
00304
00305 int nuIPs = 0;
00306 SgPoint ip1 = SG_NULLPOINT;
00307 for (SgVectorIterator<SgPoint> it(jointLibs); it; ++it)
00308 {
00309 if (AdjacentToAll(*it, interiorEmpty) && IsSplitPt(*it, Points()))
00310 {
00311 ++nuIPs;
00312 if (ip1 == SG_NULLPOINT)
00313 ip1 = *it;
00314 else
00315 {
00316 ips->first = ip1;
00317 ips->second = *it;
00318 return true;
00319 }
00320 }
00321 }
00322 }
00323 return false;
00324 }
00325
00326 bool GoRegion::Has2IntersectionPoints(const SgVector<SgPoint>& usedLibs) const
00327 {
00328 SgVector<SgPoint> jointLibs;
00329 JointLibs(&jointLibs);
00330 if (jointLibs.MinLength(2))
00331 {
00332
00333 int nuIPs = 0;
00334
00335 for (SgVectorIterator<SgPoint> it(jointLibs); it; ++it)
00336 {
00337 if (IsSplitPt(*it, Points()) && ! usedLibs.Contains(*it))
00338 {
00339 if (++nuIPs >= 2)
00340 return true;
00341 }
00342 }
00343 }
00344 return false;
00345 }
00346
00347 void GoRegion::GetIPs(SgVector<SgPoint>* ips) const
00348 {
00349 SgVector<SgPoint> jointLibs;
00350 JointLibs(&jointLibs);
00351 for (SgVectorIterator<SgPoint> it(jointLibs); it; ++it)
00352 if (IsSplitPt(*it, Points()))
00353 ips->PushBack(*it);
00354 }
00355
00356 void GoRegion::GetDivideMiaiPairs(SgVector<SgMiaiPair>& pairs) const
00357 {
00358 SgVector<SgPoint> divPs;
00359
00360 for (SgVectorIteratorOf<GoBlock> it(Blocks()); it; ++it)
00361 {
00362 SgVector<SgPoint> libs, temp;
00363 InsideLibs(*it, &libs);
00364 SgMiaiPair p1;
00365 SgPoint a = -1;
00366
00367
00368 for (SgVectorIterator<SgPoint> it2(libs); it2; ++it2)
00369 {
00370 if (IsSplitPt(*it2, Points()))
00371 temp.PushBack(*it2);
00372 }
00373 temp.Sort();
00374 divPs.PushBackList(temp);
00375
00376 for (SgVectorIterator<SgPoint> it2(temp); it2; ++it2)
00377 {
00378 if (a == -1)
00379 a = (*it2);
00380 else
00381 {
00382 if (SgPointUtil::AreAdjacent(a, *it2))
00383 {
00384 p1.first = a;
00385 p1.second = *it2;
00386 pairs.PushBack(p1);
00387 }
00388 a = *it2;
00389 }
00390 }
00391
00392 }
00393
00394 if (WRITEDEBUG)
00395 {
00396 SgDebug() << SgWritePointList(divPs, "divPs: ", true);
00397 for (SgVectorIterator<SgMiaiPair> it(pairs); it; ++it)
00398 {
00399 SgDebug() << "Pair(1: " << SgWritePoint((*it).first)
00400 << " 2: " << SgWritePoint((*it).second) << ")\n";
00401 }
00402 }
00403 }
00404
00405 SgPointSet GoRegion::AllInsideLibs() const
00406 {
00407 const int size = m_bd.Size();
00408 return (m_points - Dep().Border(size)) & m_bd.AllEmpty();
00409 }
00410
00411 bool GoRegion::Find2ConnForAll() const
00412 {
00413 if (GetFlag(GO_REGION_SINGLE_BLOCK_BOUNDARY))
00414 {
00415 const SgPointSet interior = AllInsideLibs();
00416 SgPointSet libs = (Points() & m_bd.AllEmpty()) - AllInsideLibs();
00417
00418 for (SgSetIterator it(interior); it; ++it)
00419 {
00420 if (! Find2Libs(*it, &libs))
00421 return false;
00422 }
00423 return true;
00424 }
00425
00426 return false;
00427
00428 #if UNUSED
00429 single = GetFlag(GO_REGION_SINGLE_BLOCK_BOUNDARY);
00430 if (! single)
00431 {
00432
00433
00434 GoBlock* first = Blocks().Front();
00435 if (Find2ConnForAll(m_bd, Points(), first->Stones(), Color()))
00436 twoLibs = true;
00437 else
00438 is1Vital = false;
00439 }
00440 else if (Find2ConnForAll(m_bd, Points(), bd, Color()))
00441 twoLibs = true;
00442 else
00443 is1Vital = false;
00444
00445 #endif
00446 }
00447
00448
00449 bool GoRegion::Find2ConnForAllInterior(SgMiaiStrategy* miaiStrategy,
00450 SgVector<SgPoint>& usedLibs) const
00451 {
00452 SgVector<SgMiaiPair> myStrategy;
00453 const int size = m_bd.Size();
00454 SgPointSet interior = AllInsideLibs();
00455 if (interior.IsEmpty())
00456 {
00457 return true;
00458 }
00459
00460 {
00461 SgPointSet testSet = interior;
00462 SgPointSet originalLibs = testSet.Border(size) & Dep().Border(size)
00463 & m_bd.AllEmpty() & Points();
00464 SgPointSet updateLibs = originalLibs;
00465
00466
00467 bool changed = true;
00468 while (changed)
00469 {
00470 changed = false;
00471 if (testSet.IsEmpty())
00472 {
00473 SgVector<SgPoint> jlibs;
00474 JointLibs(&jlibs);
00475 SgVector<SgPoint> ips;
00476 GetIPs(&ips);
00477 SgVector<SgMiaiPair> updateStrg;
00478
00479 for (SgSetIterator it(interior); it; ++it)
00480 {
00481 SgPoint p = *it;
00482 SgPointSet s1;
00483 s1.Include(p);
00484 SgPointSet rest = s1.Border(size) & updateLibs;
00485 if (! rest.IsEmpty())
00486 {
00487 for (SgVectorIterator<SgMiaiPair> it2(myStrategy);
00488 it2; ++it2)
00489 {
00490 SgMiaiPair x = *it2;
00491 if ( SgPointUtil::AreAdjacent(p, x.first)
00492 && SgPointUtil::AreAdjacent(p, x.second)
00493 )
00494 {
00495 if (ips.Contains(x.first))
00496 {
00497 updateLibs.Include(x.first);
00498 usedLibs.Exclude(x.first);
00499 SgPoint t = rest.PointOf();
00500 x.first = t;
00501 updateLibs.Exclude(t);
00502 rest.Exclude(t);
00503 usedLibs.Include(t);
00504 }
00505 if ( ips.Contains(x.second)
00506 && ! rest.IsEmpty()
00507 )
00508 {
00509 updateLibs.Include(x.second);
00510 usedLibs.Exclude(x.second);
00511 SgPoint t = rest.PointOf();
00512 x.second = t;
00513 updateLibs.Exclude(t);
00514 rest.Exclude(t);
00515 usedLibs.Include(t);
00516 }
00517 updateStrg.Include(x);
00518 }
00519 }
00520 }
00521 }
00522 miaiStrategy->SetStrategy(updateStrg);
00523 return true;
00524 }
00525 for (SgSetIterator it(interior); it; ++it)
00526 {
00527 SgMiaiPair miaiPair;
00528 if (Find2BestLibs(*it, updateLibs, testSet, &miaiPair))
00529 {
00530 if (miaiPair.first == miaiPair.second)
00531 {
00532 SgDebug() <<"\nmiaipair are same: "
00533 << SgWritePoint(miaiPair.first)
00534 << SgWritePoint(miaiPair.second);
00535 SgDebug() <<"\ncurrent region is:\n";
00536 Points().Write(SgDebug(), size);
00537 SG_ASSERT(false);
00538 }
00539 myStrategy.PushBack(miaiPair);
00540 usedLibs.PushBack(miaiPair.first);
00541 usedLibs.PushBack(miaiPair.second);
00542 updateLibs.Exclude(miaiPair.first);
00543 updateLibs.Exclude(miaiPair.second);
00544 updateLibs.Include(*it);
00545 testSet.Exclude(*it);
00546 changed = true;
00547 }
00548 }
00549 }
00550 }
00551 miaiStrategy->Clear();
00552 return false;
00553 }
00554
00555 bool GoRegion::ComputeIs1Vital() const
00556 {
00557 if (GetFlag(GO_REGION_STATIC_1VC))
00558 return true;
00559 else if (ComputedFlag(GO_REGION_STATIC_1VITAL))
00560 return GetFlag(GO_REGION_STATIC_1VITAL);
00561
00562 bool is1Vital = true;
00563
00564 if (! HasLibForAllBlocks())
00565 is1Vital = false;
00566 else
00567 {
00568 if (const_cast<GoRegion*>(this)
00569 ->ComputeAndGetFlag(GO_REGION_PROTECTED_CUTS))
00570 {
00571 is1Vital = true;
00572 }
00573 else if (! Find2ConnForAll())
00574 is1Vital = false;
00575 }
00576
00577 return is1Vital;
00578 }
00579
00580
00581 bool GoRegion::IsCorridor() const
00582
00583 {
00584 SG_ASSERT(! m_computedFlags.test(GO_REGION_CORRIDOR));
00585 for (SgSetIterator it(Points()); it; ++it)
00586 {
00587 if ((m_bd.NumNeighbors(*it, SgOppBW(Color()))
00588 + m_bd.NumEmptyNeighbors(*it)) > 2)
00589 return false;
00590 if (m_bd.NumNeighbors(*it, Color()) == 0)
00591
00592 return false;
00593 }
00594 return true;
00595 }
00596
00597
00598 bool GoRegion::ReplaceChain(const GoChain* old, const GoChain* newChain)
00599 {
00600 SG_ASSERT(old != newChain);
00601 SG_ASSERT(Color() == old->Color());
00602 if (m_chains.Contains(old))
00603 {
00604 m_computedFlags.reset();
00605 m_chains.Exclude(old);
00606 m_chains.Include(newChain);
00607 if (HEAVYCHECK)
00608 SG_ASSERT(m_chains.UniqueElements());
00609
00610 return true;
00611 }
00612
00613 return false;
00614 }
00615
00616 bool GoRegion::Find2Mergable(GoChain** c1, GoChain** c2) const
00617 {
00618 GoChain* test1; GoChain* test2;
00619 for (SgVectorPairIteratorOf<GoChain> it(m_chains);
00620 it.NextPair(test1, test2);)
00621 {
00622 if (Has2ConnForChains(test1, test2))
00623 {
00624 *c1 = test1;
00625 *c2 = test2;
00626 return true;
00627 }
00628 }
00629 return false;
00630 }
00631
00632 void GoRegion::Find2FreeLibs(const GoChain* c1, const GoChain* c2,
00633 SgPoint* lib1, SgPoint* lib2) const
00634 {
00635 SgPointSet libs = Points() & c1->FreeLiberties() & c2->FreeLiberties();
00636 if (CHECK)
00637 SG_ASSERT(libs.MinSetSize(2));
00638 SgSetIterator it(libs);
00639 *lib1 = *it;
00640 ++it;
00641 *lib2 = *it;
00642 }
00643
00644 void GoRegion::ReInitialize()
00645 {
00646 m_computedFlags.reset();
00647 m_computedFlags.set(GO_REGION_COMPUTED_BLOCKS);
00648 m_flags.reset();
00649 m_miaiStrategy.Clear();
00650 ComputeBasicFlags();
00651 }
00652
00653 void GoRegion::WriteID(std::ostream& stream) const
00654 {
00655 stream << SgBW(Color()) << " Region "
00656 << SgWritePoint(Points().Center());
00657 }
00658
00659 const char* kRegionFlagStrings[_GO_REGION_FLAG_COUNT + 1] =
00660 {
00661 "isSmall", "GO_REGION_CORRIDOR", "GO_REGION_STATIC_1VC",
00662 "GO_REGION_1VC", "GO_REGION_STATIC_2V", "GO_REGION_2V",
00663 "GO_REGION_SINGLE_BLOCK_BOUNDARY",
00664 "GO_REGION_OPP_CAN_LIVE_INSIDE",
00665 "GO_REGION_AT_LEAST_SEKI",
00666 "isSafe",
00667 "GO_REGION_PROTECTED_CUTS", "GO_REGION_STATIC_1VITAL",
00668 "is1Vital",
00669 "GO_REGION_USED_FOR_MERGE",
00670 "GO_REGION_VALID",
00671 "GO_REGION_COMPUTED_BLOCKS",
00672 "GO_REGION_COMPUTED_CHAINS",
00673 "GO_REGION_COMPUTED_NAKADE",
00674 "_GO_REGION_FLAG_COUNT"
00675 };
00676
00677 void GoRegion::Write(std::ostream& stream) const
00678 {
00679 WriteID(stream);
00680 stream << ", " << Points().Size()
00681 << " Points\nBlocks:" ;
00682 for (SgVectorIteratorOf<GoBlock> it(m_blocks); it; ++it)
00683 {
00684 (*it)->WriteID(stream);
00685 if ((*it)->ContainsHealthy(this))
00686 stream << ":Healthy";
00687 }
00688
00689 stream << "\nInterior Blocks: ";
00690 for (SgVectorIteratorOf<GoBlock> it(m_blocks); it; ++it)
00691 {
00692 if (IsInteriorBlock(*it))
00693 (*it)->WriteID(stream);
00694 }
00695 stream << "\nChains: ";
00696 for (SgVectorIteratorOf<GoChain> it(m_chains); it; ++it)
00697 {
00698 (*it)->WriteID(stream);
00699 if ((*it)->ContainsHealthy(this))
00700 stream << ":Healthy";
00701 }
00702
00703 stream << "\ncomputed region flags:\n";
00704
00705 for (int f = 0; f < _GO_REGION_FLAG_COUNT; ++f)
00706 {
00707 if (m_computedFlags.test(f))
00708 {
00709 stream << SgWriteLabel(kRegionFlagStrings[f])
00710 << SgWriteBoolean(m_flags.test(f))
00711 << '\n';
00712 }
00713 }
00714 stream << SgWriteLabel("not computed:");
00715 bool first = true;
00716 for (int f = 0; f < _GO_REGION_FLAG_COUNT; ++f)
00717 {
00718 if (! m_computedFlags.test(f))
00719 {
00720 if (first)
00721 first = false;
00722 else
00723 stream << ", ";
00724
00725 stream << kRegionFlagStrings[f];
00726 }
00727 }
00728 stream << '\n'
00729 << SgWriteLabel("eyes:")
00730 << m_eyes
00731 << SgWriteLabel("Miai strategy:")
00732 << m_miaiStrategy
00733 << '\n';
00734 }
00735
00736 bool GoRegion::GetFlag(GoRegionFlag flag) const
00737 {
00738 SG_ASSERT(IsValid());
00739 SG_ASSERT(m_computedFlags.test(flag));
00740 return m_flags.test(flag);
00741 }
00742
00743 bool GoRegion::ComputeAndGetFlag(GoRegionFlag flag)
00744 {
00745 SG_ASSERT(IsValid());
00746 ComputeFlag(flag);
00747 return m_flags.test(flag);
00748 }
00749
00750 bool GoRegion::ComputedFlag(GoRegionFlag flag) const
00751 {
00752 return m_computedFlags.test(flag);
00753 }
00754
00755 void GoRegion::ComputeFlag(GoRegionFlag flag)
00756 {
00757 if (! m_computedFlags.test(flag))
00758 DoComputeFlag(flag);
00759 }
00760
00761 void GoRegion::DoComputeFlag(GoRegionFlag flag)
00762 {
00763 SG_ASSERT(! m_computedFlags.test(flag));
00764 switch(flag)
00765 {
00766 case GO_REGION_SMALL:
00767 SetFlag(GO_REGION_SMALL,
00768 IsSmallRegion(m_bd, Points(), SgOppBW(Color())));
00769 break;
00770 case GO_REGION_CORRIDOR:
00771 SetFlag(GO_REGION_CORRIDOR, IsCorridor());
00772 break;
00773 case GO_REGION_1VC:
00774 SG_ASSERT(false);
00775 break;
00776 case GO_REGION_1VITAL:
00777 SG_ASSERT(false);
00778 break;
00779 case GO_REGION_STATIC_1VITAL:
00780 {
00781 bool is = ComputeIs1Vital();
00782 SetFlag(GO_REGION_STATIC_1VITAL, is);
00783 if (is)
00784 SetFlag(GO_REGION_1VITAL, true);
00785 }
00786 break;
00787 case GO_REGION_STATIC_1VC:
00788 {
00789 bool is = StaticIs1VitalAndConnected();
00790 SetFlag(GO_REGION_STATIC_1VC, is);
00791 if (is)
00792 SetFlag(GO_REGION_1VC, true);
00793 }
00794 break;
00795 case GO_REGION_2V:
00796 SG_ASSERT(false);
00797 break;
00798 case GO_REGION_STATIC_2V:
00799 {
00800 bool is = Has2SureLibs(&m_miaiStrategy);
00801 SetFlag(GO_REGION_STATIC_2V, is);
00802 if (is)
00803 {
00804 SetFlag(GO_REGION_2V, true);
00805 }
00806 }
00807 break;
00808 case GO_REGION_SINGLE_BLOCK_BOUNDARY:
00809 SG_ASSERT(m_computedFlags.test(GO_REGION_COMPUTED_BLOCKS));
00810 SetFlag(GO_REGION_SINGLE_BLOCK_BOUNDARY, m_blocks.MaxLength(1));
00811
00812
00813
00814
00815
00816 break;
00817 case GO_REGION_OPP_CAN_LIVE_INSIDE:
00818 SetFlag(GO_REGION_OPP_CAN_LIVE_INSIDE,
00819 MightMakeLife(m_bd, Points(), Dep(), SgOppBW(Color())));
00820 break;
00821 case GO_REGION_AT_LEAST_SEKI:
00822 SG_ASSERT(false);
00823 break;
00824 case GO_REGION_SAFE:
00825 SG_ASSERT(false);
00826 break;
00827 case GO_REGION_PROTECTED_CUTS:
00828 SetFlag(GO_REGION_PROTECTED_CUTS, ProtectedCuts(m_bd));
00829 break;
00830 break;
00831 case GO_REGION_COMPUTED_NAKADE:
00832 ComputeNakade();
00833 SetFlag(GO_REGION_COMPUTED_NAKADE, true);
00834 break;
00835 default:
00836 SG_ASSERT(false);
00837 }
00838 m_computedFlags.set(flag);
00839 }
00840
00841 void GoRegion::ComputeSingleBlockEyeSpace()
00842 {
00843 SG_ASSERT(m_blocks.IsLength(1));
00844 const int nu = Points().Size();
00845 SG_ASSERT(nu > 0);
00846
00847 if (nu <= 2)
00848 {
00849 m_eyes.SetEyes(1, 1);
00850 }
00851 else
00852 {
00853 bool isNakade = false, makeNakade = false, maybeSeki = false;
00854 bool sureSeki = false;
00855 bool makeFalse = false;
00856 if (nu <= 7)
00857 {
00858
00859 SgPoint vitalP(SG_NULLPOINT);
00860 TestNakade(Points(), m_bd, m_color, true,
00861 isNakade, makeNakade, makeFalse,
00862 maybeSeki, sureSeki,
00863 &vitalP);
00864 if (makeNakade || makeFalse)
00865 m_vitalPoint = vitalP;
00866 }
00867 if (sureSeki)
00868 m_eyes.SetLocalSeki();
00869 else if (maybeSeki)
00870 {
00871 m_eyes.SetMinEyes(0);
00872 m_eyes.SetMaxEyes(2);
00873 int potEyes = isNakade ? 1 : 2;
00874 m_eyes.SetExactPotEyes(potEyes);
00875 m_eyes.SetMaybeLocalSeki();
00876 }
00877 else if (isNakade || makeNakade)
00878 {
00879 int potEyes = isNakade ? 1 : 2;
00880 m_eyes.SetEyes(1, potEyes);
00881 }
00882 else if (makeFalse)
00883 m_eyes.SetEyes(0, 1);
00884
00885 else
00886
00887 {
00888 m_eyes.SetMinEyes(0);
00889 m_eyes.SetMaxEyes(2);
00890 m_eyes.SetExactPotEyes(2);
00891 }
00892 }
00893 }
00894
00895 void GoRegion::ComputeMultipleBlockEyeSpace()
00896 {
00897 SG_ASSERT(m_blocks.MinLength(2));
00898 const int nu = m_points.Size();
00899 SG_ASSERT (nu > 0);
00900
00901 int minNuEyes = 0;
00902
00903
00904
00905 bool isNakade = false;
00906 bool makeNakade = false;
00907 bool makeFalse = false;
00908
00909 if (nu <= 2)
00910 {
00911 if (minNuEyes == 1)
00912 {
00913 m_eyes.SetEyes(1, 1);
00914 return;
00915 }
00916
00917
00918
00919
00920
00921
00922
00923
00924
00925
00926
00927
00928
00929
00930
00931 return;
00932 }
00933 else if (nu <= 7)
00934 {
00935
00936 SgPoint vitalP(SG_NULLPOINT);
00937 bool maybeSeki = false, sureSeki = false;
00938 TestNakade(m_points, m_bd, m_color, true,
00939 isNakade, makeNakade,
00940 makeFalse,
00941 maybeSeki, sureSeki,
00942 &vitalP);
00943 if (makeNakade)
00944 m_vitalPoint = vitalP;
00945 }
00946 if (makeFalse)
00947 m_eyes.SetEyes(0, 1);
00948 else if (isNakade)
00949 m_eyes.SetEyes(1, 1);
00950 else if (makeNakade)
00951 m_eyes.SetEyes(1, 2);
00952 else
00953
00954 {
00955 m_eyes.SetMinEyes(minNuEyes);
00956 m_eyes.SetMaxEyes(2);
00957 m_eyes.SetExactPotEyes(2);
00958 }
00959
00960 }
00961
00962 void GoRegion::ComputeEyeSpace()
00963 {
00964 if (m_blocks.IsLength(1))
00965 ComputeSingleBlockEyeSpace();
00966 else
00967 ComputeMultipleBlockEyeSpace();
00968
00969 return;
00970 }
00971
00972 void GoRegion::ComputeNakade()
00973 {
00974
00975 if (GetFlag(GO_REGION_STATIC_2V))
00976 {
00977 m_eyes.SetMinEyes(2);
00978 }
00979 else
00980 {
00981 m_eyes.SetUnknown();
00982
00983 bool is1vital = ComputeAndGetFlag(GO_REGION_STATIC_1VITAL);
00984 if (is1vital)
00985 m_eyes.SetMinEyes(1);
00986
00987 bool isNakade = false, makeNakade = false;
00988 bool maybeSeki = false, sureSeki = false;
00989 bool makeFalse = false;
00990 int nu = Points().Size();
00991
00992 if (SgUtil::InRange(nu, 3, 7))
00993 {
00994 SgPoint vitalP(SG_NULLPOINT);
00995 TestNakade(m_points, m_bd, m_color, true,
00996 isNakade, makeNakade,
00997 makeFalse,
00998 maybeSeki, sureSeki, &vitalP);
00999 if (isNakade)
01000 {
01001 m_eyes.SetMaxEyes(1);
01002 m_eyes.SetMaxPotEyes(1);
01003 }
01004 else if (makeNakade)
01005 {
01006 m_vitalPoint = vitalP;
01007 m_eyes.SetMinPotEyes(2);
01008 }
01009
01010
01011 }
01012 }
01013
01014 m_eyes.Normalize();
01015 }
01016
01017 void GoRegion::Fini()
01018 {
01019 GoChain::Fini();
01020 GoBlock::Fini();
01021 GoRegionBoard::Fini();
01022 #ifndef NDEBUG
01023 SG_ASSERT(s_alloc == s_free);
01024 #endif
01025 }
01026
01027 #ifndef NDEBUG
01028 int GoRegion::s_alloc = 0;
01029
01030 int GoRegion::s_free = 0;
01031 #endif
01032
01033 void GoRegion::ComputeBasicFlags()
01034 {
01035 SG_ASSERT(! IsValid());
01036 m_flags.set(GO_REGION_VALID);
01037 DoComputeFlag(GO_REGION_SMALL);
01038 DoComputeFlag(GO_REGION_CORRIDOR);
01039 DoComputeFlag(GO_REGION_SINGLE_BLOCK_BOUNDARY);
01040 DoComputeFlag(GO_REGION_STATIC_1VC);
01041 DoComputeFlag(GO_REGION_STATIC_2V);
01042 SetFlag(GO_REGION_USED_FOR_MERGE, false);
01043 }
01044
01045 bool GoRegion::Has2Conn() const
01046 {
01047 SG_ASSERT(m_chains.IsLength(2));
01048 const GoChain* c1 = m_chains.Front();
01049 const GoChain* c2 = m_chains.Back();
01050 return Has2ConnForChains(c1, c2);
01051 }
01052
01053 bool GoRegion::Has2ConnForChains(const GoChain* c1,
01054 const GoChain* c2) const
01055 {
01056 return ( Points()
01057 & c1->FreeLiberties()
01058 & c2->FreeLiberties()
01059 ).MinSetSize(2);
01060 }
01061
01062 bool GoRegion::Safe2Cuts(const GoBoard& board) const
01063 {
01064 SG_ASSERT(m_blocks.IsLength(2));
01065 const int size = board.Size();
01066 GoBlock* block1 = m_blocks.Front();
01067 GoBlock* block2 = m_blocks.Back();
01068 SgPointSet cuts(Points());
01069 cuts -= board.AllEmpty();
01070 if (cuts.IsEmpty())
01071 return true;
01072 cuts &= block1->Stones().Border(size);
01073 cuts &= block2->Stones().Border(size);
01074 return cuts.IsEmpty();
01075 }
01076
01077 bool GoRegion::ProtectedCuts(const GoBoard& board) const
01078 {
01079 if (! GetFlag(GO_REGION_CORRIDOR))
01080 return false;
01081 if (m_blocks.IsLength(2))
01082 return Safe2Cuts(board);
01083
01084 bool prot = true;
01085 SgPointSet allCuts;
01086 const int size = board.Size();
01087 GoBlock* block1, *block2;
01088 for (SgVectorPairIteratorOf<GoBlock> it(m_blocks);
01089 it.NextPair(block1, block2);)
01090 {
01091 SgPointSet lib1(block1->Stones().Border(size));
01092 SgPointSet lib2(block2->Stones().Border(size));
01093 SgPointSet cuts(lib1 & lib2 & Points());
01094 if (! cuts.SubsetOf(board.AllEmpty()))
01095
01096 return false;
01097 else
01098 allCuts |= cuts;
01099 }
01100
01101
01102
01103
01104
01105
01106 return prot;
01107 }
01108
01109 void GoRegion::FindBlocks(const GoRegionBoard& ra)
01110 {
01111 SG_ASSERT(m_blocks.IsEmpty());
01112 const int size = m_bd.Size();
01113 SgPointSet area(Points().Border(size));
01114
01115 for (SgVectorIteratorOf<GoBlock> it(ra.AllBlocks(Color())); it; ++it)
01116 {
01117 if ((*it)->Stones().Overlaps(area))
01118 m_blocks.PushBack(*it);
01119 }
01120 m_computedFlags.set(GO_REGION_COMPUTED_BLOCKS);
01121 }
01122
01123 SgPointSet GoRegion::BlocksPoints() const
01124 {
01125 SgPointSet points;
01126 for (SgVectorIteratorOf<GoBlock> it(m_blocks); it; ++it)
01127 points |= (*it)->Stones();
01128 return points;
01129 }
01130
01131 void GoRegion::SetBlocks(const SgVectorOf<GoBlock>& blocks)
01132 {
01133 SG_ASSERT(m_blocks.IsEmpty());
01134 SG_ASSERT(! blocks.IsEmpty());
01135 const int size = m_bd.Size();
01136 SgPointSet area(Points().Border(size));
01137 for (SgVectorIteratorOf<GoBlock> it(blocks); it; ++it)
01138 {
01139 if ((*it)->Stones().Overlaps(area))
01140 m_blocks.PushBack(*it);
01141 }
01142 m_computedFlags.set(GO_REGION_COMPUTED_BLOCKS);
01143 }
01144
01145 void GoRegion::FindChains(const GoRegionBoard& ra)
01146 {
01147 SG_ASSERT(m_chains.IsEmpty());
01148 const int size = m_bd.Size();
01149 SgPointSet area(Points().Border(size));
01150 for (SgVectorIteratorOf<GoChain> it(ra.AllChains(Color())); it; ++it)
01151 {
01152 if ((*it)->Stones().Overlaps(area))
01153 m_chains.PushBack(*it);
01154 }
01155 m_computedFlags.set(GO_REGION_COMPUTED_CHAINS);
01156 }
01157
01158 bool GoRegion::IsSurrounded(const SgVectorOf<GoBlock>& blocks) const
01159 {
01160 const int size = m_bd.Size();
01161 SgPointSet adj(Points().Border(size));
01162 for (SgVectorIteratorOf<GoBlock> it(blocks); it; ++it)
01163 adj -= (*it)->Stones();
01164 return adj.IsEmpty();
01165 }
01166
01167 bool GoRegion::HealthyForSomeBlock(const SgVectorOf<GoBlock>& blocks) const
01168 {
01169 for (SgVectorIteratorOf<GoBlock> it(blocks); it; ++it)
01170 if ((*it)->ContainsHealthy(this))
01171 return true;
01172 return false;
01173 }
01174
01175 bool GoRegion::SomeBlockIsSafe() const
01176 {
01177 for (SgVectorIteratorOf<GoBlock> it(Blocks()); it; ++it)
01178 if ((*it)->IsSafe())
01179 return true;
01180 return false;
01181 }
01182
01183 bool GoRegion::AllBlockIsSafe() const
01184 {
01185 for (SgVectorIteratorOf<GoBlock> it(Blocks()); it; ++it)
01186 if (!(*it)->IsSafe())
01187 return false;
01188 return true;
01189 }
01190
01191 bool GoRegion::ComputedVitalForDepth(int depth) const
01192 {
01193 return GetFlag(GO_REGION_STATIC_1VC)
01194 || (ComputedFlag(GO_REGION_1VC) && m_1vcDepth >= depth);
01195 }
01196
01197
01198 void GoRegion::CheckConsistency() const
01199 {
01200 SG_ASSERT(Points().Disjoint(m_bd.All(Color())));
01201 SG_ASSERT(Points().Border(m_bd.Size()).SubsetOf(m_bd.All(Color())));
01202 SG_ASSERT(Points().IsConnected());
01203 SgPointSet blockPts;
01204 for (SgVectorIteratorOf<GoBlock> it(m_blocks); it; ++it)
01205 {
01206 SG_ASSERT(AdjacentToBlock((*it)->Anchor()));
01207 blockPts |= (*it)->Stones();
01208 }
01209 SG_ASSERT(Points().Border(m_bd.Size()).SubsetOf(blockPts));
01210 }
01211
01212
01213 void GoRegion::RemoveBlock(const GoBlock* b)
01214 {
01215 bool found = m_blocks.Exclude(b);
01216 SG_UNUSED(found);
01217 SG_ASSERT(found);
01218 ResetNonBlockFlags();
01219 }
01220
01221 bool GoRegion::AdjacentToSomeBlock(const SgVector<SgPoint>& anchors) const
01222 {
01223 for (SgVectorIteratorOf<GoBlock> it(m_blocks); it; ++it)
01224 {
01225 if (anchors.Contains((*it)->Anchor()))
01226 return true;
01227 }
01228 return false;
01229 }
01230
01231 bool GoRegion::AdjacentToBlock(SgPoint anchor) const
01232 {
01233 for (SgVectorIteratorOf<GoBlock> it(m_blocks); it; ++it)
01234 {
01235 if ((*it)->Anchor() == anchor)
01236 return true;
01237 }
01238 return false;
01239 }
01240
01241 void GoRegion::OnAddStone(SgPoint p)
01242 {
01243 SG_ASSERT(m_points.Contains(p));
01244 m_points.Exclude(p);
01245 ResetNonBlockFlags();
01246 }
01247
01248 void GoRegion::OnRemoveStone(SgPoint p)
01249 {
01250 SG_ASSERT(! m_points.Contains(p));
01251 m_points.Include(p);
01252 ResetNonBlockFlags();
01253 }
01254
01255 std::ostream& operator<<(std::ostream& stream, const GoRegion& r)
01256 {
01257 r.Write(stream);
01258 return stream;
01259 }
01260