The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
location.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2016 by David White <[email protected]>
3  Part of the Battle for Wesnoth Project http://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 /** @file */
16 
17 #ifndef MAP_LOCATION_H_INCLUDED
18 #define MAP_LOCATION_H_INCLUDED
19 
20 class config;
21 class variable_set;
22 
23 #include <cmath>
24 #include <cstdlib>
25 #include <set>
26 #include <string>
27 #include <vector>
28 #include <algorithm>
29 
30 /**
31  * Encapsulates the map of the game.
32  *
33  * Although the game is hexagonal, the map is stored as a grid.
34  * Each type of terrain is represented by a multiletter terrain code.
35  * @todo Update for new map-format.
36  */
37 /** Represents a location on the map. */
38 struct map_location {
39  /** Valid directions which can be moved in our hexagonal world. */
42 
43  static const std::vector<DIRECTION> & default_dirs();
44 
45  static DIRECTION rotate_right(DIRECTION d, unsigned int k = 1u);
46  static DIRECTION rotate_right(DIRECTION d, signed int k);
47 
49 
50  static DIRECTION parse_direction(const std::string& str);
51 
52  /**
53  * Parse_directions takes a comma-separated list, and filters out any
54  * invalid directions
55  */
56  static std::vector<DIRECTION> parse_directions(const std::string& str);
59 
60  map_location() : x(-1000), y(-1000) {}
61  map_location(int x, int y) : x(x), y(y) {}
62  map_location(const config& cfg, const variable_set *variables = nullptr);
63 
64  static const map_location & ZERO();
65  static const map_location & null_location();
66 
67  void write(config& cfg) const;
68 
69  inline bool valid() const { return x >= 0 && y >= 0; }
70 
71  inline bool valid(const int parWidth, const int parHeight) const
72  { return ((x >= 0) && (y >= 0) && (x < parWidth) && (y < parHeight)); }
73 
74  inline bool valid(const int parWidth, const int parHeight, const int border) const
75  { return ((x + border >= 0) && (y + border >= 0) && (x < parWidth + border) && (y < parHeight + border)); }
76 
77  int x, y;
78  bool matches_range(const std::string& xloc, const std::string& yloc) const;
79 
80  // Inlining those for performance reasons
81  bool operator<(const map_location& a) const { return x < a.x || (x == a.x && y < a.y); }
82  bool operator==(const map_location& a) const { return x == a.x && y == a.y; }
83  bool operator!=(const map_location& a) const { return !operator==(a); }
84 
85  /** three-way comparator */
86  int do_compare(const map_location& a) const {return x == a.x ? y - a.y : x - a.x; }
87 
88  // Location arithmetic operations treating the locations as vectors in
89  // a hex-based space. These operations form an abelian group, i.e.
90  // everything works as you would expect addition and subtraction to
91  // work, with associativity and commutativity.
93  map_location vector_sum(const map_location &a) const;
96 
97  // Do n step in the direction d
98  map_location get_direction(DIRECTION d, unsigned int n = 1u) const;
99  map_location get_direction(DIRECTION d, signed int n) const;
100 
102  DIRECTION get_relative_dir(const map_location & loc, map_location::RELATIVE_DIR_MODE mode /*= map_location::RADIAL_SYMMETRY*/ ) const;
103  DIRECTION get_relative_dir(const map_location & loc) const; //moved the default setting to .cpp file for ease of testing
104 
105  // Express as a vector in the basis N, NE. N, and NE may be obtained by zero.get_direction(NORTH), ...(NORTH_EAST), respectively.
106  std::pair<int,int> get_in_basis_N_NE() const;
107 
108  // Rotates the map_location clockwise in 60 degree increments around a center point. Negative numbers of steps are permitted.
109  map_location rotate_right_around_center(const map_location & center, int k) const;
110 
111  friend std::size_t hash_value(map_location const &a);
112 };
113 
114 /** Function which tells if two locations are adjacent. */
115 bool tiles_adjacent(const map_location& a, const map_location& b);
116 
117 /**
118  * Function which, given a location, will place all adjacent locations in res.
119  * res must point to an array of 6 location objects.
120  */
122 
123 /**
124  * Function which gives the number of hexes between two tiles
125  * (i.e. the minimum number of hexes that have to be traversed
126  * to get from one hex to the other).
127  */
128 size_t distance_between(const map_location& a, const map_location& b);
129 
130 /**
131  * Write a set of locations into a config using ranges,
132  * adding keys x=x1,..,xn and y=y1a-y1b,..,yna-ynb
133  */
134 void write_location_range(const std::set<map_location>& locs, config& cfg);
135 
136 /**
137  * Parse x,y keys of a config into a vector of locations
138  *
139  * Throws bad_lexical_cast if it fails to parse.
140  */
141 void read_locations(const config& cfg, std::vector<map_location>& locs);
142 
143 /** Write a vector of locations into a config
144  * adding keys x=x1,x2,..,xn and y=y1,y2,..,yn */
145 void write_locations(const std::vector<map_location>& locs, config& cfg);
146 
147 /** Dumps a position on a stream, for debug purposes. */
148 std::ostream &operator<<(std::ostream &s, map_location const &l);
149 /** Dumps a vector of positions on a stream, for debug purposes. */
150 std::ostream &operator<<(std::ostream &s, std::vector<map_location> const &v);
151 
152 /** Inlined bodies **/
153 
154 /** Inline direction manipulators **/
156  return (d == map_location::NDIRECTIONS) ? map_location::NDIRECTIONS : static_cast<map_location::DIRECTION>((d + (k%6u)) % 6u);
157 }
158 
160  return (k>=0) ? rotate_right(d, static_cast<unsigned int> (k)) : rotate_right(d, (static_cast<unsigned int>(-k) % 6u) * 5u);
161 }
162 
164  return rotate_right(d,3u);
165 }
166 
167 /** Old implementation: **/
168 /*map_location::DIRECTION map_location::get_opposite_dir(map_location::DIRECTION d) {
169  switch (d) {
170  case NORTH:
171  return SOUTH;
172  case NORTH_EAST:
173  return SOUTH_WEST;
174  case SOUTH_EAST:
175  return NORTH_WEST;
176  case SOUTH:
177  return NORTH;
178  case SOUTH_WEST:
179  return NORTH_EAST;
180  case NORTH_WEST:
181  return SOUTH_EAST;
182  case NDIRECTIONS:
183  default:
184  return NDIRECTIONS;
185  }
186 }*/
187 
188 
189 /** Inline constant map_location defns **/
191  static const map_location z(0,0);
192  return z;
193 }
194 
196  static const map_location l;
197  return l;
198 }
199 
200 /** Inline vector ops **/
202 {
203  return map_location(-x, -y - (x & 1)); //subtract one if we're on an odd x coordinate
204 }
205 
207 {
208  return map_location(*this).vector_sum_assign(a);
209 }
210 
212 {
213  y += ((x & 1) && (a.x & 1)); //add one if both x coords are odd
214  x += a.x;
215  y += a.y;
216  return *this;
217 }
218 
220 {
222 }
223 
224 /** Get Direction function **/
225 
227  map_location::DIRECTION dir, signed int n) const
228 {
229  return (n >= 0) ? get_direction(dir, static_cast<unsigned int> (n)) : get_direction(get_opposite_dir(dir), static_cast<unsigned int> (-n));
230 }
231 
233  map_location::DIRECTION dir, unsigned int n) const
234 {
235  if (dir == map_location::NDIRECTIONS) {
237  }
238 
239  if (dir == NORTH) {
240  return map_location(x,y-n);
241  }
242 
243  if (dir == SOUTH) {
244  return map_location(x,y+n);
245  }
246 
247  int x_factor = (static_cast<unsigned int> (dir) <= 2u) ? 1 : -1; //whether we go east + or west -
248 
249  unsigned int tmp_y = dir - 2; //South East => 0, South => 1, South West => 2, North West => 3, North => INT_MAX, North East => INT_MAX - 1
250  int y_factor = (tmp_y <= 2u) ? 1 : -1; //whether we go south + or north -
251 
252  if (tmp_y <= 2u) {
253  return map_location(x + x_factor * n, y + y_factor * ((n + ((x & 1) == 1)) / 2));
254  } else {
255  return map_location(x + x_factor * n, y + y_factor * ((n + ((x & 1) == 0)) / 2));
256  }
257 
258 /*
259  switch(dir) {
260  case NORTH: return map_location(x, y - n);
261  case SOUTH: return map_location(x, y + n);
262  case SOUTH_EAST: return map_location(x + n, y + (n+is_odd(x))/2 );
263  case SOUTH_WEST: return map_location(x - n, y + (n+is_odd(x))/2 );
264  case NORTH_EAST: return map_location(x + n, y - (n+is_even(x))/2 );
265  case NORTH_WEST: return map_location(x - n, y - (n+is_even(x))/2 );
266  default:
267  assert(false);
268  return map_location::null_location();
269  }*/
270 }
271 
272 /** inline get_adjacent, and get_distance functions **/
273 
275 {
276  res->x = a.x;
277  res->y = a.y-1;
278  ++res;
279  res->x = a.x+1;
280  res->y = a.y - (((a.x & 1)==0) ? 1:0);
281  ++res;
282  res->x = a.x+1;
283  res->y = a.y + (((a.x & 1)==1) ? 1:0);
284  ++res;
285  res->x = a.x;
286  res->y = a.y+1;
287  ++res;
288  res->x = a.x-1;
289  res->y = a.y + (((a.x & 1)==1) ? 1:0);
290  ++res;
291  res->x = a.x-1;
292  res->y = a.y - (((a.x & 1)==0) ? 1:0);
293 /* Changed this when I inlined it to eliminate util.hpp dependency.
294  res->x = a.x;
295  res->y = a.y-1;
296  ++res;
297  res->x = a.x+1;
298  res->y = a.y - (is_even(a.x) ? 1:0);
299  ++res;
300  res->x = a.x+1;
301  res->y = a.y + (is_odd(a.x) ? 1:0);
302  ++res;
303  res->x = a.x;
304  res->y = a.y+1;
305  ++res;
306  res->x = a.x-1;
307  res->y = a.y + (is_odd(a.x) ? 1:0);
308  ++res;
309  res->x = a.x-1;
310  res->y = a.y - (is_even(a.x) ? 1:0);
311 */
312 }
313 
314 inline bool tiles_adjacent(const map_location& a, const map_location& b)
315 {
316  // Two tiles are adjacent:
317  // if y is different by 1, and x by 0,
318  // or if x is different by 1 and y by 0,
319  // or if x and y are each different by 1,
320  // and the x value of the hex with the greater y value is even.
321 
322  switch (a.y - b.y) {
323  case 1 :
324  switch (a.x - b.x) {
325  case 1:
326  case -1:
327  return (a.x & 1) == 0;
328  case 0:
329  return true;
330  default:
331  return false;
332  }
333  case -1 :
334  switch (a.x - b.x) {
335  case 1:
336  case -1:
337  return (b.x & 1) == 0;
338  case 0:
339  return true;
340  default:
341  return false;
342  }
343  case 0 :
344  return ((a.x - b.x) == 1) || ((a.x - b.x) == - 1);
345  default:
346  return false;
347  }
348 
349  /*
350  const int xdiff = abs(a.x - b.x);
351  const int ydiff = abs(a.y - b.y);
352  return (ydiff == 1 && a.x == b.x) || (xdiff == 1 && a.y == b.y) ||
353  (xdiff == 1 && ydiff == 1 && (a.y > b.y ? is_even(a.x) : is_even(b.x)));
354  */
355 }
356 
357 inline size_t distance_between(const map_location& a, const map_location& b)
358 {
359  const size_t hdistance = std::abs(a.x - b.x);
360 
361  const size_t vpenalty = ( (((a.x & 1)==0) && ((b.x & 1)==1) && (a.y < b.y))
362  || (((b.x & 1)==0) && ((a.x & 1)==1) && (b.y < a.y)) ) ? 1 : 0;
363 
364 /* Don't want to include util.hpp in this header
365  const size_t vpenalty = ( (is_even(a.x) && is_odd(b.x) && (a.y < b.y))
366  || (is_even(b.x) && is_odd(a.x) && (b.y < a.y)) ) ? 1 : 0;
367 */
368  // For any non-negative integer i, i - i/2 - i%2 == i/2
369  // previously returned (hdistance + vdistance - vsavings)
370  // = hdistance + vdistance - minimum(vdistance,hdistance/2+hdistance%2)
371  // = maximum(hdistance, vdistance+hdistance-hdistance/2-hdistance%2)
372  // = maximum(hdistance,std::abs(a.y-b.y)+vpenalty+hdistance/2)
373 
374  return std::max<int>(hdistance, std::abs(a.y - b.y) + vpenalty + hdistance/2);
375 }
376 
377 
378 #endif
void write_location_range(const std::set< map_location > &locs, config &cfg)
Write a set of locations into a config using ranges, adding keys x=x1,..,xn and y=y1a-y1b,..,yna-ynb.
Definition: location.cpp:371
map_location(int x, int y)
Definition: location.hpp:61
std::ostream & operator<<(std::ostream &s, map_location const &l)
Dumps a position on a stream, for debug purposes.
Definition: location.cpp:37
GLdouble GLdouble z
Definition: glew.h:1527
static DIRECTION parse_direction(const std::string &str)
Definition: location.cpp:69
friend std::size_t hash_value(map_location const &a)
Moved out of inline because of the boost dependency.
Definition: location.cpp:63
static std::string write_translated_direction(DIRECTION dir)
Definition: location.cpp:165
bool matches_range(const std::string &xloc, const std::string &yloc) const
Definition: location.cpp:311
map_location rotate_right_around_center(const map_location &center, int k) const
Definition: location.cpp:300
void get_adjacent_tiles(const map_location &a, map_location *res)
Function which, given a location, will place all adjacent locations in res.
Definition: location.hpp:274
bool operator!=(const map_location &a) const
Definition: location.hpp:83
static const map_location & ZERO()
Old implementation:
Definition: location.hpp:190
map_location & vector_difference_assign(const map_location &a)
Definition: location.hpp:219
DIRECTION get_relative_dir(const map_location &loc, map_location::RELATIVE_DIR_MODE mode) const
Definition: location.cpp:220
GLint GLint GLint GLint GLint GLint y
Definition: glew.h:1220
#define d
static std::vector< DIRECTION > parse_directions(const std::string &str)
Parse_directions takes a comma-separated list, and filters out any invalid directions.
Definition: location.cpp:128
bool valid(const int parWidth, const int parHeight) const
Definition: location.hpp:71
GLenum mode
Definition: glew.h:2390
bool valid(const int parWidth, const int parHeight, const int border) const
Definition: location.hpp:74
GLdouble l
Definition: glew.h:6966
GLdouble GLdouble GLdouble b
Definition: glew.h:6966
bool tiles_adjacent(const map_location &a, const map_location &b)
Function which tells if two locations are adjacent.
Definition: location.hpp:314
bool valid() const
Definition: location.hpp:69
size_t distance_between(const map_location &a, const map_location &b)
Function which gives the number of hexes between two tiles (i.e.
Definition: location.hpp:357
map_location vector_sum(const map_location &a) const
Definition: location.hpp:206
const GLdouble * v
Definition: glew.h:1359
GLboolean GLboolean GLboolean GLboolean a
Definition: glew.h:7319
static DIRECTION get_opposite_dir(DIRECTION d)
Definition: location.hpp:163
static const std::vector< DIRECTION > & default_dirs()
Default list of directions.
Definition: location.cpp:55
static const map_location & null_location()
Definition: location.hpp:195
void write(config &cfg) const
Definition: location.cpp:205
Encapsulates the map of the game.
Definition: location.hpp:38
GLuint res
Definition: glew.h:9258
void write_locations(const std::vector< map_location > &locs, config &cfg)
Write a vector of locations into a config adding keys x=x1,x2,..,xn and y=y1,y2,..,yn.
Definition: location.cpp:425
static DIRECTION rotate_right(DIRECTION d, unsigned int k=1u)
Inlined bodies.
Definition: location.hpp:155
GLint GLint GLint GLint GLint x
Definition: glew.h:1220
DIRECTION
Valid directions which can be moved in our hexagonal world.
Definition: location.hpp:40
bool operator<(const map_location &a) const
Definition: location.hpp:81
map_location & vector_sum_assign(const map_location &a)
Definition: location.hpp:211
GLint GLint GLsizei GLsizei GLsizei GLint border
Definition: glew.h:1222
GLclampd n
Definition: glew.h:5903
std::pair< int, int > get_in_basis_N_NE() const
Definition: location.cpp:281
int do_compare(const map_location &a) const
three-way comparator
Definition: location.hpp:86
map_location get_direction(DIRECTION d, unsigned int n=1u) const
Definition: location.hpp:232
map_location vector_negation() const
Inline vector ops.
Definition: location.hpp:201
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:83
GLdouble s
Definition: glew.h:1358
static std::string write_direction(DIRECTION dir)
Definition: location.cpp:144
GLsizei const GLcharARB ** string
Definition: glew.h:4503
void read_locations(const config &cfg, std::vector< map_location > &locs)
Parse x,y keys of a config into a vector of locations.
Definition: location.cpp:413
bool operator==(const map_location &a) const
Definition: location.hpp:82