瀏覽代碼

- 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

DjWarmonger 11 年之前
父節點
當前提交
d17b3a14bd
共有 4 個文件被更改,包括 40 次插入10 次删除
  1. 7 0
      AI/VCAI/Fuzzy.cpp
  2. 1 0
      AI/VCAI/Fuzzy.h
  3. 14 3
      AI/VCAI/Goals.cpp
  4. 18 7
      AI/VCAI/VCAI.cpp

+ 7 - 0
AI/VCAI/Fuzzy.cpp

@@ -471,6 +471,13 @@ float FuzzyHelper::evaluate (Goals::VisitHero & g)
 	g.setpriority(Goals::VisitTile(obj->visitablePos()).sethero(g.hero).setisAbstract(g.isAbstract).accept(this));
 	g.setpriority(Goals::VisitTile(obj->visitablePos()).sethero(g.hero).setisAbstract(g.isAbstract).accept(this));
 	return g.priority;	
 	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)
 float FuzzyHelper::evaluate (Goals::BuildThis & g)
 {
 {
 	return 1;
 	return 1;

+ 1 - 0
AI/VCAI/Fuzzy.h

@@ -66,6 +66,7 @@ public:
 	float evaluate (Goals::DigAtTile & g);
 	float evaluate (Goals::DigAtTile & g);
 	float evaluate (Goals::CollectRes & g);
 	float evaluate (Goals::CollectRes & g);
 	float evaluate (Goals::Build & g);
 	float evaluate (Goals::Build & g);
+	float evaluate (Goals::GatherArmy & g);
 	float evaluate (Goals::Invalid & g);
 	float evaluate (Goals::Invalid & g);
 	float evaluate (Goals::AbstractGoal & g);
 	float evaluate (Goals::AbstractGoal & g);
 	void setPriority (Goals::TSubgoal & g);
 	void setPriority (Goals::TSubgoal & g);

+ 14 - 3
AI/VCAI/Goals.cpp

@@ -522,15 +522,26 @@ TGoalVec Explore::getAllPossibleSubgoals()
 	if ((!hero || ret.empty()) && ai->canRecruitAnyHero())
 	if ((!hero || ret.empty()) && ai->canRecruitAnyHero())
 		ret.push_back (sptr(Goals::RecruitHero()));
 		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)
 		if (h.h)
 		{
 		{
 			//FIXME: it never finds anything :?
 			//FIXME: it never finds anything :?
 			int3 t = ai->explorationNewPoint(h->getSightRadious(), h, true);
 			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)));
 				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())
 	if (ret.empty())

+ 18 - 7
AI/VCAI/VCAI.cpp

@@ -1239,6 +1239,12 @@ bool VCAI::canRecruitAnyHero (const CGTownInstance * t) const
 
 
 void VCAI::wander(HeroPtr h)
 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");
 	TimeCheck tc("looking for wander destination");
 
 
 	while (h->movement)
 	while (h->movement)
@@ -1907,8 +1913,7 @@ Goals::TSubgoal VCAI::striveToGoalInternal(Goals::TSubgoal ultimateGoal, bool on
 	{
 	{
 		Goals::TSubgoal goal = ultimateGoal;
 		Goals::TSubgoal goal = ultimateGoal;
         logAi->debugStream() << boost::format("Striving to goal of type %s") % ultimateGoal->name();
         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))
 		while(!goal->isElementar && maxGoals && (onlyAbstract || !goal->isAbstract))
 		{
 		{
             logAi->debugStream() << boost::format("Considering goal %s") % goal->name();
             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)
 		catch(goalFulfilledException &e)
 		{
 		{
 			completeGoal (goal);
 			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()); 
 				return sptr(Goals::Invalid()); 
 		}
 		}
 		catch(std::exception &e)
 		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)
 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);
 	cb->setSelection(h.h);
 
 
 	std::vector<std::vector<int3> > tiles; //tiles[distance_to_fow]
 	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);
 			tiles[0].push_back(pos);
 	});
 	});
 
 
-	int bestValue = 0;
+	float bestValue = 0; //discovered tile to node distance ratio
 	int3 bestTile(-1,-1,-1);
 	int3 bestTile(-1,-1,-1);
 
 
 	for (int i = 1; i < radius; i++)
 	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?
 			if (cb->getTile(tile)->blocked) //does it shorten the time?
 				continue;
 				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 (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
 					bestTile = tile; //return first tile that will discover anything
 					bestValue = ourValue;
 					bestValue = ourValue;