mirror of
https://github.com/vcmi/vcmi.git
synced 2026-05-22 09:55:17 +02:00
Merge remote-tracking branch 'upstream/develop' into develop
This commit is contained in:
+101
-44
@@ -49,6 +49,45 @@ SpellTypes spellType(const CSpell * spell)
|
||||
return SpellTypes::OTHER;
|
||||
}
|
||||
|
||||
BattleEvaluator::BattleEvaluator(
|
||||
std::shared_ptr<Environment> env,
|
||||
std::shared_ptr<CBattleCallback> cb,
|
||||
const battle::Unit * activeStack,
|
||||
PlayerColor playerID,
|
||||
BattleID battleID,
|
||||
BattleSide side,
|
||||
float strengthRatio,
|
||||
int simulationTurnsCount)
|
||||
:scoreEvaluator(cb->getBattle(battleID), env, strengthRatio, simulationTurnsCount),
|
||||
cachedAttack(), playerID(playerID), side(side), env(env),
|
||||
cb(cb), strengthRatio(strengthRatio), battleID(battleID), simulationTurnsCount(simulationTurnsCount)
|
||||
{
|
||||
hb = std::make_shared<HypotheticBattle>(env.get(), cb->getBattle(battleID));
|
||||
damageCache.buildDamageCache(hb, side);
|
||||
|
||||
targets = std::make_unique<PotentialTargets>(activeStack, damageCache, hb);
|
||||
cachedScore = EvaluationResult::INEFFECTIVE_SCORE;
|
||||
}
|
||||
|
||||
BattleEvaluator::BattleEvaluator(
|
||||
std::shared_ptr<Environment> env,
|
||||
std::shared_ptr<CBattleCallback> cb,
|
||||
std::shared_ptr<HypotheticBattle> hb,
|
||||
DamageCache & damageCache,
|
||||
const battle::Unit * activeStack,
|
||||
PlayerColor playerID,
|
||||
BattleID battleID,
|
||||
BattleSide side,
|
||||
float strengthRatio,
|
||||
int simulationTurnsCount)
|
||||
:scoreEvaluator(cb->getBattle(battleID), env, strengthRatio, simulationTurnsCount),
|
||||
cachedAttack(), playerID(playerID), side(side), env(env), cb(cb), hb(hb),
|
||||
damageCache(damageCache), strengthRatio(strengthRatio), battleID(battleID), simulationTurnsCount(simulationTurnsCount)
|
||||
{
|
||||
targets = std::make_unique<PotentialTargets>(activeStack, damageCache, hb);
|
||||
cachedScore = EvaluationResult::INEFFECTIVE_SCORE;
|
||||
}
|
||||
|
||||
std::vector<BattleHex> BattleEvaluator::getBrokenWallMoatHexes() const
|
||||
{
|
||||
std::vector<BattleHex> result;
|
||||
@@ -167,7 +206,7 @@ BattleAction BattleEvaluator::selectStackAction(const CStack * stack)
|
||||
score
|
||||
);
|
||||
|
||||
if (moveTarget.scorePerTurn <= score)
|
||||
if (moveTarget.score <= score)
|
||||
{
|
||||
if(evaluationResult.wait)
|
||||
{
|
||||
@@ -197,7 +236,7 @@ BattleAction BattleEvaluator::selectStackAction(const CStack * stack)
|
||||
}
|
||||
|
||||
//ThreatMap threatsToUs(stack); // These lines may be useful but they are't used in the code.
|
||||
if(moveTarget.scorePerTurn > score)
|
||||
if(moveTarget.score > score)
|
||||
{
|
||||
score = moveTarget.score;
|
||||
cachedAttack = moveTarget.cachedAttack;
|
||||
@@ -206,14 +245,13 @@ BattleAction BattleEvaluator::selectStackAction(const CStack * stack)
|
||||
if(stack->waited())
|
||||
{
|
||||
logAi->debug(
|
||||
"Moving %s towards hex %s[%d], score: %2f/%2f",
|
||||
"Moving %s towards hex %s[%d], score: %2f",
|
||||
stack->getDescription(),
|
||||
moveTarget.cachedAttack->attack.defender->getDescription(),
|
||||
moveTarget.cachedAttack->attack.defender->getPosition().hex,
|
||||
moveTarget.score,
|
||||
moveTarget.scorePerTurn);
|
||||
moveTarget.score);
|
||||
|
||||
return goTowardsNearest(stack, moveTarget.positions);
|
||||
return goTowardsNearest(stack, moveTarget.positions, *targets);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -235,7 +273,7 @@ BattleAction BattleEvaluator::selectStackAction(const CStack * stack)
|
||||
if(stack->doubleWide() && vstd::contains(brokenWallMoat, stack->getPosition()))
|
||||
return BattleAction::makeMove(stack, stack->getPosition().cloneInDirection(BattleHex::RIGHT));
|
||||
else
|
||||
return goTowardsNearest(stack, brokenWallMoat);
|
||||
return goTowardsNearest(stack, brokenWallMoat, *targets);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,7 +287,32 @@ uint64_t timeElapsed(std::chrono::time_point<std::chrono::high_resolution_clock>
|
||||
return std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
|
||||
}
|
||||
|
||||
BattleAction BattleEvaluator::goTowardsNearest(const CStack * stack, std::vector<BattleHex> hexes)
|
||||
BattleAction BattleEvaluator::moveOrAttack(const CStack * stack, BattleHex hex, const PotentialTargets & targets)
|
||||
{
|
||||
auto additionalScore = 0;
|
||||
std::optional<AttackPossibility> attackOnTheWay;
|
||||
|
||||
for(auto & target : targets.possibleAttacks)
|
||||
{
|
||||
if(!target.attack.shooting && target.from == hex && target.attackValue() > additionalScore)
|
||||
{
|
||||
additionalScore = target.attackValue();
|
||||
attackOnTheWay = target;
|
||||
}
|
||||
}
|
||||
|
||||
if(attackOnTheWay)
|
||||
{
|
||||
activeActionMade = true;
|
||||
return BattleAction::makeMeleeAttack(stack, attackOnTheWay->attack.defender->getPosition(), attackOnTheWay->from);
|
||||
}
|
||||
else
|
||||
{
|
||||
return BattleAction::makeMove(stack, hex);
|
||||
}
|
||||
}
|
||||
|
||||
BattleAction BattleEvaluator::goTowardsNearest(const CStack * stack, std::vector<BattleHex> hexes, const PotentialTargets & targets)
|
||||
{
|
||||
auto reachability = cb->getBattle(battleID)->getReachability(stack);
|
||||
auto avHexes = cb->getBattle(battleID)->battleGetAvailableHexes(reachability, stack, false);
|
||||
@@ -261,49 +324,38 @@ BattleAction BattleEvaluator::goTowardsNearest(const CStack * stack, std::vector
|
||||
|
||||
std::vector<BattleHex> targetHexes = hexes;
|
||||
|
||||
for(int i = 0; i < 5; i++)
|
||||
{
|
||||
std::sort(targetHexes.begin(), targetHexes.end(), [&](BattleHex h1, BattleHex h2) -> bool
|
||||
{
|
||||
return reachability.distances[h1] < reachability.distances[h2];
|
||||
});
|
||||
vstd::erase_if(targetHexes, [](const BattleHex & hex) { return !hex.isValid(); });
|
||||
|
||||
for(auto hex : targetHexes)
|
||||
std::sort(targetHexes.begin(), targetHexes.end(), [&](BattleHex h1, BattleHex h2) -> bool
|
||||
{
|
||||
if(vstd::contains(avHexes, hex))
|
||||
{
|
||||
return BattleAction::makeMove(stack, hex);
|
||||
}
|
||||
|
||||
if(stack->coversPos(hex))
|
||||
{
|
||||
logAi->warn("Warning: already standing on neighbouring tile!");
|
||||
//We shouldn't even be here...
|
||||
return BattleAction::makeDefend(stack);
|
||||
}
|
||||
}
|
||||
|
||||
if(reachability.distances[targetHexes.front()] <= GameConstants::BFIELD_SIZE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
std::vector<BattleHex> copy = targetHexes;
|
||||
|
||||
for(auto hex : copy)
|
||||
vstd::concatenate(targetHexes, hex.allNeighbouringTiles());
|
||||
|
||||
vstd::erase_if(targetHexes, [](const BattleHex & hex) {return !hex.isValid();});
|
||||
vstd::removeDuplicates(targetHexes);
|
||||
}
|
||||
return reachability.distances[h1] < reachability.distances[h2];
|
||||
});
|
||||
|
||||
BattleHex bestNeighbor = targetHexes.front();
|
||||
|
||||
if(reachability.distances[bestNeighbor] > GameConstants::BFIELD_SIZE)
|
||||
{
|
||||
logAi->trace("No richable hexes.");
|
||||
return BattleAction::makeDefend(stack);
|
||||
}
|
||||
|
||||
// this turn
|
||||
for(auto hex : targetHexes)
|
||||
{
|
||||
if(vstd::contains(avHexes, hex))
|
||||
{
|
||||
return moveOrAttack(stack, hex, targets);
|
||||
}
|
||||
|
||||
if(stack->coversPos(hex))
|
||||
{
|
||||
logAi->warn("Warning: already standing on neighbouring hex!");
|
||||
//We shouldn't even be here...
|
||||
return BattleAction::makeDefend(stack);
|
||||
}
|
||||
}
|
||||
|
||||
// not this turn
|
||||
scoreEvaluator.updateReachabilityMap(hb);
|
||||
|
||||
if(stack->hasBonusOfType(BonusType::FLYING))
|
||||
@@ -343,7 +395,7 @@ BattleAction BattleEvaluator::goTowardsNearest(const CStack * stack, std::vector
|
||||
return scoreEvaluator.checkPositionBlocksOurStacks(*hb, stack, hex) ? BLOCKED_STACK_PENALTY + distance : distance;
|
||||
});
|
||||
|
||||
return BattleAction::makeMove(stack, *nearestAvailableHex);
|
||||
return moveOrAttack(stack, *nearestAvailableHex, targets);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -357,11 +409,16 @@ BattleAction BattleEvaluator::goTowardsNearest(const CStack * stack, std::vector
|
||||
|
||||
if(vstd::contains(avHexes, currentDest)
|
||||
&& !scoreEvaluator.checkPositionBlocksOurStacks(*hb, stack, currentDest))
|
||||
return BattleAction::makeMove(stack, currentDest);
|
||||
{
|
||||
return moveOrAttack(stack, currentDest, targets);
|
||||
}
|
||||
|
||||
currentDest = reachability.predecessors[currentDest];
|
||||
}
|
||||
}
|
||||
|
||||
logAi->error("We should either detect that hexes are unreachable or make a move!");
|
||||
return BattleAction::makeDefend(stack);
|
||||
}
|
||||
|
||||
bool BattleEvaluator::canCastSpell()
|
||||
@@ -597,7 +654,7 @@ bool BattleEvaluator::attemptCastingSpell(const CStack * activeStack)
|
||||
#endif
|
||||
|
||||
PotentialTargets innerTargets(activeStack, innerCache, state);
|
||||
BattleExchangeEvaluator innerEvaluator(state, env, strengthRatio);
|
||||
BattleExchangeEvaluator innerEvaluator(state, env, strengthRatio, simulationTurnsCount);
|
||||
|
||||
if(!innerTargets.possibleAttacks.empty())
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user