mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	#2983б #2910 and a few other bugs fixed
This commit is contained in:
		| @@ -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; | ||||
|  | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
| @@ -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) | ||||
|   | ||||
| @@ -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? | ||||
| 							} | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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) | ||||
| 	{ | ||||
|   | ||||
| @@ -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()); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user