Hoist repeated APD score lookups (#8769)

This commit is contained in:
2026-07-24 08:29:29 -07:00
committed by GitHub
parent 6a91935a1f
commit 71a6c9f791
@@ -4,6 +4,8 @@
#include "AbstractAIScoreCalculator.hpp"
#include <array>
#include "AIScoreCalculatorSharedUtilities.hpp"
#include "src/main/cpp/net/eagle0/shardok/ai/AIScoreUtilities.hpp"
#include "src/main/cpp/net/eagle0/shardok/ai/AIStrategy.hpp"
@@ -41,16 +43,44 @@ auto AbstractAIScoreCalculator::CalculateUnitsScoreComponents(
bool isLateGame = cachedCurrentRound > 18; // Inline IsLateGame for efficiency
// APDCache now has built-in thread-local caching - no need for PreCachedAPDs
ActionPoints braveWaterCost = GetBraveWaterCost();
// Memoization cache for EffectiveDistance calls
EffectiveDistanceCache distanceCache;
// Early return for empty game states
const size_t estimatedUnitCount = cachedUnits->size();
if (estimatedUnitCount == 0) { return UnitsScoreComponents{0.0, 0.0}; }
ActionPoints braveWaterCost = GetBraveWaterCost();
struct ResolvedActionPointDistances {
const ActionPointDistances *notBraving = nullptr;
const ActionPointDistances *braving = nullptr;
};
std::array<ResolvedActionPointDistances, BattalionTypeId::BattalionTypeId_MAX + 1>
resolvedActionPointDistances{};
// A scoring call repeatedly asks for the same map/type APDs. Resolve each pointer once while
// leaving ownership and cross-call caching with ActionPointDistancesCache.
const auto notBravingApdFor = [&](int battalionTypeId, const BattalionTypeSPtr &battalionType) {
auto &resolved = resolvedActionPointDistances[battalionTypeId];
if (resolved.notBraving == nullptr) {
resolved.notBraving = GetApdCache()->GetRaw(cachedHexMap, mapId, battalionType, false);
}
return resolved.notBraving;
};
const auto bravingApdFor = [&](int battalionTypeId, const BattalionTypeSPtr &battalionType) {
if (!battalionType->allowsBraveWater) {
return static_cast<const ActionPointDistances *>(nullptr);
}
auto &resolved = resolvedActionPointDistances[battalionTypeId];
if (resolved.braving == nullptr) {
resolved.braving =
GetApdCache()->GetRaw(cachedHexMap, mapId, battalionType, true, braveWaterCost);
}
return resolved.braving;
};
// Memoization cache for EffectiveDistance calls
EffectiveDistanceCache distanceCache;
std::vector<const Unit *> attackerUnits{};
std::vector<const Unit *> defenderUnits{};
// Pre-allocate vectors based on estimated unit ratios to avoid reallocations
@@ -115,16 +145,8 @@ auto AbstractAIScoreCalculator::CalculateUnitsScoreComponents(
// Cache battalion type reference to avoid shared_ptr atomic operations
const auto &battalionType = GetBattalionType(static_cast<BattalionTypeId>(battTypeId));
// Cache APD lookups - same battalion type is used multiple times below
const auto *notBravingApd =
GetApdCache()->GetRaw(cachedHexMap, mapId, battalionType, false);
const auto *bravingApd = battalionType->allowsBraveWater ? GetApdCache()->GetRaw(
cachedHexMap,
mapId,
battalionType,
true,
braveWaterCost)
: nullptr;
const auto *notBravingApd = notBravingApdFor(battTypeId, battalionType);
const auto *bravingApd = bravingApdFor(battTypeId, battalionType);
const auto &priorityList = std::ranges::find_if(
attackerTargetPriorities,
@@ -174,9 +196,7 @@ auto AbstractAIScoreCalculator::CalculateUnitsScoreComponents(
// Cache battalion type reference to avoid shared_ptr atomic operations
const auto &battalionType = GetBattalionType(static_cast<BattalionTypeId>(battTypeId));
// Cache APD lookups for this defender unit
const auto *defenderNotBravingApd =
GetApdCache()->GetRaw(cachedHexMap, mapId, battalionType, false);
const auto *defenderNotBravingApd = notBravingApdFor(battTypeId, battalionType);
auto dv = UnitValue(
unit,
@@ -211,14 +231,8 @@ auto AbstractAIScoreCalculator::CalculateUnitsScoreComponents(
const DIST_T thisDistance = distanceCache.GetOrCompute(
attackerUnit,
unit->location(),
GetApdCache()->GetRaw(cachedHexMap, mapId, attackerBattalionType, false),
attackerBattalionType->allowsBraveWater ? GetApdCache()->GetRaw(
cachedHexMap,
mapId,
attackerBattalionType,
true,
braveWaterCost)
: nullptr,
notBravingApdFor(attackerBattTypeId, attackerBattalionType),
bravingApdFor(attackerBattTypeId, attackerBattalionType),
cachedHexMap);
if (thisDistance < closestDistanceToEnemy) {
closestDistanceToEnemy = thisDistance;
@@ -241,19 +255,8 @@ auto AbstractAIScoreCalculator::CalculateUnitsScoreComponents(
const DIST_T thisDistance = distanceCache.GetOrCompute(
defenderUnit,
unit->location(),
GetApdCache()->GetRaw(
cachedHexMap,
mapId,
defenderBattalionType,
false),
defenderBattalionType->allowsBraveWater
? GetApdCache()->GetRaw(
cachedHexMap,
mapId,
defenderBattalionType,
true,
braveWaterCost)
: nullptr,
notBravingApdFor(defenderBattTypeId, defenderBattalionType),
bravingApdFor(defenderBattTypeId, defenderBattalionType),
cachedHexMap);
if (thisDistance < closestDistanceToFriendly) {
closestDistanceToFriendly = thisDistance;