mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
TBB for battle AI spellcast an fixes
This commit is contained in:
parent
274bf739b8
commit
03395a3d8a
@ -132,7 +132,12 @@ int64_t AttackPossibility::calculateDamageReduce(
|
||||
{
|
||||
auto ourUnits = state->battleGetUnitsIf([&](const battle::Unit * u) -> bool
|
||||
{
|
||||
return u->unitSide() != defender->unitSide() && !u->isTurret();
|
||||
return u->unitSide() != defender->unitSide()
|
||||
&& !u->isTurret()
|
||||
&& u->creatureId() != CreatureID::CATAPULT
|
||||
&& u->creatureId() != CreatureID::BALLISTA
|
||||
&& u->creatureId() != CreatureID::FIRST_AID_TENT
|
||||
&& u->getCount();
|
||||
});
|
||||
|
||||
if(ourUnits.empty())
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
#include "StackWithBonuses.h"
|
||||
#include "EnemyInfo.h"
|
||||
#include "tbb/parallel_for.h"
|
||||
#include "../../lib/CStopWatch.h"
|
||||
#include "../../lib/CThreadHelper.h"
|
||||
#include "../../lib/mapObjects/CGTownInstance.h"
|
||||
@ -704,96 +705,70 @@ void BattleEvaluator::attemptCastingSpell(const CStack * activeStack)
|
||||
}
|
||||
}
|
||||
|
||||
struct ScriptsCache
|
||||
{
|
||||
//todo: re-implement scripts context cache
|
||||
};
|
||||
|
||||
auto evaluateSpellcast = [&] (PossibleSpellcast * ps, std::shared_ptr<ScriptsCache>)
|
||||
{
|
||||
auto state = std::make_shared<HypotheticBattle>(env.get(), cb);
|
||||
|
||||
spells::BattleCast cast(state.get(), hero, spells::Mode::HERO, ps->spell);
|
||||
cast.castEval(state->getServerCallback(), ps->dest);
|
||||
|
||||
auto allUnits = state->battleGetUnitsIf([](const battle::Unit * u) -> bool{ return true; });
|
||||
|
||||
auto needFullEval = vstd::contains_if(allUnits, [&](const battle::Unit * u) -> bool
|
||||
{
|
||||
auto original = cb->battleGetUnitByID(u->unitId());
|
||||
return !original || u->speed() != original->speed();
|
||||
});
|
||||
|
||||
DamageCache innerCache(&damageCache);
|
||||
innerCache.buildDamageCache(state, side);
|
||||
|
||||
if(needFullEval || !cachedAttack)
|
||||
{
|
||||
PotentialTargets innerTargets(activeStack, damageCache, state);
|
||||
BattleExchangeEvaluator innerEvaluator(state, env);
|
||||
|
||||
if(!innerTargets.possibleAttacks.empty())
|
||||
{
|
||||
innerEvaluator.updateReachabilityMap(state);
|
||||
|
||||
auto newStackAction = innerEvaluator.findBestTarget(activeStack, innerTargets, innerCache, state);
|
||||
|
||||
ps->value = newStackAction.score;
|
||||
}
|
||||
else
|
||||
{
|
||||
ps->value = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ps->value = scoreEvaluator.calculateExchange(*cachedAttack, *targets, innerCache, state);
|
||||
}
|
||||
|
||||
for(auto unit : allUnits)
|
||||
{
|
||||
auto newHealth = unit->getAvailableHealth();
|
||||
auto oldHealth = healthOfStack[unit->unitId()];
|
||||
|
||||
if(oldHealth != newHealth)
|
||||
{
|
||||
auto damage = std::abs(oldHealth - newHealth);
|
||||
auto originalDefender = cb->battleGetUnitByID(unit->unitId());
|
||||
auto dpsReduce = AttackPossibility::calculateDamageReduce(nullptr, originalDefender ? originalDefender : unit, damage, innerCache, state);
|
||||
auto ourUnit = unit->unitSide() == side ? 1 : -1;
|
||||
auto goodEffect = newHealth > oldHealth ? 1 : -1;
|
||||
|
||||
ps->value += ourUnit * goodEffect * dpsReduce;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
using EvalRunner = ThreadPool<ScriptsCache>;
|
||||
|
||||
EvalRunner::Tasks tasks;
|
||||
|
||||
for(PossibleSpellcast & psc : possibleCasts)
|
||||
tasks.push_back(std::bind(evaluateSpellcast, &psc, _1));
|
||||
|
||||
uint32_t threadCount = boost::thread::hardware_concurrency();
|
||||
|
||||
if(threadCount == 0)
|
||||
{
|
||||
logGlobal->warn("No information of CPU cores available");
|
||||
threadCount = 1;
|
||||
}
|
||||
|
||||
CStopWatch timer;
|
||||
|
||||
std::vector<std::shared_ptr<ScriptsCache>> scriptsPool;
|
||||
tbb::parallel_for(tbb::blocked_range<size_t>(0, possibleCasts.size()), [&](const tbb::blocked_range<size_t> & r)
|
||||
{
|
||||
for(auto i = r.begin(); i != r.end(); i++)
|
||||
{
|
||||
auto & ps = possibleCasts[i];
|
||||
auto state = std::make_shared<HypotheticBattle>(env.get(), cb);
|
||||
|
||||
for(uint32_t idx = 0; idx < threadCount; idx++)
|
||||
{
|
||||
scriptsPool.emplace_back();
|
||||
}
|
||||
spells::BattleCast cast(state.get(), hero, spells::Mode::HERO, ps.spell);
|
||||
cast.castEval(state->getServerCallback(), ps.dest);
|
||||
|
||||
EvalRunner runner(&tasks, scriptsPool);
|
||||
runner.run();
|
||||
auto allUnits = state->battleGetUnitsIf([](const battle::Unit * u) -> bool { return true; });
|
||||
|
||||
auto needFullEval = vstd::contains_if(allUnits, [&](const battle::Unit * u) -> bool
|
||||
{
|
||||
auto original = cb->battleGetUnitByID(u->unitId());
|
||||
return !original || u->speed() != original->speed();
|
||||
});
|
||||
|
||||
DamageCache innerCache(&damageCache);
|
||||
innerCache.buildDamageCache(state, side);
|
||||
|
||||
if(needFullEval || !cachedAttack)
|
||||
{
|
||||
PotentialTargets innerTargets(activeStack, damageCache, state);
|
||||
BattleExchangeEvaluator innerEvaluator(state, env);
|
||||
|
||||
if(!innerTargets.possibleAttacks.empty())
|
||||
{
|
||||
innerEvaluator.updateReachabilityMap(state);
|
||||
|
||||
auto newStackAction = innerEvaluator.findBestTarget(activeStack, innerTargets, innerCache, state);
|
||||
|
||||
ps.value = newStackAction.score;
|
||||
}
|
||||
else
|
||||
{
|
||||
ps.value = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ps.value = scoreEvaluator.calculateExchange(*cachedAttack, *targets, innerCache, state);
|
||||
}
|
||||
|
||||
for(auto unit : allUnits)
|
||||
{
|
||||
auto newHealth = unit->getAvailableHealth();
|
||||
auto oldHealth = healthOfStack[unit->unitId()];
|
||||
|
||||
if(oldHealth != newHealth)
|
||||
{
|
||||
auto damage = std::abs(oldHealth - newHealth);
|
||||
auto originalDefender = cb->battleGetUnitByID(unit->unitId());
|
||||
auto dpsReduce = AttackPossibility::calculateDamageReduce(nullptr, originalDefender ? originalDefender : unit, damage, innerCache, state);
|
||||
auto ourUnit = unit->unitSide() == side ? 1 : -1;
|
||||
auto goodEffect = newHealth > oldHealth ? 1 : -1;
|
||||
|
||||
ps.value += ourUnit * goodEffect * dpsReduce;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
LOGFL("Evaluation took %d ms", timer.getDiff());
|
||||
|
||||
|
@ -37,7 +37,11 @@ else()
|
||||
endif()
|
||||
|
||||
target_include_directories(BattleAI PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_link_libraries(BattleAI PRIVATE ${VCMI_LIB_TARGET})
|
||||
target_link_libraries(BattleAI PRIVATE ${VCMI_LIB_TARGET} TBB::tbb)
|
||||
|
||||
vcmi_set_output_dir(BattleAI "AI")
|
||||
enable_pch(BattleAI)
|
||||
|
||||
if(APPLE_IOS AND NOT USING_CONAN)
|
||||
install(IMPORTED_RUNTIME_ARTIFACTS TBB::tbb LIBRARY DESTINATION ${LIB_DIR}) # CMake 3.21+
|
||||
endif()
|
||||
|
@ -52,6 +52,23 @@ StackWithBonuses::StackWithBonuses(const HypotheticBattle * Owner, const battle:
|
||||
battle::CUnitState::operator=(*Stack);
|
||||
}
|
||||
|
||||
StackWithBonuses::StackWithBonuses(const HypotheticBattle * Owner, const battle::Unit * Stack)
|
||||
: battle::CUnitState(),
|
||||
origBearer(Stack->getBonusBearer()),
|
||||
owner(Owner),
|
||||
type(Stack->unitType()),
|
||||
baseAmount(Stack->unitBaseAmount()),
|
||||
id(Stack->unitId()),
|
||||
side(Stack->unitSide()),
|
||||
player(Stack->unitOwner()),
|
||||
slot(Stack->unitSlot())
|
||||
{
|
||||
localInit(Owner);
|
||||
|
||||
auto state = Stack->acquireState();
|
||||
battle::CUnitState::operator=(*state);
|
||||
}
|
||||
|
||||
StackWithBonuses::StackWithBonuses(const HypotheticBattle * Owner, const battle::UnitInfo & info)
|
||||
: battle::CUnitState(),
|
||||
origBearer(nullptr),
|
||||
@ -265,7 +282,7 @@ std::shared_ptr<StackWithBonuses> HypotheticBattle::getForUpdate(uint32_t id)
|
||||
|
||||
if(iter == stackStates.end())
|
||||
{
|
||||
const CStack * s = subject->battleGetStackByID(id, false);
|
||||
const battle::Unit * s = subject->battleGetUnitByID(id);
|
||||
|
||||
auto ret = std::make_shared<StackWithBonuses>(this, s);
|
||||
stackStates[id] = ret;
|
||||
|
@ -51,6 +51,8 @@ public:
|
||||
|
||||
StackWithBonuses(const HypotheticBattle * Owner, const battle::CUnitState * Stack);
|
||||
|
||||
StackWithBonuses(const HypotheticBattle * Owner, const battle::Unit * Stack);
|
||||
|
||||
StackWithBonuses(const HypotheticBattle * Owner, const battle::UnitInfo & info);
|
||||
|
||||
virtual ~StackWithBonuses();
|
||||
|
Loading…
Reference in New Issue
Block a user