SgBWSet GoSafetyCommands::GetSafe(int& totalRegions, const string& type) { GoModBoard modBoard(m_bd); GoBoard& bd = modBoard.Board(); GoRegionBoard regionAttachment(bd); SgBWSet safe; if (type == "benson") { GoBensonSolver solver(bd, ®ionAttachment); solver.FindSafePoints(&safe); } else if (type == "static") { GoSafetySolver solver(bd, ®ionAttachment); solver.FindSafePoints(&safe); } else throw GtpFailure() << "invalid safety solver: " << type; SgPointSet proved = safe.Both(); for (SgBWIterator it; it; ++it) { SgBlackWhite c = *it; for (SgVectorIteratorOf<GoRegion> it(regionAttachment.AllRegions(c)); it; ++it) if ((*it)->Points().SubsetOf(proved)) ++totalRegions; } return safe; }
/** List of safe points. If no color is given, safe points of both colors are listed. Arguments: benson|static [black|white]<br> Returns: number of point followed bu list of points in one line. */ void GoSafetyCommands::CmdSafe(GtpCommand& cmd) { cmd.CheckNuArgLessEqual(2); string type = cmd.Arg(0); int totalRegions = 0; SgBWSet safe = GetSafe(totalRegions, type); SgPointSet set = (cmd.NuArg() == 2 ? safe[BlackWhiteArg(cmd, 1)] : safe.Both()); cmd << set.Size(); for (SgSetIterator it(set); it; ++it) cmd << ' ' << SgWritePoint(*it); }
vector<SgPoint> GoUctDefaultMoveFilter::Get() { vector<SgPoint> rootFilter; SgBlackWhite toPlay = m_bd.ToPlay(); SgBlackWhite opp = SgOppBW(toPlay); // Safe territory if (m_param.m_checkSafety) { GoModBoard modBoard(m_bd); GoBoard& bd = modBoard.Board(); SgBWSet alternateSafe; bool isAllAlternateSafe = false; // Alternate safety is used to prune moves only in opponent territory // and only if everything is alive under alternate play. This ensures that // capturing moves that are not liberties of dead blocks and ko threats // will not be pruned. This alternate safety pruning is not going to // improve or worsen playing strength, but may cause earlier passes, // which is nice in games against humans GoSafetySolver safetySolver(bd); safetySolver.FindSafePoints(&alternateSafe); isAllAlternateSafe = (alternateSafe.Both() == bd.AllPoints()); // Benson solver guarantees that capturing moves of dead blocks are // liberties of the dead blocks and that no move in Benson safe territory // is a ko threat GoBensonSolver bensonSolver(bd); SgBWSet unconditionalSafe; bensonSolver.FindSafePoints(&unconditionalSafe); for (GoBoard::Iterator it(bd); it; ++it) { SgPoint p = *it; if (m_bd.IsLegal(p)) { bool isUnconditionalSafe = unconditionalSafe[toPlay].Contains(p); bool isUnconditionalSafeOpp = unconditionalSafe[opp].Contains(p); bool isAlternateSafeOpp = alternateSafe[opp].Contains(p); bool hasOppNeighbors = bd.HasNeighbors(p, opp); // Always generate capturing moves in own safe territory, even // if current rules do no use CaptureDead(), because the UCT // player always scores with Tromp-Taylor after two passes in the // in-tree phase if ( (isAllAlternateSafe && isAlternateSafeOpp) || isUnconditionalSafeOpp || (isUnconditionalSafe && ! hasOppNeighbors) ) rootFilter.push_back(p); } } } // Loosing ladder defense moves if (m_param.m_checkLadders) { for (GoBlockIterator it(m_bd); it; ++it) { SgPoint p = *it; if (m_bd.GetStone(p) == toPlay && m_bd.InAtari(p)) { if (m_ladder.Ladder(m_bd, p, toPlay, &m_ladderSequence, false/*twoLibIsEscape*/) < 0) { if (m_ladderSequence.Length() >= m_param.m_minLadderLength) rootFilter.push_back(m_bd.TheLiberty(p)); } } } } if (m_param.m_checkOffensiveLadders) { for (GoBlockIterator it(m_bd); it; ++it) { SgPoint p = *it; if (m_bd.GetStone(p) == opp && m_bd.NumStones(p) >= 5 && m_bd.NumLiberties(p) == 2) { if (m_ladder.Ladder(m_bd, p, toPlay, &m_ladderSequence, false/*twoLibIsEscape*/) > 0) { if (m_ladderSequence.Length() >= m_param.m_minLadderLength) rootFilter.push_back(m_ladderSequence[0]); } } } } if (m_param.m_filterFirstLine) { // Moves on edge of board, if no stone is near const SgBoardConst& bc = m_bd.BoardConst(); for (SgLineIterator it(bc, 1); it; ++it) { const SgPoint p = *it; if (m_bd.IsEmpty(p) && IsEmptyEdge(m_bd, p)) rootFilter.push_back(p); } } return rootFilter; }