Example #1
0
vector<SgPoint> GoBook::LookupAllMoves(const GoBoard& bd) const
{
    vector<SgPoint> result;
    const GoBook::MapEntry* mapEntry = LookupEntry(bd);
    if (mapEntry == 0)
        return result;
    size_t id = mapEntry->m_id;
    SG_ASSERT(id < m_entries.size());
    const vector<SgPoint>& moves = m_entries[id].m_moves;
    const int rotation = mapEntry->m_rotation;
    const int size = mapEntry->m_size;
    for (vector<SgPoint>::const_iterator it = moves.begin();
         it != moves.end(); ++it)
    {
        SgPoint p = SgPointUtil::Rotate(rotation, *it, size);
        if (! bd.IsLegal(p))
        {
            // Should not happen with 64-bit hashes, but not impossible
            SgWarning() << "illegal book move (hash code collision?)\n";
            result.clear();
            break;
        }
        result.push_back(p);
    }
    return result;
}
Example #2
0
void GoBook::Add(const GoBoard& bd, SgPoint move)
{
    if (move != SG_PASS && bd.Occupied(move))
        throw SgException("point is not empty");
    if (! bd.IsLegal(move))
        throw SgException("move is not legal");
    const GoBook::MapEntry* mapEntry = LookupEntry(bd);
    if (mapEntry == 0)
    {
        vector<SgPoint> moves;
        moves.push_back(move);
        GoBoard tempBoard;
        InsertEntry(GetSequence(bd), moves, bd.Size(), tempBoard, 0);
    }
    else
    {
        size_t id = mapEntry->m_id;
        SG_ASSERT(id < m_entries.size());
        Entry& entry = m_entries[id];
        int invRotation = SgPointUtil::InvRotation(mapEntry->m_rotation);
        SgPoint rotMove = SgPointUtil::Rotate(invRotation, move, bd.Size());
        if (! Contains(entry.m_moves, rotMove))
            entry.m_moves.push_back(rotMove);
    }
}
Example #3
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;
}
Example #4
0
void GoBook::Entry::ApplyTo(GoBoard& bd) const
{
    if (bd.Size() != m_size)
        bd.Init(m_size);
    GoBoardUtil::UndoAll(bd);
    for (vector<SgPoint>::const_iterator it = m_sequence.begin();
         it != m_sequence.end(); ++it)
    {
        SG_ASSERT(bd.IsLegal(*it));
        bd.Play(*it);
    }
}
void GoUctFeatures::
FindMoveFeaturesUI(const GoBoard& bd,
                   GoUctPlayoutPolicy<GoBoard>& policy,
                   SgPoint move,
                   FeMoveFeatures& features)
{
    SG_ASSERT(move != SG_PASS);
    if (! bd.IsLegal(move))
        return;
    FeFullBoardFeatures f(bd);
    FindAllFeatures(bd, policy, f);
    features = f.Features()[move];
}
Example #6
0
/** Insert a new position entry and all its transformations
    @param sequence A move sequence that leads to the position
    @param moves The moves to play in this position
    @param size
    @param tempBoard A local temporary work board, reused for efficiency
    (does not have to be initialized)
    @param line Line number of entry from the file (0 if unknown or entry is
    not from a file) */
void GoBook::InsertEntry(const vector<SgPoint>& sequence,
                         const vector<SgPoint>& moves, int size,
                         GoBoard& tempBoard, int line)
{
    if (moves.size() == 0)
        ThrowError("Line contains no moves");
    if (tempBoard.Size() != size)
        tempBoard.Init(size);
    Entry entry;
    entry.m_size = size;
    entry.m_line = line;
    entry.m_sequence = sequence;
    entry.m_moves = moves;
    m_entries.push_back(entry);
    size_t id = m_entries.size() - 1;
    vector<Map::iterator> newEntries;
    for (int rot = 0; rot < 8; ++rot)
    {
        GoBoardUtil::UndoAll(tempBoard);
        for (vector<SgPoint>::const_iterator it = sequence.begin();
             it != sequence.end(); ++it)
        {
            SgPoint p = SgPointUtil::Rotate(rot, *it, size);
            if (! tempBoard.IsLegal(p))
                ThrowError("Illegal move in variation");
            tempBoard.Play(p);
        }
        // It is enough to check the moves for legality for one rotation
        if (rot == 0)
            for (vector<SgPoint>::const_iterator it = moves.begin();
                 it != moves.end(); ++it)
                if (! tempBoard.IsLegal(SgPointUtil::Rotate(rot, *it, size)))
                    ThrowError("Illegal move in move list");
        MapEntry mapEntry;
        mapEntry.m_size = size;
        mapEntry.m_id = id;
        mapEntry.m_rotation = rot;
        SgHashCode hashCode = tempBoard.GetHashCodeInclToPlay();
        pair<Map::iterator,Map::iterator> e = m_map.equal_range(hashCode);
        bool isInNewEntries = false;
        for (Map::iterator it = e.first; it != e.second; ++it)
            if (it->second.m_size == size)
            {
                if (! Contains(newEntries, it))
                {
                    ostringstream o;
                    o << "Entry duplicates line "
                      << m_entries[it->second.m_id].m_line;
                    ThrowError(o.str());
                }
                isInNewEntries = true;
                break;
            }
        if (! isInNewEntries)
        {
            Map::iterator newIt =
                m_map.insert(Map::value_type(hashCode, mapEntry));
            newEntries.push_back(newIt);
        }
    }
}
Example #7
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;
    }
}