Index   Main   Namespaces   Classes   Hierarchy   Annotated   Files   Compound   Global   Pages  

GoRegion.h

Go to the documentation of this file.
00001 //----------------------------------------------------------------------------
00002 /** @file GoRegion.h
00003     A GoRegion contained in a @see GoRegionBoard.
00004 
00005     A GoRegion is a maximal connected set of points surrounded by stones 
00006     of the same color.
00007 
00008     Regions compute properties such as 1-vitality,
00009     2-vitality [Mueller 95, p. 62-63],[Mueller 97b].
00010     They are used for static and search-based safety solvers.
00011     They are also used for better move generation, e.g. in semeai.
00012 */
00013 //----------------------------------------------------------------------------
00014 
00015 #ifndef GO_REGION_H
00016 #define GO_REGION_H
00017 
00018 #include <bitset>
00019 #include <iosfwd>
00020 #include "GoBoard.h"
00021 #include "GoBoardUtil.h"
00022 #include "GoEyeCount.h"
00023 #include "SgVector.h"
00024 #include "SgIncrementalStack.h"
00025 #include "SgMiaiStrategy.h"
00026 #include "SgPointArray.h"
00027 
00028 class GoBlock;
00029 class GoChain;
00030 class GoRegionBoard;
00031 
00032 //----------------------------------------------------------------------------
00033 
00034 /** Information computed about a GoRegion.
00035     @todo Does not follow naming convention for constants in global
00036     namespace; rename to all-uppercase and use prefix GO_
00037 */
00038 enum GoRegionFlag
00039 {
00040     GO_REGION_SMALL,
00041     GO_REGION_CORRIDOR,
00042     GO_REGION_STATIC_1VC,
00043     GO_REGION_1VC,
00044     GO_REGION_STATIC_2V,
00045     GO_REGION_2V,
00046     GO_REGION_SINGLE_BLOCK_BOUNDARY,
00047     GO_REGION_OPP_CAN_LIVE_INSIDE,
00048     GO_REGION_AT_LEAST_SEKI,
00049     GO_REGION_SAFE,
00050     GO_REGION_PROTECTED_CUTS,
00051     GO_REGION_STATIC_1VITAL,
00052     GO_REGION_1VITAL,
00053     GO_REGION_USED_FOR_MERGE,
00054     GO_REGION_VALID,
00055     GO_REGION_COMPUTED_BLOCKS,
00056     GO_REGION_COMPUTED_CHAINS,
00057     GO_REGION_COMPUTED_NAKADE,
00058     _GO_REGION_FLAG_COUNT
00059 };
00060 
00061 /** Set of GoRegionFlag */
00062 typedef std::bitset<_GO_REGION_FLAG_COUNT> GoRegionFlags;
00063 
00064 //----------------------------------------------------------------------------
00065 
00066 /** GoRegion represents a region surrounded by blocks of one color.
00067 
00068     Each empty point, and each point occupied by white,
00069     is contained in exactly one black region.
00070     Similarly each empty point, and each point occupied by black,
00071     is contained in exactly one white region.
00072 
00073     A region keeps data such as its color, the blocks and chains of its color,
00074     the eye status, and a strategy to follow to keep the region safe.
00075 
00076     Regions can provide liberties for its boundary blocks.
00077     They can be "1-vital" or "2-vital". This is used by safety solvers.
00078     For details see [Mueller 1997]:
00079     Playing it safe: Recognizing secure territories in computer Go by using
00080     static rules and search. In H. Matsubara, editor, Game Programming
00081     Workshop in Japan '97, pages 80-86, Computer Shogi Association, Tokyo, 
00082     Japan, 1997.
00083 
00084     @todo Avoid cyclic dependency with GoBlock
00085 */
00086 class GoRegion
00087 {
00088 public:
00089     /** Construct region on points in color */
00090     GoRegion(const GoBoard& board, const SgPointSet& points,
00091              SgBlackWhite color);
00092 
00093     /** Destructor */
00094     ~GoRegion()
00095     {
00096 #ifndef NDEBUG
00097         ++s_free;
00098 #endif
00099     }
00100 
00101     /** Clear all flags etc. to recompute region */
00102     void ReInitialize();
00103 
00104     /** For debugging */
00105     void CheckConsistency() const;
00106 
00107     // Accessors
00108     /** The points of the region */
00109     const SgPointSet& Points() const
00110     {
00111         return m_points;
00112     }
00113 
00114     /** The dependency set, outside neighbors of m_points */
00115     SgPointSet Dep() const
00116     {
00117         return m_points.Border(m_bd.Size());
00118     }
00119 
00120     /** liberties not adjacent to boundary stones */
00121     SgPointSet AllInsideLibs() const;
00122 
00123     /** Chains of region */
00124     const SgVectorOf<GoChain>& Chains() const
00125     {
00126         return m_chains;
00127     }
00128 
00129     /** Blocks of region */
00130     const SgVectorOf<GoBlock>& Blocks() const
00131     {
00132         return m_blocks;
00133     }
00134 
00135     /** Blocks of region.
00136         Non const version used by GoRegionBoard.
00137     */
00138     SgVectorOf<GoBlock>& BlocksNonConst()
00139     {
00140         return m_blocks;
00141     }
00142 
00143     /** Interior blocks of region: all liberties are in m_points */
00144     SgVectorOf<GoBlock> InteriorBlocks() const;
00145 
00146     /** Is block an interior block of this region? */
00147     bool IsInteriorBlock(const GoBlock* block) const;
00148 
00149     /** Is block a boundary block of this region? */
00150     bool IsBoundaryBlock(const GoBlock* block) const
00151     {
00152         return ! IsInteriorBlock(block);
00153     }
00154 
00155     /** all points of region's blocks - even those not contained in Dep() */
00156     SgPointSet BlocksPoints() const;
00157 
00158     /** area of points plus interior blocks */
00159     SgPointSet PointsPlusInteriorBlocks() const;
00160 
00161     /** color of region */
00162     SgBlackWhite Color() const
00163     {
00164         return m_color;
00165     }
00166 
00167     /** minimum number of eyes in region */
00168     int MinEyes() const {return m_eyes.MinEyes();}
00169 
00170     /** maximum number of eyes in region */
00171     int MaxEyes() const {return m_eyes.MaxEyes();}
00172 
00173     /** minimum number of potential eyes in region */
00174     int MinPotEyes() const {return m_eyes.MinPotEyes();}
00175 
00176     /** maximum number of potential eyes in region */
00177     int MaxPotEyes() const {return m_eyes.MaxPotEyes();}
00178 
00179     /** Write all information */
00180     void Write(std::ostream& out) const;
00181 
00182     /** Write short identifier */
00183     void WriteID(std::ostream& out) const;
00184 
00185     // Flags
00186     /** get value of precomputed flag */
00187     bool GetFlag(GoRegionFlag flag) const;
00188 
00189     /** compute, then get value of precomputed flag */
00190     bool ComputeAndGetFlag(GoRegionFlag flag);
00191 
00192     /** test if flag has been computed */
00193     bool ComputedFlag(GoRegionFlag flag) const;
00194 
00195     /** compute the flag, set it to true or false */
00196     void ComputeFlag(GoRegionFlag flag);
00197 
00198     /** Only blocks are incrementally updated, others must be reset after
00199         move
00200     */
00201     void ResetNonBlockFlags()
00202     {   m_computedFlags.reset(); // clear all other flags.
00203         m_computedFlags.set(GO_REGION_COMPUTED_BLOCKS);
00204         m_eyes.Clear();
00205         Invalidate();
00206     }
00207 
00208     /** is region data valid? */
00209     bool IsValid() const {return m_flags.test(GO_REGION_VALID);}
00210 
00211     /** reset valid flag, region data not current anymore */
00212     void Invalidate() {m_flags.reset(GO_REGION_VALID);}
00213 
00214     /** Computes GO_REGION_SMALL, GO_REGION_CORRIDOR, 
00215         GO_REGION_SINGLE_BLOCK_BOUNDARY, 
00216         GO_REGION_STATIC_1VC, GO_REGION_STATIC_2V
00217     */
00218     void ComputeBasicFlags();
00219 
00220     /** compute flag */
00221     void DoComputeFlag(GoRegionFlag flag);
00222 
00223     /** mark that flag is computed now */
00224     void SetComputedFlag(GoRegionFlag flag) {m_computedFlags.set(flag);}
00225 
00226     /** set flag to value */
00227     void SetFlag(GoRegionFlag flag, bool value)
00228     {   m_computedFlags.set(flag);
00229         m_flags.set(flag, value);
00230     }
00231 
00232     /** store search depth used in ExVital1Task for 1vc search */
00233     void Set1VCDepth(int depth) {m_1vcDepth = depth;}
00234 
00235     // Queries
00236     /** does region have two free (unused) liberties to connect chains? */
00237     bool Has2ConnForChains(const GoChain* c1, const GoChain* c2) const;
00238 
00239     /** call Has2ConnForBlocks for region with exactly two chains*/
00240     bool Has2Conn() const;
00241 
00242     /** is this healthy for a block in list? */
00243     bool HealthyForSomeBlock(const SgVectorOf<GoBlock>& blocks) const;
00244 
00245     /** Is region completely surrounded by blocks? */
00246     bool IsSurrounded(const SgVectorOf<GoBlock>& blocks) const;
00247 
00248     /** did ExVital1Task have at least this search depth? */
00249     bool ComputedVitalForDepth(int depth) const;
00250 
00251     /** is any adjacent block safe? */
00252     bool SomeBlockIsSafe() const;
00253 
00254     /** are all adjacent block safe? */
00255     bool AllBlockIsSafe() const;
00256 
00257     /** Is block of anchor adjacent to region? */
00258     bool AdjacentToBlock(SgPoint anchor) const;
00259 
00260     /** Is one of blocks given by anchors adjacent to region? */
00261     bool AdjacentToSomeBlock(const SgVector<SgPoint>& anchors) const;
00262 
00263     /** For flat region: cuts not occupied is enough to make region 1-vital */
00264     bool Safe2Cuts(const GoBoard& board) const;
00265 
00266     /** Test if all empty points are liberties of blocks
00267         @todo does not test only for boundary block libs, but all libs.
00268     */
00269     bool AllEmptyAreLibs() const;
00270 
00271     /** Test if points of region are 2-vital for color.
00272         Condition 1: all empty points are in liberties of some boundary block
00273         Condition 2: two intersection points (@see Has2IPs)
00274         refined version: points need not be liberty, if next to both IP.
00275         Example: bent-5 in the corner, as in Berlekamp/Wolfe C.11 top left
00276         corner
00277     */
00278     bool Has2SureLibs(SgMiaiStrategy* miaiStrategy) const;
00279 
00280     /** block liberties in this region */
00281     void InsideLibs(const GoBlock* b, SgVector<SgPoint>* libs) const;
00282 
00283     /** Is a liberty of b in region? */
00284     bool HasBlockLibs(const GoBlock* b) const;
00285 
00286     /** Can a block get n libs inside region? */
00287     bool HasLibsForBlock(const GoBlock* b, int n) const;
00288 
00289     /** Does each adjacent block have a liberty in region? */
00290     bool HasLibForAllBlocks() const;
00291 
00292     /** Does each block have n liberties in region? */
00293     bool HasLibsForAllBlocks(int n) const;
00294 
00295     /** Can we find two connection paths to each interior empty point? 
00296         This implements only the simple, non-recursive case.
00297         See Find2ConnForAllInterior() for a more general solution.
00298     */
00299     bool Find2ConnForAll() const;
00300 
00301     /** find 2-connection paths for all interior empty points, using recursive
00302         extension. Erik v.d.Werf's recursive extension to Find2ConnForAll.
00303     */
00304     bool Find2ConnForAllInterior(SgMiaiStrategy* miaiStrategy,
00305                                  SgVector<SgPoint>& usedLibs) const;
00306 
00307     /** An IP divides a region into two eyes AND connects all surrounding
00308         blocks, this one defines that ip has to be adjancent to all interior
00309         points.
00310     */
00311     bool Has2IPs(const SgVector<SgPoint>& interiorEmpty, SgMiaiPair* ips)
00312         const;
00313 
00314     /** whether there are 2 intersection points, doesn't have to be adjacent
00315         to all interior points.
00316     */
00317     bool Has2IntersectionPoints(const SgVector<SgPoint>& usedLibs) const;
00318 
00319     /** Get all intersections points inside region */
00320     void GetIPs(SgVector<SgPoint>* ips) const;
00321 
00322     /** Get all SgMiaiPairs that can divide the region. A dividing 
00323         SgMiaiPair has two adjacent points that are libs from the 
00324         same boundary block, and they are split points for region.
00325         This is a loose condition for SgMiaiPairs. 
00326     */
00327     void GetDivideMiaiPairs(SgVector<SgMiaiPair>& pairs) const;
00328 
00329     /** Compute joint liberties of all m_blocks. Since we need at least 2
00330         joint libs, we stop computing if we find that this is impossible.
00331     */
00332     void JointLibs(SgVector<SgPoint>* libs) const;
00333 
00334     /** See ExEye::IsCorridor() */
00335     bool IsCorridor() const;
00336 
00337     /** update region if affected: old was merged into newChain */
00338     bool ReplaceChain(const GoChain* old, const GoChain* newChain); 
00339 
00340     /** chains are mergable if two connections are found */
00341     bool Find2Mergable(GoChain** c1, GoChain** c2) const;
00342 
00343     /** Find two so far unused liberties for connecting c1 and c2 
00344         @todo In future, must respect all other chain conditions 
00345               active in this region.
00346     */
00347     void Find2FreeLibs(const GoChain* c1, const GoChain* c2, 
00348                         SgPoint* lib1, SgPoint* lib2) const;
00349 
00350     /** Get blocks of color in area */
00351     void FindBlocks(const GoRegionBoard& ra);
00352 
00353     /** Set blocks for this region from pre-found blocks list */
00354     void SetBlocks(const SgVectorOf<GoBlock>& blocks);
00355 
00356     /** Get chain of color in area.
00357             @todo There must be faster ways to do this.
00358     */
00359     void FindChains(const GoRegionBoard& ra);
00360 
00361     /** Set safe flag for region */
00362     void SetToSafe() {SetFlag(GO_REGION_SAFE, true);}
00363 
00364     // Execute move helpers
00365     /** For incremental update - block no longer adjacent */
00366     void RemoveBlock(const GoBlock* b);
00367 
00368     /** Stone was played: remove from m_points */
00369     void OnAddStone(SgPoint p);
00370 
00371     /** Stone removed: add to m_points */
00372     void OnRemoveStone(SgPoint p);
00373 
00374     /** class finalization */
00375     static void Fini();
00376 
00377 private:
00378 
00379     /** The board */
00380     const GoBoard& m_bd;
00381 
00382     /** Flags describing attributes of region */
00383     GoRegionFlags m_flags;
00384 
00385     /** Which flags have been computed? */
00386     GoRegionFlags m_computedFlags;
00387 
00388     /** Points of region */
00389     SgPointSet m_points;
00390 
00391     /** Color of region = color of surrounding stones */
00392     SgBlackWhite m_color;
00393 
00394     /** Blocks of m_color adjacent to region. Some may be on inside */
00395     SgVectorOf<GoBlock> m_blocks;
00396 
00397     /** Chains of region */
00398     SgVectorOf<GoChain> m_chains;  
00399 
00400     /** Number of eyes in region */
00401     GoEyeCount m_eyes;
00402 
00403     /** Point to change eye status. Can be SG_NULLPOINT */
00404     SgPoint m_vitalPoint;
00405 
00406     /** search depth used in ExVital1Task for 1vc search */
00407     int m_1vcDepth;
00408 
00409     /** Miai strategy to keep region safe. */
00410     SgMiaiStrategy m_miaiStrategy;
00411 
00412     /** A simple test if all cuts between blocks are protected. 
00413         Works only for corridors (@see IsCorridor):
00414         If corridor, then opp. can get at most 2 libs (Opp2L).
00415         If Opp2L && cut point empty then opp cut move is self atari,
00416         therefore cut is protected (and remains protected if opponent
00417         is captured and plays inside again)
00418     */
00419     bool ProtectedCuts(const GoBoard& board) const;
00420 
00421     /** Static test if region is 1-vital.
00422         @todo explain the algorithm.
00423     */
00424     bool ComputeIs1Vital() const;
00425 
00426     /** Static test if region is 1-vital and all blocks are connected. */
00427     bool StaticIs1VitalAndConnected() const;
00428 
00429     /** Compute eye status for some standard small regions */
00430     void ComputeNakade();
00431 
00432     /** Compute eye space for region having only 1 block */
00433     void ComputeSingleBlockEyeSpace();
00434 
00435     /** Compute eye space for region having more than 1 block */
00436     void ComputeMultipleBlockEyeSpace();
00437 
00438     /** Compute eye space for region */
00439     void ComputeEyeSpace();
00440 
00441     /** compute at most maxNu empty points in the interior
00442         @todo does not test only for boundary block libs, but all libs.
00443     */
00444     void InteriorEmpty(SgVector<SgPoint>* interiorEmpty, int maxNu) const;
00445 
00446 #ifndef NDEBUG
00447     /** debugging bookkeeping. */
00448     static int s_alloc, s_free;
00449 #endif
00450 };
00451 
00452 std::ostream& operator<<(std::ostream& stream, const GoRegion& r);
00453 
00454 //----------------------------------------------------------------------------
00455 
00456 #endif // GO_REGION_H
00457 


17 Jun 2010 Doxygen 1.4.7