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