2024-09-28 20:50:26 +02:00
|
|
|
/*
|
|
|
|
* BattleHexArray.h, part of VCMI engine
|
|
|
|
*
|
|
|
|
* Authors: listed in file AUTHORS in main folder
|
|
|
|
*
|
|
|
|
* License: GNU General Public License v2.0 or later
|
|
|
|
* Full text of license available in license.txt file, in main folder
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include "BattleHex.h"
|
2025-01-02 12:11:18 +01:00
|
|
|
#include <boost/container/small_vector.hpp>
|
2024-09-28 20:50:26 +02:00
|
|
|
|
|
|
|
VCMI_LIB_NAMESPACE_BEGIN
|
|
|
|
|
|
|
|
/// Class representing an array of unique BattleHex objects
|
|
|
|
class DLL_LINKAGE BattleHexArray
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
static constexpr uint8_t totalSize = GameConstants::BFIELD_SIZE;
|
2025-01-02 12:11:18 +01:00
|
|
|
using StorageType = boost::container::small_vector<BattleHex, 8>;
|
2024-09-28 20:50:26 +02:00
|
|
|
|
|
|
|
using value_type = BattleHex;
|
|
|
|
using size_type = StorageType::size_type;
|
|
|
|
using reference = value_type &;
|
|
|
|
using const_reference = const value_type &;
|
|
|
|
using pointer = value_type *;
|
|
|
|
using const_pointer = const value_type *;
|
|
|
|
using difference_type = typename StorageType::difference_type;
|
|
|
|
using iterator = typename StorageType::iterator;
|
|
|
|
using const_iterator = typename StorageType::const_iterator;
|
|
|
|
using reverse_iterator = typename StorageType::reverse_iterator;
|
|
|
|
using const_reverse_iterator = typename StorageType::const_reverse_iterator;
|
|
|
|
|
2024-12-04 21:37:31 +01:00
|
|
|
using ArrayOfBattleHexArrays = std::array<BattleHexArray, GameConstants::BFIELD_SIZE>;
|
2024-09-28 20:50:26 +02:00
|
|
|
|
2024-12-04 21:37:31 +01:00
|
|
|
static const ArrayOfBattleHexArrays neighbouringTilesCache;
|
2024-12-06 19:59:05 +01:00
|
|
|
static const std::map<BattleSide, ArrayOfBattleHexArrays> neighbouringTilesDblWide;
|
2024-09-28 20:50:26 +02:00
|
|
|
|
2025-01-02 12:11:18 +01:00
|
|
|
BattleHexArray() = default;
|
2024-09-28 20:50:26 +02:00
|
|
|
|
|
|
|
template <typename Container, typename = std::enable_if_t<
|
|
|
|
std::is_convertible_v<typename Container::value_type, BattleHex>>>
|
|
|
|
BattleHexArray(const Container & container) noexcept
|
|
|
|
: BattleHexArray()
|
|
|
|
{
|
|
|
|
for(auto value : container)
|
|
|
|
{
|
|
|
|
insert(value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void resize(size_type size)
|
|
|
|
{
|
|
|
|
clear();
|
|
|
|
internalStorage.resize(size);
|
|
|
|
}
|
|
|
|
|
|
|
|
BattleHexArray(std::initializer_list<BattleHex> initList) noexcept;
|
|
|
|
|
|
|
|
/// returns all tiles, unavailable tiles will be set as invalid
|
|
|
|
/// order of returned tiles matches EDir enum
|
2024-12-05 22:01:13 +01:00
|
|
|
static BattleHexArray getAllNeighbouringTiles(BattleHex hex)
|
2024-09-28 20:50:26 +02:00
|
|
|
{
|
2024-12-05 22:01:13 +01:00
|
|
|
static ArrayOfBattleHexArrays cache;
|
|
|
|
static bool initialized = false;
|
2024-09-28 20:50:26 +02:00
|
|
|
|
2024-12-05 22:01:13 +01:00
|
|
|
if(initialized)
|
|
|
|
return cache[hex.hex];
|
2024-09-28 20:50:26 +02:00
|
|
|
|
2024-12-05 22:01:13 +01:00
|
|
|
for(BattleHex h = 0; h < GameConstants::BFIELD_SIZE; h.hex++)
|
|
|
|
{
|
|
|
|
cache[h].resize(6);
|
|
|
|
|
|
|
|
for(auto dir : BattleHex::hexagonalDirections())
|
|
|
|
cache[h].set(dir, h.cloneInDirection(dir, false));
|
|
|
|
}
|
|
|
|
initialized = true;
|
2024-09-28 20:50:26 +02:00
|
|
|
|
2024-12-05 22:01:13 +01:00
|
|
|
return cache[hex.hex];
|
2024-09-28 20:50:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void checkAndPush(BattleHex tile)
|
|
|
|
{
|
|
|
|
if(tile.isAvailable() && !contains(tile))
|
|
|
|
{
|
|
|
|
presenceFlags[tile] = 1;
|
|
|
|
internalStorage.emplace_back(tile);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void insert(BattleHex hex) noexcept
|
|
|
|
{
|
|
|
|
if(contains(hex))
|
|
|
|
return;
|
|
|
|
|
|
|
|
presenceFlags[hex] = 1;
|
|
|
|
internalStorage.emplace_back(hex);
|
|
|
|
}
|
|
|
|
|
|
|
|
void set(size_type index, BattleHex hex)
|
|
|
|
{
|
2024-11-04 13:27:19 +01:00
|
|
|
if(index >= internalStorage.size())
|
|
|
|
{
|
|
|
|
logGlobal->error("Invalid BattleHexArray::set index parameter. It is " + std::to_string(index)
|
|
|
|
+ " and current size is " + std::to_string(internalStorage.size()));
|
|
|
|
throw std::out_of_range("Invalid BattleHexArray::set index parameter. It is " + std::to_string(index)
|
|
|
|
+ " and current size is " + std::to_string(internalStorage.size()));
|
|
|
|
}
|
|
|
|
|
2024-09-28 20:50:26 +02:00
|
|
|
if(contains(hex))
|
|
|
|
return;
|
|
|
|
|
|
|
|
presenceFlags[hex] = 1;
|
|
|
|
internalStorage[index] = hex;
|
|
|
|
}
|
|
|
|
|
2025-01-02 12:11:18 +01:00
|
|
|
iterator insert(iterator pos, BattleHex hex) noexcept
|
2024-09-28 20:50:26 +02:00
|
|
|
{
|
|
|
|
if(contains(hex))
|
|
|
|
return pos;
|
|
|
|
|
|
|
|
presenceFlags[hex] = 1;
|
|
|
|
return internalStorage.insert(pos, hex);
|
|
|
|
}
|
|
|
|
|
2024-11-04 13:27:19 +01:00
|
|
|
BattleHex getClosestTile(BattleSide side, BattleHex initialPos) const;
|
|
|
|
|
2025-01-02 12:11:18 +01:00
|
|
|
void insert(const BattleHexArray & other) noexcept;
|
2024-09-28 20:50:26 +02:00
|
|
|
|
2024-12-06 19:59:05 +01:00
|
|
|
template <typename Container, typename = std::enable_if_t<
|
|
|
|
std::is_convertible_v<typename Container::value_type, BattleHex>>>
|
2025-01-02 12:11:18 +01:00
|
|
|
void insert(const Container & container) noexcept
|
2024-12-06 19:59:05 +01:00
|
|
|
{
|
|
|
|
for(auto value : container)
|
|
|
|
{
|
|
|
|
insert(value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-28 20:50:26 +02:00
|
|
|
void clear() noexcept;
|
|
|
|
inline void erase(size_type index) noexcept
|
|
|
|
{
|
|
|
|
assert(index < totalSize);
|
|
|
|
internalStorage[index] = BattleHex::INVALID;
|
|
|
|
presenceFlags[index] = 0;
|
|
|
|
}
|
|
|
|
void erase(iterator first, iterator last) noexcept;
|
|
|
|
inline void pop_back() noexcept
|
|
|
|
{
|
|
|
|
presenceFlags[internalStorage.back()] = 0;
|
|
|
|
internalStorage.pop_back();
|
|
|
|
}
|
|
|
|
|
|
|
|
inline std::vector<BattleHex> toVector() const noexcept
|
|
|
|
{
|
2025-01-02 12:11:18 +01:00
|
|
|
return std::vector<BattleHex>(internalStorage.begin(), internalStorage.end());
|
2024-09-28 20:50:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
template <typename Predicate>
|
|
|
|
iterator findIf(Predicate predicate) noexcept
|
|
|
|
{
|
|
|
|
return std::find_if(begin(), end(), predicate);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename Predicate>
|
|
|
|
const_iterator findIf(Predicate predicate) const noexcept
|
|
|
|
{
|
|
|
|
return std::find_if(begin(), end(), predicate);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename Predicate>
|
|
|
|
BattleHexArray filterBy(Predicate predicate) const noexcept
|
|
|
|
{
|
|
|
|
BattleHexArray filtered;
|
|
|
|
for(auto hex : internalStorage)
|
|
|
|
{
|
|
|
|
if(predicate(hex))
|
|
|
|
{
|
|
|
|
filtered.insert(hex);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return filtered;
|
|
|
|
}
|
|
|
|
|
2025-01-02 12:11:18 +01:00
|
|
|
[[nodiscard]] inline bool contains(BattleHex hex) const noexcept
|
2024-09-28 20:50:26 +02:00
|
|
|
{
|
|
|
|
if(hex.isValid())
|
|
|
|
return presenceFlags[hex];
|
|
|
|
/*
|
|
|
|
if(!isTower(hex))
|
|
|
|
logGlobal->warn("BattleHexArray::contains( %d ) - invalid BattleHex!", hex);
|
|
|
|
*/
|
|
|
|
|
2024-12-04 21:37:31 +01:00
|
|
|
// returns true also for invalid hexes
|
2024-09-28 20:50:26 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename Serializer>
|
|
|
|
void serialize(Serializer & s)
|
|
|
|
{
|
|
|
|
s & internalStorage;
|
|
|
|
if(!internalStorage.empty() && presenceFlags[internalStorage.front()] == 0)
|
|
|
|
{
|
|
|
|
for(auto hex : internalStorage)
|
|
|
|
presenceFlags[hex] = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-01-02 12:11:18 +01:00
|
|
|
[[nodiscard]] inline const BattleHex & back() const noexcept
|
2024-09-28 20:50:26 +02:00
|
|
|
{
|
|
|
|
return internalStorage.back();
|
|
|
|
}
|
|
|
|
|
2025-01-02 12:11:18 +01:00
|
|
|
[[nodiscard]] inline const BattleHex & front() const noexcept
|
2024-09-28 20:50:26 +02:00
|
|
|
{
|
|
|
|
return internalStorage.front();
|
|
|
|
}
|
|
|
|
|
2025-01-02 12:11:18 +01:00
|
|
|
[[nodiscard]] inline const BattleHex & operator[](size_type index) const noexcept
|
2024-09-28 20:50:26 +02:00
|
|
|
{
|
|
|
|
return internalStorage[index];
|
|
|
|
}
|
|
|
|
|
2025-01-02 12:11:18 +01:00
|
|
|
[[nodiscard]] inline const BattleHex & at(size_type index) const
|
2024-09-28 20:50:26 +02:00
|
|
|
{
|
|
|
|
return internalStorage.at(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
[[nodiscard]] inline size_type size() const noexcept
|
|
|
|
{
|
|
|
|
return internalStorage.size();
|
|
|
|
}
|
|
|
|
|
2025-01-02 12:11:18 +01:00
|
|
|
[[nodiscard]] inline iterator begin() noexcept
|
2024-09-28 20:50:26 +02:00
|
|
|
{
|
|
|
|
return internalStorage.begin();
|
|
|
|
}
|
|
|
|
|
2025-01-02 12:11:18 +01:00
|
|
|
[[nodiscard]] inline const_iterator begin() const noexcept
|
2024-09-28 20:50:26 +02:00
|
|
|
{
|
|
|
|
return internalStorage.begin();
|
|
|
|
}
|
|
|
|
|
2025-01-02 12:11:18 +01:00
|
|
|
[[nodiscard]] inline bool empty() const noexcept
|
2024-09-28 20:50:26 +02:00
|
|
|
{
|
|
|
|
return internalStorage.empty();
|
|
|
|
}
|
|
|
|
|
2025-01-02 12:11:18 +01:00
|
|
|
[[nodiscard]] inline iterator end() noexcept
|
2024-09-28 20:50:26 +02:00
|
|
|
{
|
|
|
|
return internalStorage.end();
|
|
|
|
}
|
|
|
|
|
2025-01-02 12:11:18 +01:00
|
|
|
[[nodiscard]] inline const_iterator end() const noexcept
|
2024-09-28 20:50:26 +02:00
|
|
|
{
|
|
|
|
return internalStorage.end();
|
|
|
|
}
|
|
|
|
|
2025-01-02 12:11:18 +01:00
|
|
|
[[nodiscard]] inline reverse_iterator rbegin() noexcept
|
2024-09-28 20:50:26 +02:00
|
|
|
{
|
|
|
|
return reverse_iterator(end());
|
|
|
|
}
|
|
|
|
|
2025-01-02 12:11:18 +01:00
|
|
|
[[nodiscard]] inline const_reverse_iterator rbegin() const noexcept
|
2024-09-28 20:50:26 +02:00
|
|
|
{
|
|
|
|
return const_reverse_iterator(end());
|
|
|
|
}
|
|
|
|
|
2025-01-02 12:11:18 +01:00
|
|
|
[[nodiscard]] inline reverse_iterator rend() noexcept
|
2024-09-28 20:50:26 +02:00
|
|
|
{
|
|
|
|
return reverse_iterator(begin());
|
|
|
|
}
|
|
|
|
|
2025-01-02 12:11:18 +01:00
|
|
|
[[nodiscard]] inline const_reverse_iterator rend() const noexcept
|
2024-09-28 20:50:26 +02:00
|
|
|
{
|
|
|
|
return const_reverse_iterator(begin());
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
StorageType internalStorage;
|
2024-12-13 01:03:05 +01:00
|
|
|
std::bitset<totalSize> presenceFlags = {};
|
2024-09-28 20:50:26 +02:00
|
|
|
|
2025-01-02 12:11:18 +01:00
|
|
|
[[nodiscard]] inline bool isNotValidForInsertion(BattleHex hex) const
|
2024-09-28 20:50:26 +02:00
|
|
|
{
|
|
|
|
if(isTower(hex))
|
|
|
|
return true;
|
|
|
|
if(!hex.isValid())
|
|
|
|
{
|
|
|
|
//logGlobal->warn("BattleHexArray::insert( %d ) - invalid BattleHex!", hex);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return contains(hex) || internalStorage.size() >= totalSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
[[nodiscard]] inline bool isTower(BattleHex hex) const
|
|
|
|
{
|
|
|
|
return hex == BattleHex::CASTLE_CENTRAL_TOWER || hex == BattleHex::CASTLE_UPPER_TOWER || hex == BattleHex::CASTLE_BOTTOM_TOWER;
|
|
|
|
}
|
2024-11-04 13:27:19 +01:00
|
|
|
|
|
|
|
/// returns all valid neighbouring tiles
|
2025-01-02 12:11:18 +01:00
|
|
|
static ArrayOfBattleHexArrays calculateNeighbouringTiles();
|
|
|
|
static ArrayOfBattleHexArrays calculateNeighbouringTilesDblWide(BattleSide side);
|
2024-11-04 13:27:19 +01:00
|
|
|
static BattleHexArray generateNeighbouringTiles(BattleHex hex);
|
2024-09-28 20:50:26 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
VCMI_LIB_NAMESPACE_END
|