Browse Source

Use cached neighbouring tiles where possible

MichalZr6 11 months ago
parent
commit
5f799d41b3

+ 2 - 3
AI/BattleAI/BattleExchangeVariant.cpp

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

+ 1 - 1
AI/StupidAI/StupidAI.cpp

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

+ 72 - 17
lib/battle/BattleHexArray.cpp

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

+ 21 - 14
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<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

+ 4 - 4
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));
 	}

+ 1 - 1
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)
 			{

+ 2 - 2
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;

+ 1 - 1
lib/spells/BattleSpellMechanics.cpp

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