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))
{
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;

View File

@ -107,7 +107,7 @@ static bool willSecondHexBlockMoreEnemyShooters(std::shared_ptr<CBattleCallback>
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]++;

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);
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

View File

@ -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<BattleHex, 6>;
using NeighbouringTilesCache = std::array<NeighbouringTiles, GameConstants::BFIELD_SIZE>;
using NeighbouringTilesCache = std::array<BattleHexArray, GameConstants::BFIELD_SIZE>;
static const NeighbouringTilesCache neighbouringTilesCache;
static const BattleHexArray closestTilesCacheForAttacker;
static const BattleHexArray closestTilesCacheForDefender;
BattleHexArray() noexcept
{
@ -62,16 +63,6 @@ public:
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
/// 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

View File

@ -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));
}

View File

@ -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)
{

View File

@ -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;

View File

@ -610,7 +610,7 @@ std::vector<Destination> 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);
}