void GoRegionBoard::MergeAdjacentAndAddBlock(SgPoint move,
                                             SgBlackWhite capturedColor)
{
    SgVector<SgPoint> nb;
    for (GoNbIterator it(Board(), move); it; ++it)
        if (Board().IsEmpty(*it))
            nb.PushBack(*it);

    SgVectorOf<GoBlock> captures;
    PreviousBlocksAt(nb, capturedColor, &captures);
    SG_ASSERT(captures.NonEmpty());

    SgPointSet captured;
    {for (SgVectorIteratorOf<GoBlock> it(captures); it; ++it)
        captured |= (*it)->Stones();
    }
    SgVectorOf<GoRegion> adj;
    const int size = Board().Size();
    RegionsAt(captured.Border(size), capturedColor, &adj);
    SG_ASSERT(adj.NonEmpty());
    GoRegion* r = MergeAll(adj, captured, capturedColor);
    SG_UNUSED(r);

    for (SgVectorIteratorOf<GoBlock> it(captures); it; ++it)
        RemoveBlock(*it, true, false);
        // don't remove from regions; already gone.
}
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();
            }
        }
    }
}
/** 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;
}
/** 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;
}
Esempio n. 5
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;
}
Esempio n. 6
0
void GoChain::GetBlocks(const GoRegionBoard* ra, 
                        SgVectorOf<GoBlock>* blocks) const
{
    SgBlackWhite color = Color();
    SgPointSet chainPts = Stones();
    for (SgVectorIteratorOf<GoBlock> it(ra->AllBlocks(color)); it; ++it)
        if (chainPts.Contains((*it)->Anchor()))
            blocks->PushBack(*it);
}
Esempio n. 7
0
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);
}
Esempio n. 8
0
void GoRegion::Find2FreeLibs(const GoChain* c1, const GoChain* c2,
                             SgPoint* lib1, SgPoint* lib2) const
{
    SgPointSet libs = Points() & c1->FreeLiberties() & c2->FreeLiberties();
    if (CHECK)
        SG_ASSERT(libs.MinSetSize(2));
    SgSetIterator it(libs);
    *lib1 = *it;
    ++it;
    *lib2 = *it;
}
/** 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);
}
Esempio n. 10
0
bool GoEyeUtil::IsTreeShape(const SgPointSet& area)
{
    for (SgSetIterator it(area); it; ++it)
    {
        const SgPoint p(*it);
        if (   area.Contains(p + SG_NS)
            && area.Contains(p + SG_WE)
            && area.Contains(p + SG_NS + SG_WE)
           )
           return false;
    }
    return true;
}
    void updatePointCloudFromRangeSensor()
        {
            if(!pointSetFromRangeSensor)
                return;

            SgVertexArray& disPoints = *pointSetFromRangeSensor->getOrCreateVertices();

            boost::mutex::scoped_lock lock(mtx);
            disPoints.resize(rangeSensorPoints.size());
            copy(rangeSensorPoints.begin(), rangeSensorPoints.end(), disPoints.begin());
            lock.unlock();

            pointSetFromRangeSensor->notifyUpdate();
        }
Esempio n. 12
0
long GoEyeUtil::DegreeCode8(const SgPointSet& points)
{
    int degrees[9] = {0,0,0,0,0};
    
    for (SgSetIterator it(points); it; ++it)
    {
        const SgPoint p(*it);
        int nbs = 0;
        for (SgNb8Iterator it(p); it; ++it)
        {
            if (points.Contains(*it))
                ++nbs;
        }
        ++(degrees[nbs]);
    }
    return              degrees[0] 
                 + 10 * degrees[1]
                + 100 * degrees[2]
               + 1000 * degrees[3]
              + 10000 * degrees[4]
             + 100000 * degrees[5]
            + 1000000 * degrees[6]
           + 10000000 * degrees[7]
          + 100000000 * degrees[8];
}
Esempio n. 13
0
/** Information about safe points optimized for graphical display in GoGui.
    This command is compatible with GoGui's analyze command type "gfx".
    Arguments: benson|static <br>
    Returns: GoGui gfx commands to display safe points and additional
    information in the status line
    - black and white territory: safe points
    - Color Magenta (#980098): dame points
    - Color Red: safe for black and white (should not happen)
    - Circle: unsurroundable
    - Status line: point counts, percentage of safe points
*/
void GoSafetyCommands::CmdGfx(GtpCommand& cmd)
{
    cmd.CheckNuArg(1);
    string type = cmd.Arg(0);
    int totalRegions = 0;
    SgBWSet safe = GetSafe(totalRegions, type);
    SgPointSet dame;
    SgPointSet unsurroundable;
    GoSafetyUtil::FindDameAndUnsurroundablePoints(m_bd, m_bd.AllEmpty(), safe,
                                                  &dame, &unsurroundable);
    cmd << "BLACK";
    for (SgSetIterator it(safe[SG_BLACK]); it; ++it)
        cmd << ' ' << SgWritePoint(*it);
    cmd << '\n';
    cmd << "WHITE";
    for (SgSetIterator it(safe[SG_WHITE]); it; ++it)
        cmd << ' ' << SgWritePoint(*it);
    cmd << '\n';
    cmd << "COLOR #980098";
    for (SgSetIterator it(dame); it; ++it)
        cmd << ' ' << SgWritePoint(*it);
    cmd << '\n';
    cmd << "CIRCLE";
    for (SgSetIterator it(unsurroundable); it; ++it)
        cmd << ' ' << SgWritePoint(*it);
    cmd << '\n';
    SgPointSet blackAndWhite = safe[SG_WHITE] & safe[SG_BLACK];
    if (blackAndWhite.Size() > 0)
    {
        // Shouldn't happen
        cmd << "COLOR red ";
        for (SgSetIterator it(blackAndWhite); it; ++it)
            cmd << ' ' << SgWritePoint(*it);
        cmd << '\n';
    }
    int nuBlack = safe[SG_BLACK].Size();
    int nuWhite = safe[SG_WHITE].Size();
    int nuPoints = m_bd.AllPoints().Size();
    cmd << "TEXT Solver: " << cmd.Arg(0)
        << "  B: " << nuBlack << " (" << (100 * nuBlack / nuPoints) << " %)"
        << "  W: " << nuWhite << " (" << (100 * nuWhite / nuPoints) << " %)"
        << "  Both: " << (nuBlack + nuWhite)
        << " (" << (100 * (nuBlack + nuWhite) / nuPoints) << " %)"
        << "  Regions: " << totalRegions;
}
    void updatePointCloudFromRangeCamera()
        {
            if(!pointSetFromRangeCamera)
                return;

            SgVertexArray& disPoints = *pointSetFromRangeCamera->getOrCreateVertices();
            SgColorArray& disColors = *pointSetFromRangeCamera->getOrCreateColors();

            boost::mutex::scoped_lock lock(mtx);
            disPoints.resize(rangeCameraPoints.size());
            disColors.resize(rangeCameraColors.size());
            copy(rangeCameraPoints.begin(), rangeCameraPoints.end(), disPoints.begin());
            copy(rangeCameraColors.begin(), rangeCameraColors.end(), disColors.begin());
            lock.unlock();

            pointSetFromRangeCamera->notifyUpdate();

        }
    void clearImage()
        {
            if(imageView){
                Image image;
                image.clear();
                image.setSize(1,1,3);
                *image.pixels() = 0;
                imageView->setImage(image);
            }

            if(pointSetFromRangeCamera){
                pointSetFromRangeCamera->getOrCreateVertices()->clear();
                pointSetFromRangeCamera->getOrCreateColors()->clear();
            }

            if(pointSetFromRangeSensor){
                pointSetFromRangeSensor->getOrCreateVertices()->clear();
                pointSetFromRangeSensor->getOrCreateColors()->clear();
            }
        }
