Index   Main   Namespaces   Classes   Hierarchy   Annotated   Files   Compound   Global   Pages  

GoEyeUtil.h

Go to the documentation of this file.
00001 //----------------------------------------------------------------------------
00002 /** @file GoEyeUtil.h
00003     GoBoard eye-related utility classes. */
00004 //----------------------------------------------------------------------------
00005 
00006 #ifndef GO_EYEUTIL_H
00007 #define GO_EYEUTIL_H
00008 
00009 #include "GoBoard.h"
00010 #include "GoBoardUtil.h"
00011 #include "SgPoint.h"
00012 
00013 //----------------------------------------------------------------------------
00014 
00015 namespace GoEyeUtil
00016 {
00017     /** size of largest standard nakade shape */
00018     const int NAKADE_LIMIT = 6;
00019 
00020     /** Code for how many points of each degree there are.
00021         The degree measures how many of the (up to 4) neighbors
00022         are also in the set of points.
00023 
00024         code =     1 * # degree 0
00025              +    10 * # degree 1
00026              +   100 * # degree 2
00027              +  1000 * # degree 3
00028              + 10000 * # degree 4
00029 
00030         This is a different format, but has the same information
00031         as the Cazenave/Vila "neighbour classification".
00032         E.g. their code 112224 means 2x degree 1, 3x degree 2, 1x degree 4,
00033         so the DegreeCode is 10320.
00034 
00035         The DegreeCode is not strong enough for graph isomorphism testing -
00036         there are nonisomorphic graphs with the same code -
00037         but it is good for distinguishing small graphs.
00038 
00039         For example, it can not distinguish between a "straight" and a "bent"
00040         line of three. */
00041     int DegreeCode(const SgPointSet& points);
00042 
00043     /** Like DegreeCode, but also count diagonal neighbors */
00044     long DegreeCode8(const SgPointSet& points);
00045 
00046     /** Return an empty neighbor of p. Precondition: one must exist. */
00047     template<class BOARD>
00048     SgPoint EmptyNeighbor(const BOARD& bd, SgPoint p);
00049 
00050     /** Check if area is one of the classical nakade shapes:
00051         *,**,***, **, ***, **, ***,  * ,  *  .
00052                    *   *   **  **   ***  ***
00053                                      *   ** */
00054     bool IsNakadeShape(const SgPointSet& area);
00055                        
00056     /** Check if point is a single point eye with one or two adjacent blocks.
00057         This is a fast eye detection routine, which can be used instead of
00058         Benson's static life detection, when end-of-game detection is a
00059         performance bottle-neck (e.g. for machine-learning or monte-carlo).
00060         It detects single-point eyes surrounded by a single block or by two
00061         blocks that share another single point eye.
00062         Larger eyes can be reduced to simple eyes (assuming chinese rules,
00063         so that playing on does not change the score).
00064         @todo Add example to documentation where this method fails */
00065     bool IsSimpleEye(const GoBoard& bd, SgPoint p, SgBlackWhite c);
00066 
00067     /**  */
00068     bool IsSinglePointEye(const GoBoard& bd, SgPoint p, SgBlackWhite c);
00069 
00070     /** Return true if a point can become an eye by adding one more
00071     defender's move */
00072     bool IsPossibleEye(const GoBoard& board, SgBlackWhite color, SgPoint p);
00073 
00074     /** Given opponent's safe stones, can p ever become an eye?
00075         Checks direct and diagonal neighbors. */
00076     bool CanBecomeSinglePointEye(const GoBoard& board, SgPoint p,
00077                              const SgPointSet& oppSafe);
00078 
00079     /** does playing at p create one of the standard nakade shapes? */
00080     template<class BOARD>
00081     bool MakesNakadeShape(const BOARD& bd, SgPoint p,
00082                                  SgBlackWhite toPlay);
00083 
00084     /** Return true if a point can become an eye by adding number of
00085         defender's move. */
00086     bool NumberOfMoveToEye(const GoBoard& bd, SgBlackWhite c, SgPoint p,
00087                            int& number);
00088 
00089     /** As IsSinglePointEye, but allows diagonal points to be eyes.
00090         Slightly slower, but identifies more single point eyes.
00091         E.g:
00092         @verbatim
00093         # X X X . .
00094         # O O X X X
00095         # O . O O X
00096         # . O . O X
00097         ###########
00098         @endverbatim */
00099     bool IsSinglePointEye2(const GoBoard& bd, SgPoint p, SgBlackWhite c);
00100 
00101     /** As IsSinglePointEye2, but specifying points assumed to be eyes. */
00102     bool IsSinglePointEye2(const GoBoard& bd, SgPoint p,
00103                            SgBlackWhite c, SgVector<SgPoint>& eyes);
00104 
00105     /** p is in a 2 point eye surrounded by a single chain */
00106     template<class BOARD>
00107     bool IsTwoPointEye(const BOARD& bd, SgPoint p,
00108                        SgBlackWhite c);
00109 
00110     /** As NumberOfMoveToEye2, but includes existing diagonal eyes,
00111         and allows opponent stones to be captured. */
00112     bool NumberOfMoveToEye2(const GoBoard& bd, SgBlackWhite c,
00113                             SgPoint p, int& nummoves);
00114 
00115     /** Count number of single point eyes for block p */
00116     int CountSinglePointEyes2(const GoBoard& bd, SgPoint p);
00117 
00118     /** Does block at p have two or more single point eyes? */
00119     bool SinglePointSafe2(const GoBoard& bd, SgPoint p);
00120 
00121     /** Does removing p split s into two or more parts? */
00122     bool IsSplitPt(SgPoint p, const SgPointSet& s);
00123 
00124     /** Does p locally,within a 3x3 region, split its neighbors in s?
00125         Even if the reply is 'yes', s might still be connected outside
00126         the region. */
00127     bool IsLocalSplitPt(SgPoint p, const SgPointSet& set);
00128 
00129     /** Area is tree shape if it does not contain a 2x2 square. */
00130     bool IsTreeShape(const SgPointSet& area);
00131 
00132     /** Vital point in small shape - usually has most liberties
00133         See implementation for details. */
00134     bool IsVitalPt(const SgPointSet& points, SgPoint p, SgBlackWhite opp,
00135                const GoBoard& bd);
00136 
00137     /** Analyze small region locally for number of eyes.
00138         color: the player surrounding the area.
00139         isNakade: only one eye
00140         makeNakade: attacker can reduce to one eye, defender can live locally.
00141         makeFalse: attacker can make the area into a false eye.
00142         maybeSeki, sureSeki: can there be, or is there, a seki between
00143             boundary stones and interior opponent stones?
00144         @todo: seki support is primitive only.
00145         vital is set iff makeNakade or makeFalse */
00146     void TestNakade(const SgPointSet& points, const GoBoard& bd,
00147                     SgBlackWhite color, bool isFullyEnclosed, bool& isNakade,
00148                     bool& makeNakade, bool& makeFalse, bool& maybeSeki,
00149                     bool& sureSeki, SgPoint* vital);
00150 
00151     bool CheckInterior(const GoBoard& bd, const SgPointSet& area,
00152                        SgBlackWhite opp, bool checkBlocks);
00153 }
00154 
00155 namespace {
00156 inline bool AreSameBlocks(const SgPoint anchors1[], const SgPoint anchors2[])
00157 {
00158     int i = 0;
00159     for (; anchors1[i] != SG_ENDPOINT; ++i)
00160     {
00161         if (! GoBoardUtil::ContainsAnchor(anchors2, anchors1[i]))
00162             return false;
00163     }
00164     return (anchors2[i] == SG_ENDPOINT);
00165 }
00166 }
00167 
00168 template<class BOARD>
00169 SgPoint GoEyeUtil::EmptyNeighbor(const BOARD& bd, SgPoint p)
00170 {
00171     if (bd.IsEmpty(p + SG_NS))
00172         return p + SG_NS;
00173     if (bd.IsEmpty(p - SG_NS))
00174         return p - SG_NS;
00175     if (bd.IsEmpty(p + SG_WE))
00176         return p + SG_WE;
00177     if (bd.IsEmpty(p - SG_WE))
00178         return p - SG_WE;
00179     SG_ASSERT(false);
00180     return SG_NULLPOINT;
00181 }
00182 
00183 inline bool GoEyeUtil::IsSimpleEye(const GoBoard& bd, SgPoint p,
00184                                    SgBlackWhite c)
00185 {
00186     // Function is inline despite its large size, because it returns quickly
00187     // on average, which makes the function call an overhead
00188 
00189     SgBlackWhite opp = SgOppBW(c);
00190     if (bd.HasEmptyNeighbors(p) || bd.HasNeighbors(p, opp))
00191         return false;
00192     SgArrayList<SgPoint,2> anchors;
00193     for (SgNb4Iterator it(p); it; ++it)
00194     {
00195         SgPoint nbPoint = *it;
00196         if (bd.IsBorder(nbPoint))
00197             continue;
00198         SG_ASSERT(bd.GetColor(nbPoint) == c);
00199         SgPoint nbAnchor = bd.Anchor(nbPoint);
00200         if (! anchors.Contains(nbAnchor))
00201         {
00202             if (anchors.Length() > 1)
00203                 return false;
00204             anchors.PushBack(nbAnchor);
00205         }
00206     }
00207     if (anchors.Length() == 1)
00208         return true;
00209     for (GoBoard::LibertyIterator it(bd, anchors[0]); it; ++it)
00210     {
00211         SgPoint lib = *it;
00212         if (lib == p)
00213             continue;
00214         bool isSecondSharedEye = true;
00215         SgArrayList<SgPoint,2> foundAnchors;
00216         for (SgNb4Iterator it2(lib); it2; ++it2)
00217         {
00218             SgPoint nbPoint = *it2;
00219             if (bd.IsBorder(nbPoint))
00220                 continue;
00221             if (bd.GetColor(nbPoint) != c)
00222             {
00223                 isSecondSharedEye = false;
00224                 break;
00225             }
00226             SgPoint nbAnchor = bd.Anchor(nbPoint);
00227             if (! anchors.Contains(nbAnchor))
00228             {
00229                 isSecondSharedEye = false;
00230                 break;
00231             }
00232             if (! foundAnchors.Contains(nbAnchor))
00233                 foundAnchors.PushBack(nbAnchor);
00234         }
00235         if (isSecondSharedEye && foundAnchors.Length() == 2)
00236             return true;
00237     }
00238     return false;
00239 }
00240 
00241 template<class BOARD>
00242 bool GoEyeUtil::IsTwoPointEye(const BOARD& bd, SgPoint p, 
00243                    SgBlackWhite color)
00244 {
00245     const SgBlackWhite opp = SgOppBW(color);
00246     if (bd.NumEmptyNeighbors(p) == 1
00247         && bd.NumNeighbors(p, opp) == 0
00248         )
00249     {
00250         const SgPoint p2 = GoBoardUtil::FindNeighbor(bd, p, SG_EMPTY);
00251         if (  bd.NumEmptyNeighbors(p2) == 1
00252            && bd.NumNeighbors(p2, opp) == 0
00253            )
00254         {
00255             // check if p1, p2 are adjacent to the same blocks
00256             SgPoint nbanchorp[4 + 1];
00257             SgPoint nbanchorp2[4 + 1];
00258             bd.NeighborBlocks(p, color, nbanchorp);
00259             bd.NeighborBlocks(p2, color, nbanchorp2);
00260             SG_ASSERT(nbanchorp[0] != SG_ENDPOINT);
00261             SG_ASSERT(nbanchorp2[0] != SG_ENDPOINT);
00262             return AreSameBlocks(nbanchorp, nbanchorp2);
00263         }
00264     }
00265     return false;
00266 }
00267 
00268 template<class BOARD>
00269 bool GoEyeUtil::MakesNakadeShape(const BOARD& bd, SgPoint p,
00270                                  SgBlackWhite toPlay)
00271 {
00272     SgPointSet area;
00273     area.Include(p);
00274     int nu = 1;
00275     SgVector<SgPoint> toProcess;
00276     toProcess.PushBack(p);
00277     while (toProcess.NonEmpty())
00278     {
00279         SgPoint p = toProcess.Back();
00280         toProcess.PopBack();
00281         for (SgNb4Iterator it(p); it; ++it)
00282             if (bd.IsColor(*it, toPlay) && ! area.Contains(*it))
00283             {
00284                 area.Include(*it);
00285                 toProcess.PushBack(*it);
00286                 if (++nu > NAKADE_LIMIT)
00287                     return false;
00288             }
00289     }
00290     return IsNakadeShape(area);
00291 }
00292 
00293 //----------------------------------------------------------------------------
00294 
00295 #endif // GO_EYEUTIL_H
00296 


Sun Mar 13 2011 Doxygen 1.7.1