/* * BattleHexArray.cpp, 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 * */ #include "StdInc.h" #include "BattleHexArray.h" VCMI_LIB_NAMESPACE_BEGIN BattleHexArray::BattleHexArray(std::initializer_list initList) noexcept : BattleHexArray() { for(auto hex : initList) { insert(hex); } } BattleHex BattleHexArray::getClosestTile(BattleSide side, BattleHex initialPos) const { BattleHex initialHex = BattleHex(initialPos); auto compareDistance = [initialHex](const BattleHex left, const BattleHex right) -> bool { return initialHex.getDistance(initialHex, left) < initialHex.getDistance(initialHex, right); }; BattleHexArray sortedTiles(*this); boost::sort(sortedTiles, compareDistance); //closest tiles at front int closestDistance = initialHex.getDistance(initialPos, sortedTiles.front()); //sometimes closest tiles can be many hexes away auto notClosest = [closestDistance, initialPos](const BattleHex here) -> bool { return closestDistance < here.getDistance(initialPos, here); }; vstd::erase_if(sortedTiles, notClosest); //only closest tiles are interesting auto compareHorizontal = [side, initialPos](const BattleHex left, const BattleHex right) -> bool { if(left.getX() != right.getX()) { if(side == BattleSide::ATTACKER) return left.getX() > right.getX(); //find furthest right else return left.getX() < right.getX(); //find furthest left } else { //Prefer tiles in the same row. return std::abs(left.getY() - initialPos.getY()) < std::abs(right.getY() - initialPos.getY()); } }; boost::sort(sortedTiles, compareHorizontal); return sortedTiles.front(); } BattleHexArray::NeighbouringTilesCache BattleHexArray::calculateNeighbouringTiles() { BattleHexArray::NeighbouringTilesCache ret; for(si16 hex = 0; hex < GameConstants::BFIELD_SIZE; hex++) { BattleHexArray hexes = BattleHexArray::generateNeighbouringTiles(hex); size_t index = 0; ret[hex].resize(hexes.size()); for(auto neighbour : hexes) ret[hex].set(index++, neighbour); } return ret; } BattleHexArray BattleHexArray::generateNeighbouringTiles(BattleHex hex) { BattleHexArray ret; for(auto dir : BattleHex::hexagonalDirections()) ret.checkAndPush(hex.cloneInDirection(dir, false)); return ret; } BattleHexArray BattleHexArray::generateAttackerClosestTilesCache() { assert(!neighbouringTilesCache.empty()); BattleHexArray ret; ret.resize(GameConstants::BFIELD_SIZE); for(si16 hex = 0; hex < GameConstants::BFIELD_SIZE; hex++) { ret.set(hex, neighbouringTilesCache[hex].getClosestTile(BattleSide::ATTACKER, hex)); } return ret; } BattleHexArray BattleHexArray::generateDefenderClosestTilesCache() { assert(!neighbouringTilesCache.empty()); BattleHexArray ret; ret.resize(GameConstants::BFIELD_SIZE); for(si16 hex = 0; hex < GameConstants::BFIELD_SIZE; hex++) { ret.set(hex, neighbouringTilesCache[hex].getClosestTile(BattleSide::DEFENDER, hex)); } return ret; } BattleHex BattleHexArray::getClosestTileFromAllPossibleNeighbours(BattleSide side, BattleHex pos) { if(side == BattleSide::ATTACKER) return closestTilesCacheForAttacker[pos.hex]; else if(side == BattleSide::DEFENDER) return closestTilesCacheForDefender[pos.hex]; else assert(false); // we should never be here } void BattleHexArray::merge(const BattleHexArray & other) noexcept { for(auto hex : other) { insert(hex); } } void BattleHexArray::erase(iterator first, iterator last) noexcept { for(auto it = first; it != last && it != internalStorage.end(); ++it) { presenceFlags[*it] = 0; } internalStorage.erase(first, last); } void BattleHexArray::clear() noexcept { for(auto hex : internalStorage) presenceFlags[hex] = 0; internalStorage.clear(); } const BattleHexArray::NeighbouringTilesCache BattleHexArray::neighbouringTilesCache = calculateNeighbouringTiles(); const BattleHexArray BattleHexArray::closestTilesCacheForAttacker = generateAttackerClosestTilesCache(); const BattleHexArray BattleHexArray::closestTilesCacheForDefender = generateDefenderClosestTilesCache(); VCMI_LIB_NAMESPACE_END