Esempio n. 16
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;
}
Esempio n. 17
0
bool GoEyeUtil::IsNakadeShape(const SgPointSet& area)
{
    switch (area.Size())
    {
        case 1:
        case 2:
        case 3: return true;
        case 4: return IsBulkyFour(area) || IsTShape(area);
        case 5: return IsBulkyFive(area) || IsCross(area);
        case 6: return IsRabbitySix(area);
        default: // too big
            return false;
    }
}
Esempio n. 18
0
bool GoEyeUtil::IsLocalSplitPt(SgPoint p, const SgPointSet& set)
{
    int nuNb = 0;
    for (SgNb4Iterator it(p); it; ++it)
    {
        if (set.Contains(*it))
        {
            ++nuNb;
            if (nuNb >= 2)
                break;
        }
    }
    if (nuNb >= 2)
    {
        if (set[p - SG_NS])
        {
            if (set[p - SG_WE] && TestDiagonal(set, p, -SG_NS, -SG_WE))
                return true;
            if (set[p + SG_NS] && TestOpposite(set, p, SG_NS, SG_WE))
                return true;
            if (set[p + SG_WE] && TestDiagonal(set, p, -SG_NS, +SG_WE))
                return true;
        }
        if (set[p + SG_NS])
        {
            if (set[p - SG_WE] && TestDiagonal(set, p, +SG_NS, -SG_WE))
                return true;
            if (set[p + SG_WE] && TestDiagonal(set, p, +SG_NS, +SG_WE))
                return true;
        }
        if (set[p - SG_WE] && set[p + SG_WE]
            && TestOpposite(set, p, SG_WE, SG_NS))
            return true;
    }
    return false; // no local split found.
}
Esempio n. 19
0
// 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;
}
Esempio n. 20
0
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;
}
Esempio n. 21
0
void SgNode::SetListProp(SgPropID id, const SgPointSet& value)
{
    SgVector<SgPoint> valueList;
    value.ToVector(&valueList);
    SetListProp(id, valueList);
}
Esempio n. 22
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;
    }
}