From 5f799d41b31cdf1f5174bb376836486b0fbe1458 Mon Sep 17 00:00:00 2001 From: MichalZr6 Date: Mon, 4 Nov 2024 13:27:19 +0100 Subject: [PATCH] Use cached neighbouring tiles where possible --- AI/BattleAI/BattleExchangeVariant.cpp | 5 +- AI/StupidAI/StupidAI.cpp | 2 +- lib/battle/BattleHexArray.cpp | 89 ++++++++++++++++++++++----- lib/battle/BattleHexArray.h | 35 ++++++----- lib/battle/CBattleInfoCallback.cpp | 8 +-- lib/battle/ReachabilityInfo.cpp | 2 +- lib/battle/Unit.cpp | 4 +- lib/spells/BattleSpellMechanics.cpp | 2 +- 8 files changed, 104 insertions(+), 43 deletions(-) diff --git a/AI/BattleAI/BattleExchangeVariant.cpp b/AI/BattleAI/BattleExchangeVariant.cpp index 2aba3c771..69bbb1a5f 100644 --- a/AI/BattleAI/BattleExchangeVariant.cpp +++ b/AI/BattleAI/BattleExchangeVariant.cpp @@ -959,8 +959,7 @@ std::vector BattleExchangeEvaluator::getOneTurnReachableUn if(hexStack && cb->battleMatchOwner(unit, hexStack, false)) { - BattleHexArray neighbours; - neighbours.generateNeighbouringTiles(hex); + const BattleHexArray & neighbours = BattleHexArray::neighbouringTilesCache[hex.hex]; for(BattleHex neighbour : neighbours) { reachable = unitReachability.distances.at(neighbour) <= radius; @@ -1022,7 +1021,7 @@ bool BattleExchangeEvaluator::checkPositionBlocksOurStacks(HypotheticBattle & hb if(hexStack && cb->battleMatchOwner(unit, hexStack, false)) { enemyUnit = true; - for(BattleHex neighbour : BattleHexArray::generateNeighbouringTiles(hex)) + for(BattleHex neighbour : BattleHexArray::neighbouringTilesCache[hex.hex]) { reachable = unitReachability.distances.at(neighbour) <= unitSpeed; diff --git a/AI/StupidAI/StupidAI.cpp b/AI/StupidAI/StupidAI.cpp index 79c28f41c..8ddab9b5c 100644 --- a/AI/StupidAI/StupidAI.cpp +++ b/AI/StupidAI/StupidAI.cpp @@ -107,7 +107,7 @@ static bool willSecondHexBlockMoreEnemyShooters(std::shared_ptr for(int i = 0; i < 2; i++) { - for (auto neighbour : BattleHexArray::generateNeighbouringTiles(i ? h2 : h1)) + for (auto neighbour : BattleHexArray::neighbouringTilesCache[i ? h2.hex : h1.hex]) if(const auto * s = cb->getBattle(battleID)->battleGetUnitByPos(neighbour)) if(s->isShooter()) shooters[i]++; diff --git a/lib/battle/BattleHexArray.cpp b/lib/battle/BattleHexArray.cpp index ddfa23609..261a2ef64 100644 --- a/lib/battle/BattleHexArray.cpp +++ b/lib/battle/BattleHexArray.cpp @@ -22,7 +22,7 @@ BattleHexArray::BattleHexArray(std::initializer_list initList) noexce } } -BattleHex BattleHexArray::getClosestTile(BattleSide side, BattleHex initialPos) +BattleHex BattleHexArray::getClosestTile(BattleSide side, BattleHex initialPos) const { BattleHex initialHex = BattleHex(initialPos); auto compareDistance = [initialHex](const BattleHex left, const BattleHex right) -> bool @@ -54,8 +54,76 @@ BattleHex BattleHexArray::getClosestTile(BattleSide side, BattleHex initialPos) }; 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) @@ -82,22 +150,9 @@ void BattleHexArray::clear() noexcept internalStorage.clear(); } -static BattleHexArray::NeighbouringTilesCache calculateNeighbouringTiles() -{ - BattleHexArray::NeighbouringTilesCache ret; - - for(si16 hex = 0; hex < GameConstants::BFIELD_SIZE; hex++) - { - auto hexes = BattleHexArray::generateNeighbouringTiles(hex); - - size_t index = 0; - for(auto neighbour : hexes) - ret[hex].at(index++) = neighbour; - } - - return ret; -} - const BattleHexArray::NeighbouringTilesCache BattleHexArray::neighbouringTilesCache = calculateNeighbouringTiles(); +const BattleHexArray BattleHexArray::closestTilesCacheForAttacker = generateAttackerClosestTilesCache(); +const BattleHexArray BattleHexArray::closestTilesCacheForDefender = generateDefenderClosestTilesCache(); + VCMI_LIB_NAMESPACE_END \ No newline at end of file diff --git a/lib/battle/BattleHexArray.h b/lib/battle/BattleHexArray.h index 81eb217c7..4c9810328 100644 --- a/lib/battle/BattleHexArray.h +++ b/lib/battle/BattleHexArray.h @@ -33,10 +33,11 @@ public: using reverse_iterator = typename StorageType::reverse_iterator; using const_reverse_iterator = typename StorageType::const_reverse_iterator; - using NeighbouringTiles = std::array; - using NeighbouringTilesCache = std::array; + using NeighbouringTilesCache = std::array; static const NeighbouringTilesCache neighbouringTilesCache; + static const BattleHexArray closestTilesCacheForAttacker; + static const BattleHexArray closestTilesCacheForDefender; BattleHexArray() noexcept { @@ -62,16 +63,6 @@ public: BattleHexArray(std::initializer_list initList) noexcept; - /// returns all valid neighbouring tiles - static BattleHexArray generateNeighbouringTiles(BattleHex hex) - { - BattleHexArray ret; - for(auto dir : BattleHex::hexagonalDirections()) - ret.checkAndPush(hex.cloneInDirection(dir, false)); - - return ret; - } - /// returns all tiles, unavailable tiles will be set as invalid /// order of returned tiles matches EDir enum static BattleHexArray generateAllNeighbouringTiles(BattleHex hex) @@ -86,8 +77,6 @@ public: return ret; } - BattleHex getClosestTile(BattleSide side, BattleHex initialPos); - void checkAndPush(BattleHex tile) { if(tile.isAvailable() && !contains(tile)) @@ -114,6 +103,14 @@ public: /*if(isNotValidForInsertion(hex)) return;*/ + 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())); + } + if(contains(hex)) return; @@ -133,6 +130,10 @@ public: return internalStorage.insert(pos, hex); } + static BattleHex getClosestTileFromAllPossibleNeighbours(BattleSide side, BattleHex pos); + + BattleHex getClosestTile(BattleSide side, BattleHex initialPos) const; + void merge(const BattleHexArray & other) noexcept; void clear() noexcept; @@ -295,6 +296,12 @@ private: { return hex == BattleHex::CASTLE_CENTRAL_TOWER || hex == BattleHex::CASTLE_UPPER_TOWER || hex == BattleHex::CASTLE_BOTTOM_TOWER; } + + /// returns all valid neighbouring tiles + static BattleHexArray::NeighbouringTilesCache calculateNeighbouringTiles(); + static BattleHexArray generateNeighbouringTiles(BattleHex hex); + static BattleHexArray generateAttackerClosestTilesCache(); + static BattleHexArray generateDefenderClosestTilesCache(); }; VCMI_LIB_NAMESPACE_END diff --git a/lib/battle/CBattleInfoCallback.cpp b/lib/battle/CBattleInfoCallback.cpp index 3d09b5138..ef567ccf4 100644 --- a/lib/battle/CBattleInfoCallback.cpp +++ b/lib/battle/CBattleInfoCallback.cpp @@ -204,7 +204,7 @@ bool CBattleInfoCallback::battleHasPenaltyOnLine(BattleHex from, BattleHex dest, while (next != dest) { - next = BattleHexArray::generateNeighbouringTiles(next).getClosestTile(direction, dest); + next = BattleHexArray::neighbouringTilesCache[next].getClosestTile(direction, dest); ret.insert(next); } assert(!ret.empty()); @@ -1360,7 +1360,7 @@ AttackableTiles CBattleInfoCallback::getPotentiallyAttackableHexes( } if(attacker->hasBonusOfType(BonusType::WIDE_BREATH)) { - BattleHexArray hexes = BattleHexArray::generateNeighbouringTiles(destinationTile); + BattleHexArray hexes = BattleHexArray::neighbouringTilesCache[destinationTile]; for(int i = 0; i < hexes.size(); i++) { if(hexes.at(i) == attackOriginHex) @@ -1433,9 +1433,9 @@ AttackableTiles CBattleInfoCallback::getPotentiallyShootableHexes(const battle:: AttackableTiles at; RETURN_IF_NOT_BATTLE(at); - if(attacker->hasBonusOfType(BonusType::SHOOTS_ALL_ADJACENT) && !BattleHexArray::generateNeighbouringTiles(attackerPos).contains(destinationTile)) + if(attacker->hasBonusOfType(BonusType::SHOOTS_ALL_ADJACENT) && !BattleHexArray::neighbouringTilesCache[attackerPos].contains(destinationTile)) { - auto targetHexes = BattleHexArray::generateNeighbouringTiles(destinationTile); + auto targetHexes = BattleHexArray::neighbouringTilesCache[destinationTile]; targetHexes.insert(destinationTile); boost::copy(targetHexes, vstd::set_inserter(at.hostileCreaturePositions)); } diff --git a/lib/battle/ReachabilityInfo.cpp b/lib/battle/ReachabilityInfo.cpp index a96dc3fd6..826fa6626 100644 --- a/lib/battle/ReachabilityInfo.cpp +++ b/lib/battle/ReachabilityInfo.cpp @@ -43,7 +43,7 @@ uint32_t ReachabilityInfo::distToNearestNeighbour( for(auto targetHex : targetHexes) { - for(auto & n : BattleHexArray::generateNeighbouringTiles(targetHex)) + for(auto & n : BattleHexArray::neighbouringTilesCache[targetHex]) { if(distances[n] < ret) { diff --git a/lib/battle/Unit.cpp b/lib/battle/Unit.cpp index 2e74a9133..a8b438ced 100644 --- a/lib/battle/Unit.cpp +++ b/lib/battle/Unit.cpp @@ -88,7 +88,7 @@ BattleHexArray Unit::getSurroundingHexes(BattleHex position, bool twoHex, Battle } else { - return BattleHexArray::generateNeighbouringTiles(position); + return BattleHexArray::neighbouringTilesCache[position]; } } @@ -112,7 +112,7 @@ BattleHexArray Unit::getAttackableHexes(const Unit * attacker) const hexes.pop_back(); for(auto hex : hexes) - targetableHexes.merge(BattleHexArray::generateNeighbouringTiles(hex)); + targetableHexes.merge(BattleHexArray::neighbouringTilesCache[hex]); } return targetableHexes; diff --git a/lib/spells/BattleSpellMechanics.cpp b/lib/spells/BattleSpellMechanics.cpp index 6e8fb9b5f..5a66b4331 100644 --- a/lib/spells/BattleSpellMechanics.cpp +++ b/lib/spells/BattleSpellMechanics.cpp @@ -610,7 +610,7 @@ std::vector BattleSpellMechanics::getPossibleDestinations(size_t in { hexesToCheck.insert(stack->getPosition()); - for(auto adjacent : BattleHexArray::generateNeighbouringTiles(stack->getPosition())) + for(auto adjacent : BattleHexArray::neighbouringTilesCache[stack->getPosition().hex]) hexesToCheck.insert(adjacent); }