The Battle for Wesnoth  1.19.5+dev
location.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2024
3  by David White <dave@whitevine.net>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 #pragma once
17 
18 class config;
20 class variable_set;
21 
22 #include <array>
23 #include <set>
24 #include <string>
25 #include <tuple>
26 #include <vector>
27 #include <utility>
28 
29 struct wml_loc {};
30 
31 /// Represents a map location in cubic hexagonal coordinates.
32 /// See <https://www.redblobgames.com/grids/hexagons/#coordinates-cube> for a more detailed explanation.
34  int q, r, s;
35 };
36 
37 /**
38  * Encapsulates the map of the game.
39  *
40  * Although the game is hexagonal, the map is stored as a grid.
41  * Each type of terrain is represented by a multiletter terrain code.
42  * @todo Update for new map-format.
43  */
44 /** Represents a location on the map. */
45 struct map_location {
46  /** Valid directions which can be moved in our hexagonal world. */
47  enum class direction {
48  north,
49  north_east,
50  south_east,
51  south,
52  south_west,
53  north_west,
55  };
56 
57  static std::vector<direction> all_directions();
58 
59  /** Returns the direction one would face having taken @a steps clockwise around an undefined center. */
60  static constexpr direction rotate_direction(direction d, int steps = 1)
61  {
64  }
65 
66  // Compensate for weirdness with the C++ % operator.
67  // The plain formula (d + (steps % 6)) % 6 works for almost every case, but it returns incorrect
68  // results for a counterclockwise rotation on direction::north. Instead, for any negative steps,
69  // cancel out the sign and scale by the highest possible direction value (viz., 5). This has the
70  // effect of a clockwise rotation ending at the same value as the specified counter-clockwise op.
71  int adjusted_steps = steps >= 0 ? steps : steps * -5;
72  return direction{(static_cast<int>(d) + (adjusted_steps % 6)) % 6};
73  }
74 
76  {
77  return rotate_direction(d, 3);
78  }
79 
80  static direction parse_direction(const std::string& str);
81 
82  /**
83  * Parse_directions takes a comma-separated list, and filters out any
84  * invalid directions
85  */
86  static std::vector<direction> parse_directions(const std::string& str);
87  static std::string write_direction(direction dir);
88  static std::string write_translated_direction(direction dir);
89 
90  map_location() : x(-1000), y(-1000) {}
91  map_location(int x, int y) : x(x), y(y) {}
92  map_location(int x, int y, wml_loc) : x(x - 1), y(y - 1) {}
94  map_location(const config& cfg, const variable_set *variables = nullptr);
95 
96  static const map_location & ZERO()
97  {
98  static const map_location z(0,0);
99  return z;
100  }
101 
102  static const map_location & null_location()
103  {
104  static const map_location l;
105  return l;
106  }
107 
108  void write(config& cfg) const;
109 
110  bool valid() const { return x >= 0 && y >= 0; }
111 
112  bool valid(const int parWidth, const int parHeight) const
113  { return ((x >= 0) && (y >= 0) && (x < parWidth) && (y < parHeight)); }
114 
115  bool valid(const int parWidth, const int parHeight, const int border) const
116  { return ((x + border >= 0) && (y + border >= 0) && (x < parWidth + border) && (y < parHeight + border)); }
117 
118  bool matches_range(const std::string& xloc, const std::string& yloc) const;
119 
120  // Inlining those for performance reasons
121  bool operator<(const map_location& a) const { return std::tie(x, y) < std::tie(a.x, a.y); }
122  bool operator==(const map_location& a) const { return x == a.x && y == a.y; }
123  bool operator!=(const map_location& a) const { return !operator==(a); }
124 
125  /** three-way comparator */
126  int do_compare(const map_location& a) const {return x == a.x ? y - a.y : x - a.x; }
127 
128  // Location arithmetic operations treating the locations as vectors in
129  // a hex-based space. These operations form an abelian group, i.e.
130  // everything works as you would expect addition and subtraction to
131  // work, with associativity and commutativity.
133  {
134  return map_location(-x, -y - (x & 1)); //subtract one if we're on an odd x coordinate
135  }
136 
138  {
139  return map_location(*this).vector_sum_assign(a);
140  }
141 
143  {
144  y += ((x & 1) && (a.x & 1)); //add one if both x coords are odd
145  x += a.x;
146  y += a.y;
147  return *this;
148  }
149 
151  {
153  }
154 
155  // Do n step in the direction d
156  map_location get_direction(direction dir, unsigned int n = 1u) const;
157  map_location get_direction(direction dir, signed int n) const
158  {
159  return (n >= 0) ? get_direction(dir, static_cast<unsigned int> (n)) : get_direction(get_opposite_direction(dir), static_cast<unsigned int> (-n));
160  }
161 
163  direction get_relative_dir(const map_location & loc, map_location::RELATIVE_DIR_MODE mode /*= map_location::RADIAL_SYMMETRY*/ ) const;
164  direction get_relative_dir(const map_location & loc) const; //moved the default setting to .cpp file for ease of testing
165 
167  int q = x;
168  int r = y - int((x - abs(x) % 2) / 2);
169  int s = -q - r;
170  return cubic_location{q, r, s};
171  }
173  int x = h.q;
174  int y = h.r + int((h.q - abs(h.q) % 2) / 2);
175  return map_location(x, y);
176  }
177 
178  // Rotates the map_location clockwise in 60 degree increments around a center point. Negative numbers of steps are permitted.
179  map_location rotate_right_around_center(const map_location & center, int k) const;
180 
181  friend std::size_t hash_value(const map_location& a);
182 
183  int wml_x() const { return x + 1; }
184  int wml_y() const { return y + 1; }
185 
186  void set_wml_x(int v) { x = v - 1; }
187  void set_wml_y(int v) { y = v - 1; }
188  //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().
189  void add(int x_diff, int y_diff) { x += x_diff; y += y_diff; }
190  map_location plus(int x_diff, int y_diff) const { return map_location(x + x_diff, y + y_diff); }
191 
192 
193  int x, y;
194 };
195 
196 /** Function which tells if two locations are adjacent. */
197 bool tiles_adjacent(const map_location& a, const map_location& b);
198 
199 /**
200  * Function which, given a location, will place all adjacent locations in res.
201  * res must point to an array of 6 location objects.
202  */
203 void get_adjacent_tiles(const map_location& a, map_location* res);
204 
205 /** Returns an array of the six hexes adjacent to @p center. */
206 std::array<map_location, 6> get_adjacent_tiles(const map_location& center);
207 
208 /**
209  * Function which gives the number of hexes between two tiles
210  * (i.e. the minimum number of hexes that have to be traversed
211  * to get from one hex to the other).
212  */
213 std::size_t distance_between(const map_location& a, const map_location& b);
214 
215 /**
216  * Write a set of locations into a config using ranges,
217  * adding keys x=x1,..,xn and y=y1a-y1b,..,yna-ynb
218  */
219 void write_location_range(const std::set<map_location>& locs, config& cfg);
220 
221 /**
222  * Parse x,y keys of a config into a vector of locations
223  *
224  * Throws bad_lexical_cast if it fails to parse.
225  */
226 void read_locations(const config& cfg, std::vector<map_location>& locs);
227 
228 /** Write a vector of locations into a config
229  * adding keys x=x1,x2,..,xn and y=y1,y2,..,yn */
230 void write_locations(const std::vector<map_location>& locs, config& cfg);
231 
232 /** Dumps a position on a stream, for debug purposes. */
233 std::ostream &operator<<(std::ostream &s, const map_location& l);
234 /** Dumps a vector of positions on a stream, for debug purposes. */
235 std::ostream &operator<<(std::ostream &s, const std::vector<map_location>& v);
236 
237 /** Print a direction's string representation to stream. */
238 std::ostream& operator<<(std::ostream& s, map_location::direction dir);
239 
240 namespace std {
241 template<>
242 struct hash<map_location> {
243  std::size_t operator()(const map_location& l) const noexcept {
244  // The 2000 bias supposedly ensures that the correct x is recovered for negative y
245  // This implementation copied from the Lua location_set
246  return (l.wml_x()) * 16384 + (l.wml_y()) + 2000;
247  }
248 };
249 }
Variant for storing WML attributes.
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:172
@ border
The border of the map.
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:479
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:550
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,.....
Definition: location.cpp:459
std::ostream & operator<<(std::ostream &s, const map_location &l)
Dumps a position on a stream, for debug purposes.
Definition: location.cpp:36
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:447
bool tiles_adjacent(const map_location &a, const map_location &b)
Function which tells if two locations are adjacent.
Definition: location.cpp:507
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,...
Definition: location.cpp:403
Represents a map location in cubic hexagonal coordinates.
Definition: location.hpp:33
Encapsulates the map of the game.
Definition: location.hpp:45
map_location & vector_sum_assign(const map_location &a)
Definition: location.hpp:142
map_location & vector_difference_assign(const map_location &a)
Definition: location.hpp:150
static map_location from_cubic(cubic_location h)
Definition: location.hpp:172
bool valid(const int parWidth, const int parHeight) const
Definition: location.hpp:112
static std::string write_direction(direction dir)
Definition: location.cpp:154
map_location vector_negation() const
Definition: location.hpp:132
map_location(int x, int y)
Definition: location.hpp:91
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:138
void add(int x_diff, int y_diff)
Definition: location.hpp:189
friend std::size_t hash_value(const map_location &a)
Definition: location.cpp:73
static std::vector< direction > all_directions()
Definition: location.cpp:61
void set_wml_y(int v)
Definition: location.hpp:187
bool operator==(const map_location &a) const
Definition: location.hpp:122
map_location vector_sum(const map_location &a) const
Definition: location.hpp:137
map_location get_direction(direction dir, unsigned int n=1u) const
Definition: location.cpp:364
map_location rotate_right_around_center(const map_location &center, int k) const
Definition: location.cpp:301
bool valid() const
Definition: location.hpp:110
int wml_y() const
Definition: location.hpp:184
bool operator!=(const map_location &a) const
Definition: location.hpp:123
static constexpr direction get_opposite_direction(direction d)
Definition: location.hpp:75
void set_wml_x(int v)
Definition: location.hpp:186
bool operator<(const map_location &a) const
Definition: location.hpp:121
cubic_location to_cubic() const
Definition: location.hpp:166
direction
Valid directions which can be moved in our hexagonal world.
Definition: location.hpp:47
bool valid(const int parWidth, const int parHeight, const int border) const
Definition: location.hpp:115
direction get_relative_dir(const map_location &loc, map_location::RELATIVE_DIR_MODE mode) const
Definition: location.cpp:240
static const map_location & null_location()
Definition: location.hpp:102
int wml_x() const
Definition: location.hpp:183
map_location(int x, int y, wml_loc)
Definition: location.hpp:92
static direction parse_direction(const std::string &str)
Definition: location.cpp:79
map_location get_direction(direction dir, signed int n) const
Definition: location.hpp:157
static std::string write_translated_direction(direction dir)
Definition: location.cpp:175
void write(config &cfg) const
Definition: location.cpp:225
bool matches_range(const std::string &xloc, const std::string &yloc) const
Definition: location.cpp:322
map_location plus(int x_diff, int y_diff) const
Definition: location.hpp:190
int do_compare(const map_location &a) const
three-way comparator
Definition: location.hpp:126
static constexpr direction rotate_direction(direction d, int steps=1)
Returns the direction one would face having taken steps clockwise around an undefined center.
Definition: location.hpp:60
static const map_location & ZERO()
Definition: location.hpp:96
std::size_t operator()(const map_location &l) const noexcept
Definition: location.hpp:243
static map_location::direction n
static map_location::direction s
#define d
#define h
#define b