00001 //---------------------------------------------------------------------------- 00002 /** @file SgPointSet.h 00003 Sets of points on the board. 00004 */ 00005 //---------------------------------------------------------------------------- 00006 00007 #ifndef SG_POINTSET_H 00008 #define SG_POINTSET_H 00009 00010 #include <algorithm> 00011 #include <bitset> 00012 #include <cstring> 00013 #include <iosfwd> 00014 #include <memory> 00015 #include "SgArray.h" 00016 #include "SgPoint.h" 00017 #include "SgRect.h" 00018 #include "SgVector.h" 00019 00020 //---------------------------------------------------------------------------- 00021 00022 /** Set of points. 00023 Represents a set of points on the Go board. This class is efficient for 00024 bit-level operations on the board as a whole. 00025 */ 00026 class SgPointSet 00027 { 00028 public: 00029 SgPointSet(); 00030 00031 ~SgPointSet(); 00032 00033 explicit SgPointSet(const SgVector<SgPoint>& vector); 00034 00035 SgPointSet& operator-=(const SgPointSet& other); 00036 00037 SgPointSet& operator&=(const SgPointSet& other); 00038 00039 SgPointSet& operator|=(const SgPointSet& other); 00040 00041 SgPointSet& operator^=(const SgPointSet& other); 00042 00043 bool operator==(const SgPointSet& other) const; 00044 00045 bool operator!=(const SgPointSet& other) const; 00046 00047 /** Return whether point 'p' is set. */ 00048 bool operator[](SgPoint p) const; 00049 00050 bool Disjoint(const SgPointSet& s) const; 00051 00052 /** Test if this contains a Point adjacent to a Point in s */ 00053 bool Adjacent(const SgPointSet& s) const; 00054 00055 bool Adjacent8To(SgPoint p) const; 00056 00057 /** Test if all points adjacent to this are contained in s */ 00058 bool AdjacentOnlyTo(const SgPointSet& s, int boardSize) const; 00059 00060 bool AdjacentTo(SgPoint p) const; 00061 00062 /** Test if all Points in this are adjacent to some Point in s */ 00063 bool AllAdjacentTo(const SgPointSet& s) const; 00064 00065 static const SgPointSet& AllPoints(int boardSize); 00066 00067 int Size() const; 00068 00069 bool IsSize(int size) const; 00070 00071 bool MinSetSize(int size) const; 00072 00073 bool MaxSetSize(int size) const; 00074 00075 bool IsEmpty() const; 00076 00077 bool NonEmpty() const; 00078 00079 /** 4-Neighbor points of set */ 00080 SgPointSet Border(int boardSize) const; 00081 00082 /** 8-Neighbor points of set */ 00083 SgPointSet Border8(int boardSize) const; 00084 00085 /** Compute border without clipping to board size. */ 00086 SgPointSet BorderNoClip() const; 00087 00088 /** SgPoint as close to the center of set as possible */ 00089 SgPoint Center() const; 00090 00091 /** Return whether point 'p' is set. */ 00092 bool CheckedContains(SgPoint p, bool doRangeCheck = true, 00093 bool onBoardCheck = false) const; 00094 00095 SgPointSet& Clear(); 00096 00097 /** Compute connected component by iterative Border calculation. 00098 @note Slow for large diameter sets. 00099 */ 00100 SgPointSet Component(SgPoint p) const; 00101 00102 /** Good for small diameter sets */ 00103 SgPointSet Component8(SgPoint p) const; 00104 00105 /** Good for large diameter sets */ 00106 SgPointSet ConnComp(SgPoint p) const; 00107 00108 /** 8-neighbors */ 00109 SgPointSet ConnComp8(SgPoint p) const; 00110 00111 /** Check if contains point. 00112 Can be called with out-of-board points, otherwise use 00113 ContainsPoints(). 00114 */ 00115 bool Contains(SgPoint p) const; 00116 00117 /** Check if contains point. 00118 Can only be called with on-board points, otherwise use Contains(). 00119 */ 00120 bool ContainsPoint(SgPoint p) const; 00121 00122 SgRect EnclosingRect() const; 00123 00124 SgPointSet& Exclude(SgPoint p); 00125 00126 SgPointSet& Exclude(const SgVector<SgPoint>& vector); 00127 00128 /** Include 4-neighbor points in set */ 00129 void Grow(int boardSize); 00130 00131 /** Returns newly added points */ 00132 void Grow(SgPointSet* newArea, int boardSize); 00133 00134 /** Include 8-neighbor points in set */ 00135 void Grow8(int boardSize); 00136 00137 SgPointSet& Include(SgPoint p); 00138 00139 /** Whether set is connected or not. 00140 @return True if connected or set is empty. 00141 @note Slow for large diameters. 00142 */ 00143 bool IsConnected() const; 00144 00145 /** Whether set is connected or not. */ 00146 bool Is8Connected() const; 00147 00148 /** Points of set surrounded by set */ 00149 SgPointSet Kernel(int boardSize) const; 00150 00151 /** At most 'max' common points. */ 00152 bool MaxOverlap(const SgPointSet& other, int max) const; 00153 00154 /** At least 'min' common points. */ 00155 bool MinOverlap(const SgPointSet& s, int min) const; 00156 00157 bool NewMark(SgPoint p); 00158 00159 bool Overlaps(const SgPointSet& other) const; 00160 00161 /** First point of set. 00162 @return First (smallest) point of set or SG_NULLPOINT for empty set. 00163 */ 00164 SgPoint PointOf() const; 00165 00166 /** Is this set a subset of s? */ 00167 bool SubsetOf(const SgPointSet& other) const; 00168 00169 /** Is this set a superset of s? */ 00170 bool SupersetOf(const SgPointSet& other) const; 00171 00172 void Swap(SgPointSet& other) throw(); 00173 00174 SgPointSet& Toggle(SgPoint p); 00175 00176 void ToVector(SgVector<SgPoint>* vector) const; 00177 00178 void Write(std::ostream& out, int boardSize) const; 00179 00180 /** Return whether point 'p' is close to a point in set. 00181 in implementation: const int MAX_CLOSE_DISTANCE = 3; 00182 */ 00183 bool IsCloseTo(SgPoint p) const; 00184 00185 private: 00186 /** Precomputed point sets with all points depending on board size. */ 00187 class PrecompAllPoints 00188 { 00189 public: 00190 PrecompAllPoints(); 00191 00192 const SgPointSet& Get(int boardSize) 00193 { 00194 SG_ASSERT(boardSize >= SG_MIN_SIZE); 00195 SG_ASSERT(boardSize <= SG_MAX_SIZE); 00196 return *m_allPoints[boardSize]; 00197 } 00198 00199 private: 00200 SgArray<std::auto_ptr<SgPointSet>,SG_MAX_SIZE + 1> m_allPoints; 00201 }; 00202 00203 friend class SgSetIterator; 00204 00205 std::bitset<SG_MAXPOINT> m_a; 00206 00207 static PrecompAllPoints s_allPoints; 00208 00209 SgPointSet operator>>(int n) const; 00210 00211 SgPointSet operator<<(int n) const; 00212 00213 }; 00214 00215 00216 /** Compute difference between point sets. 00217 @relatesalso SgPointSet 00218 */ 00219 inline SgPointSet operator-(const SgPointSet& L, const SgPointSet& R) 00220 { 00221 return (SgPointSet(L) -= R); 00222 } 00223 00224 /** Compute intersection between point sets. 00225 @relatesalso SgPointSet 00226 */ 00227 inline SgPointSet operator&(const SgPointSet& L, const SgPointSet& R) 00228 { 00229 return (SgPointSet(L) &= R); 00230 } 00231 00232 /** Compute union between point sets. 00233 @relatesalso SgPointSet 00234 */ 00235 inline SgPointSet operator|(const SgPointSet& L, const SgPointSet& R) 00236 { 00237 return (SgPointSet(L) |= R); 00238 } 00239 00240 /** Compute XOR between point sets. 00241 @relatesalso SgPointSet 00242 */ 00243 inline SgPointSet operator^(const SgPointSet& L, const SgPointSet& R) 00244 { 00245 return (SgPointSet(L) ^= R); 00246 } 00247 00248 inline SgPointSet::SgPointSet() 00249 { 00250 } 00251 00252 inline SgPointSet::~SgPointSet() 00253 { 00254 } 00255 00256 inline void SgPointSet::Swap(SgPointSet& other) throw() 00257 { 00258 std::swap(m_a, other.m_a); 00259 } 00260 00261 inline SgPointSet& SgPointSet::operator-=(const SgPointSet& other) 00262 { 00263 m_a &= ~other.m_a; 00264 return (*this); 00265 } 00266 00267 inline SgPointSet& SgPointSet::operator&=(const SgPointSet& other) 00268 { 00269 m_a &= other.m_a; 00270 return (*this); 00271 } 00272 00273 inline SgPointSet& SgPointSet::operator|=(const SgPointSet& other) 00274 { 00275 m_a |= other.m_a; 00276 return (*this); 00277 } 00278 00279 inline SgPointSet& SgPointSet::operator^=(const SgPointSet& other) 00280 { 00281 m_a ^= other.m_a; 00282 return (*this); 00283 } 00284 00285 inline bool SgPointSet::operator==(const SgPointSet& other) const 00286 { 00287 return m_a == other.m_a; 00288 } 00289 00290 inline bool SgPointSet::operator!=(const SgPointSet& other) const 00291 { 00292 return m_a != other.m_a; 00293 } 00294 00295 inline const SgPointSet& SgPointSet::AllPoints(int boardSize) 00296 { 00297 return s_allPoints.Get(boardSize); 00298 } 00299 00300 inline bool SgPointSet::Overlaps(const SgPointSet& other) const 00301 { 00302 return (m_a & other.m_a).any(); 00303 } 00304 00305 inline bool SgPointSet::MaxOverlap(const SgPointSet& other, int max) const 00306 { 00307 SgPointSet s(*this); 00308 s &= other; 00309 return s.Size() <= max; 00310 } 00311 00312 inline bool SgPointSet::MinOverlap(const SgPointSet& s, int min) const 00313 { 00314 return ! MaxOverlap(s, min - 1); 00315 } 00316 00317 inline bool SgPointSet::Disjoint(const SgPointSet& s) const 00318 { 00319 return ! Overlaps(s); 00320 } 00321 00322 inline bool SgPointSet::AdjacentTo(SgPoint p) const 00323 { 00324 SG_ASSERT_BOARDRANGE(p); 00325 return Contains(p + SG_NS) 00326 || Contains(p - SG_NS) 00327 || Contains(p + SG_WE) 00328 || Contains(p - SG_WE); 00329 } 00330 00331 inline bool SgPointSet::Adjacent8To(SgPoint p) const 00332 { 00333 SG_ASSERT_BOARDRANGE(p); 00334 return Contains(p + SG_NS) || Contains(p - SG_NS) || Contains(p + SG_WE) 00335 || Contains(p - SG_WE) || Contains(p + SG_NS + SG_WE) 00336 || Contains(p + SG_NS - SG_WE) || Contains(p - SG_NS + SG_WE) 00337 || Contains(p - SG_NS - SG_WE); 00338 } 00339 00340 inline bool SgPointSet::SubsetOf(const SgPointSet& other) const 00341 { 00342 return (m_a & ~other.m_a).none(); 00343 } 00344 00345 inline bool SgPointSet::SupersetOf(const SgPointSet& other) const 00346 { 00347 return (other.m_a & ~m_a).none(); 00348 } 00349 00350 inline int SgPointSet::Size() const 00351 { 00352 return static_cast<int>(m_a.count()); 00353 } 00354 00355 inline bool SgPointSet::IsEmpty() const 00356 { 00357 return m_a.none(); 00358 } 00359 00360 inline bool SgPointSet::NonEmpty() const 00361 { 00362 return ! IsEmpty(); 00363 } 00364 00365 inline SgPointSet& SgPointSet::Exclude(SgPoint p) 00366 { 00367 SG_ASSERT_BOARDRANGE(p); 00368 m_a.reset(p); 00369 return (*this); 00370 } 00371 00372 inline SgPointSet& SgPointSet::Include(SgPoint p) 00373 { 00374 SG_ASSERT_BOARDRANGE(p); 00375 m_a.set(p); 00376 return (*this); 00377 } 00378 00379 inline SgPointSet& SgPointSet::Clear() 00380 { 00381 m_a.reset(); 00382 return *this; 00383 } 00384 00385 inline SgPointSet& SgPointSet::Toggle(SgPoint p) 00386 { 00387 SG_ASSERT(p < static_cast<int>(m_a.size())); 00388 m_a.flip(p); 00389 return (*this); 00390 } 00391 00392 inline bool SgPointSet::Contains(SgPoint p) const 00393 { 00394 return m_a.test(p); 00395 } 00396 00397 inline bool SgPointSet::CheckedContains(SgPoint p, bool doRangeCheck, 00398 bool onBoardCheck) const 00399 { 00400 if (doRangeCheck) 00401 { 00402 if (onBoardCheck) 00403 SG_ASSERT_BOARDRANGE(p); 00404 else 00405 // 1 larger for nbiterators 00406 SG_ASSERTRANGE(p, SgPointUtil::Pt(0, 0), 00407 SgPointUtil::Pt(SG_MAX_SIZE + 1, SG_MAX_SIZE + 1)); 00408 } 00409 return m_a.test(p); 00410 } 00411 00412 inline bool SgPointSet::ContainsPoint(SgPoint p) const 00413 { 00414 return CheckedContains(p, true, true); 00415 } 00416 00417 inline bool SgPointSet::operator[](SgPoint p) const 00418 { 00419 return Contains(p); 00420 } 00421 00422 inline bool SgPointSet::NewMark(SgPoint p) 00423 { 00424 if (Contains(p)) 00425 return false; 00426 else 00427 { 00428 Include(p); 00429 return true; 00430 } 00431 } 00432 00433 inline SgPointSet SgPointSet::operator>>(int n) const 00434 { 00435 SgPointSet result(*this); 00436 result.m_a >>= n; 00437 return result; 00438 } 00439 00440 inline SgPointSet SgPointSet::operator<<(int n) const 00441 { 00442 SgPointSet result(*this); 00443 result.m_a <<= n; 00444 return result; 00445 } 00446 00447 //---------------------------------------------------------------------------- 00448 00449 /** Iterator to iterate through 'set'. 00450 Set may contain only board 00451 points, no 'Border' points. 00452 */ 00453 class SgSetIterator 00454 { 00455 public: 00456 /** Set may contain only board points, no 'Border' points. */ 00457 SgSetIterator(const SgPointSet& set); 00458 00459 /** Advance the state of the iteration to the next element. */ 00460 void operator++(); 00461 00462 /** Return the value of the current element. */ 00463 SgPoint operator*() const; 00464 00465 /** Return true if iteration is valid, otherwise false. */ 00466 operator bool() const; 00467 00468 private: 00469 const SgPointSet& m_set; 00470 00471 int m_index; 00472 00473 void FindNext(); 00474 00475 int Size() const; 00476 }; 00477 00478 inline SgSetIterator::SgSetIterator(const SgPointSet& set) 00479 : m_set(set), 00480 m_index(0) 00481 { 00482 FindNext(); 00483 } 00484 00485 inline void SgSetIterator::operator++() 00486 { 00487 SG_ASSERT(m_index < Size()); 00488 FindNext(); 00489 } 00490 00491 inline SgPoint SgSetIterator::operator*() const 00492 { 00493 SG_ASSERT(m_index <= Size()); 00494 SG_ASSERT_BOARDRANGE(m_index); 00495 SG_ASSERT(m_set.m_a.test(m_index)); 00496 return m_index; 00497 } 00498 00499 inline SgSetIterator::operator bool() const 00500 { 00501 return m_index < Size(); 00502 } 00503 00504 inline void SgSetIterator::FindNext() 00505 { 00506 int size = Size(); 00507 do 00508 { 00509 ++m_index; 00510 } 00511 while (m_index < size && ! m_set.m_a.test(m_index)); 00512 } 00513 00514 inline int SgSetIterator::Size() const 00515 { 00516 return static_cast<int>(m_set.m_a.size()); 00517 } 00518 00519 //---------------------------------------------------------------------------- 00520 00521 /** Point set efficient for marking and testing. 00522 A SgSimpleSet is like a SgPointSet, except that it's more efficient at 00523 marking points and testing for marked points, while taking more time to 00524 clear, and not providing bit operations on the whole set. 00525 */ 00526 class SgSimpleSet 00527 { 00528 public: 00529 SgSimpleSet(); 00530 00531 void Include(SgPoint p); 00532 00533 void Exclude(SgPoint p); 00534 00535 bool Contains(SgPoint p) const; 00536 00537 void Clear(); 00538 00539 bool IsEmpty() const; 00540 00541 bool NonEmpty() const; 00542 00543 void GetPoints(SgPointSet* points) const; 00544 00545 bool NewMark(SgPoint p); 00546 00547 private: 00548 /** Marked points. */ 00549 bool m_mark[SG_MAXPOINT]; 00550 }; 00551 00552 inline SgSimpleSet::SgSimpleSet() 00553 { 00554 Clear(); 00555 } 00556 00557 00558 inline void SgSimpleSet::Include(SgPoint p) 00559 { 00560 SG_ASSERT_BOARDRANGE(p); 00561 m_mark[p] = true; 00562 } 00563 00564 inline void SgSimpleSet::Exclude(SgPoint p) 00565 { 00566 SG_ASSERT_BOARDRANGE(p); 00567 m_mark[p] = false; 00568 } 00569 00570 inline bool SgSimpleSet::Contains(SgPoint p) const 00571 { 00572 return m_mark[p]; 00573 } 00574 00575 inline void SgSimpleSet::Clear() 00576 { 00577 std::memset(m_mark, 0, SG_MAXPOINT * sizeof(bool)); 00578 } 00579 00580 inline bool SgSimpleSet::IsEmpty() const 00581 { 00582 for (SgPoint p = 0; p < SG_MAXPOINT; ++p) 00583 if (Contains(p)) 00584 return false; 00585 return true; 00586 } 00587 00588 inline bool SgSimpleSet::NonEmpty() const 00589 { 00590 return ! IsEmpty(); 00591 } 00592 00593 inline void SgSimpleSet::GetPoints(SgPointSet* points) const 00594 { 00595 points->Clear(); 00596 for (SgPoint p = 0; p < SG_MAXPOINT; ++p) 00597 if (Contains(p)) 00598 points->Include(p); 00599 } 00600 00601 inline bool SgSimpleSet::NewMark(SgPoint p) 00602 { 00603 if (Contains(p)) 00604 return false; 00605 else 00606 { 00607 Include(p); 00608 return true; 00609 } 00610 } 00611 00612 //---------------------------------------------------------------------------- 00613 00614 #endif // SG_POINTSET_H