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

#2983б #2910 and a few other bugs fixed

This commit is contained in:
Andrii Danylchenko 2018-09-11 13:09:14 +03:00
parent 49c872e4ec
commit cf213a5acf
7 changed files with 95 additions and 19 deletions

View File

@ -523,7 +523,7 @@ creInfo infoFromDC(const dwellingContent & dc)
return ci; return ci;
} }
ui64 howManyReinforcementsCanBuy(HeroPtr h, const CGTownInstance * t) ui64 howManyReinforcementsCanBuy(HeroPtr h, const CGDwelling * t)
{ {
ui64 aivalue = 0; ui64 aivalue = 0;

View File

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

View File

@ -19,8 +19,13 @@ extern boost::thread_specific_ptr<VCAI> ai;
Goals::TSubgoal FuzzyHelper::chooseSolution(Goals::TGoalVec vec) Goals::TSubgoal FuzzyHelper::chooseSolution(Goals::TGoalVec vec)
{ {
if(vec.empty()) //no possibilities found if(vec.empty())
{
logAi->debug("FuzzyHelper found no goals. Returning Goals::Invalid.");
//no possibilities found
return sptr(Goals::Invalid()); return sptr(Goals::Invalid());
}
//a trick to switch between heroes less often - calculatePaths is costly //a trick to switch between heroes less often - calculatePaths is costly
auto sortByHeroes = [](const Goals::TSubgoal & lhs, const Goals::TSubgoal & rhs) -> bool auto sortByHeroes = [](const Goals::TSubgoal & lhs, const Goals::TSubgoal & rhs) -> bool
@ -38,7 +43,17 @@ Goals::TSubgoal FuzzyHelper::chooseSolution(Goals::TGoalVec vec)
{ {
return lhs->priority < rhs->priority; return lhs->priority < rhs->priority;
}; };
return *boost::max_element(vec, compareGoals);
for(auto goal : vec)
{
logAi->debug("FuzzyHelper evaluated goal %s, priority=%i", goal->name(), goal->priority);
}
Goals::TSubgoal result = *boost::max_element(vec, compareGoals);
logAi->debug("FuzzyHelper returned goal %s, priority=%i", result->name(), result->priority);
return result;
} }
ui64 FuzzyHelper::estimateBankDanger(const CBank * bank) ui64 FuzzyHelper::estimateBankDanger(const CBank * bank)

View File

@ -163,6 +163,9 @@ bool Goals::AbstractGoal::operator==(AbstractGoal & g)
return (town == g.town && bid == g.bid); //build specific structure in specific town return (town == g.town && bid == g.bid); //build specific structure in specific town
break; break;
case BUY_ARMY:
return town == g.town;
//no check atm //no check atm
case COLLECT_RES: case COLLECT_RES:
case TRADE: //TODO case TRADE: //TODO
@ -1441,14 +1444,16 @@ TGoalVec GatherArmy::getAllPossibleSubgoals()
ret.push_back(sptr(Goals::VisitTile(pos).sethero(hero))); ret.push_back(sptr(Goals::VisitTile(pos).sethero(hero)));
} }
//buy army in town //buy army in town
if (!t->visitingHero || t->visitingHero != hero.get(true)) if (!t->visitingHero || t->visitingHero == hero.get(true))
{ {
ui32 val = std::min<ui32>(value, howManyReinforcementsCanBuy(hero, t)); ui32 val = std::min<ui32>(value, howManyReinforcementsCanBuy(hero, t));
if (val) if (val)
{ {
auto goal = sptr(Goals::BuyArmy(t, val).sethero(hero)); auto goal = sptr(Goals::BuyArmy(t, val).sethero(hero));
if (!ai->ah->containsObjective(goal)) //avoid loops caused by reserving same objective twice if(!ai->ah->containsObjective(goal)) //avoid loops caused by reserving same objective twice
ret.push_back(goal); ret.push_back(goal);
else
logAi->debug("Can not buy army, because of ai->ah->containsObjective");
} }
} }
//build dwelling //build dwelling
@ -1460,6 +1465,8 @@ TGoalVec GatherArmy::getAllPossibleSubgoals()
auto goal = sptr(BuildThis(bid.get(), t).setpriority(priority)); auto goal = sptr(BuildThis(bid.get(), t).setpriority(priority));
if (!ai->ah->containsObjective(goal)) //avoid loops caused by reserving same objective twice if (!ai->ah->containsObjective(goal)) //avoid loops caused by reserving same objective twice
ret.push_back(goal); ret.push_back(goal);
else
logAi->debug("Can not build a structure, because of ai->ah->containsObjective");
} }
} }
} }
@ -1501,15 +1508,21 @@ TGoalVec GatherArmy::getAllPossibleSubgoals()
if(relationToOwner == PlayerRelations::SAME_PLAYER) if(relationToOwner == PlayerRelations::SAME_PLAYER)
{ {
auto dwelling = dynamic_cast<const CGDwelling *>(obj); auto dwelling = dynamic_cast<const CGDwelling *>(obj);
for(auto & creLevel : dwelling->creatures)
ui32 val = std::min<ui32>(value, howManyReinforcementsCanBuy(hero, dwelling));
if(val)
{ {
if(creLevel.first) for(auto & creLevel : dwelling->creatures)
{ {
for(auto & creatureID : creLevel.second) if(creLevel.first)
{ {
auto creature = VLC->creh->creatures[creatureID]; for(auto & creatureID : creLevel.second)
if(ai->ah->freeResources().canAfford(creature->cost)) {
objs.push_back(obj); //TODO: reserve resources? auto creature = VLC->creh->creatures[creatureID];
if(ai->ah->freeResources().canAfford(creature->cost))
objs.push_back(obj); //TODO: reserve resources?
}
} }
} }
} }

View File

@ -172,6 +172,8 @@ Goals::TSubgoal ResourceManager::whatToDo() const //suggest any goal
Goals::TSubgoal ResourceManager::whatToDo(TResources &res, Goals::TSubgoal goal) Goals::TSubgoal ResourceManager::whatToDo(TResources &res, Goals::TSubgoal goal)
{ {
logAi->trace("ResourceManager: checking goal %s which requires resources %s", goal->name(), res.toString());
TResources accumulatedResources; TResources accumulatedResources;
auto allResources = cb->getResourceAmount(); auto allResources = cb->getResourceAmount();
@ -181,19 +183,38 @@ Goals::TSubgoal ResourceManager::whatToDo(TResources &res, Goals::TSubgoal goal)
for (auto it = queue.ordered_begin(); it != queue.ordered_end(); it++) for (auto it = queue.ordered_begin(); it != queue.ordered_end(); it++)
{ {
accumulatedResources += it->resources; accumulatedResources += it->resources;
if (!accumulatedResources.canBeAfforded(allResources)) //can't afford
return collectResourcesForOurGoal(ro); logAi->trace(
"ResourceManager: checking goal %s, accumulatedResources=%s, available=%s",
it->goal->name(),
accumulatedResources.toString(),
allResources.toString());
if(!accumulatedResources.canBeAfforded(allResources))
{
//can't afford
break;
}
else //can afford all goals up to this point else //can afford all goals up to this point
{ {
if (it->goal == goal) if(it->goal == goal)
{
logAi->debug("ResourceManager: can afford goal %s", goal->name());
return goal; //can afford immediately return goal; //can afford immediately
}
} }
} }
return collectResourcesForOurGoal(ro); //fallback, ever needed?
logAi->debug("ResourceManager: can not afford goal %s", goal->name());
return collectResourcesForOurGoal(ro);
} }
bool ResourceManager::containsObjective(Goals::TSubgoal goal) const bool ResourceManager::containsObjective(Goals::TSubgoal goal) const
{ {
logAi->trace("Entering ResourceManager.containsObjective goal=%s", goal->name());
dumpToLog();
//TODO: unit tests for once //TODO: unit tests for once
for (auto objective : queue) for (auto objective : queue)
{ {
@ -205,6 +226,8 @@ bool ResourceManager::containsObjective(Goals::TSubgoal goal) const
bool ResourceManager::notifyGoalCompleted(Goals::TSubgoal goal) bool ResourceManager::notifyGoalCompleted(Goals::TSubgoal goal)
{ {
logAi->trace("Entering ResourceManager.notifyGoalCompleted goal=%s", goal->name());
if (goal->invalid()) if (goal->invalid())
logAi->warn("Attempt to complete Invalid goal"); logAi->warn("Attempt to complete Invalid goal");
@ -215,15 +238,18 @@ bool ResourceManager::notifyGoalCompleted(Goals::TSubgoal goal)
{ {
return ro.goal == goal || ro.goal->fulfillsMe (goal); return ro.goal == goal || ro.goal->fulfillsMe (goal);
}); });
if (it != queue.end()) //removed at least one if(it != queue.end()) //removed at least one
{ {
logAi->debug("Removing goal %s from ResourceManager.", it->goal->name()); logAi->debug("Removing goal %s from ResourceManager.", it->goal->name());
queue.erase(queue.s_handle_from_iterator(it)); queue.erase(queue.s_handle_from_iterator(it));
removedGoal = true; removedGoal = true;
} }
else //found nothing more to remove else //found nothing more to remove
return removedGoal; break;
} }
dumpToLog();
return removedGoal; return removedGoal;
} }
@ -248,10 +274,21 @@ bool ResourceManager::updateGoal(Goals::TSubgoal goal)
return false; return false;
} }
void ResourceManager::dumpToLog() const
{
for(auto it = queue.ordered_begin(); it != queue.ordered_end(); it++)
{
logAi->trace("ResourceManager contains goal %s which requires resources %s", it->goal->name(), it->resources.toString());
}
}
bool ResourceManager::tryPush(const ResourceObjective & o) bool ResourceManager::tryPush(const ResourceObjective & o)
{ {
auto goal = o.goal; auto goal = o.goal;
logAi->trace("ResourceManager: Trying to add goal %s which requires resources %s", goal->name(), o.resources.toString());
dumpToLog();
auto it = boost::find_if(queue, [goal](const ResourceObjective & ro) -> bool auto it = boost::find_if(queue, [goal](const ResourceObjective & ro) -> bool
{ {
return ro.goal == goal; return ro.goal == goal;

View File

@ -102,6 +102,8 @@ private:
boost::heap::binomial_heap<ResourceObjective> queue; boost::heap::binomial_heap<ResourceObjective> queue;
void dumpToLog() const;
//TODO: register? //TODO: register?
template<typename Handler> void serializeInternal(Handler & h, const int version) template<typename Handler> void serializeInternal(Handler & h, const int version)
{ {

View File

@ -933,6 +933,8 @@ void VCAI::mainLoop()
} }
} }
logAi->trace("Main loop: selecting best elementar goal");
//now choose one elementar goal to realize //now choose one elementar goal to realize
Goals::TGoalVec possibleGoals(elementarGoals.begin(), elementarGoals.end()); //copy to vector Goals::TGoalVec possibleGoals(elementarGoals.begin(), elementarGoals.end()); //copy to vector
Goals::TSubgoal goalToRealize = sptr(Goals::Invalid()); Goals::TSubgoal goalToRealize = sptr(Goals::Invalid());
@ -2205,7 +2207,7 @@ void VCAI::tryRealize(Goals::BuyArmy & g)
}); });
vstd::amin(ci.count, res / ci.cre->cost); //max count we can afford vstd::amin(ci.count, res / ci.cre->cost); //max count we can afford
if (ci.count > 0) if (ci.count > 0 && t->getUpperArmy()->getSlotFor(ci.creID) != SlotID())
{ {
cb->recruitCreatures(t, t->getUpperArmy(), ci.creID, ci.count, ci.level); cb->recruitCreatures(t, t->getUpperArmy(), ci.creID, ci.count, ci.level);
valueBought += ci.count * ci.cre->AIValue; valueBought += ci.count * ci.cre->AIValue;
@ -2379,6 +2381,13 @@ void VCAI::striveToGoal(Goals::TSubgoal basicGoal)
Goals::TSubgoal VCAI::decomposeGoal(Goals::TSubgoal ultimateGoal) Goals::TSubgoal VCAI::decomposeGoal(Goals::TSubgoal ultimateGoal)
{ {
if(ultimateGoal->isElementar)
{
logAi->warn("Trying to decompose elementar goal %s", ultimateGoal->name());
return ultimateGoal;
}
const int searchDepth = 30; const int searchDepth = 30;
const int searchDepth2 = searchDepth - 2; const int searchDepth2 = searchDepth - 2;
Goals::TSubgoal abstractGoal = sptr(Goals::Invalid()); Goals::TSubgoal abstractGoal = sptr(Goals::Invalid());