The Battle for Wesnoth  1.17.0-dev
translation.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2006 - 2021
3  by Mark de Wever <koraq@xs4all.nl>
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 #include <vector>
19 #include <map>
20 #include <cstdint>
21 #include <boost/bimap.hpp>
22 #include <boost/bimap/set_of.hpp>
23 #include <boost/bimap/multiset_of.hpp>
24 #include <boost/multi_array.hpp>
25 
26 #include "exceptions.hpp"
27 #include "map/location.hpp"
28 
29 #include <string_view>
30 
31 namespace t_translation {
32 
33  /**
34  * Return the maximum allowed map size (in either dimension),
35  * the maximum map area is, therefore, this value squared.
36  */
37  int max_map_size();
38 
39  typedef uint32_t ter_layer;
40  const ter_layer WILDCARD = 0x2A000000;
41  const ter_layer NO_LAYER = 0xFFFFFFFF;
42 
43  // The definitions for a terrain
44  /**
45  * A terrain string which is converted to a terrain is a string with 1 or 2 layers
46  * the layers are separated by a caret and each group consists of 2 to 4 characters
47  * if no second layer is defined it is stored as 0xFFFFFFFF, if the second layer
48  * is empty (needed for matching) the layer has the value 0.
49  */
50  struct terrain_code {
51  terrain_code(const std::string& b, const std::string& o);
52  explicit terrain_code(const std::string& b, ter_layer o = NO_LAYER);
53  terrain_code(ter_layer b, ter_layer o) : base(b), overlay(o) {}
54  terrain_code() : base(0), overlay(NO_LAYER) {}
55 
56  ter_layer base;
57  ter_layer overlay;
58  };
60 
61  inline bool operator<(const terrain_code& a, const terrain_code& b)
62  { return std::tie(a.base, a.overlay) < std::tie(b.base, b.overlay); };
63 
64  inline bool operator==(const terrain_code& a, const terrain_code& b)
65  { return a.base == b.base && a.overlay == b.overlay; }
66 
67  inline bool operator!=(const terrain_code& a, const terrain_code& b)
68  { return a.base != b.base || a.overlay != b.overlay; }
69 
71  { return terrain_code(a.base & b.base, a.overlay & b.overlay); }
72 
74  { return terrain_code(a.base | b.base, a.overlay | b.overlay); }
75 
76  // operator<< is defined later
77 
78  typedef std::vector<terrain_code> ter_list;
79  struct ter_map {
80 
81  ter_map() = default;
82  ter_map(const ter_map&) = default;
83  ter_map(ter_map&&) = default;
84 
85  ter_map(int w, int h, terrain_code fill = terrain_code()) : data(w * h, fill), w(w), h(h) {}
86 
87  ter_map & operator= (const ter_map &) = default;
88  ter_map & operator= (ter_map &&) = default;
89 
90  terrain_code& get(int x, int y) { std::size_t index = x * h + y; return data.at(index); }
91  const terrain_code& get(int x, int y) const { std::size_t index = x * h + y; return data.at(index); }
92 
93  std::vector<terrain_code> data;
94  int w;
95  int h;
96  std::vector<terrain_code>::iterator operator[](int x) { return data.begin() + h * x; }
97  std::vector<terrain_code>::const_iterator operator[](int x) const { return data.begin() + h * x; }
98  };
99 
100  /**
101  * This structure can be used for matching terrain strings.
102  * It optimized for strings that need to be matched often,
103  * and caches the wildcard info required for matching.
104  */
105  struct ter_match{
106  ter_match();
107  ter_match(std::string_view str, const ter_layer filler = NO_LAYER);
108  ter_match(const terrain_code& tcode);
109 
110  ter_list terrain;
111  ter_list mask;
112  ter_list masked_terrain;
114  bool is_empty;
115  };
116 
117  /** Contains an x and y coordinate used for starting positions in maps. */
119 
120  // Exception thrown if there's an error with the terrain.
121  // Note: atm most thrown result in a crash, but I like
122  // an uncatched exception better than an assert.
123  struct error : public game::error {
124  error(const std::string& message) : game::error(message) {}
125  };
126 
127  // Some types of terrain which must be known, and can't just
128  // be loaded in dynamically because they're special.
129  // It's asserted that there will be corresponding entries for
130  // these types of terrain in the terrain configuration file.
131  extern const terrain_code VOID_TERRAIN;
132  extern const terrain_code FOGGED;
133 
134  // On the map the user can use this type to make odd shaped maps look good.
135  extern const terrain_code OFF_MAP_USER;
136 
137  extern const terrain_code HUMAN_CASTLE;
138  extern const terrain_code HUMAN_KEEP;
139  extern const terrain_code SHALLOW_WATER;
140  extern const terrain_code DEEP_WATER;
141  extern const terrain_code GRASS_LAND;
142  extern const terrain_code FOREST;
143  extern const terrain_code MOUNTAIN;
144  extern const terrain_code HILL;
145 
146  extern const terrain_code CAVE_WALL;
147  extern const terrain_code CAVE;
148  extern const terrain_code UNDERGROUND_VILLAGE;
149  extern const terrain_code DWARVEN_CASTLE;
150  extern const terrain_code DWARVEN_KEEP;
151 
152  extern const terrain_code PLUS; // +
153  extern const terrain_code MINUS; // -
154  extern const terrain_code NOT; // !
155  extern const terrain_code STAR; // *
156  extern const terrain_code BASE; // references the base terrain in movement/defense aliases
157 
158  extern const ter_match ALL_OFF_MAP;
159  extern const ter_match ALL_FORESTS;
160  extern const ter_match ALL_HILLS;
161  extern const ter_match ALL_MOUNTAINS; //excluding impassable mountains
162  extern const ter_match ALL_SWAMPS;
163 
164  /**
165  * Reads a single terrain from a string.
166  *
167  * @param str The string which should contain 1 terrain code;
168  the new format of a terrain code
169  * is 2 to 4 characters in the set
170  *@verbatim
171  * [a-Z][A-Z]/|\_
172  *@endverbatim
173  * The underscore is intended for internal use.
174  * Other letters and characters are not validated but
175  * users of these letters can get nasty surprises.
176  * The * is used as wildcard in some cases.
177  * The terrain code can be two groups separated by a caret,
178  * the first group is the base terrain,
179  * the second the overlay terrain.
180  *
181  * @param filler if there's no layer this value will be used as the second layer
182  *
183  * @return A single terrain code
184  */
185  terrain_code read_terrain_code(std::string_view str, const ter_layer filler = NO_LAYER);
186 
187  /**
188  * Writes a single terrain code to a string.
189  * The writers only support the new format.
190  *
191  * @param tcode The terrain code to convert to a string
192  *
193  * @return A string containing the terrain code
194  */
195  std::string write_terrain_code(const terrain_code& tcode);
196  inline std::ostream &operator<<(std::ostream &s, const terrain_code &a)
197  { s << write_terrain_code(a); return s; }
198 
199  /**
200  * Reads a list of terrains from a string, when reading the
201  *
202  * @param str A string with one or more terrain codes (see read_terrain_code)
203  * @param filler If there's no layer, this value will be used as the second layer
204  *
205  * @returns A vector which contains the terrain codes found in the string
206  */
207  ter_list read_list(std::string_view str, const ter_layer filler = NO_LAYER);
208 
209  /**
210  * Writes a list of terrains to a string, only writes the new format.
211  *
212  * @param list A vector with one or more terrain codes
213  *
214  * @returns A string with the terrain codes, comma separated
215  * and a space behind the commas. Not padded.
216  */
217  std::string write_list(const ter_list& list);
218 
219  using starting_positions = boost::bimaps::bimap<boost::bimaps::set_of<std::string>, boost::bimaps::multiset_of<coordinate>>;
220  /**
221  * Reads a gamemap string into a 2D vector
222  *
223  * @param str A string containing the gamemap, the following rules
224  * are stated for a gamemap:
225  * * The map is square
226  * * The map can be prefixed with one or more empty lines,
227  * these lines are ignored
228  * * The map can be postfixed with one or more empty lines,
229  * these lines are ignored
230  * * Every end of line can be followed by one or more empty
231  * lines, these lines are ignored.
232  * @deprecated NOTE it's deprecated to use this feature.
233  * * Terrain strings are separated by comma's or an end of line
234  * symbol, for the last terrain string in the row. For
235  * readability it's allowed to pad strings with either spaces
236  * or tab, however the tab is deprecated.
237  * * A terrain string contains either a terrain or a terrain and
238  * starting location. The following format is used
239  * [S ]T
240  * S = starting location a positive non-zero number
241  * T = terrain code (see read_terrain_code)
242  * @param positions This parameter will be filled with the starting
243  * locations found. Starting locations can only occur once
244  * if multiple definitions occur of the same position only
245  * the last is stored. The returned value is a map:
246  * * first the starting locations
247  * * second a coordinate structure where the location was found
248  * @param border_offset
249  *
250  * @returns A 2D vector with the terrains found the vector data is stored
251  * like result[x][y] where x the column number is and y the row number.
252  */
253  ter_map read_game_map(std::string_view str, starting_positions& positions, coordinate border_offset = coordinate{ 0, 0 });
254 
255  /**
256  * Write a gamemap in to a vector string.
257  *
258  * @param map A terrain vector, as returned from read_game_map
259  * @param positions A starting positions map, as returned from read_game_map
260  * @param border_offset
261  *
262  * @returns A terrain string which can be read with read_game_map.
263  * For readability the map is padded to groups of 12 chars,
264  * followed by a comma and space.
265  */
266  std::string write_game_map(const ter_map& map, const starting_positions& positions = starting_positions(), coordinate border_offset = coordinate{ 0, 0 });
267 
268  /**
269  * Tests whether a specific terrain matches a list of expressions.
270  * The list can use wildcard matching with *.
271  * It also has an inversion function.
272  * When a ! is found the result of the match is inverted.
273  * The matching stops at the first match (regardless of the ! found)
274  * the data is match from start to end.
275  *
276  * Example:
277  * Ww, W* does match and returns true
278  * Ww, {!, W*} does match and returns false (due to the !)
279  * WW, Ww doesn't match and return false
280  *
281  * Multilayer rules:
282  * If a terrain has multiple layers, each layer will be matched separately,
283  * returning true only if both layers match.
284  *
285  * Example:
286  * A*^* matches Abcd but also Abcd^Abcd
287  * A*^ matches Abcd but *not* Abcd^Abcd
288  * A*^Abcd does not match Abcd but matches Abcd^Abcd
289  *
290  * Note: If an expression doesn't specify a second layer (i.e. it contains
291  * no caret) the second layer will be filled in with a default value
292  * (See read_terrain_code and read_list).
293  *
294  * In the terrain building code, the second layer will default to the wildcard,
295  * so both A* and A*^* will match Abcd^Abcd
296  *
297  * @param src the value to match (may not contain wildcards)
298  * @param dest the list of expressions to match against
299  *
300  * @returns the result of the match (depending on the !'s)
301  */
302  bool terrain_matches(const terrain_code& src, const ter_list& dest);
303 
304  /**
305  * Tests whether a specific terrain matches an expression,
306  * for matching rules see above.
307  *
308  * @param src the value to match (may not contain wildcards)
309  * @param dest the expression to match against
310  *
311  * @returns the result of the match (depending on the !'s)
312  */
313  bool terrain_matches(const terrain_code& src, const terrain_code& dest);
314 
315  /**
316  * Tests whether a certain terrain matches a list of expressions, for matching
317  * rules see above. The matching requires some bit mask which impose a
318  * certain overhead. This version uses a cache to cache the masks so if
319  * a list needs to be matched often this version is preferred.
320  *
321  * @param src the value to match (may not contain wildcards)
322  * @param dest the cached list of expressions to match against
323  *
324  * @returns the result of the match (depending on the !'s)
325  */
326  bool terrain_matches(const terrain_code& src, const ter_match& dest);
327 
328  /**
329  * Tests whether a terrain code contains a wildcard
330  *
331  * @param tcode the terrain code to test for a wildcard
332  *
333  * @returns true if wildcard found, else false
334  */
335  bool has_wildcard(const terrain_code& tcode);
336 
337  /**
338  * Tests whether a terrain-code list contains at least
339  * one item with a wildcard
340  *
341  * @param list the list to test for a wildcard
342  *
343  * @returns true if a wildcard found, else false
344  */
345  bool has_wildcard(const ter_list& list);
346 
347  // These terrain letters are in the builder format,
348  // and not usable in other parts of the engine
349  const ter_layer TB_STAR = '*' << 24; // It can be assumed this is the equivalent of STAR
350  const ter_layer TB_DOT = '.' << 24;
351 
352  /**
353  * Reads a builder map.
354  * A builder map differs a great deal from a normal map,
355  * hence the different functions.
356  *
357  * @param str The map data, a terrain letter is either a * or a . or a number as
358  * anchor. The star or dot are stored in the base part of the terrain
359  * and the anchor in the overlay part. If more letters are allowed as
360  * special case they will be stored in the base part.
361  * Anchor 0 is no anchor.
362  *
363  * @returns A 2D vector with the data found the vector data is stored
364  * like result[y][x] where x the column number is and y the row number.
365  */
366  ter_map read_builder_map(const std::string& str);
367 
368 } // end namespace t_translation
const terrain_code CAVE
ter_map(int w, int h, terrain_code fill=terrain_code())
Definition: translation.hpp:85
const terrain_code NONE_TERRAIN
Definition: translation.hpp:59
const terrain_code FOREST
boost::bimaps::bimap< boost::bimaps::set_of< std::string >, boost::bimaps::multiset_of< coordinate > > starting_positions
const terrain_code DWARVEN_KEEP
error(const std::string &message)
bool terrain_matches(const terrain_code &src, const terrain_code &dest)
Tests whether a specific terrain matches an expression, for matching rules see above.
#define a
uint32_t ter_layer
Definition: translation.hpp:39
A terrain string which is converted to a terrain is a string with 1 or 2 layers the layers are separa...
Definition: translation.hpp:50
std::vector< terrain_code > data
Definition: translation.hpp:93
const ter_layer NO_LAYER
Definition: translation.hpp:41
#define h
ter_map read_game_map(std::string_view str, starting_positions &starting_positions, coordinate border_offset)
Reads a gamemap string into a 2D vector.
const terrain_code HUMAN_KEEP
const terrain_code HILL
const ter_match ALL_MOUNTAINS("!,*^V*,!,M*")
terrain_code read_terrain_code(std::string_view str, const ter_layer filler)
Reads a single terrain from a string.
terrain_code(ter_layer b, ter_layer o)
Definition: translation.hpp:53
const terrain_code VOID_TERRAIN
VOID_TERRAIN is used for shrouded hexes.
#define b
std::vector< terrain_code >::const_iterator operator[](int x) const
Definition: translation.hpp:97
int max_map_size()
Return the maximum allowed map size (in either dimension), the maximum map area is, therefore, this value squared.
Definition: translation.cpp:37
const terrain_code MOUNTAIN
std::ostream & operator<<(std::ostream &s, const terrain_code &a)
bool operator<(const terrain_code &a, const terrain_code &b)
Definition: translation.hpp:61
const terrain_code FOGGED
const terrain_code STAR
const terrain_code DWARVEN_CASTLE
const terrain_code MINUS
const ter_layer TB_STAR
const terrain_code PLUS
const terrain_code NOT
const ter_layer TB_DOT
const ter_match ALL_HILLS("!,*^V*,!,H*")
const terrain_code OFF_MAP_USER
std::string write_terrain_code(const terrain_code &tcode)
Writes a single terrain code to a string.
const terrain_code HUMAN_CASTLE
terrain_code operator &(const terrain_code &a, const terrain_code &b)
Definition: translation.hpp:70
Encapsulates the map of the game.
Definition: location.hpp:38
std::vector< terrain_code >::iterator operator[](int x)
Definition: translation.hpp:96
const terrain_code BASE
const ter_match ALL_SWAMPS("!,*^V*,*^B*,!,S*")
bool operator==(const terrain_code &a, const terrain_code &b)
Definition: translation.hpp:64
terrain_code operator|(const terrain_code &a, const terrain_code &b)
Definition: translation.hpp:73
static map_location::DIRECTION s
ter_map read_builder_map(const std::string &str)
Reads a builder map.
bool operator!=(const terrain_code &a, const terrain_code &b)
Definition: translation.hpp:67
std::string write_list(const ter_list &list)
Writes a list of terrains to a string, only writes the new format.
int w
std::size_t index(const std::string &str, const std::size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
Definition: unicode.cpp:72
const terrain_code CAVE_WALL
bool has_wildcard(const terrain_code &tcode)
Tests whether a terrain code contains a wildcard.
std::string write_game_map(const ter_map &map, const starting_positions &starting_positions, coordinate border_offset)
Write a gamemap in to a vector string.
const terrain_code DEEP_WATER
const ter_match ALL_OFF_MAP
Base class for all the errors encountered by the engine.
Definition: exceptions.hpp:28
const terrain_code UNDERGROUND_VILLAGE
std::vector< terrain_code > ter_list
Definition: translation.hpp:78
const ter_layer WILDCARD
Definition: translation.hpp:40
const terrain_code SHALLOW_WATER
This structure can be used for matching terrain strings.
std::string::const_iterator iterator
Definition: tokenizer.hpp:25
const terrain_code GRASS_LAND
ter_list read_list(std::string_view str, const ter_layer filler)
Reads a list of terrains from a string, when reading the.
const ter_match ALL_FORESTS