The Battle for Wesnoth  1.15.0-dev
translation.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2006 - 2018 by Mark de Wever <koraq@xs4all.nl>
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 #include <vector>
20 #include <map>
21 #include <cstdint>
22 #include <boost/bimap.hpp>
23 #include <boost/bimap/set_of.hpp>
24 #include <boost/bimap/multiset_of.hpp>
25 #include <boost/multi_array.hpp>
26 
27 #include "exceptions.hpp"
28 #include "map/location.hpp"
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  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(const std::string& 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(const std::string& 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(utils::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  *
249  * @returns A 2D vector with the terrains found the vector data is stored
250  * like result[x][y] where x the column number is and y the row number.
251  */
252  ter_map read_game_map(const std::string& str, starting_positions& positions, coordinate border_offset = coordinate{ 0, 0 });
253 
254  /**
255  * Write a gamemap in to a vector string.
256  *
257  * @param map A terrain vector, as returned from read_game_map
258  * @param positions A starting positions map, as returned from read_game_map
259  *
260  * @returns A terrain string which can be read with read_game_map.
261  * For readability the map is padded to groups of 12 chars,
262  * followed by a comma and space.
263  */
264  std::string write_game_map(const ter_map& map, const starting_positions& positions = starting_positions(), coordinate border_offset = coordinate{ 0, 0 });
265 
266  /**
267  * Tests whether a specific terrain matches a list of expressions.
268  * The list can use wildcard matching with *.
269  * It also has an inversion function.
270  * When a ! is found the result of the match is inverted.
271  * The matching stops at the first match (regardless of the ! found)
272  * the data is match from start to end.
273  *
274  * Example:
275  * Ww, W* does match and returns true
276  * Ww, {!, W*} does match and returns false (due to the !)
277  * WW, Ww doesn't match and return false
278  *
279  * Multilayer rules:
280  * If a terrain has multiple layers, each layer will be matched separately,
281  * returning true only if both layers match.
282  *
283  * Example:
284  * A*^* matches Abcd but also Abcd^Abcd
285  * A*^ matches Abcd but *not* Abcd^Abcd
286  * A*^Abcd does not match Abcd but matches Abcd^Abcd
287  *
288  * Note: If an expression doesn't specify a second layer (i.e. it contains
289  * no caret) the second layer will be filled in with a default value
290  * (See read_terrain_code and read_list).
291  *
292  * In the terrain building code, the second layer will default to the wildcard,
293  * so both A* and A*^* will match Abcd^Abcd
294  *
295  * @param src the value to match (may not contain wildcards)
296  * @param dest the list of expressions to match against
297  *
298  * @returns the result of the match (depending on the !'s)
299  */
300  bool terrain_matches(const terrain_code& src, const ter_list& dest);
301 
302  /**
303  * Tests whether a specific terrain matches an expression,
304  * for matching rules see above.
305  *
306  * @param src the value to match (may not contain wildcards)
307  * @param dest the expression to match against
308  *
309  * @returns the result of the match (depending on the !'s)
310  */
311  bool terrain_matches(const terrain_code& src, const terrain_code& dest);
312 
313  /**
314  * Tests whether a certain terrain matches a list of expressions, for matching
315  * rules see above. The matching requires some bit mask which impose a
316  * certain overhead. This version uses a cache to cache the masks so if
317  * a list needs to be matched often this version is preferred.
318  *
319  * @param src the value to match (may not contain wildcards)
320  * @param dest the cached list of expressions to match against
321  *
322  * @returns the result of the match (depending on the !'s)
323  */
324  bool terrain_matches(const terrain_code& src, const ter_match& dest);
325 
326  /**
327  * Tests whether a terrain code contains a wildcard
328  *
329  * @param tcode the terrain code to test for a wildcard
330  *
331  * @returns true if wildcard found, else false
332  */
333  bool has_wildcard(const terrain_code& tcode);
334 
335  /**
336  * Tests whether a terrain-code list contains at least
337  * one item with a wildcard
338  *
339  * @param list the list to test for a wildcard
340  *
341  * @returns true if a wildcard found, else false
342  */
343  bool has_wildcard(const ter_list& list);
344 
345  // These terrain letters are in the builder format,
346  // and not usable in other parts of the engine
347  const ter_layer TB_STAR = '*' << 24; // It can be assumed this is the equivalent of STAR
348  const ter_layer TB_DOT = '.' << 24;
349 
350  /**
351  * Reads a builder map.
352  * A builder map differs a great deal from a normal map,
353  * hence the different functions.
354  *
355  * @param str The map data, a terrain letter is either a * or a . or a number as
356  * anchor. The star or dot are stored in the base part of the terrain
357  * and the anchor in the overlay part. If more letters are allowed as
358  * special case they will be stored in the base part.
359  * Anchor 0 is no anchor.
360  *
361  * @returns A 2D vector with the data found the vector data is stored
362  * like result[y][x] where x the column number is and y the row number.
363  */
364  ter_map read_builder_map(const std::string& str);
365 
366 } // 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
const terrain_code HUMAN_KEEP
const terrain_code HILL
const ter_match ALL_MOUNTAINS("!,*^V*,!,M*")
terrain_code(ter_layer b, ter_layer o)
Definition: translation.hpp:53
const terrain_code VOID_TERRAIN
#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:35
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:42
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
ter_map read_game_map(const std::string &str, starting_positions &starting_positions, coordinate border_offset)
Reads a gamemap string into a 2D vector.
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:71
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:29
const terrain_code UNDERGROUND_VILLAGE
ter_list read_list(utils::string_view str, const ter_layer filler)
Reads a list of terrains from a string, when reading the.
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:24
const terrain_code GRASS_LAND
terrain_code read_terrain_code(const std::string &str, const ter_layer filler)
Reads a single terrain from a string.
const ter_match ALL_FORESTS