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