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