void GoSafetySolver::FindHealthy() { for (SgBWIterator it; it; ++it) { SgBlackWhite color(*it); for (SgVectorIteratorOf<GoRegion> it(Regions()->AllRegions(color)); it; ++it) (*it)->ComputeFlag(GO_REGION_STATIC_1VITAL); } // used to just call GoStaticSafetySolver::FindHealthy() here, // but that works with GoBlock's and now we use GoChain's. // Code is duplicated though. Can maybe use a template function. for (SgBWIterator it; it; ++it) { SgBlackWhite color(*it); for (SgVectorIteratorOf<GoRegion> it(Regions()->AllRegions(color)); it; ++it) { GoRegion* r = *it; for (SgVectorIteratorOf<GoChain> it2(r->Chains()); it2; ++it2) { if (RegionHealthyForBlock(*r, **it2)) // virtual call (*it2)->AddHealthy(r); } } } }
void GoRegionBoard::OnExecutedUncodedMove(int move, SgBlackWhite moveColor) { if (DEBUG_REGION_BOARD) SgDebug() << "OnExecutedUncodedMove " << SgWritePoint(move) << '\n'; { m_stack.StartMoveInfo(); if (move != SG_PASS) { SG_ASSERT(! Board().LastMoveInfo(GO_MOVEFLAG_SUICIDE)); // can't handle yet, // should be forbidden anyway. @todo allowed in Chinese rules. bool fWasCapture = Board().LastMoveInfo(GO_MOVEFLAG_CAPTURING); UpdateBlock(move, moveColor); { GoRegion* r = PreviousRegionAt(move, moveColor); bool split = GoEyeUtil::IsSplitPt(move, r->Points()); r->OnAddStone(move); PushStone(r, move); SgPointSet points = r->Points(); // needed even after RemoveRegion(r). if (split || points.IsEmpty()) // must remove old region before generating new ones, // because removing clears m_anchor[] RemoveRegion(r); if (split) // find new regions { for (SgConnCompIterator it(points, Board().Size()); it; ++it) GenRegion(*it, moveColor); } } if (fWasCapture) { // FindNewNeighborRegions(move, moveColor); MergeAdjacentAndAddBlock(move, SgOppBW(moveColor)); } m_code = Board().GetHashCode(); if (HEAVYCHECK) CheckConsistency(); } } { for (SgBWIterator it; it; ++it) { SgBlackWhite color(*it); for (SgVectorIteratorOf<GoRegion> it(AllRegions(color)); it; ++it) { GoRegion* r1 = *it; if (! r1->IsValid()) r1->ComputeBasicFlags(); } } } }
void GoSafetySolver::Merge(GoChain* c1, GoChain* c2, GoRegion* r, bool bySearch) { SG_ASSERT(! r->GetFlag(GO_REGION_USED_FOR_MERGE)); r->SetFlag(GO_REGION_USED_FOR_MERGE, true); GoChainCondition* c = 0; if (bySearch) c = new GoChainCondition(GO_CHAIN_BY_SEARCH); else { SgPoint lib1, lib2; r->Find2FreeLibs(c1, c2, &lib1, &lib2); c = new GoChainCondition(GO_CHAIN_TWO_LIBERTIES_IN_REGION, lib1, lib2); } GoChain* m = new GoChain(c1, c2, c); SgBlackWhite color = c1->Color(); bool found = Regions()->AllChains(color).Exclude(c1); SG_DEBUG_ONLY(found); SG_ASSERT(found); found = Regions()->AllChains(color).Exclude(c2); SG_ASSERT(found); Regions()->AllChains(color).Include(m); SG_ASSERT(Regions()->AllChains(color).UniqueElements()); for (SgVectorIteratorOf<GoRegion> it(Regions()->AllRegions(color)); it; ++it) { GoRegion* r = *it; bool replace1 = r->ReplaceChain(c1, m); bool replace2 = r->ReplaceChain(c2, m); if (replace1 || replace2) { r->ReInitialize(); r->ComputeFlag(GO_REGION_STATIC_1VITAL); } } if (DEBUG_MERGE_CHAINS) { SgDebug() << "\nmerge:"; c1->WriteID(SgDebug()); SgDebug() << " + "; c2->WriteID(SgDebug()); SgDebug() << " = "; m->WriteID(SgDebug()); SgDebug() << '\n'; } delete c1; delete c2; }
void GoSafetySolver::FindClosure(SgVectorOf<GoBlock>* blocks) const { SgVectorOf<GoBlock> toTest(*blocks); while (toTest.NonEmpty()) { const GoBlock* b = toTest.Back(); toTest.PopBack(); for (SgVectorIteratorOf<GoRegion> it(b->Healthy()); it; ++it) { GoRegion* r = *it; for (SgVectorIteratorOf<GoChain> it(r->Chains()); it; ++it) { GoBlock* b2 = *it; if (! blocks->Contains(b2) && b2->ContainsHealthy(r)) { blocks->PushBack(b2); toTest.PushBack(b2); } } } } }
bool GoSafetySolver::FindSurroundedSingleRegion(SgBWSet* safe, SgBlackWhite color) { SgPointSet anySafe(safe->Both()); for (SgVectorIteratorOf<GoRegion> it(Regions()->AllRegions(color)); it; ++it) { GoRegion* r = *it; if ( ! r->GetFlag(GO_REGION_SAFE) && r->SomeBlockIsSafe() && ! r->Points().Overlaps(anySafe) && GoSafetyUtil::ExtendedIsTerritory(Board(), Regions(), r->PointsPlusInteriorBlocks(), (*safe)[color], color) ) { GoSafetyUtil::AddToSafe(Board(), r->Points(), color, safe, "surr-safe-1", 0, true); Regions()->SetSafeFlags(*safe); return true; } } return false; }
bool GoSafetySolver::RegionHealthyForBlock(const GoRegion& r, const GoBlock& b) const { return GoStaticSafetySolver::RegionHealthyForBlock(r, b) || r.GetFlag(GO_REGION_STATIC_1VITAL); }
void GoSafetySolver::GenBlocksRegions() { if (UpToDate()) /* */ return; /* */ GoStaticSafetySolver::GenBlocksRegions(); Regions()->GenChains(); // merge blocks adjacent to 1-vital with 2 conn. points for (SgBWIterator it; it; ++it) { SgBlackWhite color(*it); for (SgVectorIteratorOf<GoRegion> it(Regions()->AllRegions(color)); it; ++it) { GoRegion* r = *it; r->ComputeFlag(GO_REGION_STATIC_1VITAL); } bool changed = true; while (changed) { changed = false; for (SgVectorIteratorOf<GoRegion> it(Regions()->AllRegions(color)); it; ++it) { GoRegion* r = *it; if ( r->GetFlag(GO_REGION_STATIC_1VC) && r->Chains().IsLength(2) && r->Has2Conn() // || r->Safe2Cuts(Board()) changed from && to || // @todo does not work if blocks are already chains??? // must explicitly keep chain libs info. ) // easy case of only 2 chains { GoChain* c1 = r->Chains().Front(); GoChain* c2 = r->Chains().Back(); Merge(c1, c2, r, false); // false = not by search changed = true; break; // to leave iteration } else if ( r->GetFlag(GO_REGION_STATIC_1VITAL) && r->GetFlag(GO_REGION_CORRIDOR) && ! r->GetFlag(GO_REGION_USED_FOR_MERGE) ) { GoChain* c1 = 0; GoChain* c2 = 0; if (r->Find2Mergable(&c1, &c2)) { Merge(c1, c2, r, false); changed = true; break; // to leave iteration } } } } } m_code = Board().GetHashCode(); }
void GoRegionBoard::OnUndoneMove() // Called after a move has been undone. The board is guaranteed to be in // a legal state. { //SG_ASSERT(false); // incremental code is incomplete, do not call if (DEBUG_REGION_BOARD) SgDebug() << "OnUndoneMove " << '\n'; const bool IS_UNDO = false; SgVectorOf<GoRegion> changed; for (int val = m_stack.PopEvent(); val != SG_NEXTMOVE; val = m_stack.PopEvent()) { switch (val) { case REGION_REMOVE: { GoRegion* r = static_cast<GoRegion*>(m_stack.PopPtr()); AddRegion(r, IS_UNDO); changed.Insert(r); } break; case REGION_ADD: { GoRegion* r = static_cast<GoRegion*>(m_stack.PopPtr()); RemoveRegion(r, IS_UNDO); } break; case REGION_REMOVE_BLOCK: { GoBlock* b = static_cast<GoBlock*>(m_stack.PopPtr()); AddBlock(b, IS_UNDO); for (int nu = m_stack.PopInt(); nu > 0; --nu) { GoRegion* r = static_cast<GoRegion*>(m_stack.PopPtr()); if (CHECK) SG_ASSERT(! r->Blocks().Contains(b)); r->BlocksNonConst().PushBack(b); changed.Insert(r); } } break; case REGION_ADD_BLOCK: { GoBlock* b = static_cast<GoBlock*>(m_stack.PopPtr()); RemoveBlock(b, IS_UNDO, true); } break; case REGION_ADD_STONE: { GoRegion* r = static_cast<GoRegion*>(m_stack.PopPtr()); SgPoint p = m_stack.PopInt(); r->OnRemoveStone(p); m_region[r->Color()][p] = r; changed.Insert(r); } break; case REGION_ADD_STONE_TO_BLOCK: { GoBlock* b = static_cast<GoBlock*>(m_stack.PopPtr()); SgPoint p = m_stack.PopInt(); b->RemoveStone(p); m_block[p] = 0; } break; default: SG_ASSERT(false); } } for (SgVectorIteratorOf<GoRegion> it(changed); it; ++it) { (*it)->ResetNonBlockFlags(); (*it)->ComputeBasicFlags(); } if (HEAVYCHECK) { for (SgBWIterator it; it; ++it) { SgBlackWhite color(*it); for (SgVectorIteratorOf<GoRegion> it(AllRegions(color)); it; ++it) { const GoRegion* r = *it; SG_UNUSED(r); SG_ASSERT(r->IsValid()); } } } m_code = Board().GetHashCode(); if (HEAVYCHECK) CheckConsistency(); }