Beispiel #1
0
bool GoEyeUtil::IsVitalPt(const SgPointSet& points, SgPoint p,
                SgBlackWhite opp,
                const GoBoard& bd)
{
    // in corridors a vital point has 2 nbs, in big ones it may have 3 or 4.
    // but: 2 in following
    // example: unsettled nakade, non-flat points are all occupied by opp.
    // .a       a is vital Point.
    //  o.
    //  .
    int numNb = bd.NumEmptyNeighbors(p) + bd.NumNeighbors(p, opp);
    if (numNb >= 2)
    {
        if (numNb >= 4)
            /* */ return true; /* */
        int nu = IsTreeShape(points) ? 2 : 3;
        if (numNb >= nu)
        {
            if (numNb == 2 && bd.IsEmpty(p))
                return IsSplitPt(p, points);
            else
                return true;
        }
    }
    return false;
}
/** Return true, if point is on edge line and no stone is within a
    Manhattan distance of 4. */
bool IsEmptyEdge(const GoBoard& bd, SgPoint p)
{
    SG_ASSERT (bd.IsEmpty(p));
    SG_ASSERT (bd.Line(p) == 1);
    if (bd.Num8EmptyNeighbors(p) < 5)
        return false;
    const SgPoint pUp = p + bd.Up(p);
    SG_ASSERT(bd.Line(pUp) == 2);
    SG_ASSERT(bd.Pos(pUp) >= 2); // (1,1) goes to (2,2)
    if (bd.Num8EmptyNeighbors(pUp) < 8)
        return false;

    switch (bd.Pos(p))
    {
        case 1: // (1,1) point
        case 2: // (1,2) point
        case 3:
            return IsEmptyOrInCorner(bd, p, bd.Left(p))
                && IsEmptyOrInCorner(bd, p, bd.Right(p));
            // assume in empty corner, 1st line is always
            // dominated bymove on 2nd line above
        default: // > 3, can test both sides easily
            return   IsEmpty2x3Box(bd, p + 2*bd.Left(p))
                  && IsEmpty2x3Box(bd, p + 2*bd.Right(p))
                  ;
    }
}
Beispiel #3
0
bool GoEyeUtil::NumberOfMoveToEye(const GoBoard& board, SgBlackWhite color,
                                  SgPoint p, int& number)
{
    SG_ASSERT(board.IsEmpty(p));
    SgBlackWhite att = SgOppBW(color);  // attacker

    if ( board.Line(p) == 1) // corner or edge
    {
        if ( board.Num8Neighbors(p, att) > 0 )
            return false;
        else
        {
            number = board.Num8EmptyNeighbors(p);
            return true;
        }
    }
    else // in center
    {
        if ( board.Num8Neighbors(p, att) >= 2 )
            return false;
        else if ( board.NumNeighbors(p, att) > 0 )
            return false;
        else // only 0 or 1 attacker point and not in NB4
        {
            number = board.Num8EmptyNeighbors(p);
            return true;
        }
    }
    
}
Beispiel #4
0
bool GoEyeUtil::IsSinglePointEye(const GoBoard& bd, SgPoint p,
                                 SgBlackWhite color)
{
    SG_ASSERT(bd.IsEmpty(p));
    const SgBlackWhite opp = SgOppBW(color);
    if (bd.HasEmptyNeighbors(p) || bd.HasNeighbors(p, opp))
        return false;
    if (bd.Line(p) == 1)
        return ! (bd.HasDiagonals(p, SG_EMPTY) || bd.HasDiagonals(p, opp));
    return (bd.NumDiagonals(p, SG_EMPTY) + bd.NumDiagonals(p, opp)) <= 1;
}
Beispiel #5
0
bool GoEyeUtil::CheckInterior(const GoBoard& bd, const SgPointSet& area,
                   SgBlackWhite opp, bool checkBlocks)
{
    bool hasSingleNbPoint = false;
    int nuPoints = 0;
    for (SgSetIterator it(area); it; ++it)
    {
        const SgPoint p(*it);
        if (bd.IsEmpty(p))
        {
            int nuNbs = 0;
            if (area.Contains(p + SG_NS))
                ++nuNbs;
            if (area.Contains(p - SG_NS))
                ++nuNbs;
            if (area.Contains(p + SG_WE))
                ++nuNbs;
            if (area.Contains(p - SG_WE))
                ++nuNbs;
            if (nuNbs == 1)
                hasSingleNbPoint = true;
            else if (nuNbs > 2)
                return false;
        }
        else if (p == bd.Anchor(p))
        {
            if (bd.GetColor(p) != opp)
            // if own stones on inside: not a tree shape.
                return false;
            int nuLibs = bd.NumLiberties(p);
            if (nuLibs == 1)
                hasSingleNbPoint = true;
            else if (checkBlocks && nuLibs > 2)
                return false;
        }
        ++nuPoints;
    }
    return nuPoints == 1 || hasSingleNbPoint;
}
void GoBoardCheckPerformance::CheckPerformance(const GoBoard& board,
                                               ostream& out)
{
    const int NUM_REPETITIONS = 10000;
    int i;

    double startTime = SgTime::Get();
    int sum1 = 0;
    for (i = 0; i < NUM_REPETITIONS; ++i)
    {
        for (SgPoint p = 0; p < SG_MAXPOINT; ++p)
        {   if (board.IsEmpty(p))
                sum1 += p;
        }
    }
    double endTime1 = SgTime::Get();

    int sum2 = 0;
    for (i = 0; i < NUM_REPETITIONS; ++i)
    {
        for (SgPoint p = board.FirstBoardPoint(); p <= board.LastBoardPoint();
             ++p)
        {   if (board.IsEmpty(p))
                sum2 += p;
        }
    }
    double endTime2 = SgTime::Get();

    int sum3 = 0;
    for (i = 0; i < NUM_REPETITIONS; ++i)
        for (GoBoard::Iterator it(board); it; ++it)
        {
            if (board.IsEmpty(*it))
                sum3 += *it;
        }
    double endTime3 = SgTime::Get();

    int sum4 = 0;
    for (i = 0; i < NUM_REPETITIONS; ++i)
    {
        for (SgPoint p = 0; p < SG_MAXPOINT; ++p)
        {
            if (board.IsEmpty(p))
                sum4 += p;
        }
    }
    double endTime4 = SgTime::Get();

    int sum5 = 0;
    for (i = 0; i < NUM_REPETITIONS; ++i)
    {
        for (SgPoint p = board.FirstBoardPoint(); p <= board.LastBoardPoint();
             ++p)
        {
            if (board.IsEmpty(p))
                sum5 += p;
        }
    }
    double endTime5 = SgTime::Get();

    SG_ASSERT(sum1 == sum2);
    SG_ASSERT(sum2 == sum3);
    SG_ASSERT(sum3 == sum4);
    SG_ASSERT(sum4 == sum5);

    double time1 = endTime1 - startTime;
    double time2 = endTime2 - endTime1;
    double time3 = endTime3 - endTime2;
    double time4 = endTime4 - endTime3;
    double time5 = endTime5 - endTime4;

    out << "Time1: " << time1 << " For 0..SG_MAXPOINT\n"
        << "Time2: " << time2 << " First/LastBoardPoint\n"
        << "Time3: " << time3 << " GoBoard::Iterator\n"
        << "Time4: " << time4 << " For 0..SG_MAXPOINT, no dependency\n"
        << "Time5: " << time5 << " First/LastBoardPoint, no dependency\n";
}
//----------------------------------------------------------------------------
inline bool IsEmpty2x3Box(const GoBoard& bd, SgPoint p)
{
    SG_ASSERT (bd.Line(p) == 1);
    SG_ASSERT (bd.Pos(p) > 1);
    return bd.IsEmpty(p) && bd.Num8EmptyNeighbors(p) == 5;
}
Beispiel #8
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;
    }
}