The Battle for Wesnoth  1.17.0-dev
location.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2021
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. */
40  enum DIRECTION { NORTH=0, NORTH_EAST=1, SOUTH_EAST=2, SOUTH=3,
41  SOUTH_WEST=4, NORTH_WEST=5, NDIRECTIONS=6 };
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 
141  enum RELATIVE_DIR_MODE { DEFAULT , RADIAL_SYMMETRY };
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 }
void set_wml_y(int v)
Definition: location.hpp:157
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:399
map_location(int x, int y)
Definition: location.hpp:71
map_location & vector_sum_assign(const map_location &a)
Definition: location.hpp:121
std::ostream & operator<<(std::ostream &s, const map_location &l)
Dumps a position on a stream, for debug purposes.
Definition: location.cpp:37
map_location & vector_difference_assign(const map_location &a)
Definition: location.hpp:129
map_location(int x, int y, wml_loc)
Definition: location.hpp:72
static const map_location & ZERO()
Definition: location.hpp:75
#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:475
int do_compare(const map_location &a) const
three-way comparator
Definition: location.hpp:105
int wml_x() const
Definition: location.hpp:153
void set_wml_x(int v)
Definition: location.hpp:156
STL namespace.
bool valid(const int parWidth, const int parHeight, const int border) const
Definition: location.hpp:94
map_location vector_negation() const
Definition: location.hpp:111
static DIRECTION rotate_right(DIRECTION d, unsigned int k=1u)
Definition: location.hpp:45
#define d
#define b
void write(std::ostream &out, const configr_of &cfg, unsigned int level)
Definition: parser.cpp:764
std::size_t operator()(const map_location &l) const noexcept
Definition: location.hpp:210
map_location plus(int x_diff, int y_diff) const
Definition: location.hpp:160
void add(int x_diff, int y_diff)
Definition: location.hpp:159
bool tiles_adjacent(const map_location &a, const map_location &b)
Function which tells if two locations are adjacent.
Definition: location.cpp:503
bool operator!=(const map_location &a) const
Definition: location.hpp:102
int wml_y() const
Definition: location.hpp:154
bool valid() const
Definition: location.hpp:89
bool operator==(const map_location &a) const
Definition: location.hpp:101
static const std::string & get_direction(std::size_t n)
Definition: display.cpp:962
static DIRECTION rotate_right(DIRECTION d, signed int k)
Definition: location.hpp:50
Encapsulates the map of the game.
Definition: location.hpp:38
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:546
bool operator<(const map_location &a) const
Definition: location.hpp:100
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:455
map_location vector_sum(const map_location &a) const
Definition: location.hpp:116
std::size_t hash_value(const map_location &a)
Definition: location.cpp:60
bool operator==(const config &a, const config &b)
Definition: config.cpp:1475
static map_location::DIRECTION s
DIRECTION
Valid directions which can be moved in our hexagonal world.
Definition: location.hpp:40
static DIRECTION get_opposite_dir(DIRECTION d)
Definition: location.hpp:55
static const map_location & null_location()
Definition: location.hpp:81
bool valid(const int parWidth, const int parHeight) const
Definition: location.hpp:91
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:61
map_location get_direction(DIRECTION dir, signed int n) const
Definition: location.hpp:136
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:443