1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-03-17 20:58:07 +02:00

NKAI: stability fixes and regression

This commit is contained in:
Andrii Danylchenko 2024-04-20 10:33:37 +03:00
parent ed76d8a652
commit 3939c4b9d3
7 changed files with 52 additions and 6 deletions

View File

@ -1111,7 +1111,24 @@ void AIGateway::recruitCreatures(const CGDwelling * d, const CArmedInstance * re
if(!recruiter->getSlotFor(creID).validSlot())
{
continue;
for(auto stack : recruiter->Slots())
{
if(!stack.second->type)
continue;
auto duplicatingSlot = recruiter->getSlotFor(stack.second->type);
if(duplicatingSlot != stack.first)
{
cb->mergeStacks(recruiter, recruiter, stack.first, duplicatingSlot);
break;
}
}
if(!recruiter->getSlotFor(creID).validSlot())
{
continue;
}
}
vstd::amin(count, cb->getResourceAmount() / creID.toCreature()->getFullRecruitCost());

View File

@ -91,7 +91,7 @@ bool HeroPtr::operator<(const HeroPtr & rhs) const
const CGHeroInstance * HeroPtr::get(bool doWeExpectNull) const
{
return get(cb);
return get(cb, doWeExpectNull);
}
const CGHeroInstance * HeroPtr::get(const CPlayerSpecificInfoCallback * cb, bool doWeExpectNull) const
@ -300,6 +300,19 @@ uint64_t timeElapsed(std::chrono::time_point<std::chrono::high_resolution_clock>
return std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
}
int getDuplicatingSlots(const CArmedInstance * army)
{
int duplicatingSlots = 0;
for(auto stack : army->Slots())
{
if(stack.second->type && army->getSlotFor(stack.second->type) != stack.first)
duplicatingSlots++;
}
return duplicatingSlots;
}
// todo: move to obj manager
bool shouldVisit(const Nullkiller * ai, const CGHeroInstance * h, const CGObjectInstance * obj)
{
@ -347,13 +360,14 @@ bool shouldVisit(const Nullkiller * ai, const CGHeroInstance * h, const CGObject
return false;
const CGDwelling * d = dynamic_cast<const CGDwelling *>(obj);
auto duplicatingSlotsCount = getDuplicatingSlots(h);
for(auto level : d->creatures)
{
for(auto c : level.second)
{
if(level.first
&& h->getSlotFor(CreatureID(c)) != SlotID()
&& (h->getSlotFor(CreatureID(c)) != SlotID() || duplicatingSlotsCount > 0)
&& ai->cb->getResourceAmount().canAfford(c.toCreature()->getFullRecruitCost()))
{
return true;

View File

@ -242,6 +242,7 @@ uint64_t timeElapsed(std::chrono::time_point<std::chrono::high_resolution_clock>
// todo: move to obj manager
bool shouldVisit(const Nullkiller * ai, const CGHeroInstance * h, const CGObjectInstance * obj);
int getDuplicatingSlots(const CArmedInstance * army);
template <class T>
class SharedPool

View File

@ -318,7 +318,7 @@ void Nullkiller::makeTurn()
Goals::TGoalVec bestTasks;
for(int i = 1; i <= settings->getMaxPass(); i++)
for(int i = 1; i <= settings->getMaxPass() && cb->getPlayerStatus(playerID) == EPlayerStatus::INGAME; i++)
{
auto start = std::chrono::high_resolution_clock::now();
updateAiState(i);
@ -372,6 +372,9 @@ void Nullkiller::makeTurn()
for(auto bestTask : selectedTasks)
{
if(cb->getPlayerStatus(playerID) != EPlayerStatus::INGAME)
return;
std::string taskDescription = bestTask->toString();
HeroPtr hero = bestTask->getHero();
HeroRole heroRole = HeroRole::MAIN;

View File

@ -158,6 +158,8 @@ uint64_t getCreatureBankArmyReward(const CGObjectInstance * target, const CGHero
const auto& slots = hero->Slots();
ui64 weakestStackPower = 0;
int duplicatingSlots = getDuplicatingSlots(hero);
if (slots.size() >= GameConstants::ARMY_SIZE)
{
//No free slot, we might discard our weakest stack
@ -172,7 +174,7 @@ uint64_t getCreatureBankArmyReward(const CGObjectInstance * target, const CGHero
{
//Only if hero has slot for this creature in the army
auto ccre = dynamic_cast<const CCreature*>(c.data.type);
if (hero->getSlotFor(ccre).validSlot())
if (hero->getSlotFor(ccre).validSlot() || duplicatingSlots > 0)
{
result += (c.data.type->getAIValue() * c.data.count) * c.chance;
}
@ -1125,7 +1127,7 @@ float PriorityEvaluator::evaluate(Goals::TSubgoal task)
}
#if NKAI_TRACE_LEVEL >= 2
logAi->trace("Evaluated %s, loss: %f, turn: %d, turns main: %f, scout: %f, gold: %f, cost: %d, army gain: %d, danger: %d, role: %s, strategical value: %f, cwr: %f, fear: %f, result %f",
logAi->trace("Evaluated %s, loss: %f, turn: %d, turns main: %f, scout: %f, gold: %f, cost: %d, army gain: %f, danger: %d, role: %s, strategical value: %f, cwr: %f, fear: %f, result %f",
task->toString(),
evaluationContext.armyLossPersentage,
(int)evaluationContext.turn,

View File

@ -104,6 +104,13 @@ void ExecuteHeroChain::accept(AIGateway * ai)
const CGHeroInstance * hero = node->targetHero;
HeroPtr heroPtr = hero;
if(!heroPtr.validAndSet())
{
logAi->error("Hero %s was lost. Exit hero chain.", heroPtr.name);
return;
}
if(node->parentIndex >= i)
{
logAi->error("Invalid parentIndex while executing node " + node->coord.toString());

View File

@ -375,6 +375,8 @@ int main(int argc, char * argv[])
while(!headlessQuit)
boost::this_thread::sleep_for(boost::chrono::milliseconds(200));
boost::this_thread::sleep_for(boost::chrono::milliseconds(500));
quitApplication();
}