1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-03-17 20:58:07 +02:00

Use cached neighbouring tiles where possible

This commit is contained in:
MichalZr6 2024-11-04 13:27:19 +01:00
parent a99274d72e
commit 5f799d41b3
8 changed files with 104 additions and 43 deletions

View File

@ -959,8 +959,7 @@ std::vector<const battle::Unit *> BattleExchangeEvaluator::getOneTurnReachableUn
if(hexStack && cb->battleMatchOwner(unit, hexStack, false)) if(hexStack && cb->battleMatchOwner(unit, hexStack, false))
{ {
BattleHexArray neighbours; const BattleHexArray & neighbours = BattleHexArray::neighbouringTilesCache[hex.hex];
neighbours.generateNeighbouringTiles(hex);
for(BattleHex neighbour : neighbours) for(BattleHex neighbour : neighbours)
{ {
reachable = unitReachability.distances.at(neighbour) <= radius; reachable = unitReachability.distances.at(neighbour) <= radius;
@ -1022,7 +1021,7 @@ bool BattleExchangeEvaluator::checkPositionBlocksOurStacks(HypotheticBattle & hb
if(hexStack && cb->battleMatchOwner(unit, hexStack, false)) if(hexStack && cb->battleMatchOwner(unit, hexStack, false))
{ {
enemyUnit = true; enemyUnit = true;
for(BattleHex neighbour : BattleHexArray::generateNeighbouringTiles(hex)) for(BattleHex neighbour : BattleHexArray::neighbouringTilesCache[hex.hex])
{ {
reachable = unitReachability.distances.at(neighbour) <= unitSpeed; reachable = unitReachability.distances.at(neighbour) <= unitSpeed;

View File

@ -107,7 +107,7 @@ static bool willSecondHexBlockMoreEnemyShooters(std::shared_ptr<CBattleCallback>
for(int i = 0; i < 2; i++) 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(const auto * s = cb->getBattle(battleID)->battleGetUnitByPos(neighbour))
if(s->isShooter()) if(s->isShooter())
shooters[i]++; shooters[i]++;

View File

@ -22,7 +22,7 @@ BattleHexArray::BattleHexArray(std::initializer_list<BattleHex> initList) noexce
} }
} }
BattleHex BattleHexArray::getClosestTile(BattleSide side, BattleHex initialPos) BattleHex BattleHexArray::getClosestTile(BattleSide side, BattleHex initialPos) const
{ {
BattleHex initialHex = BattleHex(initialPos); BattleHex initialHex = BattleHex(initialPos);
auto compareDistance = [initialHex](const BattleHex left, const BattleHex right) -> bool auto compareDistance = [initialHex](const BattleHex left, const BattleHex right) -> bool
@ -56,6 +56,74 @@ BattleHex BattleHexArray::getClosestTile(BattleSide side, BattleHex initialPos)
return sortedTiles.front(); 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 void BattleHexArray::merge(const BattleHexArray & other) noexcept
{ {
for(auto hex : other) for(auto hex : other)
@ -82,22 +150,9 @@ void BattleHexArray::clear() noexcept
internalStorage.clear(); 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::NeighbouringTilesCache BattleHexArray::neighbouringTilesCache = calculateNeighbouringTiles();
const BattleHexArray BattleHexArray::closestTilesCacheForAttacker = generateAttackerClosestTilesCache();
const BattleHexArray BattleHexArray::closestTilesCacheForDefender = generateDefenderClosestTilesCache();
VCMI_LIB_NAMESPACE_END VCMI_LIB_NAMESPACE_END

View File

@ -33,10 +33,11 @@ public:
using reverse_iterator = typename StorageType::reverse_iterator; using reverse_iterator = typename StorageType::reverse_iterator;
using const_reverse_iterator = typename StorageType::const_reverse_iterator; using const_reverse_iterator = typename StorageType::const_reverse_iterator;
using NeighbouringTiles = std::array<BattleHex, 6>; using NeighbouringTilesCache = std::array<BattleHexArray, GameConstants::BFIELD_SIZE>;
using NeighbouringTilesCache = std::array<NeighbouringTiles, GameConstants::BFIELD_SIZE>;
static const NeighbouringTilesCache neighbouringTilesCache; static const NeighbouringTilesCache neighbouringTilesCache;
static const BattleHexArray closestTilesCacheForAttacker;
static const BattleHexArray closestTilesCacheForDefender;
BattleHexArray() noexcept BattleHexArray() noexcept
{ {
@ -62,16 +63,6 @@ public:
BattleHexArray(std::initializer_list<BattleHex> initList) noexcept; BattleHexArray(std::initializer_list<BattleHex> 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 /// returns all tiles, unavailable tiles will be set as invalid
/// order of returned tiles matches EDir enum /// order of returned tiles matches EDir enum
static BattleHexArray generateAllNeighbouringTiles(BattleHex hex) static BattleHexArray generateAllNeighbouringTiles(BattleHex hex)
@ -86,8 +77,6 @@ public:
return ret; return ret;
} }
BattleHex getClosestTile(BattleSide side, BattleHex initialPos);
void checkAndPush(BattleHex tile) void checkAndPush(BattleHex tile)
{ {
if(tile.isAvailable() && !contains(tile)) if(tile.isAvailable() && !contains(tile))
@ -114,6 +103,14 @@ public:
/*if(isNotValidForInsertion(hex)) /*if(isNotValidForInsertion(hex))
return;*/ 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)) if(contains(hex))
return; return;
@ -133,6 +130,10 @@ public:
return internalStorage.insert(pos, hex); 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 merge(const BattleHexArray & other) noexcept;
void clear() 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; 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 VCMI_LIB_NAMESPACE_END

View File

@ -204,7 +204,7 @@ bool CBattleInfoCallback::battleHasPenaltyOnLine(BattleHex from, BattleHex dest,
while (next != dest) while (next != dest)
{ {
next = BattleHexArray::generateNeighbouringTiles(next).getClosestTile(direction, dest); next = BattleHexArray::neighbouringTilesCache[next].getClosestTile(direction, dest);
ret.insert(next); ret.insert(next);
} }
assert(!ret.empty()); assert(!ret.empty());
@ -1360,7 +1360,7 @@ AttackableTiles CBattleInfoCallback::getPotentiallyAttackableHexes(
} }
if(attacker->hasBonusOfType(BonusType::WIDE_BREATH)) if(attacker->hasBonusOfType(BonusType::WIDE_BREATH))
{ {
BattleHexArray hexes = BattleHexArray::generateNeighbouringTiles(destinationTile); BattleHexArray hexes = BattleHexArray::neighbouringTilesCache[destinationTile];
for(int i = 0; i < hexes.size(); i++) for(int i = 0; i < hexes.size(); i++)
{ {
if(hexes.at(i) == attackOriginHex) if(hexes.at(i) == attackOriginHex)
@ -1433,9 +1433,9 @@ AttackableTiles CBattleInfoCallback::getPotentiallyShootableHexes(const battle::
AttackableTiles at; AttackableTiles at;
RETURN_IF_NOT_BATTLE(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); targetHexes.insert(destinationTile);
boost::copy(targetHexes, vstd::set_inserter(at.hostileCreaturePositions)); boost::copy(targetHexes, vstd::set_inserter(at.hostileCreaturePositions));
} }

View File

@ -43,7 +43,7 @@ uint32_t ReachabilityInfo::distToNearestNeighbour(
for(auto targetHex : targetHexes) for(auto targetHex : targetHexes)
{ {
for(auto & n : BattleHexArray::generateNeighbouringTiles(targetHex)) for(auto & n : BattleHexArray::neighbouringTilesCache[targetHex])
{ {
if(distances[n] < ret) if(distances[n] < ret)
{ {

View File

@ -88,7 +88,7 @@ BattleHexArray Unit::getSurroundingHexes(BattleHex position, bool twoHex, Battle
} }
else else
{ {
return BattleHexArray::generateNeighbouringTiles(position); return BattleHexArray::neighbouringTilesCache[position];
} }
} }
@ -112,7 +112,7 @@ BattleHexArray Unit::getAttackableHexes(const Unit * attacker) const
hexes.pop_back(); hexes.pop_back();
for(auto hex : hexes) for(auto hex : hexes)
targetableHexes.merge(BattleHexArray::generateNeighbouringTiles(hex)); targetableHexes.merge(BattleHexArray::neighbouringTilesCache[hex]);
} }
return targetableHexes; return targetableHexes;

View File

@ -610,7 +610,7 @@ std::vector<Destination> BattleSpellMechanics::getPossibleDestinations(size_t in
{ {
hexesToCheck.insert(stack->getPosition()); hexesToCheck.insert(stack->getPosition());
for(auto adjacent : BattleHexArray::generateNeighbouringTiles(stack->getPosition())) for(auto adjacent : BattleHexArray::neighbouringTilesCache[stack->getPosition().hex])
hexesToCheck.insert(adjacent); hexesToCheck.insert(adjacent);
} }