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