bool GoRegion::ProtectedCuts(const GoBoard& board) const
{
    if (! GetFlag(GO_REGION_CORRIDOR))
        return false;
    if (m_blocks.IsLength(2))
        /* */ return Safe2Cuts(board); /* */ // easy case of only 2 blocks

    bool prot = true;
    SgPointSet allCuts;
    const int size = board.Size();
    GoBlock* block1, *block2;
    for (SgVectorPairIteratorOf<GoBlock> it(m_blocks);
         it.NextPair(block1, block2);)
    {
        SgPointSet lib1(block1->Stones().Border(size));
        SgPointSet lib2(block2->Stones().Border(size));
        SgPointSet cuts(lib1 & lib2 & Points());
        if (! cuts.SubsetOf(board.AllEmpty()))
        // cut occupied by opponent. Bad for us.
            return false;
        else
            allCuts |= cuts;
    }
    // no eye space left ? hard to distinguish false eyes from ok
    // AR why must this be checked??? Should not matter for flat regions.
    // Try to take it out.
    //if (Points().SubsetOf(allCuts | allCuts.Border()))
    //  prot = false;

    return prot;
}
Beispiel #2
0
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;
}
int LibertyAveragex10(const GoBoard& board, SgBlackWhite color)
{
    int nuLibs = 0, nuBlocks = 0;
    const int size = board.Size();
    for (SgConnCompIterator it(board.All(color), board.Size()); it; ++it)
    {
        ++nuBlocks;
        nuLibs += ((*it).Border(size) & board.AllEmpty()).Size();
    }
    return (nuBlocks == 0) ? 0 : 10 * nuLibs / nuBlocks;
}
bool GoRegion::Safe2Cuts(const GoBoard& board) const
{
    SG_ASSERT(m_blocks.IsLength(2));
    const int size = board.Size();
    GoBlock* block1 = m_blocks.Front();
    GoBlock* block2 = m_blocks.Back();
    SgPointSet cuts(Points());
    cuts -= board.AllEmpty();
    if (cuts.IsEmpty())
        /* */ return true; /* */
    cuts &= block1->Stones().Border(size);
    cuts &= block2->Stones().Border(size);
    return cuts.IsEmpty();
}
Beispiel #5
0
void GoEyeUtil::TestNakade(const SgPointSet& points,
                           const GoBoard& bd,
                           SgBlackWhite color,
                           bool isFullyEnclosed,
                           bool& isNakade,
                           bool& makeNakade,
                           bool& makeFalse,
                           bool& maybeSeki,
                           bool& sureSeki,
                           SgPoint* vital)
{   // handles case
    // of more than 1 point passing vital point test.
    // passes back vital point if exactly one is found.
    // @todo handle case where vital is illegal or suicide (eye within eye?).
    // also test bigger, would-be-alive shapes in atari.
    // @todo handle seki.
    
    SG_UNUSED(makeFalse);
    isNakade = makeNakade = maybeSeki = sureSeki = false;
    SgPoint vitalP(SG_NULLPOINT);
    const SgBlackWhite opp = SgOppBW(color);
    const int nuPoints = points.Size();
    
    SG_ASSERT(nuPoints >= 3); // don't call for smaller areas, no need,
    // and results in isNakade = false which is confusing.
    
    if (nuPoints == 4) // special case 4 point areas
    {
        if (IsBulkyFour(points))
        {
            if (   isFullyEnclosed
                && TwoDiagonalStonesInBulkyFour(bd, points, opp)
               )
                makeNakade = true;
            else
                isNakade = true;
            /* */ return; /* */
        }
        else if (   isFullyEnclosed
                 && points.SubsetOf(bd.AllEmpty())
                 && IsBentFour(points, bd.Size(), vital)
                )
        {
            makeNakade = true;
            /* */ return; /* */
        }
    }
    else if (isFullyEnclosed && nuPoints == 5) // special case 5 point areas
    {
        const GoEyeStatus status = BulkyFiveNakade(bd, points, opp);
        if (ProcessStatus(status, isNakade, makeNakade))
            /* */ return; /* */
    }
    else if (isFullyEnclosed && nuPoints == 6) // special case 6 point areas
    {
        if (Is2x3Area (points))
        {
            GoEyeStatus status = Special2x3Cases(bd, points, opp);
            if (ProcessStatus(status, isNakade, makeNakade))
                /* */ return; /* */
        }   
    }
    if (   isFullyEnclosed
        && AlmostFilledByNakade(bd, points, opp)
       )
    {
        isNakade = true;
        /* */ return; /* */
    }
        
    if (   isFullyEnclosed
        && (   AlmostFilledByLivingShape(bd, points, opp)
            || ContainsLivingShape(bd, points, opp)
           )
       )
    {   // not nakade, 2 eyes
        /* */ return; /* */
    }
        
    int nuMakeNakade = 0;
    int nuVitalOccupied = 0;
    bool hasDivider = false;
    // counting number of nakade fixes bug with stretched 5 pt eye 
    // that had 3 vital pts,
    // one of them occupied. was classified as 'isNakade7 = 1 eye.
    // see sgf/ld200,#20
    for (SgSetIterator it(points); it; ++it)
    {
        SgPoint p(*it);
        if (IsVitalPt(points, p, opp, bd))
        {
            if (bd.IsEmpty(p))
            {
                if (bd.IsLegal(p, opp))
                {
                    ++nuMakeNakade;
                    vitalP = p;
                }
                else
                    hasDivider = true;
            }
            else
                ++nuVitalOccupied;
        }
    }
    
    if (hasDivider)
    { // alive 
    }
    else if (nuMakeNakade == 1) // exactly one way to make nakade here.
    {
        makeNakade = true;
        *vital = vitalP;
    }
    else if (nuMakeNakade > 0) 
        isNakade = false;
    else if (nuVitalOccupied < 3)
        isNakade = true;
    else
    {
        maybeSeki = true;
        // @todo if (IsSureSekiShape(...)) sureSeki = true;
    }
}