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