/** Find global moves that match a playout pattern or set a block into atari. @param[out] pattern @param[out] atari @param[out] empty As a side effect, this function finds all empty points on the board @return @c true if any such moves was found */ bool GoUctDefaultPriorKnowledge::FindGlobalPatternAndAtariMoves( SgPointSet& pattern, SgPointSet& atari, GoPointList& empty) { // Minimum value for pattern gamma to be used. static const float EPSILON = 0.00000000001; const GoBoard& bd = Board(); SG_ASSERT(empty.IsEmpty()); const GoUctPatterns<GoBoard>& patterns = m_policy.GlobalPatterns(); bool result = false; m_maxPatternGamma = -1.f; for (GoBoard::Iterator it(bd); it; ++it) if (bd.IsEmpty(*it)) { empty.PushBack(*it); float gamma = patterns.GetPatternGamma(bd, *it, bd.ToPlay()); if (gamma > EPSILON) { pattern.Include(*it); result = true; m_patternGammas[*it] = gamma; if (gamma > m_maxPatternGamma) m_maxPatternGamma = gamma; } if (SetsAtari(bd, *it)) { atari.Include(*it); result = true; } } return result; }
/** Find global moves that match a playout pattern or set a block into atari. @param[out] pattern @param[out] atari @param[out] empty As a side effect, this function finds all empty points on the board @return @c true if any such moves was found */ bool GoUctDefaultPriorKnowledge::FindGlobalPatternAndAtariMoves( SgPointSet& pattern, SgPointSet& atari, GoPointList& empty) const { SG_ASSERT(empty.IsEmpty()); const GoUctPatterns<GoBoard>& patterns = m_policy.Patterns(); bool result = false; for (GoBoard::Iterator it(m_bd); it; ++it) if (m_bd.IsEmpty(*it)) { empty.PushBack(*it); if (patterns.MatchAny(*it)) { pattern.Include(*it); result = true; } if (SetsAtari(m_bd, *it)) { atari.Include(*it); result = true; } } return result; }
SgPointSet SpUtil::GetRelevantMoves(GoBoard& bd, SgBlackWhite toPlay, bool useFilter) { SgPointSet legal; for (SgSetIterator it(bd.AllEmpty()); it; ++it) if (bd.IsLegal(*it)) legal.Include(*it); if (! useFilter) return legal; GoSafetySolver safetySolver(bd); SgBWSet safe; safetySolver.FindSafePoints(&safe); SgBlackWhite opp = SgOppBW(toPlay); SgPointSet moves; const GoRules& rules = bd.Rules(); const bool captureDead = rules.CaptureDead(); //const bool japaneseScoring = rules.JapaneseScoring(); for (SgSetIterator it(legal); it; ++it) { SgPoint p = *it; const bool isSafe = safe[toPlay].Contains(p); const bool isSafeOpp = safe[opp].Contains(p); const bool hasOppNeighbors = bd.HasNeighbors(p, opp); if ( (! isSafe && ! isSafeOpp) || (isSafe && captureDead && hasOppNeighbors) // || (isSafeOpp && ! japaneseScoring) ) moves.Include(p); } return moves; }
void GoBlock::CheckConsistency() const { SG_ASSERT(Stones().SubsetOf(m_bd.All(Color()))); SgPoint anchor = Anchor(); SG_ASSERT(m_bd.Anchor(anchor) == Anchor()); SgPointSet stones; for (GoBoard::StoneIterator it(m_bd, anchor); it; ++it) stones.Include(*it); SG_ASSERT(Stones() == stones); }
// improved by using recursive extension to find 2-conn paths. bool GoRegion::Find2ConnForAllInterior(SgMiaiStrategy* miaiStrategy, SgVector<SgPoint>& usedLibs) const { SgVector<SgMiaiPair> myStrategy; const int size = m_bd.Size(); SgPointSet interior = AllInsideLibs(); if (interior.IsEmpty()) { return true; } //if (GetFlag(GO_REGION_SINGLE_BLOCK_BOUNDARY)) { SgPointSet testSet = interior; SgPointSet originalLibs = testSet.Border(size) & Dep().Border(size) & m_bd.AllEmpty() & Points(); SgPointSet updateLibs = originalLibs; // now try to find miai-paths to remaining interior points recursively bool changed = true; while (changed) { changed = false; if (testSet.IsEmpty()) { SgVector<SgPoint> jlibs; JointLibs(&jlibs); SgVector<SgPoint> ips; GetIPs(&ips); SgVector<SgMiaiPair> updateStrg; for (SgSetIterator it(interior); it; ++it) { SgPoint p = *it; SgPointSet s1; s1.Include(p); SgPointSet rest = s1.Border(size) & updateLibs; if (! rest.IsEmpty()) { for (SgVectorIterator<SgMiaiPair> it2(myStrategy); it2; ++it2) { SgMiaiPair x = *it2; if ( SgPointUtil::AreAdjacent(p, x.first) && SgPointUtil::AreAdjacent(p, x.second) ) { if (ips.Contains(x.first)) { updateLibs.Include(x.first); usedLibs.Exclude(x.first); SgPoint t = rest.PointOf(); x.first = t; updateLibs.Exclude(t); rest.Exclude(t); usedLibs.Include(t); } if ( ips.Contains(x.second) && ! rest.IsEmpty() ) { updateLibs.Include(x.second); usedLibs.Exclude(x.second); SgPoint t = rest.PointOf(); x.second = t; updateLibs.Exclude(t); rest.Exclude(t); usedLibs.Include(t); } updateStrg.Include(x); } } } } miaiStrategy->SetStrategy(updateStrg); /* */ return true; /* */ } for (SgSetIterator it(interior); it; ++it) { SgMiaiPair miaiPair; if (Find2BestLibs(*it, updateLibs, testSet, &miaiPair)) { if (miaiPair.first == miaiPair.second) { SgDebug() <<"\nmiaipair are same: " << SgWritePoint(miaiPair.first) << SgWritePoint(miaiPair.second); SgDebug() <<"\ncurrent region is:\n"; Points().Write(SgDebug(), size); SG_ASSERT(false); } myStrategy.PushBack(miaiPair); usedLibs.PushBack(miaiPair.first); usedLibs.PushBack(miaiPair.second); updateLibs.Exclude(miaiPair.first); updateLibs.Exclude(miaiPair.second); updateLibs.Include(*it); testSet.Exclude(*it); changed = true; } } } // while loop for recursive finding } miaiStrategy->Clear(); return false; }
bool GoEyeUtil::NumberOfMoveToEye2(const GoBoard& board, SgBlackWhite color, SgPoint p, int& nummoves) { nummoves = 0; bool capturing = false; SgVector<SgPoint> usedpoints; usedpoints.PushBack(p); SgPointSet counted; // Can never turn own stone into an eye if (board.IsColor(p, color)) return false; // If opponent stone then it must be captured to make eye if (board.IsColor(p, SgOppBW(color))) { capturing = true; // If it is obviously safe then it can never be an eye if (SinglePointSafe2(board, p)) // Quick, naive safety test return false; for (GoBoard::LibertyIterator libit(board, p); libit; ++libit) counted.Include(*libit); } // Count immediate adjacencies for (SgNb4Iterator nb(p); nb; ++nb) { SgPoint adj = *nb; // Empty points must be filled if (board.IsColor(adj, SG_EMPTY)) { counted.Include(adj); } // If adjacent opponent then can never be an eye else if (board.IsColor(adj, SgOppBW(color))) { if (capturing) counted.Include(adj); // must capture and then fill else return false; } } // Up to one diagonal can be ignored: estimate most costly SgPoint toignore = SG_NULLPOINT; int maxcost = 0; int infcost = 1000; if (board.Line(p) > 1) { for (SgNb4DiagIterator nbd(p); nbd; ++nbd) { SgPoint diag = *nbd; int cost = 0; if ( board.IsColor(diag, SG_EMPTY) && ! IsSinglePointEye2(board, diag, color, usedpoints)) { cost = 1; } else if (board.IsColor(diag, SgOppBW(color))) { // quick safety test if (SinglePointSafe2(board, diag)) cost = infcost; else cost = board.NumLiberties(diag); } if (cost > maxcost) { maxcost = cost; toignore = diag; } } } // Now mark points that must be played to secure diagonals for (SgNb4DiagIterator nbd(p); nbd; ++nbd) { SgPoint diag = *nbd; if (diag == toignore) continue; // Empty points must be filled (unless they are eyes) if ( board.IsColor(diag, SG_EMPTY) && ! IsSinglePointEye2(board, diag, color, usedpoints)) { counted.Include(diag); } // Opponent stones on diagonals must be captured and filled else if (board.IsColor(diag, SgOppBW(color))) { if (SinglePointSafe2(board, diag)) return false; else { counted.Include(diag); for (GoBoard::LibertyIterator libit(board, diag); libit; ++libit) counted.Include(*libit); } } } nummoves = counted.Size(); return true; }