/* * 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<BattleHex> initList) noexcept : BattleHexArray() { for(auto hex : initList) { insert(hex); } } BattleHex BattleHexArray::getClosestTile(BattleSide side, BattleHex initialPos) const { if(this->empty()) return BattleHex(); BattleHex initialHex = BattleHex(initialPos); int closestDistance = std::numeric_limits<int>::max(); BattleHexArray closestTiles; for(auto hex : internalStorage) { int distance = initialHex.getDistance(initialHex, hex); if(distance < closestDistance) { closestDistance = distance; closestTiles.clear(); closestTiles.insert(hex); } else if(distance == closestDistance) closestTiles.insert(hex); } auto compareHorizontal = [side, initialPos](const BattleHex & left, const BattleHex & right) { if(left.getX() != right.getX()) { return (side == BattleSide::ATTACKER) ? (left.getX() > right.getX()) : (left.getX() < right.getX()); } return std::abs(left.getY() - initialPos.getY()) < std::abs(right.getY() - initialPos.getY()); }; auto bestTile = std::min_element(closestTiles.begin(), closestTiles.end(), compareHorizontal); return (bestTile != closestTiles.end()) ? *bestTile : BattleHex(); //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