mirror of
https://github.com/nolen777/eagle0.git
synced 2026-07-29 01:55:42 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
db09df4576 | ||
|
|
567846156c | ||
|
|
14f1ab992c | ||
|
|
42cb9291fc | ||
|
|
aa2bf97078 | ||
|
|
6976db961b | ||
|
|
1823543706 | ||
|
|
c452b8be69 | ||
|
|
53612938b6 | ||
|
|
ccb64480a8 | ||
|
|
4f0a172036 | ||
|
|
ca45eba76b | ||
|
|
8f58543a4c | ||
|
|
453242e06a | ||
|
|
249a564ac7 | ||
|
|
701c822e1a | ||
|
|
2ca4b6e8d4 | ||
|
|
fe060e4489 | ||
|
|
6dc29ec746 | ||
|
|
8b9ac89205 | ||
|
|
74bbd490d7 | ||
|
|
7a5f89ea87 | ||
|
|
bdcddb88e4 | ||
|
|
cccc7971c1 | ||
|
|
82d2ca915d | ||
|
|
319dc0b19e | ||
|
|
2573f0f2af | ||
|
|
641244103f | ||
|
|
1b7909d914 | ||
|
|
9d7dfd8f5f | ||
|
|
42edef2313 | ||
|
|
7ad6677b90 | ||
|
|
ce19c34b8b | ||
|
|
d675e3781f | ||
|
|
2164a98abe | ||
|
|
b61ce58f4c | ||
|
|
7a11c8fa9a | ||
|
|
62438ec4f6 | ||
|
|
afcc6a9a3e | ||
|
|
b6a094064a | ||
|
|
70b8eb6513 | ||
|
|
e4c7a0c98b | ||
|
|
67573e7a8a | ||
|
|
c60dce4504 | ||
|
|
8250d3d42f | ||
|
|
5407c8aa65 | ||
|
|
d282634264 | ||
|
|
fff0e6dd30 | ||
|
|
a1ccdc672c | ||
|
|
6802da55ed | ||
|
|
57dae50cf7 | ||
|
|
4bce809fab | ||
|
|
2ff2cdab79 | ||
|
|
76839dcd59 | ||
|
|
effd5451b6 | ||
|
|
00ac74f944 | ||
|
|
728f1969ce | ||
|
|
fab757f9dd | ||
|
|
fa006ba947 | ||
|
|
2b61fb0fcf | ||
|
|
62bcd3b669 | ||
|
|
0fc394174c | ||
|
|
14015aebc7 | ||
|
|
5acdcea0b0 | ||
|
|
709d3b9219 | ||
|
|
0f028e73d3 | ||
|
|
f0fa1f1a1d | ||
|
|
0a52e41c3d | ||
|
|
9ef750956c | ||
|
|
b70d541224 | ||
|
|
a8299738d2 | ||
|
|
e789309827 | ||
|
|
f8066454a8 | ||
|
|
a80c8e6d1b | ||
|
|
3dc8541aee | ||
|
|
b7cd003b4c | ||
|
|
bae90633a5 | ||
|
|
56eff84f30 | ||
|
|
375ae7cecb | ||
|
|
ac8a9358ff | ||
|
|
8bc900eef9 | ||
|
|
845a85ed1f | ||
|
|
a1a7a8abf8 | ||
|
|
9cc4dca5b2 | ||
|
|
ea244506d3 | ||
|
|
9827414e92 |
@@ -37,7 +37,7 @@ int main(const int argc, char** argv) {
|
||||
|
||||
void ModifyMap(HexMapProto& map) {
|
||||
const int terrainCount = map.terrain_size();
|
||||
for (int i = 0; i < terrainCount; i++) {
|
||||
for (int i = 0; i < terrainCount; ++i) {
|
||||
const auto existingTerrainType = map.terrain(i).type();
|
||||
const auto newTerrain =
|
||||
static_cast<net::eagle0::shardok::common::Terrain_Type>(existingTerrainType + 2);
|
||||
|
||||
@@ -37,7 +37,7 @@ auto CalculateMap(
|
||||
.name = mapName,
|
||||
.positionsRequiringCrossing = {}};
|
||||
|
||||
for (std::size_t i = 0; i < hexMap->attacker_starting_positions()->size(); i++) {
|
||||
for (std::size_t i = 0; i < hexMap->attacker_starting_positions()->size(); ++i) {
|
||||
const auto* positionList = hexMap->attacker_starting_positions()->Get(i);
|
||||
const auto* positions = positionList->positions();
|
||||
if (positions->empty()) continue;
|
||||
|
||||
@@ -54,7 +54,7 @@ void runBattle(const std::vector<shardok::Unit>& units) {
|
||||
const auto p1UnitCount = randInt(1, static_cast<int>(maxP1UnitCount));
|
||||
std::vector<shardok::Unit> p1Units{};
|
||||
p1Units.reserve(p1UnitCount);
|
||||
for (int i = 0; i < p1UnitCount; i++) {
|
||||
for (int i = 0; i < p1UnitCount; ++i) {
|
||||
auto unit = units[i];
|
||||
unit.mutate_player_id(0);
|
||||
p1Units.push_back(std::move(unit));
|
||||
@@ -64,7 +64,7 @@ void runBattle(const std::vector<shardok::Unit>& units) {
|
||||
const auto p2UnitCount = randInt(1, static_cast<int>(maxP2UnitCount));
|
||||
std::vector<shardok::Unit> p2Units{};
|
||||
p2Units.reserve(p2UnitCount);
|
||||
for (int i = p1UnitCount; i < p1UnitCount + p2UnitCount; i++) {
|
||||
for (int i = p1UnitCount; i < p1UnitCount + p2UnitCount; ++i) {
|
||||
auto unit = units[i];
|
||||
unit.mutate_player_id(1);
|
||||
p2Units.push_back(std::move(unit));
|
||||
@@ -158,7 +158,7 @@ auto main(int /*argc*/, char** argv) -> int {
|
||||
|
||||
std::array<std::thread, THREAD_COUNT> threads;
|
||||
|
||||
for (int i = 0; i < THREAD_COUNT; i++) {
|
||||
for (int i = 0; i < THREAD_COUNT; ++i) {
|
||||
threads[i] = std::thread(runBattlesThread, randomUnits);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ struct TargetAndAttackLocations {
|
||||
Coords target;
|
||||
CoordsSet attackLocations;
|
||||
|
||||
auto operator==(const TargetAndAttackLocations& rhs) const -> bool = default;
|
||||
[[nodiscard]] auto operator==(const TargetAndAttackLocations& rhs) const -> bool = default;
|
||||
};
|
||||
|
||||
struct TargetPriorityList {
|
||||
@@ -39,7 +39,7 @@ struct TargetPriorityList {
|
||||
priorityOrder(po) {}
|
||||
};
|
||||
|
||||
auto EffectiveDistance(
|
||||
[[nodiscard]] auto EffectiveDistance(
|
||||
const Unit* unit,
|
||||
const HexMap* map,
|
||||
const AttackLocations& attackLocations,
|
||||
@@ -47,7 +47,7 @@ auto EffectiveDistance(
|
||||
const BattalionTypeGetter& battalionTypeGetter,
|
||||
ActionPoints braveWaterCost) -> DIST_T;
|
||||
|
||||
auto EffectiveDistance(
|
||||
[[nodiscard]] auto EffectiveDistance(
|
||||
const Unit* unit,
|
||||
const HexMap* map,
|
||||
const CoordsSet& locations,
|
||||
@@ -55,14 +55,14 @@ auto EffectiveDistance(
|
||||
const BattalionTypeGetter& battalionTypeGetter,
|
||||
ActionPoints braveWaterCost) -> DIST_T;
|
||||
|
||||
auto EffectiveDistance(
|
||||
[[nodiscard]] auto EffectiveDistance(
|
||||
const Unit* unit,
|
||||
const ActionPointDistances* notBravingApd,
|
||||
const ActionPointDistances* bravingApd,
|
||||
const CoordsSet& locations) -> DIST_T;
|
||||
|
||||
// Chooses a list of targets in priority order for each unit.
|
||||
auto GenerateTargetPriorities(
|
||||
[[nodiscard]] auto GenerateTargetPriorities(
|
||||
const std::vector<const Unit*>& occupants,
|
||||
const HexMap* map,
|
||||
const CoordsSet& targets,
|
||||
|
||||
@@ -53,8 +53,8 @@ AttackLocationsCache::AttackLocationsCache(const HexMap *hexMap, const SettingsG
|
||||
|
||||
auto emptySet = CoordsSet(columnCount, rowCount);
|
||||
|
||||
for (MapIndex r = 0; r < hexMap->row_count(); r++) {
|
||||
for (MapIndex c = 0; c < hexMap->column_count(); c++) {
|
||||
for (MapIndex r = 0; r < hexMap->row_count(); ++r) {
|
||||
for (MapIndex c = 0; c < hexMap->column_count(); ++c) {
|
||||
auto location = Coords(r, c);
|
||||
const auto terrain = GetTerrain(hexMap, location);
|
||||
|
||||
|
||||
@@ -21,16 +21,12 @@
|
||||
|
||||
namespace shardok {
|
||||
|
||||
// No need to forward declare internal functions - use the public interface instead
|
||||
|
||||
// Helper constants and static variables
|
||||
static const std::vector<double> kAverageSequence = {0.5};
|
||||
static const auto kAverageGenerator = std::make_shared<SequenceRandomGenerator>(kAverageSequence);
|
||||
|
||||
constexpr bool kMultithread = true;
|
||||
constexpr bool kLogging = false;
|
||||
|
||||
// Helper function to determine if a command type is deterministic
|
||||
static auto IsDeterministic(const CommandType type) -> bool {
|
||||
switch (type) {
|
||||
case net::eagle0::shardok::common::MOVE_COMMAND:
|
||||
@@ -63,7 +59,6 @@ static auto RandomnessSampleForRepeat(const int repeatIteration, const int maxRe
|
||||
return static_cast<double>(repeatIteration) / static_cast<double>(maxRepeatCount - 1);
|
||||
}
|
||||
|
||||
// Helper function to sort commands by score
|
||||
static auto CommandSorter(
|
||||
const AICommandEvaluator::IndexAndScore& l,
|
||||
const AICommandEvaluator::IndexAndScore& r) -> bool {
|
||||
@@ -83,7 +78,7 @@ AICommandEvaluator::AICommandEvaluator(
|
||||
BattalionTypeGetter battalionTypeGetter)
|
||||
: scorer_(scorer),
|
||||
apdCache_(apdCache),
|
||||
battalionTypeGetter_(std::move(battalionTypeGetter)) {} // Move the function object
|
||||
battalionTypeGetter_(std::move(battalionTypeGetter)) {}
|
||||
|
||||
auto AICommandEvaluator::PerformLookahead(
|
||||
const PlayerId pid,
|
||||
@@ -336,7 +331,7 @@ auto AICommandEvaluator::FindBestCommand(
|
||||
|
||||
std::vector<CommandEvaluation> commandEvaluations(commandCount);
|
||||
|
||||
for (uint32_t index = 0; index < commandCount; index++) {
|
||||
for (uint32_t index = 0; index < commandCount; ++index) {
|
||||
const auto originalIndex = filteredIndices[index];
|
||||
const auto& guessedDescriptor = guessedDescriptors->at(originalIndex);
|
||||
const auto guessedCommandType = guessedDescriptor->GetCommandType();
|
||||
@@ -423,7 +418,7 @@ auto AICommandEvaluator::FindBestCommand(
|
||||
ScoreValue sum = 0.0;
|
||||
const int sampleCount = std::max(1, maxRepeatCount);
|
||||
commandEvaluations[index].lookaheadFutures.reserve(sampleCount);
|
||||
for (int repeatIteration = 0; repeatIteration < sampleCount; repeatIteration++) {
|
||||
for (int repeatIteration = 0; repeatIteration < sampleCount; ++repeatIteration) {
|
||||
// In each iteration, use a double from [0, 1] as the random roll
|
||||
auto sequence =
|
||||
std::vector{RandomnessSampleForRepeat(repeatIteration, sampleCount)};
|
||||
@@ -587,7 +582,7 @@ auto AICommandEvaluator::EvaluateCommand(
|
||||
const int sampleCount = std::max(1, maxRepeatCount);
|
||||
lookaheadFutures.reserve(sampleCount);
|
||||
|
||||
for (int repeatIteration = 0; repeatIteration < sampleCount; repeatIteration++) {
|
||||
for (int repeatIteration = 0; repeatIteration < sampleCount; ++repeatIteration) {
|
||||
auto sequence = std::vector{RandomnessSampleForRepeat(repeatIteration, sampleCount)};
|
||||
auto evaluation = EvaluateWithRandomness(
|
||||
pid,
|
||||
|
||||
@@ -78,7 +78,7 @@ public:
|
||||
private:
|
||||
const AIScoreCalculator& scorer_;
|
||||
const APDCache& apdCache_;
|
||||
BattalionTypeGetter battalionTypeGetter_; // Store by value
|
||||
BattalionTypeGetter battalionTypeGetter_;
|
||||
|
||||
struct ImmediateAndLookaheadScore {
|
||||
ScoreValue immediateScore{};
|
||||
|
||||
@@ -104,17 +104,14 @@ auto DefenderDistanceBuf(
|
||||
pointCostToDesiredTargetWithBraving);
|
||||
}
|
||||
|
||||
std::sort(
|
||||
begin(pointCosts),
|
||||
end(pointCosts),
|
||||
[](const WithoutAndWith &left, const WithoutAndWith &right) {
|
||||
return left.without == right.without ? left.with < right.with
|
||||
: left.without < right.without;
|
||||
});
|
||||
std::ranges::sort(pointCosts, [](const WithoutAndWith &left, const WithoutAndWith &right) {
|
||||
return left.without == right.without ? left.with < right.with
|
||||
: left.without < right.without;
|
||||
});
|
||||
|
||||
// experiment: add dummy values to the end with very high cost, so there's never an advantage
|
||||
// to leaving a defender unit alive in a castle.
|
||||
for (size_t i = attackerUnits.size(); i < 20; i++) { pointCosts.emplace_back(999, 999); }
|
||||
for (size_t i = attackerUnits.size(); i < 20; ++i) { pointCosts.emplace_back(999, 999); }
|
||||
|
||||
double sum = 0.0;
|
||||
double decr = kPerUnitDebufDecay;
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
namespace shardok {
|
||||
|
||||
auto DefenderDistanceBuf(
|
||||
[[nodiscard]] auto DefenderDistanceBuf(
|
||||
const Coords &defenderLocation,
|
||||
const HexMap *hexMap,
|
||||
const MapId &mapId,
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
namespace shardok {
|
||||
|
||||
inline auto CurrentAIExperimentId() -> int {
|
||||
[[nodiscard]] inline auto CurrentAIExperimentId() -> int {
|
||||
const char* rawValue = std::getenv("SHARDOK_SCORING_EXPERIMENT_ID");
|
||||
if (rawValue == nullptr) { return 0; }
|
||||
|
||||
@@ -28,7 +28,9 @@ inline auto CurrentAIExperimentId() -> int {
|
||||
return experimentId;
|
||||
}
|
||||
|
||||
inline auto IsAIExperiment(const int id) -> bool { return CurrentAIExperimentId() == id; }
|
||||
[[nodiscard]] inline auto IsAIExperiment(const int id) -> bool {
|
||||
return CurrentAIExperimentId() == id;
|
||||
}
|
||||
|
||||
} // namespace shardok
|
||||
|
||||
|
||||
@@ -18,12 +18,12 @@ struct CoordsAndDistance {
|
||||
int distance;
|
||||
};
|
||||
|
||||
auto MinimumDistanceAndTarget(
|
||||
[[nodiscard]] auto MinimumDistanceAndTarget(
|
||||
const ActionPointDistances *apd,
|
||||
const Coords &origin,
|
||||
const CoordsSet &destinations) -> CoordsAndDistance;
|
||||
|
||||
auto MinimumDistance(
|
||||
[[nodiscard]] auto MinimumDistance(
|
||||
const ActionPointDistances *apd,
|
||||
const Coords &origin,
|
||||
const CoordsSet &destinations) -> int;
|
||||
|
||||
@@ -20,12 +20,12 @@ using GameState = net::eagle0::shardok::storage::fb::GameState;
|
||||
using PlayerInfo = net::eagle0::shardok::storage::fb::PlayerInfo;
|
||||
using Unit = net::eagle0::shardok::storage::fb::Unit;
|
||||
|
||||
auto HasAttachedHeroWithProfession(
|
||||
[[nodiscard]] auto HasAttachedHeroWithProfession(
|
||||
const Unit *unit,
|
||||
net::eagle0::shardok::storage::fb::Profession profession) -> bool;
|
||||
|
||||
auto CastleClaimCapableAttackerUnitCount(const GameStateW &gameState) -> int;
|
||||
auto PlayerInfoForPid(const GameStateW &, PlayerId pid) -> const PlayerInfo *;
|
||||
[[nodiscard]] auto CastleClaimCapableAttackerUnitCount(const GameStateW &gameState) -> int;
|
||||
[[nodiscard]] auto PlayerInfoForPid(const GameStateW &, PlayerId pid) -> const PlayerInfo *;
|
||||
|
||||
} // namespace shardok
|
||||
|
||||
|
||||
@@ -26,11 +26,13 @@ struct AIStrategy {
|
||||
};
|
||||
|
||||
extern AIStrategy FleeStrategy;
|
||||
auto AttackUnitsStrategy(const vector<TargetPriorityList>& targetPriorities) -> AIStrategy;
|
||||
auto AttackCastlesStrategy(const vector<TargetPriorityList>& targetPriorities) -> AIStrategy;
|
||||
[[nodiscard]] auto AttackUnitsStrategy(const vector<TargetPriorityList>& targetPriorities)
|
||||
-> AIStrategy;
|
||||
[[nodiscard]] auto AttackCastlesStrategy(const vector<TargetPriorityList>& targetPriorities)
|
||||
-> AIStrategy;
|
||||
extern AIStrategy HoldCastlesStrategy;
|
||||
extern AIStrategy ScatterStrategy;
|
||||
auto CrossRiversStrategy(const CoordsSet& targetLocations) -> AIStrategy;
|
||||
[[nodiscard]] auto CrossRiversStrategy(const CoordsSet& targetLocations) -> AIStrategy;
|
||||
|
||||
} // namespace shardok
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ public:
|
||||
AIEvaluationCounter(AIEvaluationCounter&&) = delete;
|
||||
auto operator=(AIEvaluationCounter&&) -> AIEvaluationCounter& = delete;
|
||||
|
||||
static int GetCurrentCount();
|
||||
[[nodiscard]] static int GetCurrentCount();
|
||||
};
|
||||
|
||||
// Configuration structure for iterative deepening time budget
|
||||
@@ -44,7 +44,7 @@ struct AITimeBudget {
|
||||
// Time budget is calculated dynamically based on number of available commands:
|
||||
// budget = msPerCommand × numCommands (clamped to 200-5000ms)
|
||||
// If isAllAiBattle is true, uses allAiBattleTimeBudgetMaximum instead of the normal maximum.
|
||||
auto CalculateTimeBudget(
|
||||
[[nodiscard]] auto CalculateTimeBudget(
|
||||
PlayerId playerId,
|
||||
const GameSettingsSPtr& settings,
|
||||
const GameStateW& state,
|
||||
|
||||
@@ -17,9 +17,9 @@ using net::eagle0::shardok::storage::fb::Unit;
|
||||
using ScoreValue = double;
|
||||
class AttackLocations;
|
||||
|
||||
auto ContextFreeUnitValue(const Unit *unit) -> ScoreValue;
|
||||
[[nodiscard]] auto ContextFreeUnitValue(const Unit *unit) -> ScoreValue;
|
||||
|
||||
auto GetRangedAttackBonus(
|
||||
[[nodiscard]] auto GetRangedAttackBonus(
|
||||
const Unit *unit,
|
||||
bool isAttacker,
|
||||
const HexMap *map,
|
||||
@@ -32,7 +32,7 @@ auto GetRangedAttackBonus(
|
||||
double minVigorToCast,
|
||||
ActionPoints archeryActionPointCost = 0) -> double;
|
||||
|
||||
auto UnitValue(
|
||||
[[nodiscard]] auto UnitValue(
|
||||
const Unit *unit,
|
||||
bool isAttacker,
|
||||
const std::vector<const Unit *> &attackerUnits,
|
||||
|
||||
@@ -18,7 +18,7 @@ auto UnitIdsRequiringWaterCrossing(
|
||||
const BattalionTypeGetter &battalionTypeGetter) -> vector<UnitId> {
|
||||
// Put out all the fires, except on bridges
|
||||
fb::HexMapW mapCopy = fb::CopyHexMap(gameState->hex_map());
|
||||
for (uint32_t index = 0; index < mapCopy->terrain()->size(); index++) {
|
||||
for (uint32_t index = 0; index < mapCopy->terrain()->size(); ++index) {
|
||||
if (IsWater(mapCopy->terrain()->Get(index)->type())) continue;
|
||||
// const_cast is safe because we own the mutable buffer (mapCopy)
|
||||
const_cast<net::eagle0::shardok::storage::fb::Terrain *>(
|
||||
@@ -155,7 +155,7 @@ auto WaterCrossingTiles(
|
||||
// 1) the tile is water
|
||||
// 2) the tile does not already have a bridge (that is not on fire)
|
||||
// 3) the tile is not already frozen
|
||||
for (int index = 0; index < mapSize; index++) {
|
||||
for (int index = 0; index < mapSize; ++index) {
|
||||
const auto startTerrain = *hexMap->terrain()->Get(index);
|
||||
|
||||
if (!IsWater(startTerrain.type())) continue;
|
||||
|
||||
@@ -31,7 +31,7 @@ static inline void AssertValid(const Coords& c, const HexMap* hexMap) {
|
||||
}
|
||||
|
||||
// Units that need a water crossing to reach at least one of the destinations
|
||||
auto UnitIdsRequiringWaterCrossing(
|
||||
[[nodiscard]] auto UnitIdsRequiringWaterCrossing(
|
||||
const GameStateW& gameState,
|
||||
PlayerId pid,
|
||||
const CoordsSet& destinations,
|
||||
@@ -39,14 +39,14 @@ auto UnitIdsRequiringWaterCrossing(
|
||||
const BattalionTypeGetter& battalionTypeGetter) -> vector<UnitId>;
|
||||
|
||||
// Units belonging to the player that are capable of creating water crossings
|
||||
auto UnitIdsToCreateWaterCrossing(
|
||||
[[nodiscard]] auto UnitIdsToCreateWaterCrossing(
|
||||
const GameStateW& gameState,
|
||||
PlayerId pid,
|
||||
const BattalionTypeGetter& battalionTypeGetter) -> vector<UnitId>;
|
||||
|
||||
// Whether a unit of the given type can reach destination from origin, given the current state
|
||||
// of the map
|
||||
auto CanReach(
|
||||
[[nodiscard]] auto CanReach(
|
||||
const Coords& origin,
|
||||
const Coords& destination,
|
||||
const HexMap* hexMap,
|
||||
@@ -56,11 +56,12 @@ auto CanReach(
|
||||
|
||||
// Returns the *non*-water tiles from which you could bridge/freeze water to allow a unit to cross
|
||||
// from origin to destination
|
||||
auto CrossingStartLocations(const HexMap* hexMap, const CoordsSet& waterCrossingTiles) -> CoordsSet;
|
||||
[[nodiscard]] auto CrossingStartLocations(const HexMap* hexMap, const CoordsSet& waterCrossingTiles)
|
||||
-> CoordsSet;
|
||||
|
||||
// Returns the water tiles that, if they were bridged/frozen, would allow a unit to cross from
|
||||
// origin to destination
|
||||
auto WaterCrossingTiles(
|
||||
[[nodiscard]] auto WaterCrossingTiles(
|
||||
const Coords& origin,
|
||||
const Coords& destination,
|
||||
const HexMap* hexMap,
|
||||
@@ -68,7 +69,7 @@ auto WaterCrossingTiles(
|
||||
const BattalionTypeSPtr& battalionType) -> CoordsSet;
|
||||
|
||||
// Returns the set of tiles that the attacker should try to approach in order to bridge/freeze
|
||||
auto IntendedCrossingStarts(
|
||||
[[nodiscard]] auto IntendedCrossingStarts(
|
||||
const GameStateW& gameState,
|
||||
const vector<UnitId>& unitIdsCreatingCrossing,
|
||||
const CoordsSet& tilesToStartCrossingFrom,
|
||||
@@ -76,7 +77,7 @@ auto IntendedCrossingStarts(
|
||||
const BattalionTypeGetter& battalionTypeGetter) -> CoordsSet;
|
||||
|
||||
// Calculate score based on water crossing strategy
|
||||
auto WaterCrossingScore(
|
||||
[[nodiscard]] auto WaterCrossingScore(
|
||||
PlayerId playerId,
|
||||
const BattalionTypeGetter& battalionTypeGetter,
|
||||
const GameStateW& gameState,
|
||||
|
||||
@@ -51,7 +51,7 @@ IterativeDeepeningAI::IterativeDeepeningAI(
|
||||
castleCoords(castleCoords),
|
||||
scorer(scorer),
|
||||
apdCache(apdCache),
|
||||
battalionTypeGetter(std::move(battalionTypeGetter)) {} // Move the function object
|
||||
battalionTypeGetter(std::move(battalionTypeGetter)) {}
|
||||
|
||||
auto IterativeDeepeningAI::IterativeSearch(
|
||||
const GameSettingsSPtr& settings,
|
||||
|
||||
@@ -79,7 +79,7 @@ private:
|
||||
CoordsSet castleCoords;
|
||||
const AIScoreCalculator& scorer;
|
||||
const APDCache& apdCache;
|
||||
BattalionTypeGetter battalionTypeGetter; // Store by value, not reference!
|
||||
BattalionTypeGetter battalionTypeGetter;
|
||||
|
||||
// Reusable vectors to reduce memory allocations
|
||||
mutable std::vector<std::vector<ScoreValue>> scoresByDepth;
|
||||
|
||||
@@ -182,7 +182,7 @@ auto ShardokAIClient::StandardChooseCommandIndex(
|
||||
<< " round=" << guessedState->current_round() << "\n";
|
||||
|
||||
const auto maxDump = std::max(commandCount, realAvailableCommands->size());
|
||||
for (size_t i = 0; i < maxDump; i++) {
|
||||
for (size_t i = 0; i < maxDump; ++i) {
|
||||
const auto realName = i < realAvailableCommands->size()
|
||||
? net::eagle0::shardok::common::CommandType_Name(
|
||||
(*realAvailableCommands)[i]->GetCommandType())
|
||||
@@ -214,13 +214,13 @@ auto ShardokAIClient::StandardChooseCommandIndex(
|
||||
// Group by unit to find the missing position per unit
|
||||
std::unordered_map<int, std::set<std::pair<int, int>>> realPositions;
|
||||
std::unordered_map<int, std::set<std::pair<int, int>>> guessedPositions;
|
||||
for (size_t i = 0; i < realAvailableCommands->size(); i++) {
|
||||
for (size_t i = 0; i < realAvailableCommands->size(); ++i) {
|
||||
const auto &cmd = (*realAvailableCommands)[i];
|
||||
realPositions[cmd->GetActorUnitId()].emplace(
|
||||
cmd->GetTargetRow(),
|
||||
cmd->GetTargetColumn());
|
||||
}
|
||||
for (size_t i = 0; i < commandCount; i++) {
|
||||
for (size_t i = 0; i < commandCount; ++i) {
|
||||
const auto &cmd = (*guessedCommands)[i];
|
||||
guessedPositions[cmd->GetActorUnitId()].emplace(
|
||||
cmd->GetTargetRow(),
|
||||
@@ -250,7 +250,7 @@ auto ShardokAIClient::StandardChooseCommandIndex(
|
||||
|
||||
// Dump all guessed state units for full picture
|
||||
std::cerr << " Guessed state units (" << guessedState->units()->size() << " total):\n";
|
||||
for (size_t i = 0; i < guessedState->units()->size(); i++) {
|
||||
for (size_t i = 0; i < guessedState->units()->size(); ++i) {
|
||||
const auto *u = guessedState->units()->Get(static_cast<unsigned int>(i));
|
||||
std::cerr << " unit_id=" << u->unit_id() << " player=" << u->player_id()
|
||||
<< " status=" << static_cast<int>(u->status()) << " loc=("
|
||||
@@ -263,7 +263,7 @@ auto ShardokAIClient::StandardChooseCommandIndex(
|
||||
"AI command count mismatch: guessed=" + std::to_string(commandCount) +
|
||||
" real=" + std::to_string(realAvailableCommands->size()));
|
||||
}
|
||||
for (size_t i = 0; i < commandCount; i++) {
|
||||
for (size_t i = 0; i < commandCount; ++i) {
|
||||
CheckCommand((*realAvailableCommands)[i], (*guessedCommands)[i]);
|
||||
}
|
||||
|
||||
@@ -490,7 +490,7 @@ auto ShardokAIClient::ChooseCommandIndex(
|
||||
if (totalChoices % 1000 == 0) {
|
||||
std::cout << "TYPES CHOSEN:\n";
|
||||
vector<std::pair<int, CommandType>> choices{};
|
||||
for (int i = 0; i <= net::eagle0::shardok::common::CommandType_MAX; i++) {
|
||||
for (int i = 0; i <= net::eagle0::shardok::common::CommandType_MAX; ++i) {
|
||||
if (typeChosenCount[i] != 0) {
|
||||
choices.emplace_back(typeChosenCount[i], static_cast<CommandType>(i));
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ auto SortActionsByWeight(
|
||||
std::vector<size_t> sortedIndices(actions.size());
|
||||
std::iota(sortedIndices.begin(), sortedIndices.end(), 0);
|
||||
|
||||
std::sort(sortedIndices.begin(), sortedIndices.end(), [&weights](size_t a, size_t b) {
|
||||
std::ranges::sort(sortedIndices, [&weights](size_t a, size_t b) {
|
||||
return weights[a] > weights[b];
|
||||
});
|
||||
|
||||
@@ -398,9 +398,8 @@ std::vector<size_t> ShardokGameEngine::filterActions(
|
||||
const MCTSGameState& /*state*/) const {
|
||||
// All filtering is already done in getLegalActions() using AICommandFilter
|
||||
// This method is used by simulation policies and doesn't need additional filtering
|
||||
std::vector<size_t> indices;
|
||||
indices.reserve(actions.size());
|
||||
for (size_t i = 0; i < actions.size(); ++i) { indices.push_back(i); }
|
||||
std::vector<size_t> indices(actions.size());
|
||||
std::iota(indices.begin(), indices.end(), 0);
|
||||
return indices;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ using net::eagle0::shardok::storage::fb::PlayerInfo;
|
||||
|
||||
using ScoreValue = double;
|
||||
|
||||
auto AttackerHoldsCriticalTilesVictoryScore(
|
||||
[[nodiscard]] auto AttackerHoldsCriticalTilesVictoryScore(
|
||||
const GameStateW& gameState,
|
||||
const CoordsSet& criticalTileLocations,
|
||||
const PlayerInfo* player,
|
||||
@@ -32,12 +32,12 @@ auto AttackerHoldsCriticalTilesVictoryScore(
|
||||
const BattalionTypeGetter& battalionTypeGetter,
|
||||
ActionPoints braveWaterCost) -> ScoreValue;
|
||||
|
||||
auto DefenderHoldsCriticalTilesVictoryScore(
|
||||
[[nodiscard]] auto DefenderHoldsCriticalTilesVictoryScore(
|
||||
const GameStateW& gameState,
|
||||
const CoordsSet& criticalTileLocations,
|
||||
const PlayerInfo* player) -> ScoreValue;
|
||||
|
||||
auto LastPlayerStandingVictoryScore(
|
||||
[[nodiscard]] auto LastPlayerStandingVictoryScore(
|
||||
const GameStateW& gameState,
|
||||
const PlayerInfo* player,
|
||||
const APDCache& apdCache,
|
||||
|
||||
@@ -230,7 +230,7 @@ auto MakeMCTSOptimizedAIScoreCalculator(
|
||||
std::vector<BattalionTypeSPtr> battalionTypes(BattalionTypeId::BattalionTypeId_MAX + 1);
|
||||
for (int typeId = BattalionTypeId::BattalionTypeId_MIN;
|
||||
typeId <= BattalionTypeId::BattalionTypeId_MAX;
|
||||
typeId++) {
|
||||
++typeId) {
|
||||
auto battalionTypeId = static_cast<BattalionTypeId>(typeId);
|
||||
battalionTypes[battalionTypeId] = settingsGetter.GetBattalionType(battalionTypeId);
|
||||
}
|
||||
|
||||
@@ -356,7 +356,7 @@ auto MakeStandardAIScoreCalculatorWithExperiment(
|
||||
std::vector<BattalionTypeSPtr> battalionTypes(BattalionTypeId::BattalionTypeId_MAX + 1);
|
||||
for (int typeId = BattalionTypeId::BattalionTypeId_MIN;
|
||||
typeId <= BattalionTypeId::BattalionTypeId_MAX;
|
||||
typeId++) {
|
||||
++typeId) {
|
||||
auto battalionTypeId = static_cast<BattalionTypeId>(typeId);
|
||||
battalionTypes[battalionTypeId] = settingsGetter.GetBattalionType(battalionTypeId);
|
||||
}
|
||||
|
||||
+2
-4
@@ -7,8 +7,7 @@
|
||||
#include "src/main/cpp/net/eagle0/shardok/ai/AIScoreUtilities.hpp"
|
||||
#include "src/main/cpp/net/eagle0/shardok/library/map/CoordsSet.hpp"
|
||||
|
||||
namespace shardok {
|
||||
namespace score_calculator_internal {
|
||||
namespace shardok::score_calculator_internal {
|
||||
|
||||
auto EffectiveDistanceCache::GetOrCompute(
|
||||
const Unit* unit,
|
||||
@@ -125,5 +124,4 @@ auto AttackerMultiplierForTargetDistance(
|
||||
isLateGame);
|
||||
}
|
||||
|
||||
} // namespace score_calculator_internal
|
||||
} // namespace shardok
|
||||
} // namespace shardok::score_calculator_internal
|
||||
|
||||
+8
-9
@@ -24,8 +24,7 @@
|
||||
#include "src/main/flatbuffer/net/eagle0/shardok/storage/hex_map_generated.h"
|
||||
#include "src/main/flatbuffer/net/eagle0/shardok/storage/unit_generated.h"
|
||||
|
||||
namespace shardok {
|
||||
namespace score_calculator_internal {
|
||||
namespace shardok::score_calculator_internal {
|
||||
|
||||
using HexMap = net::eagle0::shardok::storage::fb::HexMap;
|
||||
using Unit = net::eagle0::shardok::storage::fb::Unit;
|
||||
@@ -51,13 +50,13 @@ struct EffectiveDistanceCache {
|
||||
struct CacheKey {
|
||||
UnitId unitId;
|
||||
Coords target;
|
||||
bool operator==(const CacheKey& other) const {
|
||||
[[nodiscard]] bool operator==(const CacheKey& other) const {
|
||||
return unitId == other.unitId && target == other.target;
|
||||
}
|
||||
};
|
||||
|
||||
struct CacheKeyHash {
|
||||
size_t operator()(const CacheKey& key) const {
|
||||
[[nodiscard]] size_t operator()(const CacheKey& key) const {
|
||||
return std::hash<UnitId>{}(key.unitId) ^ (std::hash<int>{}(key.target.row()) << 1) ^
|
||||
(std::hash<int>{}(key.target.column()) << 2);
|
||||
}
|
||||
@@ -65,7 +64,7 @@ struct EffectiveDistanceCache {
|
||||
|
||||
mutable gtl::flat_hash_map<CacheKey, DIST_T, CacheKeyHash> cache;
|
||||
|
||||
DIST_T GetOrCompute(
|
||||
[[nodiscard]] DIST_T GetOrCompute(
|
||||
const Unit* unit,
|
||||
const Coords& target,
|
||||
const ActionPointDistances* notBravingApd,
|
||||
@@ -75,11 +74,12 @@ struct EffectiveDistanceCache {
|
||||
|
||||
/// Calculate score for FLEE strategy
|
||||
/// Returns negative score based on fleeing units
|
||||
auto FleeStrategyScoreForState(const GameStateW& gameState, PlayerId playerId) -> ScoreValue;
|
||||
[[nodiscard]] auto FleeStrategyScoreForState(const GameStateW& gameState, PlayerId playerId)
|
||||
-> ScoreValue;
|
||||
|
||||
/// Calculate attacker multiplier based on distance to priority targets
|
||||
/// This is used to weight attacker units by their proximity to objectives
|
||||
auto AttackerMultiplierForTargetDistance(
|
||||
[[nodiscard]] auto AttackerMultiplierForTargetDistance(
|
||||
const Unit* attackingUnit,
|
||||
const std::vector<TargetAndAttackLocations>& priorityList,
|
||||
const std::vector<const Unit*>& occupants,
|
||||
@@ -89,7 +89,6 @@ auto AttackerMultiplierForTargetDistance(
|
||||
const ActionPointDistances* bravingApd,
|
||||
bool isLateGame) -> double;
|
||||
|
||||
} // namespace score_calculator_internal
|
||||
} // namespace shardok
|
||||
} // namespace shardok::score_calculator_internal
|
||||
|
||||
#endif // EAGLE0_SHARDOK_AI_SCORE_PRIVATE_AI_SCORE_CALCULATOR_SHARED_UTILITIES_HPP
|
||||
|
||||
@@ -10,8 +10,7 @@
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
namespace shardok {
|
||||
namespace ai_battle_simulator {
|
||||
namespace shardok::ai_battle_simulator {
|
||||
|
||||
using net::eagle0::shardok::ai_battle_simulator::AIAlgorithmType;
|
||||
using net::eagle0::shardok::ai_battle_simulator::PlayerConfig;
|
||||
@@ -110,5 +109,4 @@ std::string AiBattleConfigLoader::ToJsonString(const BattleConfigProto& config)
|
||||
return jsonString;
|
||||
}
|
||||
|
||||
} // namespace ai_battle_simulator
|
||||
} // namespace shardok
|
||||
} // namespace shardok::ai_battle_simulator
|
||||
|
||||
@@ -13,8 +13,7 @@
|
||||
#include "src/main/protobuf/net/eagle0/shardok/ai_battle_simulator/ai_battle_config.pb.h"
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
namespace shardok {
|
||||
namespace ai_battle_simulator {
|
||||
namespace shardok::ai_battle_simulator {
|
||||
|
||||
using BattleConfigProto = net::eagle0::shardok::ai_battle_simulator::BattleConfig;
|
||||
|
||||
@@ -41,7 +40,6 @@ public:
|
||||
[[nodiscard]] static std::string ToJsonString(const BattleConfigProto& config);
|
||||
};
|
||||
|
||||
} // namespace ai_battle_simulator
|
||||
} // namespace shardok
|
||||
} // namespace shardok::ai_battle_simulator
|
||||
|
||||
#endif // EAGLE0_SHARDOK_AI_BATTLE_SIMULATOR_AI_BATTLE_CONFIG_HPP
|
||||
|
||||
@@ -28,8 +28,7 @@
|
||||
#include "src/main/protobuf/net/eagle0/shardok/common/player_info.pb.h"
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
namespace shardok {
|
||||
namespace ai_battle_simulator {
|
||||
namespace shardok::ai_battle_simulator {
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -331,10 +330,6 @@ GameStateW AiBattleSimulator::CreateInitialGameState() const {
|
||||
// Load map
|
||||
auto hexMapProto = LoadMap(config_.map_name());
|
||||
|
||||
// Create player info protos
|
||||
std::vector<net::eagle0::shardok::common::PlayerInfo> playerInfoProtos;
|
||||
playerInfoProtos.reserve(2);
|
||||
|
||||
// Attacker info
|
||||
net::eagle0::shardok::common::PlayerInfo attackerInfo;
|
||||
attackerInfo.set_player_id(ATTACKER_ID);
|
||||
@@ -344,7 +339,6 @@ GameStateW AiBattleSimulator::CreateInitialGameState() const {
|
||||
net::eagle0::shardok::common::VICTORY_CONDITION_LAST_PLAYER_STANDING);
|
||||
attackerInfo.add_victory_conditions(
|
||||
net::eagle0::shardok::common::VICTORY_CONDITION_HOLDS_CRITICAL_TILES);
|
||||
playerInfoProtos.push_back(std::move(attackerInfo));
|
||||
|
||||
// Defender info
|
||||
net::eagle0::shardok::common::PlayerInfo defenderInfo;
|
||||
@@ -355,7 +349,10 @@ GameStateW AiBattleSimulator::CreateInitialGameState() const {
|
||||
net::eagle0::shardok::common::VICTORY_CONDITION_LAST_PLAYER_STANDING);
|
||||
defenderInfo.add_victory_conditions(
|
||||
net::eagle0::shardok::common::VICTORY_CONDITION_WIN_AFTER_MAX_ROUNDS);
|
||||
playerInfoProtos.push_back(std::move(defenderInfo));
|
||||
|
||||
std::vector<net::eagle0::shardok::common::PlayerInfo> playerInfoProtos{
|
||||
std::move(attackerInfo),
|
||||
std::move(defenderInfo)};
|
||||
|
||||
// Create units from config
|
||||
std::vector<net::eagle0::shardok::storage::fb::Unit> units;
|
||||
@@ -961,5 +958,4 @@ BattleResult AiBattleSimulator::CreateResultFromGameState(
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace ai_battle_simulator
|
||||
} // namespace shardok
|
||||
} // namespace shardok::ai_battle_simulator
|
||||
|
||||
@@ -30,7 +30,9 @@ class ShardokEngine;
|
||||
// Type alias for hex map
|
||||
using HexMap = net::eagle0::shardok::storage::fb::HexMap;
|
||||
|
||||
namespace ai_battle_simulator {
|
||||
} // namespace shardok
|
||||
|
||||
namespace shardok::ai_battle_simulator {
|
||||
|
||||
using BattleConfigProto = net::eagle0::shardok::ai_battle_simulator::BattleConfig;
|
||||
|
||||
@@ -146,7 +148,6 @@ private:
|
||||
CreateResultFromGameState(const GameStateW& state, int totalRounds, int totalCommands) const;
|
||||
};
|
||||
|
||||
} // namespace ai_battle_simulator
|
||||
} // namespace shardok
|
||||
} // namespace shardok::ai_battle_simulator
|
||||
|
||||
#endif // EAGLE0_SHARDOK_AI_BATTLE_SIMULATOR_AI_BATTLE_SIMULATOR_HPP
|
||||
|
||||
+2
-1
@@ -191,7 +191,8 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
std::cout << "],\"has_game_status\":" << (hasGameStatus ? "true" : "false") << "}\n";
|
||||
return 0;
|
||||
} else if (!resultPath.empty()) {
|
||||
}
|
||||
if (!resultPath.empty()) {
|
||||
ActionResult result;
|
||||
if (!result.ParseFromString(ReadFile(resultPath))) {
|
||||
throw std::runtime_error("Failed to parse Shardok action result proto");
|
||||
|
||||
@@ -7,8 +7,7 @@
|
||||
#include "src/main/cpp/net/eagle0/common/mcts/abstract/MCTSTypes.hpp"
|
||||
#include "src/main/cpp/net/eagle0/shardok/ai/ShardokAIClient.hpp"
|
||||
|
||||
namespace shardok {
|
||||
namespace ai_testing_common {
|
||||
namespace shardok::ai_testing_common {
|
||||
|
||||
auto AIClientFactory::Create(
|
||||
PlayerId playerId,
|
||||
@@ -30,5 +29,4 @@ auto AIClientFactory::Create(
|
||||
mctsConfig);
|
||||
}
|
||||
|
||||
} // namespace ai_testing_common
|
||||
} // namespace shardok
|
||||
} // namespace shardok::ai_testing_common
|
||||
|
||||
@@ -8,8 +8,7 @@
|
||||
#include "src/main/cpp/net/eagle0/shardok/library/ShardokEngine.hpp"
|
||||
#include "src/main/flatbuffer/net/eagle0/shardok/storage/game_state.hpp"
|
||||
|
||||
namespace shardok {
|
||||
namespace ai_testing_common {
|
||||
namespace shardok::ai_testing_common {
|
||||
|
||||
auto GamePhaseRunner::RunSetupPhase(
|
||||
ShardokEngine& engine,
|
||||
@@ -58,5 +57,4 @@ auto GamePhaseRunner::RunSingleTurn(ShardokEngine& engine, PlayerId playerId, Sh
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace ai_testing_common
|
||||
} // namespace shardok
|
||||
} // namespace shardok::ai_testing_common
|
||||
|
||||
@@ -9,8 +9,7 @@
|
||||
#include "src/main/cpp/net/eagle0/common/byte_vector.hpp"
|
||||
#include "src/main/cpp/net/eagle0/shardok/util/BattalionTypeRegistrar.hpp"
|
||||
|
||||
namespace shardok {
|
||||
namespace ai_testing_common {
|
||||
namespace shardok::ai_testing_common {
|
||||
|
||||
auto GameSettingsFactory::CreateDefault() -> GameSettingsSPtr {
|
||||
auto settings = std::make_shared<GameSettings>();
|
||||
@@ -31,5 +30,4 @@ auto GameSettingsFactory::CreateDefault() -> GameSettingsSPtr {
|
||||
return settings;
|
||||
}
|
||||
|
||||
} // namespace ai_testing_common
|
||||
} // namespace shardok
|
||||
} // namespace shardok::ai_testing_common
|
||||
|
||||
@@ -10,8 +10,7 @@
|
||||
|
||||
#include "src/main/cpp/net/eagle0/shardok/library/settings/GameSettings.hpp"
|
||||
|
||||
namespace shardok {
|
||||
namespace ai_testing_common {
|
||||
namespace shardok::ai_testing_common {
|
||||
|
||||
/**
|
||||
* Factory class for creating GameSettings instances with standard configuration.
|
||||
@@ -33,7 +32,6 @@ public:
|
||||
static auto CreateDefault() -> GameSettingsSPtr;
|
||||
};
|
||||
|
||||
} // namespace ai_testing_common
|
||||
} // namespace shardok
|
||||
} // namespace shardok::ai_testing_common
|
||||
|
||||
#endif // EAGLE0_SHARDOK_AI_TESTING_COMMON_GAME_SETTINGS_FACTORY_HPP
|
||||
|
||||
@@ -32,9 +32,8 @@ private:
|
||||
static auto CannotBecomeOutlaw(const GameStateW &gameState, PlayerId pid) -> bool {
|
||||
if (pid == UNCONTROLLED_PLAYER_ID) return false;
|
||||
|
||||
const auto &player = std::find_if(
|
||||
std::begin(*gameState->player_infos()),
|
||||
std::end(*gameState->player_infos()),
|
||||
const auto &player = std::ranges::find_if(
|
||||
*gameState->player_infos(),
|
||||
[pid](const PlayerInfoFb *pi) { return pi->player_id() == pid; });
|
||||
|
||||
return (player != std::end(*gameState->player_infos()) && player->cannot_become_outlaw());
|
||||
@@ -43,9 +42,8 @@ private:
|
||||
static auto IsAttacker(const GameStateW &gameState, PlayerId pid) -> bool {
|
||||
if (pid == UNCONTROLLED_PLAYER_ID) return false;
|
||||
|
||||
const auto &player = std::find_if(
|
||||
std::begin(*gameState->player_infos()),
|
||||
std::end(*gameState->player_infos()),
|
||||
const auto &player = std::ranges::find_if(
|
||||
*gameState->player_infos(),
|
||||
[pid](const PlayerInfoFb *pi) { return pi->player_id() == pid; });
|
||||
|
||||
return (player == std::end(*gameState->player_infos()) || !player->is_defender());
|
||||
|
||||
@@ -189,12 +189,12 @@ struct BattalionType {
|
||||
}
|
||||
|
||||
[[nodiscard]] auto GetCostToEnterTerrain(const TerrainProto &terrain) const -> ActionCost {
|
||||
if (HasBridge(terrain.modifier()))
|
||||
return ActionCost(
|
||||
ActionCost::standard,
|
||||
if (HasBridge(terrain.modifier())) {
|
||||
return {ActionCost::standard,
|
||||
ActionPoints(std::ceil(
|
||||
100.0 * minimumCostToEnterBridge /
|
||||
terrain.modifier().bridge().integrity().value())));
|
||||
terrain.modifier().bridge().integrity().value()))};
|
||||
}
|
||||
if (IsFrozen(terrain.modifier())) return costToEnterIce;
|
||||
|
||||
auto terrainCost = GetCostToEnterTerrainType(terrain.type());
|
||||
@@ -208,11 +208,11 @@ struct BattalionType {
|
||||
[[nodiscard]] auto GetCostToEnterTerrain(
|
||||
const net::eagle0::shardok::storage::fb::Terrain_::Type terrainType,
|
||||
const net::eagle0::shardok::storage::fb::TileModifier &tm) const -> ActionCost {
|
||||
if (tm.bridge().present())
|
||||
return ActionCost(
|
||||
ActionCost::standard,
|
||||
if (tm.bridge().present()) {
|
||||
return {ActionCost::standard,
|
||||
ActionPoints(
|
||||
std::ceil(100.0 * minimumCostToEnterBridge / tm.bridge().integrity())));
|
||||
std::ceil(100.0 * minimumCostToEnterBridge / tm.bridge().integrity()))};
|
||||
}
|
||||
if (tm.ice().present()) return costToEnterIce;
|
||||
|
||||
auto terrainCost = GetCostToEnterTerrainType(terrainType);
|
||||
|
||||
@@ -44,7 +44,7 @@ inline constexpr DamageType DamageType_aessence = DamageType::DamageType_aessenc
|
||||
inline constexpr DamageType DamageType_impact = DamageType::DamageType_impact;
|
||||
inline constexpr int NUM_DAMAGE_TYPES = static_cast<int>(DamageType::NUM_DAMAGE_TYPES);
|
||||
|
||||
static inline bool DamageTypeGetsTerrainDefense(const DamageType type) {
|
||||
[[nodiscard]] static inline bool DamageTypeGetsTerrainDefense(const DamageType type) {
|
||||
switch (type) {
|
||||
case DamageType_slashing:
|
||||
case DamageType_puncturing:
|
||||
@@ -132,11 +132,13 @@ public:
|
||||
return damageByType.at(PenetratingIndex(type));
|
||||
};
|
||||
|
||||
bool operator==(const CombatDamage& cmpr) const { return damageByType == cmpr.damageByType; }
|
||||
[[nodiscard]] bool operator==(const CombatDamage& cmpr) const {
|
||||
return damageByType == cmpr.damageByType;
|
||||
}
|
||||
|
||||
bool operator!=(const CombatDamage& cmpr) const { return !(*this == cmpr); }
|
||||
[[nodiscard]] bool operator!=(const CombatDamage& cmpr) const { return !(*this == cmpr); }
|
||||
|
||||
bool operator<=(const CombatDamage& cmpr) const {
|
||||
[[nodiscard]] bool operator<=(const CombatDamage& cmpr) const {
|
||||
return std::ranges::equal(
|
||||
damageByType,
|
||||
cmpr.damageByType,
|
||||
@@ -145,7 +147,7 @@ public:
|
||||
});
|
||||
}
|
||||
|
||||
bool operator>=(const CombatDamage& cmpr) const {
|
||||
[[nodiscard]] bool operator>=(const CombatDamage& cmpr) const {
|
||||
return std::ranges::equal(
|
||||
damageByType,
|
||||
cmpr.damageByType,
|
||||
@@ -154,11 +156,15 @@ public:
|
||||
});
|
||||
}
|
||||
|
||||
bool operator>(const CombatDamage& cmpr) const { return ((*this >= cmpr) && !(*this == cmpr)); }
|
||||
[[nodiscard]] bool operator>(const CombatDamage& cmpr) const {
|
||||
return ((*this >= cmpr) && !(*this == cmpr));
|
||||
}
|
||||
|
||||
bool operator<(const CombatDamage& cmpr) const { return ((*this <= cmpr) && !(*this == cmpr)); }
|
||||
[[nodiscard]] bool operator<(const CombatDamage& cmpr) const {
|
||||
return ((*this <= cmpr) && !(*this == cmpr));
|
||||
}
|
||||
|
||||
CombatDamage operator+(const CombatDamage& add) const {
|
||||
[[nodiscard]] CombatDamage operator+(const CombatDamage& add) const {
|
||||
return Builder()
|
||||
.SetSlashing(
|
||||
GetNormalDamageOfType(DamageType_slashing) +
|
||||
@@ -219,7 +225,7 @@ public:
|
||||
.Build();
|
||||
}
|
||||
|
||||
CombatDamage operator*(const double factor) const {
|
||||
[[nodiscard]] CombatDamage operator*(const double factor) const {
|
||||
return Builder()
|
||||
.SetSlashing(GetNormalDamageOfType(DamageType_slashing) * factor)
|
||||
.SetPuncturing(GetNormalDamageOfType(DamageType_puncturing) * factor)
|
||||
@@ -442,7 +448,7 @@ public:
|
||||
|
||||
[[nodiscard]] auto ToBuilder() const -> Builder {
|
||||
Builder builder = Builder();
|
||||
for (int i = 0; i < static_cast<int>(NUM_DAMAGE_TYPES); i++) {
|
||||
for (int i = 0; i < static_cast<int>(NUM_DAMAGE_TYPES); ++i) {
|
||||
const auto type = static_cast<DamageType>(i);
|
||||
builder.SetDamageByType(type, false, this->GetNormalDamageOfType(type));
|
||||
builder.SetDamageByType(type, true, this->GetPenetratingDamageOfType(type));
|
||||
@@ -451,7 +457,9 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
inline CombatDamage operator*(const double factor, const CombatDamage& dmg) { return dmg * factor; }
|
||||
[[nodiscard]] inline CombatDamage operator*(const double factor, const CombatDamage& dmg) {
|
||||
return dmg * factor;
|
||||
}
|
||||
} // namespace shardok
|
||||
|
||||
#endif // EAGLE0_SHARDOK_LIBRARY_COMBAT_DAMAGE_HPP
|
||||
|
||||
@@ -21,19 +21,23 @@ using WeatherFb = net::eagle0::shardok::storage::fb::Weather;
|
||||
using TerrainProto = net::eagle0::shardok::common::Terrain;
|
||||
using Terrain = net::eagle0::shardok::storage::fb::Terrain;
|
||||
|
||||
auto PropensityByTerrain(const Terrain *terrain, const SettingsGetter &settings) -> int;
|
||||
[[nodiscard]] auto PropensityByTerrain(const Terrain *terrain, const SettingsGetter &settings)
|
||||
-> int;
|
||||
|
||||
auto PropensityByTerrain(const TerrainProto &terrain, const SettingsGetter &settings) -> int;
|
||||
[[nodiscard]] auto PropensityByTerrain(const TerrainProto &terrain, const SettingsGetter &settings)
|
||||
-> int;
|
||||
|
||||
auto PropensityByTerrain(
|
||||
[[nodiscard]] auto PropensityByTerrain(
|
||||
const TerrainType &terrainType,
|
||||
const TileModifierProto &modifier,
|
||||
const SettingsGetter &settings) -> int;
|
||||
|
||||
auto GetFireDamage(int troops, double openEndedPercentileRoll1, double openEndedPercentileRoll2)
|
||||
-> CombatDamage;
|
||||
[[nodiscard]] auto GetFireDamage(
|
||||
int troops,
|
||||
double openEndedPercentileRoll1,
|
||||
double openEndedPercentileRoll2) -> CombatDamage;
|
||||
|
||||
auto GetExtinguishOdds(
|
||||
[[nodiscard]] auto GetExtinguishOdds(
|
||||
const SettingsGetter &settings,
|
||||
const Terrain *terrain,
|
||||
const WeatherFb *currentWeather,
|
||||
@@ -41,7 +45,7 @@ auto GetExtinguishOdds(
|
||||
double intelligence,
|
||||
bool ownTile) -> PercentileRollOdds;
|
||||
|
||||
auto GetStartFireOdds(
|
||||
[[nodiscard]] auto GetStartFireOdds(
|
||||
const SettingsGetter &settings,
|
||||
const Terrain &terrain,
|
||||
const WeatherFb ¤tWeather,
|
||||
|
||||
@@ -36,25 +36,19 @@ public:
|
||||
using BaseType::BaseType;
|
||||
|
||||
// Default constructor
|
||||
GameStateW() : BaseType() {}
|
||||
GameStateW() = default;
|
||||
|
||||
// Copy constructor
|
||||
GameStateW(const GameStateW& other) : BaseType(other) {}
|
||||
GameStateW(const GameStateW& other) = default;
|
||||
|
||||
// Move constructor
|
||||
GameStateW(GameStateW&& other) noexcept : BaseType(std::move(other)) {}
|
||||
GameStateW(GameStateW&& other) noexcept = default;
|
||||
|
||||
// Copy assignment
|
||||
GameStateW& operator=(const GameStateW& other) {
|
||||
BaseType::operator=(other);
|
||||
return *this;
|
||||
}
|
||||
GameStateW& operator=(const GameStateW& other) = default;
|
||||
|
||||
// Move assignment
|
||||
GameStateW& operator=(GameStateW&& other) noexcept {
|
||||
BaseType::operator=(std::move(other));
|
||||
return *this;
|
||||
}
|
||||
GameStateW& operator=(GameStateW&& other) noexcept = default;
|
||||
|
||||
// Constructor from base type
|
||||
GameStateW(const BaseType& base) : BaseType(base) {}
|
||||
|
||||
@@ -42,7 +42,7 @@ private:
|
||||
[[nodiscard]] virtual auto InternalExecute(
|
||||
const GameStateW& currentState,
|
||||
const std::shared_ptr<RandomGenerator>& generator) const -> std::vector<ActionResult> {
|
||||
return InternalExecuteWithRoll(currentState, generator, std::optional<int32_t>());
|
||||
return InternalExecuteWithRoll(currentState, generator, std::nullopt);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual auto InternalExecuteWithRoll(
|
||||
|
||||
@@ -443,7 +443,7 @@ void ShardokEngine::PostPlacementCommands(
|
||||
reinforcementPositions);
|
||||
|
||||
// first make sure they're all valid and there are no duplicates
|
||||
for (size_t i = 0; i < placementInfos.size(); i++) {
|
||||
for (size_t i = 0; i < placementInfos.size(); ++i) {
|
||||
const UnitPlacementInfo &pi = placementInfos[i];
|
||||
|
||||
const auto it = std::ranges::find_if(*placementCommands, [pi](const CommandSPtr &cmd) {
|
||||
@@ -455,7 +455,7 @@ void ShardokEngine::PostPlacementCommands(
|
||||
}
|
||||
|
||||
// check that we're not double-filling any location or double-placing any unit
|
||||
for (size_t j = i + 1; j < placementInfos.size(); j++) {
|
||||
for (size_t j = i + 1; j < placementInfos.size(); ++j) {
|
||||
const UnitPlacementInfo &other = placementInfos[j];
|
||||
|
||||
if (pi.unitId == other.unitId)
|
||||
|
||||
+6
-6
@@ -31,7 +31,7 @@ auto ActionPointDistances::BraveWaterPossibleCoords(const HexMap* hexMap) const
|
||||
const int indexCount = hexMap->row_count() * hexMap->column_count();
|
||||
info->details.reserve(indexCount);
|
||||
const auto indexToCoords = CreateIndexToCoords(hexMap);
|
||||
for (int i = 0; i < indexCount; i++) {
|
||||
for (int i = 0; i < indexCount; ++i) {
|
||||
if (const Terrain* terrain = hexMap->terrain()->Get(i);
|
||||
IsWater(terrain->type()) && !terrain->modifier().bridge().present() &&
|
||||
!terrain->modifier().ice().present()) {
|
||||
@@ -71,7 +71,7 @@ auto ActionPointDistances::CreateIndexToCoords(const HexMap* hexMap) -> std::vec
|
||||
const int indexCount = hexMap->row_count() * columnCount;
|
||||
std::vector<Coords> indexToCoords;
|
||||
indexToCoords.reserve(indexCount);
|
||||
for (int i = 0; i < indexCount; i++) {
|
||||
for (int i = 0; i < indexCount; ++i) {
|
||||
indexToCoords.emplace_back(
|
||||
static_cast<int8_t>(i / columnCount),
|
||||
static_cast<int8_t>(i % columnCount));
|
||||
@@ -85,7 +85,7 @@ auto ActionPointDistances::CreateAdjacencyTable(const HexMap* hexMap)
|
||||
const int indexCount = hexMap->row_count() * columnCount;
|
||||
std::vector<std::array<int, 6>> adjacencyTable;
|
||||
adjacencyTable.reserve(indexCount);
|
||||
for (int i = 0; i < indexCount; i++) {
|
||||
for (int i = 0; i < indexCount; ++i) {
|
||||
const Coords coords(
|
||||
static_cast<int8_t>(i / columnCount),
|
||||
static_cast<int8_t>(i % columnCount));
|
||||
@@ -119,7 +119,7 @@ void ActionPointDistances::PopulateOne(
|
||||
|
||||
// Find starting index (the one with distance 0)
|
||||
const int distanceCount = static_cast<int>(ds.size());
|
||||
for (int i = 0; i < distanceCount; i++) {
|
||||
for (int i = 0; i < distanceCount; ++i) {
|
||||
if (ds[i] == 0) {
|
||||
pq.emplace(0, i);
|
||||
break;
|
||||
@@ -141,7 +141,7 @@ void ActionPointDistances::PopulateOne(
|
||||
|
||||
// Prefetch terrain data for all neighbors to reduce memory stalls
|
||||
const std::array<int, 6>& neighbors = adjacencyTable[currentIndex];
|
||||
for (int i = 0; i < 6 && neighbors[i] != -1; i++) {
|
||||
for (int i = 0; i < 6 && neighbors[i] != -1; ++i) {
|
||||
__builtin_prefetch(hexMap->terrain()->Get(neighbors[i]), 0, 3);
|
||||
}
|
||||
|
||||
@@ -243,7 +243,7 @@ OnDemandActionPointDistances::OnDemandActionPointDistances(
|
||||
|
||||
auto braveWaterPossibleCoords = includeBravingWater ? BraveWaterPossibleCoords(map) : nullptr;
|
||||
|
||||
for (int fromIndex = 0; fromIndex < indexCount; fromIndex++) {
|
||||
for (int fromIndex = 0; fromIndex < indexCount; ++fromIndex) {
|
||||
distances[fromIndex] = std::async(
|
||||
std::launch::deferred,
|
||||
&OnDemandActionPointDistances::GenerateDistances,
|
||||
|
||||
+10
-8
@@ -43,7 +43,7 @@ protected:
|
||||
const std::shared_ptr<BraveableTileInfo> &braveWaterPossibleCoords,
|
||||
const std::vector<Coords> &indexToCoords,
|
||||
const std::vector<std::array<int, 6>> &adjacencyTable);
|
||||
static auto GenerateDistances(
|
||||
[[nodiscard]] static auto GenerateDistances(
|
||||
int fromIndex,
|
||||
const HexMap *hexMap,
|
||||
bool includeBravingWater,
|
||||
@@ -51,13 +51,15 @@ protected:
|
||||
const BattalionTypeSPtr &battalionType,
|
||||
const std::shared_ptr<BraveableTileInfo> &braveWaterPossibleCoords)
|
||||
-> std::vector<DIST_T>;
|
||||
auto BraveWaterPossibleCoords(const HexMap *hexMap) const -> std::shared_ptr<BraveableTileInfo>;
|
||||
[[nodiscard]] auto BraveWaterPossibleCoords(const HexMap *hexMap) const
|
||||
-> std::shared_ptr<BraveableTileInfo>;
|
||||
|
||||
// Create coordinate lookup table for efficient index->coords conversion
|
||||
static auto CreateIndexToCoords(const HexMap *hexMap) -> std::vector<Coords>;
|
||||
[[nodiscard]] static auto CreateIndexToCoords(const HexMap *hexMap) -> std::vector<Coords>;
|
||||
|
||||
// Create adjacency lookup table for efficient neighbor access
|
||||
static auto CreateAdjacencyTable(const HexMap *hexMap) -> std::vector<std::array<int, 6>>;
|
||||
[[nodiscard]] static auto CreateAdjacencyTable(const HexMap *hexMap)
|
||||
-> std::vector<std::array<int, 6>>;
|
||||
|
||||
[[nodiscard]] auto ToIndex(const Coords &coords) const -> int {
|
||||
return coords.row() * column_count + coords.column();
|
||||
@@ -70,9 +72,9 @@ public:
|
||||
|
||||
virtual ~ActionPointDistances() = default;
|
||||
|
||||
virtual auto Distance(int fromIndex, int toIndex) const -> DIST_T = 0;
|
||||
[[nodiscard]] virtual auto Distance(int fromIndex, int toIndex) const -> DIST_T = 0;
|
||||
|
||||
virtual auto Distance(const Coords &from, const Coords &to) const -> DIST_T = 0;
|
||||
[[nodiscard]] virtual auto Distance(const Coords &from, const Coords &to) const -> DIST_T = 0;
|
||||
};
|
||||
|
||||
class OnDemandActionPointDistances final : public ActionPointDistances {
|
||||
@@ -91,11 +93,11 @@ public:
|
||||
|
||||
~OnDemandActionPointDistances() override = default;
|
||||
|
||||
auto Distance(const int fromIndex, const int toIndex) const -> int16_t override {
|
||||
[[nodiscard]] auto Distance(const int fromIndex, const int toIndex) const -> int16_t override {
|
||||
return distances[fromIndex].get()[toIndex];
|
||||
}
|
||||
|
||||
auto Distance(const Coords &from, const Coords &to) const -> int16_t override {
|
||||
[[nodiscard]] auto Distance(const Coords &from, const Coords &to) const -> int16_t override {
|
||||
return Distance(ToIndex(from), ToIndex(to));
|
||||
}
|
||||
};
|
||||
|
||||
+1
-1
@@ -77,7 +77,7 @@ static auto CreateIceClearedMap(const HexMap* map) -> fb::HexMapW {
|
||||
auto* mutableMap = mapCopy.Get();
|
||||
auto* terrainVec = mutableMap->mutable_terrain();
|
||||
|
||||
for (size_t i = 0; i < terrainVec->size(); i++) {
|
||||
for (size_t i = 0; i < terrainVec->size(); ++i) {
|
||||
// Only process tiles with ice
|
||||
// const_cast is safe here because we own the mutable buffer (mapCopy)
|
||||
if (auto* terrain = const_cast<Terrain*>(terrainVec->GetMutableObject(i));
|
||||
|
||||
+6
-6
@@ -22,7 +22,7 @@ struct MapId {
|
||||
uint64_t terrainTypesId;
|
||||
uint64_t modifierId;
|
||||
|
||||
auto operator==(const MapId& other) const -> bool {
|
||||
[[nodiscard]] auto operator==(const MapId& other) const -> bool {
|
||||
return terrainTypesId == other.terrainTypesId && modifierId == other.modifierId;
|
||||
}
|
||||
};
|
||||
@@ -34,7 +34,7 @@ struct FullCacheKey {
|
||||
bool includeBravingWater;
|
||||
int braveWaterCost;
|
||||
|
||||
bool operator==(const FullCacheKey& other) const {
|
||||
[[nodiscard]] bool operator==(const FullCacheKey& other) const {
|
||||
return mapId == other.mapId && battalionTypeId == other.battalionTypeId &&
|
||||
includeBravingWater == other.includeBravingWater &&
|
||||
braveWaterCost == other.braveWaterCost;
|
||||
@@ -43,7 +43,7 @@ struct FullCacheKey {
|
||||
|
||||
// Hash function for FullCacheKey
|
||||
struct FullCacheKeyHash {
|
||||
size_t operator()(const FullCacheKey& key) const {
|
||||
[[nodiscard]] size_t operator()(const FullCacheKey& key) const {
|
||||
// Pack small fields into a single 64-bit value
|
||||
uint64_t packed = (static_cast<uint64_t>(key.battalionTypeId) << 32) |
|
||||
(static_cast<uint64_t>(key.braveWaterCost) << 1) |
|
||||
@@ -85,7 +85,7 @@ private:
|
||||
// Epoch system removed - TLS cache uses size-based eviction instead
|
||||
|
||||
// Helper to build cache key
|
||||
static auto MakeCacheKey(
|
||||
[[nodiscard]] static auto MakeCacheKey(
|
||||
const MapId& mapId,
|
||||
const BattalionTypeSPtr& battalionType,
|
||||
bool includeBravingWater,
|
||||
@@ -107,7 +107,7 @@ public:
|
||||
bool includeBravingWater,
|
||||
int braveWaterActionPointCost = -1) -> const ActionPointDistances*;
|
||||
|
||||
static auto GetMapId(const HexMap* map) -> MapId;
|
||||
[[nodiscard]] static auto GetMapId(const HexMap* map) -> MapId;
|
||||
|
||||
// Consolidate the thread-safe cache into the persistent cache and clear
|
||||
// the current thread's local cache. This is only safe if we know reads
|
||||
@@ -116,7 +116,7 @@ public:
|
||||
|
||||
// Cache management methods
|
||||
static void ClearThreadLocalCache();
|
||||
static size_t GetThreadLocalCacheSize();
|
||||
[[nodiscard]] static size_t GetThreadLocalCacheSize();
|
||||
};
|
||||
|
||||
using APDCache = std::shared_ptr<ActionPointDistancesCache>;
|
||||
|
||||
+3
-3
@@ -42,13 +42,13 @@ auto FixedActionPointDistances::Create(
|
||||
|
||||
int chunkSize = (indexCount + ASYNC_COUNT - 1) / ASYNC_COUNT;
|
||||
// Break into chunks for async
|
||||
for (int chunkIdx = 0; chunkIdx < ASYNC_COUNT; chunkIdx++) {
|
||||
for (int chunkIdx = 0; chunkIdx < ASYNC_COUNT; ++chunkIdx) {
|
||||
futures[chunkIdx] = std::async(std::launch::async, [=]() -> vector<vector<DIST_T>> {
|
||||
vector<vector<DIST_T>> chunkVec;
|
||||
chunkVec.reserve(chunkSize);
|
||||
const int chunkStartIndex = chunkIdx * chunkSize;
|
||||
|
||||
for (int i = 0; i < chunkSize; i++) {
|
||||
for (int i = 0; i < chunkSize; ++i) {
|
||||
const auto fromIndex = chunkStartIndex + i;
|
||||
if (fromIndex >= indexCount) { continue; }
|
||||
chunkVec.push_back(ActionPointDistances::GenerateDistances(
|
||||
@@ -65,7 +65,7 @@ auto FixedActionPointDistances::Create(
|
||||
|
||||
apd->distances.reserve(indexCount);
|
||||
|
||||
for (int chunkIdx = 0; chunkIdx < ASYNC_COUNT; chunkIdx++) {
|
||||
for (int chunkIdx = 0; chunkIdx < ASYNC_COUNT; ++chunkIdx) {
|
||||
auto resultsVec = futures[chunkIdx].get();
|
||||
apd->distances.insert(apd->distances.end(), resultsVec.begin(), resultsVec.end());
|
||||
}
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ private:
|
||||
|
||||
public:
|
||||
// Factory method to create FixedActionPointDistances
|
||||
static auto Create(
|
||||
[[nodiscard]] static auto Create(
|
||||
const HexMap *map,
|
||||
const BattalionTypeSPtr &battalionType,
|
||||
bool includeBravingWater,
|
||||
|
||||
+5
-5
@@ -68,7 +68,7 @@ void ApplyResolvedUnit(
|
||||
// If a VIP was captured, alter the morale of all this player's units
|
||||
if (status == net::eagle0::shardok::storage::fb::UnitStatus_CAPTURED_UNIT &&
|
||||
unit.has_attached_hero() && unit.attached_hero().is_vip()) {
|
||||
for (uint32_t i = 0; i < inoutState->units()->size(); i++) {
|
||||
for (uint32_t i = 0; i < inoutState->units()->size(); ++i) {
|
||||
auto *playerUnit = GetMutableUnit(inoutState, i);
|
||||
if (playerUnit->player_id() != unit.player_id()) continue;
|
||||
if (playerUnit->unit_id() == unit.unit_id()) continue;
|
||||
@@ -248,12 +248,12 @@ void MutatingApplyResult(
|
||||
static_cast<net::eagle0::shardok::storage::fb::GameStatus_::State>(
|
||||
result.game_status().state())));
|
||||
const int winningShardokIdCount = result.game_status().winning_shardok_ids_size();
|
||||
for (int i = 0; i < winningShardokIdCount; i++) {
|
||||
for (int i = 0; i < winningShardokIdCount; ++i) {
|
||||
mutatingGameState->mutable_status()->mutable_winning_shardok_ids()->Mutate(
|
||||
i,
|
||||
result.game_status().winning_shardok_ids(i));
|
||||
}
|
||||
for (int i = winningShardokIdCount; i < 10; i++) {
|
||||
for (int i = winningShardokIdCount; i < 10; ++i) {
|
||||
mutatingGameState->mutable_status()->mutable_winning_shardok_ids()->Mutate(i, -1);
|
||||
}
|
||||
|
||||
@@ -385,10 +385,10 @@ void MutatingApplyResult(
|
||||
internalAssert(mutatingGameState->mutate_eligible_charger_id(-1));
|
||||
}
|
||||
const int possibleChargeeCount = result.possible_chargees_size();
|
||||
for (int i = 0; i < possibleChargeeCount; i++) {
|
||||
for (int i = 0; i < possibleChargeeCount; ++i) {
|
||||
mutatingGameState->mutable_possible_chargee_ids()->Mutate(i, result.possible_chargees(i));
|
||||
}
|
||||
for (int i = possibleChargeeCount; i < 6; i++) {
|
||||
for (int i = possibleChargeeCount; i < 6; ++i) {
|
||||
mutatingGameState->mutable_possible_chargee_ids()->Mutate(i, -1);
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -23,11 +23,11 @@ void MutatingApplyResult(
|
||||
GameStateW& mutatingGameState,
|
||||
const ActionResultProto& actionResult,
|
||||
const SettingsGetter& settings);
|
||||
auto ApplyResult(
|
||||
[[nodiscard]] auto ApplyResult(
|
||||
GameStateW startingState,
|
||||
const ActionResultProto& actionResult,
|
||||
const SettingsGetter& settings) -> GameStateW;
|
||||
auto ApplyResults(
|
||||
[[nodiscard]] auto ApplyResults(
|
||||
const GameStateW& startingState,
|
||||
const std::vector<ActionResultProto>& actionResults,
|
||||
const SettingsGetter& settings) -> GameStateW;
|
||||
|
||||
@@ -19,7 +19,7 @@ auto CopyWithExtraUnits(const GameStateW& original, int additionalCount) -> Game
|
||||
|
||||
// Add the requested units plus some extra slack for future use
|
||||
int extraSlack = std::max(5, additionalCount * 2);
|
||||
for (int i = 0; i < additionalCount + extraSlack; i++) {
|
||||
for (int i = 0; i < additionalCount + extraSlack; ++i) {
|
||||
Unit unit;
|
||||
unit.mutate_unit_id(static_cast<int16_t>(endGST.units.size()));
|
||||
if (i < additionalCount) {
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
|
||||
namespace shardok {
|
||||
|
||||
auto CopyWithExtraUnits(const GameStateW& original, int additionalCount) -> GameStateW;
|
||||
[[nodiscard]] auto CopyWithExtraUnits(const GameStateW& original, int additionalCount)
|
||||
-> GameStateW;
|
||||
|
||||
} // namespace shardok
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ auto BurnStructuresResult(const GameStateW &gameState, const SettingsGetter &set
|
||||
*result.mutable_changed_tile_modifiers() = {burnedTmcs.begin(), burnedTmcs.end()};
|
||||
return result;
|
||||
} else {
|
||||
return std::optional<ActionResultProto>();
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,10 +25,9 @@ static inline auto GameIsOver(const GameStatusFb* status) -> bool {
|
||||
}
|
||||
|
||||
auto UpdateGameStatusAction::GetPlayerInfo(int playerId) const -> const PlayerInfoFb* {
|
||||
return *std::find_if(
|
||||
std::begin(*gameState->player_infos()),
|
||||
std::end(*gameState->player_infos()),
|
||||
[playerId](const PlayerInfoFb* pi) { return pi->player_id() == playerId; });
|
||||
return *std::ranges::find_if(*gameState->player_infos(), [playerId](const PlayerInfoFb* pi) {
|
||||
return pi->player_id() == playerId;
|
||||
});
|
||||
}
|
||||
|
||||
static inline auto HasVictoryCondition(const PlayerInfoFb* pi, const VictoryCondition condition)
|
||||
|
||||
@@ -29,7 +29,7 @@ auto UpdateOpponentKnowledgeAction::InternalExecute(
|
||||
|
||||
auto unitAfter = *unit;
|
||||
|
||||
for (PlayerId pid = 0; pid < 10; pid++) {
|
||||
for (PlayerId pid = 0; pid < 10; ++pid) {
|
||||
if (pid == unitPid) continue;
|
||||
if (static_cast<unsigned int>(pid) >= playerCount) continue;
|
||||
int bump = PlayerIsDefender(currentState, pid) ? defenderKnowledgeGain
|
||||
|
||||
+1
-1
@@ -126,7 +126,7 @@ void BraveWaterCommandFactory::AddAvailableBraveWaterCommands(
|
||||
}
|
||||
|
||||
for (const auto &target : braveWaterTargets) {
|
||||
std::optional<UnitId> ambusher = std::optional<UnitId>();
|
||||
std::optional<UnitId> ambusher = std::nullopt;
|
||||
const auto &targetOccupant = Occupant(units, target);
|
||||
if (targetOccupant) { ambusher = targetOccupant->unit_id(); }
|
||||
commands.push_back(BraveWaterCommandFactory(settings)
|
||||
|
||||
@@ -19,7 +19,7 @@ private:
|
||||
public:
|
||||
explicit CommandFactoriesList(const SettingsGetter& settings);
|
||||
|
||||
auto GetFactories() const -> std::vector<std::shared_ptr<const CommandFactory>>;
|
||||
[[nodiscard]] auto GetFactories() const -> std::vector<std::shared_ptr<const CommandFactory>>;
|
||||
};
|
||||
} // namespace shardok
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ public:
|
||||
|
||||
virtual void AddAvailableCommands(CommandList& commands, const CommandParams& params) const = 0;
|
||||
|
||||
virtual auto IncludeInFollowUps() const -> bool { return true; }
|
||||
[[nodiscard]] virtual auto IncludeInFollowUps() const -> bool { return true; }
|
||||
};
|
||||
} // namespace shardok
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ void FearCommandFactory::AddAvailableFearCommands(
|
||||
|
||||
if (costForFear.IsPossible(remainingActionPoints)) {
|
||||
const int range = settings.Backing().fear_range();
|
||||
for (int distance = 1; distance <= range; distance++) {
|
||||
for (int distance = 1; distance <= range; ++distance) {
|
||||
const auto coordsSet = TilesWithExactDistance(hexMap, position, distance);
|
||||
|
||||
for (const Coords &fearCoords : coordsSet) {
|
||||
|
||||
+1
-1
@@ -46,7 +46,7 @@ auto LightningBoltCommandFactory::AddAvailableLightningBoltCommands(
|
||||
ActionCost::UsesAllActionCost(settings.Backing().lightning_action_point_cost());
|
||||
const int lightningRange = settings.Backing().lightning_range();
|
||||
if (costForLightning.IsPossible(remainingActionPoints)) {
|
||||
for (int distance = 1; distance <= lightningRange; distance++) {
|
||||
for (int distance = 1; distance <= lightningRange; ++distance) {
|
||||
CoordsSet coords = TilesWithExactDistance(hexMap, position, distance);
|
||||
|
||||
for (const Coords &lightningCoords : coords) {
|
||||
|
||||
+1
-1
@@ -41,7 +41,7 @@ void RaiseDeadCommandFactory::AddAvailableRaiseDeadCommands(
|
||||
const BattalionTypeSPtr &undeadType = settings.GetBattalionType(
|
||||
net::eagle0::shardok::storage::fb::BattalionTypeId_UNDEAD);
|
||||
|
||||
for (int distance = 1; distance <= range; distance++) {
|
||||
for (int distance = 1; distance <= range; ++distance) {
|
||||
const CoordsSet coordsSet = TilesWithExactDistance(hexMap, position, distance);
|
||||
|
||||
for (const Coords &raiseDeadCoords : coordsSet) {
|
||||
|
||||
@@ -34,7 +34,7 @@ void ScoutCommandFactory::AddAvailableScoutCommands(
|
||||
const Coords unitLocation = unit->location();
|
||||
|
||||
if (costForScout.IsPossible(remainingActionPoints)) {
|
||||
for (int distance = 1; distance <= scoutRange; distance++) {
|
||||
for (int distance = 1; distance <= scoutRange; ++distance) {
|
||||
CoordsSet coordsSet = TilesWithExactDistance(hexMap, unitLocation, distance);
|
||||
|
||||
for (const Coords& scoutCoords : coordsSet) {
|
||||
|
||||
@@ -46,13 +46,13 @@ public:
|
||||
|
||||
~ArcheryCommand() override = default;
|
||||
|
||||
auto GetCommandType() const -> CommandType override {
|
||||
[[nodiscard]] auto GetCommandType() const -> CommandType override {
|
||||
return net::eagle0::shardok::common::ARCHERY_COMMAND;
|
||||
}
|
||||
|
||||
auto CanUseClientRoll() const -> bool override { return true; }
|
||||
|
||||
auto GetCommandProto() const -> CommandProto override;
|
||||
[[nodiscard]] auto GetCommandProto() const -> CommandProto override;
|
||||
|
||||
[[nodiscard]] int GetActorUnitId() const override { return attackerId; }
|
||||
[[nodiscard]] MapIndex GetTargetRow() const override { return defenderLocation.row(); }
|
||||
|
||||
@@ -32,11 +32,11 @@ public:
|
||||
|
||||
~ControlCommand() override = default;
|
||||
|
||||
auto GetCommandType() const -> CommandType override {
|
||||
[[nodiscard]] auto GetCommandType() const -> CommandType override {
|
||||
return net::eagle0::shardok::common::CONTROL_COMMAND;
|
||||
}
|
||||
|
||||
auto GetCommandProto() const -> CommandProto override;
|
||||
[[nodiscard]] auto GetCommandProto() const -> CommandProto override;
|
||||
[[nodiscard]] auto CanBeFollowUp() const -> bool override { return false; }
|
||||
[[nodiscard]] auto CanDoWithLowMorale() const -> bool override { return true; }
|
||||
[[nodiscard]] auto CanDoWhileStunned() const -> bool override { return false; }
|
||||
|
||||
@@ -41,11 +41,11 @@ public:
|
||||
[[nodiscard]] auto ExecuteWithRoll(const GameStateW& currentState, double roll) const
|
||||
-> vector<ActionResult>;
|
||||
|
||||
auto GetCommandType() const -> CommandType override {
|
||||
[[nodiscard]] auto GetCommandType() const -> CommandType override {
|
||||
return net::eagle0::shardok::common::DISMISS_UNIT_COMMAND;
|
||||
}
|
||||
|
||||
auto GetCommandProto() const -> CommandProto override;
|
||||
[[nodiscard]] auto GetCommandProto() const -> CommandProto override;
|
||||
[[nodiscard]] auto CanBeFollowUp() const -> bool override { return false; }
|
||||
[[nodiscard]] auto CanDoWithLowMorale() const -> bool override { return true; }
|
||||
[[nodiscard]] auto CanDoWhileStunned() const -> bool override { return false; }
|
||||
|
||||
@@ -75,7 +75,7 @@ auto EndTurnCommand::InternalExecute(
|
||||
// Any heroes in fire get burninated
|
||||
// Decrement stun counters, increment cast state
|
||||
const auto beforeFireUnitsCount = runningGameState->units()->size();
|
||||
for (size_t i = 0; i < beforeFireUnitsCount; i++) {
|
||||
for (size_t i = 0; i < beforeFireUnitsCount; ++i) {
|
||||
const auto *beforeUnit = runningGameState->units()->Get(static_cast<unsigned int>(i));
|
||||
if (beforeUnit->status() != net::eagle0::shardok::storage::fb::UnitStatus_NORMAL_UNIT)
|
||||
continue;
|
||||
@@ -114,7 +114,7 @@ auto EndTurnCommand::InternalExecute(
|
||||
endTurnResult.mutable_next_player()->set_value(NextPlayerId(currentState, GetPlayerId()));
|
||||
|
||||
const auto unitsAtEndOfRoundCount = runningGameState->units()->size();
|
||||
for (size_t i = 0; i < unitsAtEndOfRoundCount; i++) {
|
||||
for (size_t i = 0; i < unitsAtEndOfRoundCount; ++i) {
|
||||
// Grab the unit fresh because it might have been modified by a previous iteration of the
|
||||
// loop
|
||||
const auto *eorUnit = runningGameState->units()->Get(static_cast<unsigned int>(i));
|
||||
|
||||
@@ -85,7 +85,7 @@ auto FearCommand::GetFearOdds(
|
||||
double attackerWisdom,
|
||||
const double defenderCharisma) -> PercentileRollOdds {
|
||||
const std::array otherFactors = {
|
||||
MakeOtherFactor(int(50.0 - defenderCharisma), opponentCharismaString)};
|
||||
MakeOtherFactor(static_cast<int>(50.0 - defenderCharisma), opponentCharismaString)};
|
||||
return MakeOdds(
|
||||
fearBaseOdds,
|
||||
0,
|
||||
|
||||
@@ -31,11 +31,11 @@ public:
|
||||
int agilityXp,
|
||||
int professionKnowledgeBump);
|
||||
|
||||
auto GetCommandType() const -> CommandType override {
|
||||
[[nodiscard]] auto GetCommandType() const -> CommandType override {
|
||||
return net::eagle0::shardok::common::FORTIFY_COMMAND;
|
||||
}
|
||||
|
||||
auto GetCommandProto() const -> CommandProto override;
|
||||
[[nodiscard]] auto GetCommandProto() const -> CommandProto override;
|
||||
|
||||
[[nodiscard]] int GetActorUnitId() const override { return fortifyingUnitId; }
|
||||
};
|
||||
|
||||
@@ -37,7 +37,7 @@ public:
|
||||
return net::eagle0::shardok::common::HIDE_COMMAND;
|
||||
}
|
||||
|
||||
auto GetCommandProto() const -> CommandProto override;
|
||||
[[nodiscard]] auto GetCommandProto() const -> CommandProto override;
|
||||
|
||||
[[nodiscard]] int GetActorUnitId() const override { return actorId; }
|
||||
[[nodiscard]] MapIndex GetTargetRow() const override { return target.row(); }
|
||||
|
||||
@@ -143,8 +143,9 @@ auto HolyWaveInspireAction::InternalExecute(
|
||||
|
||||
resultProto.set_type(net::eagle0::shardok::common::INSPIRED_TROOPS);
|
||||
|
||||
float newMorale = moraleBefore + float(inspireBuf);
|
||||
float moraleCap = inspiredUnit->battalion().base_morale() + float(maxInspireOverBase);
|
||||
float newMorale = moraleBefore + static_cast<float>(inspireBuf);
|
||||
float moraleCap =
|
||||
inspiredUnit->battalion().base_morale() + static_cast<float>(maxInspireOverBase);
|
||||
if (moraleCap < newMorale) newMorale = moraleCap;
|
||||
if (newMorale > 100) newMorale = 100;
|
||||
|
||||
|
||||
@@ -51,11 +51,11 @@ public:
|
||||
|
||||
~MeleeCommand() override = default;
|
||||
|
||||
auto GetCommandType() const -> CommandType override {
|
||||
[[nodiscard]] auto GetCommandType() const -> CommandType override {
|
||||
return net::eagle0::shardok::common::MELEE_COMMAND;
|
||||
}
|
||||
|
||||
auto GetCommandProto() const -> CommandProto override;
|
||||
[[nodiscard]] auto GetCommandProto() const -> CommandProto override;
|
||||
|
||||
auto CanUseClientRoll() const -> bool override { return true; }
|
||||
|
||||
|
||||
@@ -33,11 +33,11 @@ public:
|
||||
|
||||
~MeteorCancelCommand() override = default;
|
||||
|
||||
auto GetCommandType() const -> CommandType override {
|
||||
[[nodiscard]] auto GetCommandType() const -> CommandType override {
|
||||
return net::eagle0::shardok::common::METEOR_CANCEL_COMMAND;
|
||||
}
|
||||
|
||||
auto GetCommandProto() const -> CommandProto override;
|
||||
[[nodiscard]] auto GetCommandProto() const -> CommandProto override;
|
||||
[[nodiscard]] auto IsRequiredToEndTurn() const -> bool override { return requiredToEndTurn; }
|
||||
[[nodiscard]] auto CanDoWithLowMorale() const -> bool override { return true; }
|
||||
[[nodiscard]] auto CanDoWithLowVigor() const -> bool override { return true; }
|
||||
|
||||
@@ -33,11 +33,11 @@ public:
|
||||
const CoordsSet& nextRoundTargets);
|
||||
~MeteorStartCommand() override = default;
|
||||
|
||||
auto GetCommandType() const -> CommandType override {
|
||||
[[nodiscard]] auto GetCommandType() const -> CommandType override {
|
||||
return net::eagle0::shardok::common::METEOR_START_COMMAND;
|
||||
}
|
||||
|
||||
auto GetCommandProto() const -> CommandProto override;
|
||||
[[nodiscard]] auto GetCommandProto() const -> CommandProto override;
|
||||
|
||||
[[nodiscard]] int GetActorUnitId() const override { return casterId; }
|
||||
};
|
||||
|
||||
@@ -38,11 +38,11 @@ public:
|
||||
|
||||
~MeteorTargetCommand() override = default;
|
||||
|
||||
auto GetCommandType() const -> CommandType override {
|
||||
[[nodiscard]] auto GetCommandType() const -> CommandType override {
|
||||
return net::eagle0::shardok::common::METEOR_TARGET_COMMAND;
|
||||
}
|
||||
|
||||
auto GetCommandProto() const -> CommandProto override;
|
||||
[[nodiscard]] auto GetCommandProto() const -> CommandProto override;
|
||||
[[nodiscard]] auto IsRequiredToEndTurn() const -> bool override { return requiredToEndTurn; }
|
||||
[[nodiscard]] auto CanDoWithLowMorale() const -> bool override { return true; }
|
||||
[[nodiscard]] auto CanDoWithLowVigor() const -> bool override { return true; }
|
||||
|
||||
@@ -135,9 +135,8 @@ auto shardok::MoveCommand::InternalExecute(
|
||||
KnownAdjacentEnemies(player, allUnits, map, allyPids, destination);
|
||||
|
||||
for (const Unit* possibleChargee : newAdjacentEnemies) {
|
||||
if (std::find_if(
|
||||
knownAdjacentEnemies.begin(),
|
||||
knownAdjacentEnemies.end(),
|
||||
if (std::ranges::find_if(
|
||||
knownAdjacentEnemies,
|
||||
[possibleChargee](const Unit* adj) {
|
||||
return adj->unit_id() == possibleChargee->unit_id();
|
||||
}) == knownAdjacentEnemies.end()) {
|
||||
|
||||
@@ -109,7 +109,7 @@ auto GetNewUnit(
|
||||
unit.mutate_player_id(playerId);
|
||||
unit.mutate_commanding_unit_id(commandingUnitId);
|
||||
|
||||
for (uint32_t i = 0; i < unit.opponent_knowledge()->size(); i++) {
|
||||
for (uint32_t i = 0; i < unit.opponent_knowledge()->size(); ++i) {
|
||||
unit.mutable_opponent_knowledge()->Mutate(i, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -46,11 +46,11 @@ public:
|
||||
|
||||
~ReinforceCommand() override = default;
|
||||
|
||||
auto GetCommandType() const -> CommandType override {
|
||||
[[nodiscard]] auto GetCommandType() const -> CommandType override {
|
||||
return net::eagle0::shardok::common::REINFORCE_COMMAND;
|
||||
}
|
||||
|
||||
auto GetCommandProto() const -> CommandProto override;
|
||||
[[nodiscard]] auto GetCommandProto() const -> CommandProto override;
|
||||
|
||||
[[nodiscard]] auto IsRequiredToEndTurn() const -> bool override { return false; }
|
||||
[[nodiscard]] auto CanBeFollowUp() const -> bool override { return true; }
|
||||
|
||||
@@ -34,7 +34,7 @@ public:
|
||||
return net::eagle0::shardok::common::RELEASE_UNIT_COMMAND;
|
||||
}
|
||||
|
||||
auto GetCommandProto() const -> CommandProto override;
|
||||
[[nodiscard]] auto GetCommandProto() const -> CommandProto override;
|
||||
[[nodiscard]] auto CanBeFollowUp() const -> bool override { return false; }
|
||||
[[nodiscard]] auto CanDoWithLowMorale() const -> bool override { return true; }
|
||||
[[nodiscard]] auto CanDoWhileStunned() const -> bool override { return false; }
|
||||
|
||||
@@ -57,7 +57,7 @@ public:
|
||||
return net::eagle0::shardok::common::REPAIR_COMMAND;
|
||||
}
|
||||
|
||||
auto GetCommandProto() const -> CommandProto override;
|
||||
[[nodiscard]] auto GetCommandProto() const -> CommandProto override;
|
||||
|
||||
[[nodiscard]] auto IsRequiredToEndTurn() const -> bool override { return false; }
|
||||
[[nodiscard]] auto CanBeFollowUp() const -> bool override { return true; }
|
||||
|
||||
@@ -55,11 +55,11 @@ public:
|
||||
[[nodiscard]] auto ExecuteWithRoll(const GameStateW& currentState, double roll) const
|
||||
-> vector<ActionResult>;
|
||||
|
||||
auto GetCommandType() const -> CommandType override {
|
||||
[[nodiscard]] auto GetCommandType() const -> CommandType override {
|
||||
return net::eagle0::shardok::common::SCOUT_COMMAND;
|
||||
}
|
||||
|
||||
auto GetCommandProto() const -> CommandProto override;
|
||||
[[nodiscard]] auto GetCommandProto() const -> CommandProto override;
|
||||
|
||||
[[nodiscard]] auto CanBeFollowUp() const -> bool override { return true; }
|
||||
[[nodiscard]] auto CanDoWithLowMorale() const -> bool override { return false; }
|
||||
|
||||
@@ -43,11 +43,11 @@ public:
|
||||
|
||||
~StartFireCommand() override = default;
|
||||
|
||||
auto GetCommandType() const -> CommandType override {
|
||||
[[nodiscard]] auto GetCommandType() const -> CommandType override {
|
||||
return net::eagle0::shardok::common::START_FIRE_COMMAND;
|
||||
}
|
||||
|
||||
auto GetCommandProto() const -> CommandProto override;
|
||||
[[nodiscard]] auto GetCommandProto() const -> CommandProto override;
|
||||
|
||||
[[nodiscard]] auto CanBeFollowUp() const -> bool override { return true; }
|
||||
[[nodiscard]] auto CanDoWithLowMorale() const -> bool override { return false; }
|
||||
|
||||
+2
-2
@@ -47,7 +47,7 @@ auto GetAcceptOdds(
|
||||
|
||||
double baseDeadliness = settings.Backing().base_deadliness();
|
||||
|
||||
for (int i = 0; i < NUM_RUNS; i++) {
|
||||
for (int i = 0; i < NUM_RUNS; ++i) {
|
||||
double defenderRoll;
|
||||
if (statsKnown) {
|
||||
defenderRoll = i * 100.0 / (NUM_RUNS - 1);
|
||||
@@ -114,7 +114,7 @@ auto GetAcceptOdds(
|
||||
|
||||
Hero defendingHero = defender->attached_hero();
|
||||
defenderWins = 0;
|
||||
for (int i = 0; i < NUM_RUNS; i++) {
|
||||
for (int i = 0; i < NUM_RUNS; ++i) {
|
||||
double defenderRoll;
|
||||
if (heroStatsKnown) {
|
||||
defenderRoll = i * 100.0 / (NUM_RUNS - 1);
|
||||
|
||||
@@ -141,7 +141,7 @@ public:
|
||||
return Wrapper(); // Return empty wrapper for invalid data
|
||||
}
|
||||
|
||||
size_t offset;
|
||||
size_t offset = 0;
|
||||
std::memcpy(&offset, str.data(), sizeof(size_t));
|
||||
|
||||
size_t size = str.size() - sizeof(size_t);
|
||||
@@ -159,7 +159,7 @@ public:
|
||||
return Wrapper(); // Return empty wrapper for invalid data
|
||||
}
|
||||
|
||||
size_t offset;
|
||||
size_t offset = 0;
|
||||
std::memcpy(&offset, bv.data(), sizeof(size_t));
|
||||
|
||||
size_t size = bv.size() - sizeof(size_t);
|
||||
|
||||
@@ -46,15 +46,15 @@ auto ConvertVictoryCondition(const net::eagle0::shardok::common::VictoryConditio
|
||||
|
||||
auto FromPlayerInfoProto(flatbuffers::FlatBufferBuilder& fbb, const PlayerInfoProto& piProto)
|
||||
-> flatbuffers::Offset<net::eagle0::shardok::storage::fb::PlayerInfo> {
|
||||
auto alliesVec = std::vector<AlliedPlayer>();
|
||||
std::vector<AlliedPlayer> alliesVec;
|
||||
alliesVec.reserve(piProto.allies_size());
|
||||
for (const auto& apProto : piProto.allies()) { alliesVec.emplace_back(apProto.player_id()); }
|
||||
const auto alliesOffset = fbb.CreateVectorOfStructs(alliesVec);
|
||||
|
||||
auto vcVec = std::vector<int8_t>();
|
||||
std::vector<int8_t> vcVec;
|
||||
const int victoryConditionCount = piProto.victory_conditions_size();
|
||||
vcVec.reserve(victoryConditionCount);
|
||||
for (int i = 0; i < victoryConditionCount; i++) {
|
||||
for (int i = 0; i < victoryConditionCount; ++i) {
|
||||
vcVec.push_back(ConvertVictoryCondition(piProto.victory_conditions(i)));
|
||||
}
|
||||
const auto vcOffset = fbb.CreateVector(vcVec);
|
||||
@@ -142,7 +142,7 @@ auto SetupInitialGameState(
|
||||
&endGameCondition);
|
||||
auto gameIdOffset = fbb.CreateString(gameId);
|
||||
|
||||
auto playerInfoVec = std::vector<Offset<PlayerInfo>>();
|
||||
std::vector<Offset<PlayerInfo>> playerInfoVec;
|
||||
playerInfoVec.reserve(playerInfoProtos.size());
|
||||
for (const auto& piProto : playerInfoProtos) {
|
||||
playerInfoVec.push_back(FromPlayerInfoProto(fbb, piProto));
|
||||
@@ -162,7 +162,7 @@ auto SetupInitialGameState(
|
||||
// Add slack units: 3 per necromancer, minimum 5 for general use
|
||||
const int slackUnits = std::max(5, necromancerCount * 3);
|
||||
|
||||
auto unitsVec = std::vector<Unit>();
|
||||
std::vector<Unit> unitsVec;
|
||||
unitsVec.reserve(units.size() + slackUnits);
|
||||
for (const auto& unit : units) {
|
||||
Unit modifiedUnit = unit;
|
||||
@@ -191,7 +191,7 @@ auto SetupInitialGameState(
|
||||
}
|
||||
|
||||
// Add slack units for future expansion (e.g., necromancer raise dead)
|
||||
for (int i = 0; i < slackUnits; i++) {
|
||||
for (int i = 0; i < slackUnits; ++i) {
|
||||
Unit slackUnit;
|
||||
slackUnit.mutate_unit_id(static_cast<int16_t>(units.size() + i));
|
||||
slackUnit.mutate_status(net::eagle0::shardok::storage::fb::UnitStatus_RESERVED_SLOT);
|
||||
|
||||
@@ -28,7 +28,7 @@ using net::eagle0::shardok::storage::fb::Unit;
|
||||
using Weather = net::eagle0::shardok::storage::fb::Weather;
|
||||
using GameStatusProto = net::eagle0::shardok::common::GameStatus;
|
||||
|
||||
auto SetupInitialGameState(
|
||||
[[nodiscard]] auto SetupInitialGameState(
|
||||
const GameId& gameId,
|
||||
const HexMapProto& hexMapProto,
|
||||
const std::vector<PlayerInfoProto>& playerInfoProtos,
|
||||
@@ -37,14 +37,14 @@ auto SetupInitialGameState(
|
||||
bool isWinter,
|
||||
const SettingsGetter& settings) -> GameStateW;
|
||||
|
||||
auto FromPlayerInfoProto(
|
||||
[[nodiscard]] auto FromPlayerInfoProto(
|
||||
flatbuffers::FlatBufferBuilder& fbb,
|
||||
const PlayerInfoProto& playerInfoProto)
|
||||
-> flatbuffers::Offset<net::eagle0::shardok::storage::fb::PlayerInfo>;
|
||||
|
||||
auto ToPlayerInfoProto(const PlayerInfo* fbPI) -> PlayerInfoProto;
|
||||
auto ToWeatherProto(const Weather* fbW) -> net::eagle0::shardok::common::Weather;
|
||||
auto ToProto(const GameStatus* fbStatus) -> GameStatusProto;
|
||||
[[nodiscard]] auto ToPlayerInfoProto(const PlayerInfo* fbPI) -> PlayerInfoProto;
|
||||
[[nodiscard]] auto ToWeatherProto(const Weather* fbW) -> net::eagle0::shardok::common::Weather;
|
||||
[[nodiscard]] auto ToProto(const GameStatus* fbStatus) -> GameStatusProto;
|
||||
|
||||
} // namespace shardok::fb
|
||||
|
||||
|
||||
@@ -22,15 +22,15 @@ using HexMap = net::eagle0::shardok::storage::fb::HexMap;
|
||||
using HexMapW = Wrapper<HexMap>;
|
||||
using HexMapProto = net::eagle0::shardok::common::HexMap;
|
||||
|
||||
auto ConvertHexMapProto(
|
||||
[[nodiscard]] auto ConvertHexMapProto(
|
||||
FlatBufferBuilder& fbb,
|
||||
const net::eagle0::shardok::common::HexMap& mapProto,
|
||||
bool isWinter = false,
|
||||
float initialWinterIceIntegrity = 0.0f) -> Offset<HexMap>;
|
||||
|
||||
auto ToProto(const HexMap* hexMap) -> HexMapProto;
|
||||
[[nodiscard]] auto ToProto(const HexMap* hexMap) -> HexMapProto;
|
||||
|
||||
auto CopyHexMap(const HexMap* hexMap) -> HexMapW;
|
||||
[[nodiscard]] auto CopyHexMap(const HexMap* hexMap) -> HexMapW;
|
||||
|
||||
} // namespace shardok::fb
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace shardok::fb {
|
||||
using Terrain = net::eagle0::shardok::storage::fb::Terrain;
|
||||
using TerrainProto = net::eagle0::shardok::common::Terrain;
|
||||
|
||||
auto ToTerrainProto(const Terrain* terrain) -> TerrainProto;
|
||||
[[nodiscard]] auto ToTerrainProto(const Terrain* terrain) -> TerrainProto;
|
||||
|
||||
} // namespace shardok::fb
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace shardok::fb {
|
||||
using TileModifier = net::eagle0::shardok::storage::fb::TileModifier;
|
||||
using TileModifierProto = net::eagle0::shardok::common::TileModifier;
|
||||
|
||||
auto ToTileModifierProto(const TileModifier& tileModifier) -> TileModifierProto;
|
||||
[[nodiscard]] auto ToTileModifierProto(const TileModifier& tileModifier) -> TileModifierProto;
|
||||
|
||||
} // namespace shardok::fb
|
||||
|
||||
|
||||
@@ -23,10 +23,12 @@ namespace shardok {
|
||||
using Coords = net::eagle0::shardok::storage::fb::Coords;
|
||||
using CoordsProto = net::eagle0::shardok::common::Coords;
|
||||
|
||||
auto MakeCoordsProto(int row, int column) -> net::eagle0::shardok::common::Coords;
|
||||
[[nodiscard]] auto MakeCoordsProto(int row, int column) -> net::eagle0::shardok::common::Coords;
|
||||
|
||||
static inline auto IsUnplaced(const Coords &c) -> bool { return c.row() < 0 || c.column() < 0; }
|
||||
static inline auto IsUnplaced(const CoordsProto &c) -> bool {
|
||||
[[nodiscard]] static inline auto IsUnplaced(const Coords &c) -> bool {
|
||||
return c.row() < 0 || c.column() < 0;
|
||||
}
|
||||
[[nodiscard]] static inline auto IsUnplaced(const CoordsProto &c) -> bool {
|
||||
return c.row() < 0 || c.column() < 0;
|
||||
}
|
||||
|
||||
@@ -41,14 +43,15 @@ static inline auto IsUnplaced(const CoordsProto &c) -> bool {
|
||||
} // namespace shardok
|
||||
|
||||
namespace net::eagle0::shardok::storage::fb {
|
||||
auto operator==(const Coords &lhs, const net::eagle0::shardok::common::Coords &rhs) -> bool;
|
||||
[[nodiscard]] auto operator==(const Coords &lhs, const net::eagle0::shardok::common::Coords &rhs)
|
||||
-> bool;
|
||||
}
|
||||
|
||||
namespace net::eagle0::shardok::common {
|
||||
auto operator==(
|
||||
[[nodiscard]] auto operator==(
|
||||
const net::eagle0::shardok::common::Coords &lhs,
|
||||
const net::eagle0::shardok::common::Coords &rhs) -> bool;
|
||||
auto operator==(
|
||||
[[nodiscard]] auto operator==(
|
||||
const net::eagle0::shardok::common::Coords &lhs,
|
||||
const net::eagle0::shardok::storage::fb::Coords &rhs) -> bool;
|
||||
} // namespace net::eagle0::shardok::common
|
||||
@@ -56,7 +59,7 @@ auto operator==(
|
||||
namespace std {
|
||||
template<>
|
||||
struct hash<net::eagle0::shardok::common::Coords> {
|
||||
auto operator()(const net::eagle0::shardok::common::Coords &c) const -> size_t {
|
||||
[[nodiscard]] auto operator()(const net::eagle0::shardok::common::Coords &c) const -> size_t {
|
||||
return size_t(c.row() << 16 | c.column());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace shardok {
|
||||
|
||||
constexpr bool kCoordsSetIndexChecks = false;
|
||||
|
||||
constexpr size_t STANDARD_SIZE = 12 * 14;
|
||||
constexpr size_t STANDARD_SIZE = size_t{12} * 14;
|
||||
|
||||
using HexMap = net::eagle0::shardok::storage::fb::HexMap;
|
||||
using BackingBitset = common::IterableBitset<168>;
|
||||
@@ -34,7 +34,7 @@ private:
|
||||
uint32_t indexCount;
|
||||
|
||||
[[nodiscard]] auto Index(const int row, const int column) const -> int {
|
||||
return row * mapWidth + column;
|
||||
return (row * mapWidth) + column;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto Index(const Coords& c) const -> int { return Index(c.row(), c.column()); }
|
||||
@@ -137,7 +137,7 @@ public:
|
||||
}
|
||||
|
||||
void Filter(const std::function<bool(int, int)>& f) {
|
||||
for (uint32_t i = 0; i < indexCount; i++) {
|
||||
for (uint32_t i = 0; i < indexCount; ++i) {
|
||||
if (Contains(i) && !f(i / mapWidth, i % mapWidth)) { Remove(i); }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,11 +41,11 @@ inline HexMapDirection& operator++(HexMapDirection& dir) {
|
||||
}
|
||||
|
||||
struct HexMapDirectionsTo {
|
||||
HexMapDirection main;
|
||||
HexMapDirection secondary; // Only valid if exactly on the line
|
||||
bool usesSecondary;
|
||||
HexMapDirection main{};
|
||||
HexMapDirection secondary{}; // Only valid if exactly on the line
|
||||
bool usesSecondary{};
|
||||
|
||||
bool Matches(const HexMapDirection dir) {
|
||||
bool Matches(const HexMapDirection dir) const {
|
||||
return dir == main || (usesSecondary && dir == secondary);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -13,13 +13,13 @@
|
||||
namespace shardok {
|
||||
using HexMap = net::eagle0::shardok::storage::fb::HexMap;
|
||||
|
||||
auto GetModifierHash(const HexMap* map) -> uint64_t;
|
||||
[[nodiscard]] auto GetModifierHash(const HexMap* map) -> uint64_t;
|
||||
|
||||
// Helper function to compute modifier byte for consistent hashing
|
||||
// Excludes ice from hash since AI pathfinding should ignore ice
|
||||
// Compact bit layout: bridge=bit0, fire=bit1, snow=bit2
|
||||
template<typename TileModifier>
|
||||
auto ComputeModifierByte(const TileModifier& modifier) -> int8_t {
|
||||
[[nodiscard]] auto ComputeModifierByte(const TileModifier& modifier) -> int8_t {
|
||||
return static_cast<int8_t>(
|
||||
modifier.bridge().present() | modifier.fire().present() << 1 |
|
||||
modifier.snow().present() << 2);
|
||||
@@ -27,7 +27,7 @@ auto ComputeModifierByte(const TileModifier& modifier) -> int8_t {
|
||||
|
||||
// Overload for protobuf modifier
|
||||
template<typename ProtoModifier>
|
||||
auto ComputeModifierByteProto(const ProtoModifier& modifier) -> int8_t {
|
||||
[[nodiscard]] auto ComputeModifierByteProto(const ProtoModifier& modifier) -> int8_t {
|
||||
return static_cast<int8_t>(
|
||||
modifier.has_bridge() | modifier.has_fire() << 1 | modifier.has_snow() << 2);
|
||||
}
|
||||
|
||||
@@ -34,23 +34,25 @@ using TerrainType::Terrain_Type_UNKNOWN;
|
||||
|
||||
constexpr int kTerrainTypeCount = net::eagle0::shardok::common::Terrain_Type_Type_ARRAYSIZE;
|
||||
|
||||
auto AllowsHiding(const Terrain* terrain) -> bool;
|
||||
auto AllowsHiding(net::eagle0::shardok::storage::fb::Terrain_::Type type) -> bool;
|
||||
auto AllowsHiding(const net::eagle0::shardok::storage::fb::TileModifier& modifier) -> bool;
|
||||
[[nodiscard]] auto AllowsHiding(const Terrain* terrain) -> bool;
|
||||
[[nodiscard]] auto AllowsHiding(net::eagle0::shardok::storage::fb::Terrain_::Type type) -> bool;
|
||||
[[nodiscard]] auto AllowsHiding(const net::eagle0::shardok::storage::fb::TileModifier& modifier)
|
||||
-> bool;
|
||||
|
||||
auto AllowsHiding(const TerrainProto& terrain) -> bool;
|
||||
auto AllowsHiding(TerrainType type) -> bool;
|
||||
auto AllowsHiding(const TileModifierProto& modifier) -> bool;
|
||||
[[nodiscard]] auto AllowsHiding(const TerrainProto& terrain) -> bool;
|
||||
[[nodiscard]] auto AllowsHiding(TerrainType type) -> bool;
|
||||
[[nodiscard]] auto AllowsHiding(const TileModifierProto& modifier) -> bool;
|
||||
|
||||
auto AllowsFortification(const Terrain* terrain) -> bool;
|
||||
[[nodiscard]] auto AllowsFortification(const Terrain* terrain) -> bool;
|
||||
|
||||
auto IsWater(net::eagle0::shardok::storage::fb::Terrain_::Type type) -> bool;
|
||||
auto IsWater(TerrainType type) -> bool;
|
||||
[[nodiscard]] auto IsWater(net::eagle0::shardok::storage::fb::Terrain_::Type type) -> bool;
|
||||
[[nodiscard]] auto IsWater(TerrainType type) -> bool;
|
||||
|
||||
auto IsTraversible(const net::eagle0::shardok::storage::fb::Terrain& terrain) -> bool;
|
||||
[[nodiscard]] auto IsTraversible(const net::eagle0::shardok::storage::fb::Terrain& terrain) -> bool;
|
||||
|
||||
auto MakeHexMapTerrain(TerrainType tp, TileModifierProto mod = TileModifierProto()) -> TerrainProto;
|
||||
auto MakeHexMapTerrain(
|
||||
[[nodiscard]] auto MakeHexMapTerrain(TerrainType tp, TileModifierProto mod = TileModifierProto())
|
||||
-> TerrainProto;
|
||||
[[nodiscard]] auto MakeHexMapTerrain(
|
||||
net::eagle0::shardok::storage::fb::Terrain_::Type tp,
|
||||
const net::eagle0::shardok::storage::fb::TileModifier& mod =
|
||||
net::eagle0::shardok::storage::fb::TileModifier()) -> Terrain;
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace shardok {
|
||||
using SingleModifier = net::eagle0::shardok::common::TileModifier_SingleModifier;
|
||||
using TileModifierProto = net::eagle0::shardok::common::TileModifier;
|
||||
|
||||
SingleModifier MakeSingleModifier(const std::optional<double>& integ = std::optional<double>());
|
||||
SingleModifier MakeSingleModifier(const std::optional<double>& integ = std::nullopt);
|
||||
|
||||
bool operator==(const SingleModifier& lhs, const SingleModifier& rhs);
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ public:
|
||||
return settings.backingStruct;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto GetRandomGenerator() const -> const std::shared_ptr<RandomGenerator> {
|
||||
[[nodiscard]] auto GetRandomGenerator() const -> std::shared_ptr<RandomGenerator> {
|
||||
return settings.randomGenerator;
|
||||
}
|
||||
|
||||
|
||||
@@ -130,7 +130,7 @@ int32_t MutatingInternalTakeDamage(
|
||||
|
||||
double takenDamage = 0.0;
|
||||
|
||||
for (int i = 0; i < NUM_DAMAGE_TYPES; i++) {
|
||||
for (int i = 0; i < NUM_DAMAGE_TYPES; ++i) {
|
||||
const auto damageType = static_cast<DamageType>(i);
|
||||
const double armamentAdjustment =
|
||||
1.0 - ((type->baseResistanceByType[i] +
|
||||
|
||||
@@ -52,7 +52,7 @@ auto MutatingTakeDamage(
|
||||
const CombatDamage heroDamage = heroDamageRatio * damage;
|
||||
|
||||
double vigorHit = 0.0;
|
||||
for (int i = 0; i < NUM_DAMAGE_TYPES; i++) {
|
||||
for (int i = 0; i < NUM_DAMAGE_TYPES; ++i) {
|
||||
vigorHit += heroDamage.GetNormalDamageOfType(DamageType(i)) * kHeroMortalityFactor;
|
||||
vigorHit += heroDamage.GetPenetratingDamageOfType(DamageType(i)) * kHeroMortalityFactor;
|
||||
// TODO: hero should have adjustments for damage types too
|
||||
|
||||
@@ -45,7 +45,7 @@ auto OpponentKnowledge(const Unit &unit, const PlayerId toPlayer) -> int {
|
||||
if (toPlayer == -1) {
|
||||
// handle observer, with pid -1
|
||||
int8_t max = 0;
|
||||
for (uint32_t i = 0; i < unit.opponent_knowledge()->size(); i++) {
|
||||
for (uint32_t i = 0; i < unit.opponent_knowledge()->size(); ++i) {
|
||||
max = std::max(max, unit.opponent_knowledge()->Get(i));
|
||||
}
|
||||
return max;
|
||||
@@ -59,7 +59,7 @@ auto OpponentKnowledge(const Unit *unit, const PlayerId toPlayer) -> int {
|
||||
if (toPlayer == -1) {
|
||||
// handle observer, with pid -1
|
||||
int8_t max = 0;
|
||||
for (uint32_t i = 0; i < unit->opponent_knowledge()->size(); i++) {
|
||||
for (uint32_t i = 0; i < unit->opponent_knowledge()->size(); ++i) {
|
||||
max = std::max(max, unit->opponent_knowledge()->Get(i));
|
||||
}
|
||||
return max;
|
||||
@@ -190,7 +190,7 @@ void MutatingBumpOpponentKnowledge(Unit *unit, const PlayerId pid, const int bum
|
||||
|
||||
void MutatingBumpAllKnowledgeToMinimum(Unit *unit, const int minimum) {
|
||||
const auto current = unit->opponent_knowledge();
|
||||
for (uint32_t i = 0; i < current->size(); i++) {
|
||||
for (uint32_t i = 0; i < current->size(); ++i) {
|
||||
if (current->Get(i) < minimum) { unit->mutable_opponent_knowledge()->Mutate(i, minimum); }
|
||||
}
|
||||
}
|
||||
@@ -220,7 +220,7 @@ auto InternalTakeDamageFb(
|
||||
CombatDamage heroDamage = heroDamageRatio * totalDamage;
|
||||
|
||||
double vigorHit = 0.0;
|
||||
for (int i = 0; i < NUM_DAMAGE_TYPES; i++) {
|
||||
for (int i = 0; i < NUM_DAMAGE_TYPES; ++i) {
|
||||
const auto damageType = static_cast<DamageType>(i);
|
||||
vigorHit += heroDamage.GetNormalDamageOfType(damageType) * heroMortalityFactor;
|
||||
vigorHit += heroDamage.GetPenetratingDamageOfType(damageType) * heroMortalityFactor;
|
||||
@@ -237,7 +237,7 @@ auto InternalTakeDamageFb(
|
||||
double takenDamage = 0.0;
|
||||
double terrainAdjustment = battalionType->GetDamageTakenMultiplierForTerrain(&terrain);
|
||||
|
||||
for (int i = 0; i < NUM_DAMAGE_TYPES; i++) {
|
||||
for (int i = 0; i < NUM_DAMAGE_TYPES; ++i) {
|
||||
const auto damageType = static_cast<DamageType>(i);
|
||||
double armamentAdjustment = 1.0 - (battalionType->baseResistanceByType[i] +
|
||||
(battalion.armament() / 100.0) *
|
||||
|
||||
@@ -22,12 +22,12 @@ namespace shardok {
|
||||
using Unit = net::eagle0::shardok::storage::fb::Unit;
|
||||
using Units = flatbuffers::Vector<const Unit *>;
|
||||
|
||||
auto IsDestroyed(const Unit &unit) -> bool;
|
||||
[[nodiscard]] auto IsDestroyed(const Unit &unit) -> bool;
|
||||
|
||||
auto MaxActionPoints(const Unit &unit) -> ActionPoints;
|
||||
[[nodiscard]] auto MaxActionPoints(const Unit &unit) -> ActionPoints;
|
||||
|
||||
auto OpponentKnowledge(const Unit &unit, PlayerId toPlayer) -> int;
|
||||
auto OpponentKnowledge(const Unit *unit, PlayerId toPlayer) -> int;
|
||||
[[nodiscard]] auto OpponentKnowledge(const Unit &unit, PlayerId toPlayer) -> int;
|
||||
[[nodiscard]] auto OpponentKnowledge(const Unit *unit, PlayerId toPlayer) -> int;
|
||||
|
||||
// Returns the casualty count.
|
||||
auto MutatingApplyDamageFrom(
|
||||
@@ -50,7 +50,7 @@ auto MutatingApplyEnvironmentalDamage(
|
||||
double baseDeadliness,
|
||||
const BattalionTypeSPtr &type) -> int32_t;
|
||||
|
||||
auto WithTakenDamageFb(
|
||||
[[nodiscard]] auto WithTakenDamageFb(
|
||||
const Unit *victim,
|
||||
const CombatDamage &amount,
|
||||
const Terrain &terrain,
|
||||
@@ -71,8 +71,10 @@ void MutatingBumpCharismaXp(Unit *unit, int newXp);
|
||||
void MutatingBumpOpponentKnowledge(Unit *unit, PlayerId pid, int bump);
|
||||
void MutatingBumpAllKnowledgeToMinimum(Unit *unit, int bump);
|
||||
|
||||
auto ReserveUnitsForPlayer(const Units *units, PlayerId pid) -> std::map<UnitId, const Unit *>;
|
||||
auto PlacedUnitsForPlayer(const Units *units, PlayerId pid) -> std::map<UnitId, const Unit *>;
|
||||
[[nodiscard]] auto ReserveUnitsForPlayer(const Units *units, PlayerId pid)
|
||||
-> std::map<UnitId, const Unit *>;
|
||||
[[nodiscard]] auto PlacedUnitsForPlayer(const Units *units, PlayerId pid)
|
||||
-> std::map<UnitId, const Unit *>;
|
||||
|
||||
} // namespace shardok
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ auto CombatUtils::CalculateBattalionDamageGiven(
|
||||
const double totalSwing =
|
||||
randomnessAdjustment * moraleAdjustment * charismaAdjustment * braveryAdjustment;
|
||||
|
||||
for (int i = 0; i < static_cast<int>(NUM_DAMAGE_TYPES); i++) {
|
||||
for (int i = 0; i < static_cast<int>(NUM_DAMAGE_TYPES); ++i) {
|
||||
double damagePerTroop =
|
||||
(type->baseMeleeDamageByType[i] +
|
||||
(battalion.training() / 100.0) * type->maxAugmentMeleeDamageByType[i]);
|
||||
@@ -111,8 +111,8 @@ auto CombatUtils::CalculateUnitDamageGiven(
|
||||
const bool hasHero = unit->has_attached_hero();
|
||||
CombatDamage battalionDamage = CalculateBattalionDamageGiven(
|
||||
unit->battalion(),
|
||||
(hasHero ? unit->attached_hero().charisma() : std::optional<double>()),
|
||||
(hasHero ? unit->attached_hero().bravery() : std::optional<double>()),
|
||||
(hasHero ? std::optional<double>{unit->attached_hero().charisma()} : std::nullopt),
|
||||
(hasHero ? std::optional<double>{unit->attached_hero().bravery()} : std::nullopt),
|
||||
battalionRoll,
|
||||
settings);
|
||||
|
||||
@@ -148,7 +148,7 @@ auto CombatUtils::CalculateUnitArcheryDamageGiven(
|
||||
|
||||
const double totalSwing = randomnessAdjustment * moraleAdjustment * charismaAdjustment;
|
||||
|
||||
for (int i = 0; i < static_cast<int>(NUM_DAMAGE_TYPES); i++) {
|
||||
for (int i = 0; i < static_cast<int>(NUM_DAMAGE_TYPES); ++i) {
|
||||
double damagePerTroop =
|
||||
type->baseMissileDamageByType[i] +
|
||||
(battalion.training() / 100.0) * type->maxAugmentMissileDamageByType[i];
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user