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