00001 //---------------------------------------------------------------------------- 00002 /** @file SgPoint.h 00003 Definitions of points on the board. 00004 00005 Points are defined in a way that they can be used as indices in an array, 00006 for a one-dimensional representation of a two-dimensional board with 00007 border (off-board) points between rows and columns. 00008 They are also compatible with SgMove (i.e. they use no negative integers, 00009 there is no overlap with the negative values for special moves 00010 in SgMove), so they can be used as move integers for games where a move 00011 can be described by a single point on the board. 00012 @see sgboardrepresentation 00013 */ 00014 //---------------------------------------------------------------------------- 00015 /** @page sgboardrepresentation Board Representation 00016 00017 The board is represented as a one-dimensional array. 00018 Neighbors of a point can be computed with offsets <tt>WE</tt> and 00019 <tt>NS</tt>, so that the four neighbors of point <tt>p</tt> are: 00020 <pre> 00021 p + SG_NS 00022 p - SG_WE p p + SG_WE 00023 p - SG_NS 00024 </pre> 00025 The board is surrounded by one line of border points (if size is 00026 SG_MAX_SIZE) in all directions; also diagonally out from the corners. 00027 00028 @section sgcoordinates Coordinates 00029 00030 SgPointUtil::Pt, SgPointUtil::Row, and SgPointUtil::Col can be used to 00031 convert between points and coordinates. The coordinates start with 1 and 00032 the conversion is independent of the board size. <tt>Pt(1, 1)</tt>, which 00033 corresponds to A1, is the lower left corner of the board. 00034 00035 @section sgpointnumbers Point numbers 00036 00037 The following point numbers are valid, if the code was compiled with 00038 <code>SG_MAX_SIZE = 19</code> (which is used in the default version of 00039 SgPoint.h). 00040 00041 <pre> 00042 19|381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 00043 18|361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 00044 17|341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 00045 16|321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 00046 15|301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 00047 14|281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 00048 13|261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 00049 12|241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 00050 11|221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 00051 10|201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 00052 9|181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 00053 8|161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 00054 7|141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 00055 6|121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 00056 5|101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 00057 4| 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 00058 3| 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 00059 2| 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 00060 1| 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 00061 [A] [B] [C] [D] [E] [F] [G] [H] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] 00062 </pre> 00063 */ 00064 //---------------------------------------------------------------------------- 00065 00066 #ifndef SG_POINT_H 00067 #define SG_POINT_H 00068 00069 #include <climits> 00070 #include <cstdlib> 00071 #include <iosfwd> 00072 #include <string> 00073 #include "SgArray.h" 00074 #include "SgMove.h" 00075 #include "SgUtil.h" 00076 00077 //---------------------------------------------------------------------------- 00078 00079 /** Minimum board size. */ 00080 const int SG_MIN_SIZE = 2; 00081 00082 /** Maximum board size. */ 00083 const int SG_MAX_SIZE = 19; 00084 00085 /** Point or SG_PASS. */ 00086 typedef int SgPoint; 00087 00088 /** Marker used for marking the end of points lists stored in arrays. */ 00089 const SgPoint SG_ENDPOINT = 0; 00090 00091 /** For symmetry, and for use in loops etc. */ 00092 const int SG_MINPOINT = 0; 00093 00094 /** Board plus borders. */ 00095 const int SG_MAXPOINT = SG_MAX_SIZE * SG_MAX_SIZE + 3 * (SG_MAX_SIZE + 1); 00096 00097 /** Maximum number of points on board. */ 00098 const int SG_MAX_ONBOARD = SG_MAX_SIZE * SG_MAX_SIZE; 00099 00100 /** The maximum number of moves. 00101 Limit using the largest possible board size and pass move. 00102 */ 00103 const int SG_MAX_MOVES = SG_MAX_ONBOARD + 1; 00104 00105 /** West-East : offset of horizontal neighbors */ 00106 const int SG_WE = 1; 00107 00108 /** North-South: offset of vertical neighbors. */ 00109 const int SG_NS = SG_MAX_SIZE + 1; 00110 00111 /** Special parameter of type Point */ 00112 const SgPoint SG_NULLPOINT = SG_NULLMOVE; 00113 00114 /* Pass move. 00115 For games in which moves can be described by a SgPoint and pass is a 00116 legal move, such that legal moves can be stored in an array indexed by 00117 the move. 00118 @note SG_PASS should not be used in games that cannot use SgPoint to 00119 describe a move or in which pass is not legal, because of the potential 00120 conflict with the integer range for describing moves in those games. 00121 */ 00122 const SgMove SG_PASS = SG_MAXPOINT + 1; 00123 00124 /** Test if move is not a point. 00125 Returns true for special moves with negative values as defined in SgMove.h 00126 (e.g. SG_NULLMOVE) and for SG_PASS. 00127 */ 00128 inline bool SgIsSpecialMove(SgMove m) 00129 { 00130 return m < 0 || m == SG_PASS; 00131 } 00132 00133 /** Coordinate in range 0 to SG_MAX_SIZE. */ 00134 typedef int SgGrid; 00135 00136 #define SG_ASSERT_GRIDRANGE(c) SG_ASSERTRANGE(c, 1, SG_MAX_SIZE) 00137 00138 #define SG_ASSERT_BOARDRANGE(p) \ 00139 SG_ASSERTRANGE(p, SgPointUtil::Pt(1, 1), \ 00140 SgPointUtil::Pt(SG_MAX_SIZE, SG_MAX_SIZE)) 00141 00142 //---------------------------------------------------------------------------- 00143 00144 /** Write point. 00145 Wrapper class to allow overloading the output stream operator, 00146 because SgPoint is a typedef int. 00147 */ 00148 struct SgWritePoint 00149 { 00150 SgPoint m_p; 00151 00152 explicit SgWritePoint(SgPoint p); 00153 }; 00154 00155 /** @relatesalso SgWritePoint */ 00156 std::ostream& operator<<(std::ostream& out, const SgWritePoint& writePoint); 00157 00158 inline SgWritePoint::SgWritePoint(SgPoint p) 00159 : m_p(p) 00160 { 00161 } 00162 00163 //---------------------------------------------------------------------------- 00164 00165 /** Read point. 00166 For overloading input stream operator for SgPoint (which is an integer). 00167 Usage: 00168 @code 00169 istream& in; 00170 SgPoint point; 00171 in >> SgReadPoint(point); 00172 if (! in) 00173 SgDebug() << "Invalid point\n"; 00174 @endcode 00175 */ 00176 class SgReadPoint 00177 { 00178 public: 00179 SgReadPoint(SgPoint& point); 00180 00181 void Read(std::istream& in) const; 00182 00183 private: 00184 SgPoint& m_point; 00185 }; 00186 00187 inline SgReadPoint::SgReadPoint(SgPoint& point) 00188 : m_point(point) 00189 { 00190 } 00191 00192 /** @relatesalso SgReadPoint */ 00193 inline std::istream& operator>>(std::istream& in, 00194 const SgReadPoint& readPoint) 00195 { 00196 readPoint.Read(in); 00197 return in; 00198 } 00199 00200 //---------------------------------------------------------------------------- 00201 00202 namespace SgPointUtil { 00203 00204 inline char Letter(int coord) 00205 { 00206 return 'A' + static_cast<char>(coord - (coord >= 9 ? 0 : 1)); 00207 } 00208 00209 std::string PointToString(SgPoint p); 00210 00211 SgPoint Pt(int col, int row); 00212 00213 /** Lookup table internally used by SgPointUtil::Row(). */ 00214 class PointToRow 00215 { 00216 public: 00217 PointToRow() 00218 { 00219 m_row.Fill(-1); 00220 for (SgGrid row = 1; row <= SG_MAX_SIZE; ++row) 00221 for (SgGrid col = 1; col <= SG_MAX_SIZE; ++col) 00222 m_row[Pt(col, row)] = row; 00223 } 00224 00225 SgGrid Row(SgPoint p) const 00226 { 00227 SG_ASSERT_BOARDRANGE(p); 00228 SG_ASSERT(m_row[p] >= 0); 00229 return m_row[p]; 00230 } 00231 00232 private: 00233 SgArray<SgGrid,SG_MAXPOINT> m_row; 00234 }; 00235 00236 /** Lookup table internally used by SgPointUtil::Col(). */ 00237 class PointToCol 00238 { 00239 public: 00240 PointToCol() 00241 { 00242 m_col.Fill(-1); 00243 for (SgGrid row = 1; row <= SG_MAX_SIZE; ++row) 00244 for (SgGrid col = 1; col <= SG_MAX_SIZE; ++col) 00245 m_col[Pt(col, row)] = col; 00246 } 00247 00248 SgGrid Col(SgPoint p) const 00249 { 00250 SG_ASSERT_BOARDRANGE(p); 00251 SG_ASSERT(m_col[p] >= 0); 00252 return m_col[p]; 00253 } 00254 00255 private: 00256 SgArray<SgGrid,SG_MAXPOINT> m_col; 00257 }; 00258 00259 /** Return column of point. 00260 The lower left corner of the coordinate grid is (1, 1). 00261 */ 00262 inline SgGrid Col(SgPoint p) 00263 { 00264 static PointToCol pointToCol; 00265 return pointToCol.Col(p); 00266 } 00267 00268 /** Return row of point. 00269 The lower left corner of the coordinate grid is (1, 1). 00270 */ 00271 inline SgGrid Row(SgPoint p) 00272 { 00273 static PointToRow pointToRow; 00274 return pointToRow.Row(p); 00275 } 00276 00277 /** Converts from (col, row) to a one-dimensional point. 00278 Only for on board points; will trigger assertion for off-board points. 00279 */ 00280 inline SgPoint Pt(int col, int row) 00281 { 00282 SG_ASSERT_GRIDRANGE(col); 00283 SG_ASSERT_GRIDRANGE(row); 00284 return SG_NS * row + col; 00285 } 00286 00287 inline bool InBoardRange(SgPoint p) 00288 { 00289 return SgUtil::InRange(p, Pt(1, 1), Pt(SG_MAX_SIZE, SG_MAX_SIZE)); 00290 } 00291 00292 /** True if the two points are adjacent to each other. */ 00293 inline bool AreAdjacent(SgPoint p1, SgPoint p2) 00294 { 00295 int d = p2 - p1; 00296 return (d == SG_NS || d == SG_WE || d == -SG_NS || d == -SG_WE); 00297 } 00298 00299 /** True if the two points are diagonally adjacent to each other. */ 00300 inline bool AreDiagonal(SgPoint p1, SgPoint p2) 00301 { 00302 return (p2 == p1 - SG_NS - SG_WE || p2 == p1 - SG_NS + SG_WE 00303 || p2 == p1 + SG_NS - SG_WE || p2 == p1 + SG_NS + SG_WE); 00304 } 00305 00306 /** Manhattan distance between two points on the board */ 00307 inline int Distance(SgPoint p1, SgPoint p2) 00308 { 00309 return (std::abs(SgPointUtil::Row(p1) - SgPointUtil::Row(p2)) 00310 + std::abs(SgPointUtil::Col(p1) - SgPointUtil::Col(p2))); 00311 } 00312 00313 /** p2 is in 3x3 area around p1. */ 00314 inline bool In8Neighborhood(SgPoint p1, SgPoint p2) 00315 { 00316 int d = p2 - p1; 00317 return (d == 0 || d == SG_NS || d == SG_WE || d == -SG_NS || d == -SG_WE 00318 || d == SG_NS - SG_WE || d == SG_NS + SG_WE 00319 || d == -SG_NS - SG_WE || d == -SG_NS + SG_WE); 00320 } 00321 00322 /** Rotate/mirror point. 00323 Rotates and/or mirrors a point on a given board according to a given 00324 rotation mode. 00325 <table> 00326 <tr><th>Mode</th><th>col</th><th>row</th></tr> 00327 <tr><td>0</td><td>col</td><td>row</td></tr> 00328 <tr><td>1</td><td>size - col + 1</td><td>row</td></tr> 00329 <tr><td>2</td><td>col</td><td>size - row + 1</td></tr> 00330 <tr><td>3</td><td>row</td><td>col</td></tr> 00331 <tr><td>4</td><td>size - row + 1</td><td>col</td></tr> 00332 <tr><td>5</td><td>row</td><td>size - col + 1</td></tr> 00333 <tr><td>6</td><td>size - col + 1</td><td>size - row + 1</td></tr> 00334 <tr><td>7</td><td>size - row + 1</td><td>size - col + 1</td></tr> 00335 </table> 00336 @param rotation The rotation mode in [0..7] 00337 @param p The point to be rotated (SG_PASS is allowed and returned 00338 unmodified) 00339 @param size The board size 00340 @return The rotated mirrored point 00341 */ 00342 SgPoint Rotate(int rotation, SgPoint p, int size); 00343 00344 /** Return the inverse rotation as used in SgPointUtil::Rotate. 00345 @param rotation The rotation mode in [0..7] 00346 @return The inverse rotation mode 00347 */ 00348 int InvRotation(int rotation); 00349 00350 } // namespace SgPointUtil 00351 00352 //---------------------------------------------------------------------------- 00353 00354 #endif // SG_POINT_H