mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	- Significantly improved exploration algorithm
- Workaround to make AI gather army when exploration is not possible anymore - Possibly fixed issue with AI not capturing guarded objects
This commit is contained in:
		| @@ -471,6 +471,13 @@ float FuzzyHelper::evaluate (Goals::VisitHero & g) | ||||
| 	g.setpriority(Goals::VisitTile(obj->visitablePos()).sethero(g.hero).setisAbstract(g.isAbstract).accept(this)); | ||||
| 	return g.priority;	 | ||||
| } | ||||
| float FuzzyHelper::evaluate (Goals::GatherArmy & g) | ||||
| { | ||||
| 	//the more army we need, the more important goal | ||||
| 	//the more army we lack, the less important goal | ||||
| 	float army = g.hero->getArmyStrength(); | ||||
| 	return g.value / std::min(g.value - army, 1000.0f); | ||||
| } | ||||
| float FuzzyHelper::evaluate (Goals::BuildThis & g) | ||||
| { | ||||
| 	return 1; | ||||
|   | ||||
| @@ -66,6 +66,7 @@ public: | ||||
| 	float evaluate (Goals::DigAtTile & g); | ||||
| 	float evaluate (Goals::CollectRes & g); | ||||
| 	float evaluate (Goals::Build & g); | ||||
| 	float evaluate (Goals::GatherArmy & g); | ||||
| 	float evaluate (Goals::Invalid & g); | ||||
| 	float evaluate (Goals::AbstractGoal & g); | ||||
| 	void setPriority (Goals::TSubgoal & g); | ||||
|   | ||||
| @@ -522,15 +522,26 @@ TGoalVec Explore::getAllPossibleSubgoals() | ||||
| 	if ((!hero || ret.empty()) && ai->canRecruitAnyHero()) | ||||
| 		ret.push_back (sptr(Goals::RecruitHero())); | ||||
|  | ||||
| 	if (!hero && ret.empty()) | ||||
| 	if (ret.empty()) | ||||
| 	{ | ||||
| 		auto h = ai->primaryHero(); //we may need to gather big army to break! | ||||
| 		HeroPtr h; | ||||
| 		if (hero) //there is some hero set and it's us | ||||
| 		{ | ||||
| 			 if (hero == ai->primaryHero()) | ||||
| 				h = hero; | ||||
| 		} | ||||
| 		else //no hero is set, so we choose our main | ||||
| 			h = ai->primaryHero(); | ||||
| 		 //we may need to gather big army to break! | ||||
| 		if (h.h) | ||||
| 		{ | ||||
| 			//FIXME: it never finds anything :? | ||||
| 			int3 t = ai->explorationNewPoint(h->getSightRadious(), h, true); | ||||
| 			if (cb->isInTheMap(t)) | ||||
| 			if (cb->isInTheMap(t))  | ||||
| 				ret.push_back (sptr(ClearWayTo(t).setisAbstract(true).sethero(h))); | ||||
| 			else //just in case above fails - gather army if no further exploration possible | ||||
| 				ret.push_back (sptr(GatherArmy(h->getArmyStrength() + 1).sethero(h))); | ||||
| 			//do not set abstract to keep our hero free once he gets reinforcements | ||||
| 		} | ||||
| 	} | ||||
| 	if (ret.empty()) | ||||
|   | ||||
| @@ -1239,6 +1239,12 @@ bool VCAI::canRecruitAnyHero (const CGTownInstance * t) const | ||||
|  | ||||
| void VCAI::wander(HeroPtr h) | ||||
| { | ||||
| 	//unclaim objects that are now dangerous for us | ||||
| 	erase_if(reservedHeroesMap[h], [h](const CGObjectInstance * obj) -> bool | ||||
| 	{ | ||||
| 		return !isSafeToVisit(h, obj->visitablePos()); | ||||
| 	}); | ||||
|  | ||||
| 	TimeCheck tc("looking for wander destination"); | ||||
|  | ||||
| 	while (h->movement) | ||||
| @@ -1907,8 +1913,7 @@ Goals::TSubgoal VCAI::striveToGoalInternal(Goals::TSubgoal ultimateGoal, bool on | ||||
| 	{ | ||||
| 		Goals::TSubgoal goal = ultimateGoal; | ||||
|         logAi->debugStream() << boost::format("Striving to goal of type %s") % ultimateGoal->name(); | ||||
| 		int maxGoals = 100; //preventing deadlock for mutually dependent goals | ||||
| 		//FIXME: do not try to realize goal when loop didn't suceed | ||||
| 		int maxGoals = 30; //preventing deadlock for mutually dependent goals | ||||
| 		while(!goal->isElementar && maxGoals && (onlyAbstract || !goal->isAbstract)) | ||||
| 		{ | ||||
|             logAi->debugStream() << boost::format("Considering goal %s") % goal->name(); | ||||
| @@ -1970,7 +1975,7 @@ Goals::TSubgoal VCAI::striveToGoalInternal(Goals::TSubgoal ultimateGoal, bool on | ||||
| 		catch(goalFulfilledException &e) | ||||
| 		{ | ||||
| 			completeGoal (goal); | ||||
| 			if (ultimateGoal->fulfillsMe(goal) || maxGoals > 98) //completed goal was main goal //TODO: find better condition | ||||
| 			if (ultimateGoal->fulfillsMe(goal) || maxGoals > 28) //completed goal was main goal //TODO: find better condition | ||||
| 				return sptr(Goals::Invalid());  | ||||
| 		} | ||||
| 		catch(std::exception &e) | ||||
| @@ -2172,7 +2177,7 @@ int3 VCAI::explorationBestNeighbour(int3 hpos, int radius, HeroPtr h) | ||||
|  | ||||
| int3 VCAI::explorationNewPoint(int radius, HeroPtr h, bool breakUnsafe) | ||||
| { | ||||
|     logAi->debugStream() << "Looking for an another place for exploration..."; | ||||
|     //logAi->debugStream() << "Looking for an another place for exploration..."; | ||||
| 	cb->setSelection(h.h); | ||||
|  | ||||
| 	std::vector<std::vector<int3> > tiles; //tiles[distance_to_fow] | ||||
| @@ -2184,7 +2189,7 @@ int3 VCAI::explorationNewPoint(int radius, HeroPtr h, bool breakUnsafe) | ||||
| 			tiles[0].push_back(pos); | ||||
| 	}); | ||||
|  | ||||
| 	int bestValue = 0; | ||||
| 	float bestValue = 0; //discovered tile to node distance ratio | ||||
| 	int3 bestTile(-1,-1,-1); | ||||
|  | ||||
| 	for (int i = 1; i < radius; i++) | ||||
| @@ -2196,10 +2201,16 @@ int3 VCAI::explorationNewPoint(int radius, HeroPtr h, bool breakUnsafe) | ||||
| 		{ | ||||
| 			if (cb->getTile(tile)->blocked) //does it shorten the time? | ||||
| 				continue; | ||||
| 			int ourValue = howManyTilesWillBeDiscovered(tile, radius); | ||||
| 			if (!cb->getPathInfo(tile)->reachable()) | ||||
| 				continue; | ||||
|  | ||||
| 			CGPath path; | ||||
| 			cb->getPath2(tile, path); | ||||
| 			float ourValue = (float)howManyTilesWillBeDiscovered(tile, radius) / (path.nodes.size() + 1); //+1 prevents erratic jumps | ||||
|  | ||||
| 			if (ourValue > bestValue) //avoid costly checks of tiles that don't reveal much | ||||
| 			{ | ||||
| 				if(cb->getPathInfo(tile)->reachable()  && (isSafeToVisit(h, tile) || breakUnsafe) && !isBlockedBorderGate(tile)) | ||||
| 				if((isSafeToVisit(h, tile) || breakUnsafe) && !isBlockedBorderGate(tile)) | ||||
| 				{ | ||||
| 					bestTile = tile; //return first tile that will discover anything | ||||
| 					bestValue = ourValue; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user