Browse Source

#2983б #2910 and a few other bugs fixed

Andrii Danylchenko 7 years ago
parent
commit
cf213a5acf

+ 1 - 1
AI/VCAI/AIUtility.cpp

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

+ 1 - 1
AI/VCAI/AIUtility.h

@@ -179,7 +179,7 @@ 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 CGTownInstance * t);
+ui64 howManyReinforcementsCanBuy(HeroPtr h, const CGDwelling * t);
 ui64 howManyReinforcementsCanGet(HeroPtr h, const CGTownInstance * t);
 int3 whereToExplore(HeroPtr h);
 uint32_t distanceToTile(const CGHeroInstance * hero, int3 pos);

+ 17 - 2
AI/VCAI/FuzzyHelper.cpp

@@ -19,8 +19,13 @@ extern boost::thread_specific_ptr<VCAI> ai;
 
 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());
+	}
 
 	//a trick to switch between heroes less often - calculatePaths is costly
 	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 *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)

+ 21 - 8
AI/VCAI/Goals.cpp

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

+ 43 - 6
AI/VCAI/ResourceManager.cpp

@@ -172,6 +172,8 @@ Goals::TSubgoal ResourceManager::whatToDo() const //suggest any 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;
 	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++)
 	{
 		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
 		{
-			if (it->goal == goal)
+			if(it->goal == goal)
+			{
+				logAi->debug("ResourceManager: can afford goal %s", goal->name());
 				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
 {
+	logAi->trace("Entering ResourceManager.containsObjective goal=%s", goal->name());
+	dumpToLog();
+
 	//TODO: unit tests for once
 	for (auto objective : queue)
 	{
@@ -205,6 +226,8 @@ bool ResourceManager::containsObjective(Goals::TSubgoal goal) const
 
 bool ResourceManager::notifyGoalCompleted(Goals::TSubgoal goal)
 {
+	logAi->trace("Entering ResourceManager.notifyGoalCompleted goal=%s", goal->name());
+
 	if (goal->invalid())
 		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);
 		});
-		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());
 			queue.erase(queue.s_handle_from_iterator(it));
 			removedGoal = true;
 		}
 		else //found nothing more to remove
-			return removedGoal;
+			break;
 	}
+
+	dumpToLog();
+
 	return removedGoal;
 }
 
@@ -248,10 +274,21 @@ bool ResourceManager::updateGoal(Goals::TSubgoal goal)
 		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)
 {
 	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
 	{
 		return ro.goal == goal;

+ 2 - 0
AI/VCAI/ResourceManager.h

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

+ 10 - 1
AI/VCAI/VCAI.cpp

@@ -933,6 +933,8 @@ void VCAI::mainLoop()
 			}
 		}
 
+		logAi->trace("Main loop: selecting best elementar goal");
+
 		//now choose one elementar goal to realize
 		Goals::TGoalVec possibleGoals(elementarGoals.begin(), elementarGoals.end()); //copy to vector
 		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
-		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);
 			valueBought += ci.count * ci.cre->AIValue;
@@ -2379,6 +2381,13 @@ void VCAI::striveToGoal(Goals::TSubgoal basicGoal)
 
 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 searchDepth2 = searchDepth - 2;
 	Goals::TSubgoal abstractGoal = sptr(Goals::Invalid());