1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-11-24 08:32:34 +02:00

AI: fix freeze on BuyArmy

This commit is contained in:
Andrii Danylchenko 2018-12-30 16:40:05 +02:00
parent cbbb85fa87
commit 2c401931c4
4 changed files with 42 additions and 21 deletions

View File

@ -524,7 +524,8 @@ creInfo infoFromDC(const dwellingContent & dc)
return ci;
}
ui64 howManyReinforcementsCanBuy(HeroPtr h, const CGDwelling * t)
ui64 howManyReinforcementsCanBuy(const CArmedInstance * h, const CGDwelling * t)
{
ui64 aivalue = 0;
@ -552,7 +553,7 @@ ui64 howManyReinforcementsCanBuy(HeroPtr h, const CGDwelling * t)
return aivalue;
}
ui64 howManyReinforcementsCanGet(HeroPtr h, const CGTownInstance * t)
ui64 howManyReinforcementsCanGet(const CArmedInstance * h, const CGTownInstance * t)
{
ui64 ret = 0;
int freeHeroSlots = GameConstants::ARMY_SIZE - h->stacksCount();

View File

@ -179,8 +179,8 @@ bool compareMovement(HeroPtr lhs, HeroPtr rhs);
bool compareHeroStrength(HeroPtr h1, HeroPtr h2);
bool compareArmyStrength(const CArmedInstance * a1, const CArmedInstance * a2);
bool compareArtifacts(const CArtifactInstance * a1, const CArtifactInstance * a2);
ui64 howManyReinforcementsCanBuy(HeroPtr h, const CGDwelling * t);
ui64 howManyReinforcementsCanGet(HeroPtr h, const CGTownInstance * t);
ui64 howManyReinforcementsCanBuy(const CArmedInstance * h, const CGDwelling * t);
ui64 howManyReinforcementsCanGet(const CArmedInstance * h, const CGTownInstance * t);
int3 whereToExplore(HeroPtr h);
uint32_t distanceToTile(const CGHeroInstance * hero, int3 pos);

View File

@ -64,7 +64,7 @@ TGoalVec GatherArmy::getAllPossibleSubgoals()
if(ai->isAccessibleForHero(pos, hero))
{
//grab army from town
if(!t->visitingHero && howManyReinforcementsCanGet(hero, t))
if(!t->visitingHero && howManyReinforcementsCanGet(hero.get(), t))
{
if(!vstd::contains(ai->townVisitsThisWeek[hero], t))
ret.push_back(sptr(VisitTile(pos).sethero(hero)));
@ -72,10 +72,23 @@ TGoalVec GatherArmy::getAllPossibleSubgoals()
//buy army in town
if (!t->visitingHero || t->visitingHero == hero.get(true))
{
ui32 val = std::min<ui32>(value, howManyReinforcementsCanBuy(hero, t));
std::vector<int> values = {
value,
(int)howManyReinforcementsCanBuy(t->getUpperArmy(), t),
(int)howManyReinforcementsCanBuy(hero.get(), t) };
int val = *std::min_element(values.begin(), values.end());
logAi->trace(
"Army value need %i, to hero %i, to town %i",
value,
(int)howManyReinforcementsCanBuy(hero.get(), t),
(int)howManyReinforcementsCanBuy(t->getUpperArmy(), t));
if (val)
{
auto goal = sptr(BuyArmy(t, val).sethero(hero));
if(!ai->ah->containsObjective(goal)) //avoid loops caused by reserving same objective twice
ret.push_back(goal);
else
@ -137,7 +150,7 @@ TGoalVec GatherArmy::getAllPossibleSubgoals()
{
auto dwelling = dynamic_cast<const CGDwelling *>(obj);
ui32 val = std::min<ui32>(value, howManyReinforcementsCanBuy(hero, dwelling));
ui32 val = std::min<ui32>(value, howManyReinforcementsCanBuy(hero.get(), dwelling));
if(val)
{

View File

@ -1456,12 +1456,13 @@ void VCAI::wander(HeroPtr h)
auto compareReinforcements = [h](const CGTownInstance * lhs, const CGTownInstance * rhs) -> bool
{
auto r1 = howManyReinforcementsCanGet(h, lhs),
r2 = howManyReinforcementsCanGet(h, rhs);
const CGHeroInstance * hptr = h.get();
auto r1 = howManyReinforcementsCanGet(hptr, lhs),
r2 = howManyReinforcementsCanGet(hptr, rhs);
if (r1 != r2)
return r1 < r2;
else
return howManyReinforcementsCanBuy(h, lhs) < howManyReinforcementsCanBuy(h, rhs);
return howManyReinforcementsCanBuy(hptr, lhs) < howManyReinforcementsCanBuy(hptr, rhs);
};
std::vector<const CGTownInstance *> townsReachable;
@ -2200,6 +2201,8 @@ void VCAI::tryRealize(Goals::BuyArmy & g)
ui64 valueBought = 0;
//buy the stacks with largest AI value
makePossibleUpgrades(t);
while (valueBought < g.value)
{
auto res = ah->allResources();
@ -2209,7 +2212,15 @@ void VCAI::tryRealize(Goals::BuyArmy & g)
{
auto ci = infoFromDC(t->creatures[i]);
if(!ci.count || ci.creID == -1 || (g.objid != -1 && ci.creID != g.objid))
if(!ci.count
|| ci.creID == -1
|| (g.objid != -1 && ci.creID != g.objid)
|| t->getUpperArmy()->getSlotFor(ci.creID) == SlotID())
continue;
vstd::amin(ci.count, res / ci.cre->cost); //max count we can afford
if(!ci.count)
continue;
ci.level = i; //this is important for Dungeon Summoning Portal
@ -2223,21 +2234,17 @@ void VCAI::tryRealize(Goals::BuyArmy & g)
*boost::max_element(creaturesInDwellings, [&res](const creInfo & lhs, const creInfo & rhs)
{
//max value of creatures we can buy with our res
int value1 = lhs.cre->AIValue * (std::min(lhs.count, res / lhs.cre->cost)),
value2 = rhs.cre->AIValue * (std::min(rhs.count, res / rhs.cre->cost));
int value1 = lhs.cre->AIValue * lhs.count,
value2 = rhs.cre->AIValue * rhs.count;
return value1 < value2;
});
vstd::amin(ci.count, res / ci.cre->cost); //max count we can afford
if (ci.count > 0 && t->getUpperArmy()->getSlotFor(ci.creID) != SlotID())
{
cb->recruitCreatures(t, t->getUpperArmy(), ci.creID, ci.count, ci.level);
valueBought += ci.count * ci.cre->AIValue;
}
else
throw cannotFulfillGoalException("Can't buy any more creatures!");
cb->recruitCreatures(t, t->getUpperArmy(), ci.creID, ci.count, ci.level);
valueBought += ci.count * ci.cre->AIValue;
}
throw goalFulfilledException(sptr(g)); //we bought as many creatures as we wanted
}