1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-22 22:13:35 +02:00

BattleAI: fast targets optimization

This commit is contained in:
Andrii Danylchenko 2023-08-08 18:38:41 +03:00
parent e7394ad20c
commit ba9998ac66
8 changed files with 74 additions and 31 deletions

View File

@ -507,7 +507,12 @@ void CBattleAI::attemptCastingSpell()
{ {
spells::BattleCast temp(cb.get(), hero, spells::Mode::HERO, spell); spells::BattleCast temp(cb.get(), hero, spells::Mode::HERO, spell);
for(auto & target : temp.findPotentialTargets()) if(!spell->isDamage() && spell->getTargetType() == spells::AimType::LOCATION)
continue;
const bool FAST = true;
for(auto & target : temp.findPotentialTargets(FAST))
{ {
PossibleSpellcast ps; PossibleSpellcast ps;
ps.dest = target; ps.dest = target;

View File

@ -600,6 +600,8 @@ void BattleExchangeEvaluator::updateReachabilityMap(HypotheticBattle & hb)
if(unit->isTurret()) if(unit->isTurret())
continue; continue;
auto unitSpeed = unit->speed(turn);
if(turnBattle.battleCanShoot(unit)) if(turnBattle.battleCanShoot(unit))
{ {
for(BattleHex hex = BattleHex::TOP_LEFT; hex.isValid(); hex = hex + 1) for(BattleHex hex = BattleHex::TOP_LEFT; hex.isValid(); hex = hex + 1)
@ -614,7 +616,7 @@ void BattleExchangeEvaluator::updateReachabilityMap(HypotheticBattle & hb)
for(BattleHex hex = BattleHex::TOP_LEFT; hex.isValid(); hex = hex + 1) for(BattleHex hex = BattleHex::TOP_LEFT; hex.isValid(); hex = hex + 1)
{ {
bool reachable = unitReachability.distances[hex] <= unit->speed(turn); bool reachable = unitReachability.distances[hex] <= unitSpeed;
if(!reachable && unitReachability.accessibility[hex] == EAccessibility::ALIVE_STACK) if(!reachable && unitReachability.accessibility[hex] == EAccessibility::ALIVE_STACK)
{ {
@ -624,7 +626,7 @@ void BattleExchangeEvaluator::updateReachabilityMap(HypotheticBattle & hb)
{ {
for(BattleHex neighbor : hex.neighbouringTiles()) for(BattleHex neighbor : hex.neighbouringTiles())
{ {
reachable = unitReachability.distances[neighbor] <= unit->speed(turn); reachable = unitReachability.distances[neighbor] <= unitSpeed;
if(reachable) break; if(reachable) break;
} }

View File

@ -84,17 +84,6 @@ PotentialTargets::PotentialTargets(const battle::Unit * attacker, const Hypothet
{ {
return lhs.damageDiff() > rhs.damageDiff(); return lhs.damageDiff() > rhs.damageDiff();
}); });
if (!possibleAttacks.empty())
{
auto & bestAp = possibleAttacks[0];
logGlobal->debug("Battle AI best: %s -> %s at %d from %d, affects %d units: d:%lld a:%lld c:%lld s:%lld",
bestAp.attack.attacker->unitType()->getJsonKey(),
state.battleGetUnitByPos(bestAp.dest)->unitType()->getJsonKey(),
(int)bestAp.dest, (int)bestAp.from, (int)bestAp.affectedUnits.size(),
bestAp.defenderDamageReduce, bestAp.attackerDamageReduce, bestAp.collateralDamageReduce, bestAp.shootersBlockedDmg);
}
} }
int64_t PotentialTargets::bestActionValue() const int64_t PotentialTargets::bestActionValue() const

View File

@ -590,7 +590,7 @@ std::vector<AimType> BattleSpellMechanics::getTargetTypes() const
return ret; return ret;
} }
std::vector<Destination> BattleSpellMechanics::getPossibleDestinations(size_t index, AimType aimType, const Target & current) const std::vector<Destination> BattleSpellMechanics::getPossibleDestinations(size_t index, AimType aimType, const Target & current, bool fast) const
{ {
//TODO: BattleSpellMechanics::getPossibleDestinations //TODO: BattleSpellMechanics::getPossibleDestinations
@ -602,19 +602,66 @@ std::vector<Destination> BattleSpellMechanics::getPossibleDestinations(size_t in
switch(aimType) switch(aimType)
{ {
case AimType::CREATURE: case AimType::CREATURE:
case AimType::LOCATION: {
for(int i = 0; i < GameConstants::BFIELD_SIZE; i++) auto stacks = battle()->battleGetAllStacks();
for(auto stack : stacks)
{ {
BattleHex dest(i); Target tmp = current;
if(dest.isAvailable()) tmp.emplace_back(stack->getPosition());
detail::ProblemImpl ignored;
if(canBeCastAt(tmp, ignored))
ret.emplace_back(stack->getPosition());
}
break;
}
case AimType::LOCATION:
if(fast)
{
auto stacks = battle()->battleGetAllStacks();
std::set<BattleHex> hexesToCheck;
for(auto stack : stacks)
{ {
Target tmp = current; hexesToCheck.insert(stack->getPosition());
tmp.emplace_back(dest);
detail::ProblemImpl ignored; for(auto adjacent : stack->getPosition().neighbouringTiles())
hexesToCheck.insert(adjacent);
}
if(canBeCastAt(tmp, ignored)) for(auto hex : hexesToCheck)
ret.emplace_back(dest); {
if(hex.isAvailable())
{
Target tmp = current;
tmp.emplace_back(hex);
detail::ProblemImpl ignored;
if(canBeCastAt(tmp, ignored))
ret.emplace_back(hex);
}
}
}
else
{
for(int i = 0; i < GameConstants::BFIELD_SIZE; i++)
{
BattleHex dest(i);
if(dest.isAvailable())
{
Target tmp = current;
tmp.emplace_back(dest);
detail::ProblemImpl ignored;
if(canBeCastAt(tmp, ignored))
ret.emplace_back(dest);
}
} }
} }
break; break;

View File

@ -50,7 +50,7 @@ public:
/// Returns vector of all possible destinations for specified aim type /// Returns vector of all possible destinations for specified aim type
/// index - ??? /// index - ???
/// current - ??? /// current - ???
std::vector<Destination> getPossibleDestinations(size_t index, AimType aimType, const Target & current) const override final; std::vector<Destination> getPossibleDestinations(size_t index, AimType aimType, const Target & current, bool fast) const override final;
/// Returns true if spell can be cast on unit /// Returns true if spell can be cast on unit
bool isReceptive(const battle::Unit * target) const override; bool isReceptive(const battle::Unit * target) const override;

View File

@ -326,7 +326,7 @@ bool BattleCast::castIfPossible(ServerCallback * server, Target target)
return false; return false;
} }
std::vector<Target> BattleCast::findPotentialTargets() const std::vector<Target> BattleCast::findPotentialTargets(bool fast) const
{ {
//TODO: for more than 2 destinations per target much more efficient algorithm is required //TODO: for more than 2 destinations per target much more efficient algorithm is required
@ -354,7 +354,7 @@ std::vector<Target> BattleCast::findPotentialTargets() const
if(previous.empty()) if(previous.empty())
{ {
Target empty; Target empty;
destinations = m->getPossibleDestinations(index, targetTypes.at(index), empty); destinations = m->getPossibleDestinations(index, targetTypes.at(index), empty, fast);
for(auto & destination : destinations) for(auto & destination : destinations)
{ {
@ -367,7 +367,7 @@ std::vector<Target> BattleCast::findPotentialTargets() const
{ {
for(const Target & current : previous) for(const Target & current : previous)
{ {
destinations = m->getPossibleDestinations(index, targetTypes.at(index), current); destinations = m->getPossibleDestinations(index, targetTypes.at(index), current, fast);
for(auto & destination : destinations) for(auto & destination : destinations)
{ {

View File

@ -139,7 +139,7 @@ public:
///cast with silent check for permitted cast ///cast with silent check for permitted cast
bool castIfPossible(ServerCallback * server, Target target); bool castIfPossible(ServerCallback * server, Target target);
std::vector<Target> findPotentialTargets() const; std::vector<Target> findPotentialTargets(bool fast = false) const;
private: private:
///spell school level ///spell school level
@ -199,7 +199,7 @@ public:
virtual std::vector<AimType> getTargetTypes() const = 0; virtual std::vector<AimType> getTargetTypes() const = 0;
virtual std::vector<Destination> getPossibleDestinations(size_t index, AimType aimType, const Target & current) const = 0; virtual std::vector<Destination> getPossibleDestinations(size_t index, AimType aimType, const Target & current, bool fast = false) const = 0;
virtual const Spell * getSpell() const = 0; virtual const Spell * getSpell() const = 0;

View File

@ -34,7 +34,7 @@ public:
MOCK_CONST_METHOD1(isReceptive, bool(const battle::Unit * )); MOCK_CONST_METHOD1(isReceptive, bool(const battle::Unit * ));
MOCK_CONST_METHOD0(getTargetTypes, std::vector<AimType>()); MOCK_CONST_METHOD0(getTargetTypes, std::vector<AimType>());
MOCK_CONST_METHOD3(getPossibleDestinations, std::vector<Destination>(size_t, AimType, const Target &)); MOCK_CONST_METHOD4(getPossibleDestinations, std::vector<Destination>(size_t, AimType, const Target &, bool));
MOCK_CONST_METHOD0(getSpell, const Spell *()); MOCK_CONST_METHOD0(getSpell, const Spell *());