The Battle for Wesnoth  1.15.0-dev
location.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2018 by David White <dave@whitevine.net>
3  Part of the Battle for Wesnoth Project https://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 #pragma once
18 
19 class config;
20 class variable_set;
21 
22 #include <array>
23 #include <cmath>
24 #include <cstdlib>
25 #include <set>
26 #include <string>
27 #include <tuple>
28 #include <vector>
29 #include <algorithm>
30 #include <utility>
31 
32 struct wml_loc {};
33 
34 /**
35  * Encapsulates the map of the game.
36  *
37  * Although the game is hexagonal, the map is stored as a grid.
38  * Each type of terrain is represented by a multiletter terrain code.
39  * @todo Update for new map-format.
40  */
41 /** Represents a location on the map. */
42 struct map_location {
43  /** Valid directions which can be moved in our hexagonal world. */
44  enum DIRECTION { NORTH=0, NORTH_EAST=1, SOUTH_EAST=2, SOUTH=3,
45  SOUTH_WEST=4, NORTH_WEST=5, NDIRECTIONS=6 };
46 
47  static const std::vector<DIRECTION> & default_dirs();
48 
49  static DIRECTION rotate_right(DIRECTION d, unsigned int k = 1u)
50  {
51  return (d == map_location::NDIRECTIONS) ? map_location::NDIRECTIONS : static_cast<map_location::DIRECTION>((d + (k%6u)) % 6u);
52  }
53 
54  static DIRECTION rotate_right(DIRECTION d, signed int k)
55  {
56  return (k>=0) ? rotate_right(d, static_cast<unsigned int> (k)) : rotate_right(d, (static_cast<unsigned int>(-k) % 6u) * 5u);
57  }
58 
60  {
61  return rotate_right(d,3u);
62  }
63 
64  static DIRECTION parse_direction(const std::string& str);
65 
66  /**
67  * Parse_directions takes a comma-separated list, and filters out any
68  * invalid directions
69  */
70  static std::vector<DIRECTION> parse_directions(const std::string& str);
71  static std::string write_direction(DIRECTION dir);
72  static std::string write_translated_direction(DIRECTION dir);
73 
74  map_location() : x(-1000), y(-1000) {}
75  map_location(int x, int y) : x(x), y(y) {}
76  map_location(int x, int y, wml_loc) : x(x - 1), y(y - 1) {}
77  map_location(const config& cfg, const variable_set *variables = nullptr);
78 
79  static const map_location & ZERO()
80  {
81  static const map_location z(0,0);
82  return z;
83  }
84 
85  static const map_location & null_location()
86  {
87  static const map_location l;
88  return l;
89  }
90 
91  void write(config& cfg) const;
92 
93  bool valid() const { return x >= 0 && y >= 0; }
94 
95  bool valid(const int parWidth, const int parHeight) const
96  { return ((x >= 0) && (y >= 0) && (x < parWidth) && (y < parHeight)); }
97 
98  bool valid(const int parWidth, const int parHeight, const int border) const
99  { return ((x + border >= 0) && (y + border >= 0) && (x < parWidth + border) && (y < parHeight + border)); }
100 
101  bool matches_range(const std::string& xloc, const std::string& yloc) const;
102 
103  // Inlining those for performance reasons
104  bool operator<(const map_location& a) const { return std::tie(x, y) < std::tie(a.x, a.y); }
105  bool operator==(const map_location& a) const { return x == a.x && y == a.y; }
106  bool operator!=(const map_location& a) const { return !operator==(a); }
107 
108  /** three-way comparator */
109  int do_compare(const map_location& a) const {return x == a.x ? y - a.y : x - a.x; }
110 
111  // Location arithmetic operations treating the locations as vectors in
112  // a hex-based space. These operations form an abelian group, i.e.
113  // everything works as you would expect addition and subtraction to
114  // work, with associativity and commutativity.
116  {
117  return map_location(-x, -y - (x & 1)); //subtract one if we're on an odd x coordinate
118  }
119 
121  {
122  return map_location(*this).vector_sum_assign(a);
123  }
124 
126  {
127  y += ((x & 1) && (a.x & 1)); //add one if both x coords are odd
128  x += a.x;
129  y += a.y;
130  return *this;
131  }
132 
134  {
135  return vector_sum_assign(a.vector_negation());
136  }
137 
138  // Do n step in the direction d
139  map_location get_direction(DIRECTION dir, unsigned int n = 1u) const;
140  map_location get_direction(DIRECTION dir, signed int n) const
141  {
142  return (n >= 0) ? get_direction(dir, static_cast<unsigned int> (n)) : get_direction(get_opposite_dir(dir), static_cast<unsigned int> (-n));
143  }
144 
145  enum RELATIVE_DIR_MODE { DEFAULT , RADIAL_SYMMETRY };
146  DIRECTION get_relative_dir(const map_location & loc, map_location::RELATIVE_DIR_MODE mode /*= map_location::RADIAL_SYMMETRY*/ ) const;
147  DIRECTION get_relative_dir(const map_location & loc) const; //moved the default setting to .cpp file for ease of testing
148 
149  // Express as a vector in the basis N, NE. N, and NE may be obtained by zero.get_direction(NORTH), ...(NORTH_EAST), respectively.
150  std::pair<int,int> get_in_basis_N_NE() const;
151 
152  // Rotates the map_location clockwise in 60 degree increments around a center point. Negative numbers of steps are permitted.
153  map_location rotate_right_around_center(const map_location & center, int k) const;
154 
155  friend std::size_t hash_value(const map_location& a);
156 
157  int wml_x() const { return x + 1; }
158  int wml_y() const { return y + 1; }
159 
160  void set_wml_x(int v) { x = v - 1; }
161  void set_wml_y(int v) { y = v - 1; }
162  //on purpose these functions don't take map_location objects, if you use map_location objects to store 'differences' between 2 locations use vector_sum().
163  void add(int x_diff, int y_diff) { x += x_diff; y += y_diff; }
164  map_location plus(int x_diff, int y_diff) const { return map_location(x + x_diff, y + y_diff); }
165 
166 
167  int x, y;
168 };
169 
170 using adjacent_loc_array_t = std::array<map_location, 6>;
171 
172 /** Function which tells if two locations are adjacent. */
173 bool tiles_adjacent(const map_location& a, const map_location& b);
174 
175 /**
176  * Function which, given a location, will place all adjacent locations in res.
177  * res must point to an array of 6 location objects.
178  */
179 void get_adjacent_tiles(const map_location& a, map_location* res);
180 
181 /**
182  * Function which gives the number of hexes between two tiles
183  * (i.e. the minimum number of hexes that have to be traversed
184  * to get from one hex to the other).
185  */
186 std::size_t distance_between(const map_location& a, const map_location& b);
187 
188 /**
189  * Write a set of locations into a config using ranges,
190  * adding keys x=x1,..,xn and y=y1a-y1b,..,yna-ynb
191  */
192 void write_location_range(const std::set<map_location>& locs, config& cfg);
193 
194 /**
195  * Parse x,y keys of a config into a vector of locations
196  *
197  * Throws bad_lexical_cast if it fails to parse.
198  */
199 void read_locations(const config& cfg, std::vector<map_location>& locs);
200 
201 /** Write a vector of locations into a config
202  * adding keys x=x1,x2,..,xn and y=y1,y2,..,yn */
203 void write_locations(const std::vector<map_location>& locs, config& cfg);
204 
205 /** Dumps a position on a stream, for debug purposes. */
206 std::ostream &operator<<(std::ostream &s, const map_location& l);
207 /** Dumps a vector of positions on a stream, for debug purposes. */
208 std::ostream &operator<<(std::ostream &s, const std::vector<map_location>& v);
209 
210 namespace std {
211 template<>
212 struct hash<map_location> {
213  std::size_t operator()(const map_location& l) const {
214  // The 2000 bias supposedly ensures that the correct x is recovered for negative y
215  // This implementation copied from the Lua location_set
216  return (l.wml_x()) * 16384 + (l.wml_y()) + 2000;
217  }
218 };
219 }
void set_wml_y(int v)
Definition: location.hpp:161
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:441
map_location(int x, int y)
Definition: location.hpp:75
map_location & vector_sum_assign(const map_location &a)
Definition: location.hpp:125
std::ostream & operator<<(std::ostream &s, const map_location &l)
Dumps a position on a stream, for debug purposes.
Definition: location.cpp:35
map_location & vector_difference_assign(const map_location &a)
Definition: location.hpp:133
map_location(int x, int y, wml_loc)
Definition: location.hpp:76
static const map_location & ZERO()
Definition: location.hpp:79
#define a
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.cpp:517
std::size_t operator()(const map_location &l) const
Definition: location.hpp:213
int do_compare(const map_location &a) const
three-way comparator
Definition: location.hpp:109
int wml_x() const
Definition: location.hpp:157
void set_wml_x(int v)
Definition: location.hpp:160
STL namespace.
bool valid(const int parWidth, const int parHeight, const int border) const
Definition: location.hpp:98
map_location vector_negation() const
Definition: location.hpp:115
static DIRECTION rotate_right(DIRECTION d, unsigned int k=1u)
Definition: location.hpp:49
#define d
#define b
void write(std::ostream &out, const configr_of &cfg, unsigned int level)
Definition: parser.cpp:749
map_location plus(int x_diff, int y_diff) const
Definition: location.hpp:164
void add(int x_diff, int y_diff)
Definition: location.hpp:163
bool tiles_adjacent(const map_location &a, const map_location &b)
Function which tells if two locations are adjacent.
Definition: location.cpp:557
bool operator!=(const map_location &a) const
Definition: location.hpp:106
int wml_y() const
Definition: location.hpp:158
bool valid() const
Definition: location.hpp:93
bool operator==(const map_location &a) const
Definition: location.hpp:105
std::array< map_location, 6 > adjacent_loc_array_t
Definition: location.hpp:170
static const std::string & get_direction(std::size_t n)
Definition: display.cpp:709
static DIRECTION rotate_right(DIRECTION d, signed int k)
Definition: location.hpp:54
Encapsulates the map of the game.
Definition: location.hpp:42
std::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.cpp:600
bool operator<(const map_location &a) const
Definition: location.hpp:104
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:497
map_location vector_sum(const map_location &a) const
Definition: location.hpp:120
std::size_t hash_value(const map_location &a)
Definition: location.cpp:58
bool operator==(const config &a, const config &b)
Definition: config.cpp:1354
static map_location::DIRECTION s
DIRECTION
Valid directions which can be moved in our hexagonal world.
Definition: location.hpp:44
static DIRECTION get_opposite_dir(DIRECTION d)
Definition: location.hpp:59
static const map_location & null_location()
Definition: location.hpp:85
bool valid(const int parWidth, const int parHeight) const
Definition: location.hpp:95
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:68
map_location get_direction(DIRECTION dir, signed int n) const
Definition: location.hpp:140
static map_location::DIRECTION n
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:485