BattleHexArray.h 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. /*
  2. * BattleHexArray.h, part of VCMI engine
  3. *
  4. * Authors: listed in file AUTHORS in main folder
  5. *
  6. * License: GNU General Public License v2.0 or later
  7. * Full text of license available in license.txt file, in main folder
  8. *
  9. */
  10. #pragma once
  11. #include "BattleHex.h"
  12. #include <boost/container/small_vector.hpp>
  13. #include <vstd/RNG.h>
  14. VCMI_LIB_NAMESPACE_BEGIN
  15. /**
  16. * @brief Class representing a collection of unique, valid BattleHex objects.
  17. * The BattleHexArray is a specialized container designed for storing instances
  18. * of BattleHex. Key notes:
  19. * - Each BattleHex in the array is unique.
  20. * - Invalid BattleHex objects (e.g., those with an out-of-bounds or special
  21. * value) cannot be inserted into the array.
  22. * - Maintains an efficient storage mechanism for fast access and presence tracking system using bitset for quick existence checks.
  23. * - Attempting to insert invalid BattleHex objects will have no effect.
  24. *
  25. */
  26. class DLL_LINKAGE BattleHexArray
  27. {
  28. public:
  29. static constexpr uint8_t totalSize = GameConstants::BFIELD_SIZE;
  30. using StorageType = boost::container::small_vector<BattleHex, 8>;
  31. using ArrayOfBattleHexArrays = std::array<BattleHexArray, totalSize>;
  32. using value_type = BattleHex;
  33. using size_type = StorageType::size_type;
  34. using reference = value_type &;
  35. using const_reference = const value_type &;
  36. using pointer = value_type *;
  37. using const_pointer = const value_type *;
  38. using difference_type = typename StorageType::difference_type;
  39. using const_iterator = typename StorageType::const_iterator;
  40. using const_reverse_iterator = typename StorageType::const_reverse_iterator;
  41. BattleHexArray() = default;
  42. template <typename Container, typename = std::enable_if_t<
  43. std::is_convertible_v<typename Container::value_type, BattleHex>>>
  44. BattleHexArray(const Container & container) noexcept
  45. : BattleHexArray()
  46. {
  47. for(auto value : container)
  48. {
  49. insert(value);
  50. }
  51. }
  52. void resize(size_type size)
  53. {
  54. clear();
  55. internalStorage.resize(size);
  56. }
  57. BattleHexArray(std::initializer_list<BattleHex> initList) noexcept;
  58. void checkAndPush(const BattleHex & tile)
  59. {
  60. if(tile.isAvailable() && !contains(tile))
  61. {
  62. presenceFlags.set(tile.toInt());
  63. internalStorage.emplace_back(tile);
  64. }
  65. }
  66. void insert(const BattleHex & hex) noexcept
  67. {
  68. if(contains(hex))
  69. return;
  70. presenceFlags.set(hex.toInt());
  71. internalStorage.emplace_back(hex);
  72. }
  73. void set(size_type index, const BattleHex & hex)
  74. {
  75. if(index >= internalStorage.size())
  76. {
  77. logGlobal->error("Invalid BattleHexArray::set index parameter. It is " + std::to_string(index)
  78. + " and current size is " + std::to_string(internalStorage.size()));
  79. throw std::out_of_range("Invalid BattleHexArray::set index parameter. It is " + std::to_string(index)
  80. + " and current size is " + std::to_string(internalStorage.size()));
  81. }
  82. if(contains(hex))
  83. return;
  84. presenceFlags.set(hex.toInt());
  85. internalStorage[index] = hex;
  86. }
  87. void insert(const BattleHexArray & other) noexcept;
  88. template <typename Container, typename = std::enable_if_t<
  89. std::is_convertible_v<typename Container::value_type, BattleHex>>>
  90. void insert(const Container & container) noexcept
  91. {
  92. for(auto value : container)
  93. {
  94. insert(value);
  95. }
  96. }
  97. template<typename Predicate>
  98. void sort(Predicate pred)
  99. {
  100. std::sort(internalStorage.begin(), internalStorage.end(), pred);
  101. }
  102. template<typename Predicate>
  103. void eraseIf(Predicate pred)
  104. {
  105. vstd::erase_if(internalStorage, pred);
  106. // reinit presence flags
  107. presenceFlags = {};
  108. for(const auto & hex : internalStorage)
  109. presenceFlags.set(hex.toInt());
  110. }
  111. void shuffle(vstd::RNG & rand)
  112. {
  113. int64_t n = internalStorage.size();
  114. for(int64_t i = n - 1; i > 0; --i)
  115. {
  116. auto randIndex = rand.nextInt64(0, i);
  117. std::swap(internalStorage[i], internalStorage[randIndex]);
  118. }
  119. }
  120. void clear() noexcept;
  121. inline void erase(const BattleHex & target) noexcept
  122. {
  123. assert(contains(target));
  124. vstd::erase(internalStorage, target);
  125. presenceFlags.reset(target.toInt());
  126. }
  127. inline void pop_back() noexcept
  128. {
  129. presenceFlags.reset(internalStorage.back().toInt());
  130. internalStorage.pop_back();
  131. }
  132. inline std::vector<BattleHex> toVector() const noexcept
  133. {
  134. return std::vector<BattleHex>(internalStorage.begin(), internalStorage.end());
  135. }
  136. [[nodiscard]] std::string toString(const std::string & delimiter = ", ") const noexcept
  137. {
  138. std::string result = "[";
  139. for(auto it = internalStorage.begin(); it != internalStorage.end(); ++it)
  140. {
  141. if(it != internalStorage.begin())
  142. result += delimiter;
  143. result += std::to_string(it->toInt());
  144. }
  145. result += "]";
  146. return result;
  147. }
  148. template <typename Predicate>
  149. const_iterator findIf(Predicate predicate) const noexcept
  150. {
  151. return std::find_if(begin(), end(), predicate);
  152. }
  153. template <typename Predicate>
  154. BattleHexArray filterBy(Predicate predicate) const noexcept
  155. {
  156. BattleHexArray filtered;
  157. for(const auto & hex : internalStorage)
  158. {
  159. if(predicate(hex))
  160. {
  161. filtered.insert(hex);
  162. }
  163. }
  164. return filtered;
  165. }
  166. /// get (precomputed) all possible surrounding tiles
  167. static const BattleHexArray & getAllNeighbouringTiles(const BattleHex & hex) noexcept
  168. {
  169. static const BattleHexArray invalid;
  170. if (hex.isValid())
  171. return allNeighbouringTiles[hex.toInt()];
  172. else
  173. return invalid;
  174. }
  175. /// get (precomputed) only valid and available surrounding tiles
  176. static const BattleHexArray & getNeighbouringTiles(const BattleHex & hex) noexcept
  177. {
  178. static const BattleHexArray invalid;
  179. if (hex.isValid())
  180. return neighbouringTiles[hex.toInt()];
  181. else
  182. return invalid;
  183. }
  184. /// get (precomputed) only valid and available surrounding tiles for double wide creatures
  185. static const BattleHexArray & getNeighbouringTilesDoubleWide(const BattleHex & hex, BattleSide side) noexcept
  186. {
  187. assert(hex.isValid() && (side == BattleSide::ATTACKER || side == BattleSide::DEFENDER));
  188. return neighbouringTilesDoubleWide.at(side)[hex.toInt()];
  189. }
  190. /// note: returns true when param is ivalid BattleHex
  191. [[nodiscard]] inline bool contains(const BattleHex & hex) const noexcept
  192. {
  193. if(hex.isValid())
  194. return presenceFlags.test(hex.toInt());
  195. return true;
  196. }
  197. template <typename Serializer>
  198. void serialize(Serializer & s)
  199. {
  200. s & internalStorage;
  201. if(!s.saving)
  202. {
  203. for(const auto & hex : internalStorage)
  204. presenceFlags.set(hex.toInt());
  205. }
  206. }
  207. [[nodiscard]] inline const BattleHex & back() const noexcept
  208. {
  209. return internalStorage.back();
  210. }
  211. [[nodiscard]] inline const BattleHex & front() const noexcept
  212. {
  213. return internalStorage.front();
  214. }
  215. [[nodiscard]] inline const BattleHex & operator[](size_type index) const noexcept
  216. {
  217. return internalStorage[index];
  218. }
  219. [[nodiscard]] inline const BattleHex & at(size_type index) const
  220. {
  221. return internalStorage.at(index);
  222. }
  223. [[nodiscard]] inline size_type size() const noexcept
  224. {
  225. return internalStorage.size();
  226. }
  227. [[nodiscard]] inline const_iterator begin() const noexcept
  228. {
  229. return internalStorage.begin();
  230. }
  231. [[nodiscard]] inline bool empty() const noexcept
  232. {
  233. return internalStorage.empty();
  234. }
  235. [[nodiscard]] inline const_iterator end() const noexcept
  236. {
  237. return internalStorage.end();
  238. }
  239. [[nodiscard]] inline const_reverse_iterator rbegin() const noexcept
  240. {
  241. return const_reverse_iterator(end());
  242. }
  243. [[nodiscard]] inline const_reverse_iterator rend() const noexcept
  244. {
  245. return const_reverse_iterator(begin());
  246. }
  247. bool operator ==(const BattleHexArray & other) const noexcept
  248. {
  249. if(internalStorage != other.internalStorage || presenceFlags != other.presenceFlags)
  250. return false;
  251. return true;
  252. }
  253. private:
  254. StorageType internalStorage;
  255. std::bitset<totalSize> presenceFlags;
  256. static const ArrayOfBattleHexArrays neighbouringTiles;
  257. static const ArrayOfBattleHexArrays allNeighbouringTiles;
  258. static const std::map<BattleSide, ArrayOfBattleHexArrays> neighbouringTilesDoubleWide;
  259. static ArrayOfBattleHexArrays precalculateNeighbouringTiles();
  260. static ArrayOfBattleHexArrays precalculateAllNeighbouringTiles();
  261. static ArrayOfBattleHexArrays precalculateNeighbouringTilesDoubleWide(BattleSide side);
  262. };
  263. VCMI_LIB_NAMESPACE_END