00001 //---------------------------------------------------------------------------- 00002 /** @file GoRegionBoard.h 00003 A GoRegionBoard provides the connected components of a GoBoard. 00004 */ 00005 //---------------------------------------------------------------------------- 00006 00007 #ifndef GO_REGIONBOARD_H 00008 #define GO_REGIONBOARD_H 00009 00010 #include "GoBoard.h" 00011 #include "GoRegion.h" 00012 00013 class GoBlock; 00014 class GoChain; 00015 00016 //---------------------------------------------------------------------------- 00017 00018 /** GoRegionBoard provides GoRegion, GoBlock and optionally GoChain. 00019 To keep it updated during search, call OnExecutedMove 00020 (or OnExecutedUncodedMove) and OnUndoneMove when Executing/Undoing a move. 00021 00022 A GoRegionBoard depends on a GoBoard (supplied at construction) 00023 for keeping the low-level board state, Go rules etc. 00024 00025 There is a certain amount of duplication between the private blocks of a 00026 GoBoard and the GoBlock's in a GoRegionBoard. 00027 00028 GoChain's are not updated automatically for performance reasons 00029 - call GenChains() to update them. 00030 */ 00031 class GoRegionBoard 00032 { 00033 public: 00034 00035 /** Constructor */ 00036 explicit GoRegionBoard(const GoBoard& board); 00037 00038 /** release memory. Calls Clear() */ 00039 virtual ~GoRegionBoard(); 00040 00041 /** delete all blocks and regions, set board size */ 00042 void Clear(); 00043 00044 /** For debugging */ 00045 void CheckConsistency() const; 00046 00047 /** Have blocks and regions been computed for current board position? */ 00048 bool UpToDate() const 00049 { 00050 return ! m_invalid 00051 && m_boardSize == m_board.Size() 00052 && m_code == Board().GetHashCode(); 00053 } 00054 00055 bool ComputedHealthy() const 00056 { 00057 return m_computedHealthy; 00058 } 00059 00060 /** Have chains been computed for current board position? */ 00061 bool ChainsUpToDate() const 00062 { 00063 return UpToDate() && m_chainsCode == Board().GetHashCode(); 00064 } 00065 00066 /** MUST call before playing move on GoBoard */ 00067 void ExecuteMovePrologue(); 00068 00069 /** Called after a move or added stone has been successfully executed. 00070 The board is guaranteed to be in a legal state. 00071 */ 00072 void OnExecutedMove(GoPlayerMove playerMove); 00073 00074 /** Similar to OnExecutedMove, but move is not coded into one int. */ 00075 void OnExecutedUncodedMove(int move, SgBlackWhite moveColor); 00076 00077 /** Called after a move has been undone. 00078 The board is guaranteed to be in a legal state. 00079 */ 00080 void OnUndoneMove(); 00081 00082 /** All GoBlock's of given color */ 00083 SgVectorOf<GoBlock>& AllBlocks(SgBlackWhite color) 00084 { 00085 return m_allBlocks[color]; 00086 } 00087 00088 /** All GoBlock's of given color */ 00089 const SgVectorOf<GoBlock>& AllBlocks(SgBlackWhite color) const 00090 { 00091 return m_allBlocks[color]; 00092 } 00093 00094 /** All GoChain's of given color */ 00095 SgVectorOf<GoChain>& AllChains(SgBlackWhite color) 00096 { 00097 return m_allChains[color]; 00098 } 00099 00100 /** All GoChain's of given color */ 00101 const SgVectorOf<GoChain>& AllChains(SgBlackWhite color) const 00102 { 00103 return m_allChains[color]; 00104 } 00105 00106 /** All GoRegion's of given color */ 00107 SgVectorOf<GoRegion>& AllRegions(SgBlackWhite color) 00108 { 00109 return m_allRegions[color]; 00110 } 00111 00112 /** All GoRegion's of given color */ 00113 const SgVectorOf<GoRegion>& AllRegions(SgBlackWhite color) const 00114 { 00115 return m_allRegions[color]; 00116 } 00117 00118 /** See GoBoard::All */ 00119 const SgPointSet& All(SgBlackWhite color) const 00120 { 00121 return Board().All(color); 00122 } 00123 00124 /** See GoBoard::AllEmpty */ 00125 const SgPointSet& AllEmpty() const {return Board().AllEmpty();} 00126 00127 /** See GoBoard::AllPoints */ 00128 const SgPointSet& AllPoints() const {return Board().AllPoints();} 00129 00130 /** See GoBoard::IsColor */ 00131 bool IsColor(SgPoint p, int c) const {return Board().IsColor(p, c);} 00132 00133 /** write information on all GoBlock's */ 00134 void WriteBlocks(std::ostream& stream) const; 00135 00136 /** write information on all GoRegion's */ 00137 void WriteRegions(std::ostream& stream) const; 00138 00139 /** generate all blocks and regions */ 00140 void GenBlocksRegions(); 00141 00142 /** Compute all GoChain's 00143 @todo currently this only creates 1 chain for each block. 00144 The merging is only done in GoSafetySolver::GenBlocksRegions() 00145 and must be moved here. 00146 */ 00147 void GenChains(); 00148 00149 /** Clear all flags etc. to recompute regions and blocks */ 00150 void ReInitializeBlocksRegions(); 00151 00152 /** mark all regions that the given attribute has been computed */ 00153 void SetComputedFlagForAll(GoRegionFlag flag); 00154 00155 const GoBoard& Board() const 00156 { 00157 return m_board; 00158 } 00159 00160 /** Searches the list of all blocks for the block. 00161 Boundary must belong to a single block. 00162 */ 00163 GoBlock* GetBlock(const SgPointSet& boundary, 00164 SgBlackWhite color) const; 00165 00166 /** For incremental update, region where stone was just played */ 00167 GoRegion* PreviousRegionAt(SgPoint p, SgBlackWhite color) const 00168 { 00169 SG_ASSERT(Board().Occupied(p)); 00170 SG_ASSERT(m_region[color][p] != 0); 00171 return m_region[color][p]; 00172 } 00173 00174 /** Region of color at point p */ 00175 GoRegion* RegionAt(SgPoint p, SgBlackWhite color) const 00176 { 00177 SG_ASSERT(UpToDate()); 00178 SG_ASSERT(! Board().IsColor(p, color)); 00179 SG_ASSERT(m_region[color][p] != 0); 00180 return m_region[color][p]; 00181 } 00182 00183 /** Region of color in area */ 00184 void RegionsAt(const SgPointSet& area, SgBlackWhite color, 00185 SgVectorOf<GoRegion>* regions) const; 00186 00187 /** Region of color adjacent to points */ 00188 void AdjacentRegions(const SgVector<SgPoint>& points, SgBlackWhite color, 00189 SgVectorOf<GoRegion>* regions) const; 00190 00191 /** Return GoBlock's just captured on last move, before update. 00192 For incremental update. 00193 Can be called for any empty point. 00194 returns 0 if no previous block there. 00195 */ 00196 void PreviousBlocksAt(const SgVector<SgPoint>& area, SgBlackWhite color, 00197 SgVectorOf<GoBlock>* captures) const; 00198 00199 /** GoBlock at point p*/ 00200 GoBlock* BlockAt(SgPoint p) const 00201 { 00202 SG_ASSERT(m_block[p] != 0); 00203 return m_block[p]; 00204 } 00205 00206 /** GoChain at point p*/ 00207 GoChain* ChainAt(SgPoint p) const; 00208 00209 /** Is block at point p marked as safe?*/ 00210 bool IsSafeBlock(SgPoint p) const; 00211 00212 /** Set safe flag for block at p*/ 00213 void SetToSafe(SgPoint p) const; 00214 00215 /** Set safe flags for all blocks in safe*/ 00216 void SetSafeFlags(const SgBWSet& safe); 00217 00218 /** Set m_computedHealthy flag to true */ 00219 void SetComputedHealthy(); 00220 00221 /** class initialization */ 00222 static bool Init(); 00223 00224 /** class finalization */ 00225 static void Fini(); 00226 00227 private: 00228 00229 // Compute from scratch helpers 00230 /** Generate blocks */ 00231 void GenBlocks(); 00232 00233 /** Set the m_has1Eye flag for all blocks with 1 eye */ 00234 void FindBlocksWithEye(); 00235 00236 // Execute move helpers 00237 /** Generate the block with given anchor */ 00238 GoBlock* GenBlock(SgPoint anchor, SgBlackWhite color); 00239 00240 /** Generate a region of color in area */ 00241 GoRegion* GenRegion(const SgPointSet& area, SgBlackWhite color); 00242 00243 /** incremental update of block after move */ 00244 void UpdateBlock(int move, SgBlackWhite moveColor); 00245 00246 /** Sets m_region elements to point to r */ 00247 void SetRegionArrays(GoRegion* r); 00248 00249 /** add block to GoRegionBoard */ 00250 void AddBlock(GoBlock* b, bool isExecute = true); 00251 00252 /** remove block from GoRegionBoard */ 00253 void RemoveBlock(GoBlock* b, bool isExecute, bool removeFromRegions); 00254 00255 /** add region to GoRegionBoard */ 00256 void AddRegion(GoRegion* r, bool isExecute = true); 00257 00258 /** remove region from GoRegionBoard */ 00259 void RemoveRegion(GoRegion* r, bool isExecute = true); 00260 00261 /** For all captured stones: merge its adjacent previous regions into one. 00262 then for all captured stones: add their area to its single adjacent 00263 region. 00264 */ 00265 void MergeAdjacentAndAddBlock(SgPoint move, SgBlackWhite capturedColor); 00266 00267 /** Merge all regions and the captured area into new large region */ 00268 GoRegion* MergeAll(const SgVectorOf<GoRegion>& regions, 00269 const SgPointSet& captured, SgBlackWhite color); 00270 00271 // Undo move helpers 00272 /** stores incremental state changes for execute/undo moves */ 00273 SgIncrementalStack m_stack; 00274 00275 /** push on m_stack */ 00276 void PushRegion(int type, GoRegion* r); 00277 00278 /** push on m_stack */ 00279 void PushStone(GoRegion* r, SgPoint move); 00280 00281 /** push on m_stack */ 00282 void PushBlock(int type, GoBlock* b); 00283 00284 /** add stome to b and push information on m_stack */ 00285 void AppendStone(GoBlock* b, SgPoint move); 00286 00287 // data members 00288 00289 const GoBoard& m_board; 00290 00291 /** pointer to region, defined only at anchor of region */ 00292 SgBWArray<SgPointArray<GoRegion*> > m_region; 00293 00294 /** pointer from stone to block, 0 if empty point */ 00295 SgPointArray<GoBlock*> m_block; 00296 00297 /** All blocks on board */ 00298 SgBWArray<SgVectorOf<GoBlock> > m_allBlocks; 00299 00300 /** All chains on board */ 00301 SgBWArray<SgVectorOf<GoChain> > m_allChains; 00302 00303 /** All regions on board */ 00304 SgBWArray<SgVectorOf<GoRegion> > m_allRegions; 00305 00306 /** Code for last time block and region information was computed */ 00307 SgHashCode m_code; 00308 00309 /** Code for last time chain information was computed */ 00310 SgHashCode m_chainsCode; 00311 00312 /** does block and region data match current board? */ 00313 bool m_invalid; 00314 00315 /** has healthy count been computed for all blocks? 00316 @todo in fully incremental mode, this should be determined locally 00317 for each block, not globally. 00318 */ 00319 bool m_computedHealthy; 00320 00321 /** Boardsize is needed to avoid problems with resizing an empty board */ 00322 int m_boardSize; 00323 00324 /** debugging bookkeeping. @todo do it in debug only */ 00325 static int s_alloc, s_free; 00326 00327 }; 00328 00329 //---------------------------------------------------------------------------- 00330 00331 #endif // GO_REGIONBOARD_H