浏览代码

- Explore goal will also use fuzzy comparison
- Fixed AI afraid of town with Castle built: #1514, #1515, #1584

DjWarmonger 12 年之前
父节点
当前提交
bf3fe0e274
共有 3 个文件被更改,包括 41 次插入80 次删除
  1. 1 1
      AI/VCAI/Fuzzy.cpp
  2. 39 78
      AI/VCAI/Goals.cpp
  3. 1 1
      AI/VCAI/Goals.h

+ 1 - 1
AI/VCAI/Fuzzy.cpp

@@ -159,7 +159,7 @@ void FuzzyHelper::initTacticalAdvantage()
 		ta.castleWalls = new fl::InputLVar("CastleWalls");
 		ta.castleWalls->addTerm(new fl::SingletonTerm("NONE", CGTownInstance::NONE));
 		ta.castleWalls->addTerm(new fl::TrapezoidalTerm("MEDIUM", CGTownInstance::FORT, 2.5));
-		ta.castleWalls->addTerm(new fl::ShoulderTerm("HIGH", CGTownInstance::CITADEL - 0.1, CGTownInstance::CASTLE));
+		ta.castleWalls->addTerm(new fl::ShoulderTerm("HIGH", CGTownInstance::CITADEL - 0.1, CGTownInstance::CASTLE, false));
 		engine.addInputLVar(ta.castleWalls);
 
 		ta.bankPresent = new fl::InputLVar("Bank");

+ 39 - 78
AI/VCAI/Goals.cpp

@@ -368,6 +368,33 @@ std::string Explore::completeMessage() const
 
 TSubgoal Explore::whatToDoToAchieve()
 {
+	auto ret = fh->chooseSolution(getAllPossibleSubgoals());
+	if (hero) //use best step for this hero
+		return ret;
+	else
+	{
+		if (ret->hero.get(true))
+			return sptr (sethero(ret->hero.h).setisAbstract(true)); //choose this hero and then continue with him
+		else
+			return ret; //other solutions, like buying hero from tavern
+	}
+};
+
+TGoalVec Explore::getAllPossibleSubgoals()
+{
+	TGoalVec ret;
+	std::vector<const CGHeroInstance *> heroes;
+	if (hero)
+		heroes.push_back(hero.h);
+	else
+	{
+		heroes = cb->getHeroesInfo();
+		erase_if(heroes, [](const CGHeroInstance *h)
+		{
+			return !h->movement; //only hero with movement are of interest for us
+		});
+	}
+
 	auto objs = ai->visitableObjs; //try to use buildings that uncover map
 	erase_if(objs, [&](const CGObjectInstance *obj) -> bool
 	{
@@ -389,94 +416,28 @@ TSubgoal Explore::whatToDoToAchieve()
 				return true;
 		}
 	});
-	if (objs.size())
-	{
-		if (hero.get(true))
-		{
-			for (auto obj : objs)
-			{
-				auto pos = obj->visitablePos();
-				//FIXME: this confition fails if everything but guarded subterranen gate was explored. in this case we should gather army for hero
-				if (isSafeToVisit(hero, pos) && ai->isAccessibleForHero(pos, hero))
-					return sptr (Goals::VisitTile(pos).sethero(hero));
-			}
-		}
-		else
-		{
-			for (auto obj : objs)
-			{
-				auto pos = obj->visitablePos();
-				if (ai->isAccessible (pos)) //TODO: check safety?
-					return sptr (Goals::VisitTile(pos).sethero(hero));
-			}
-		}
-	}
 
-	if (hero)
+	for (auto h : heroes)
 	{
-		int3 t = whereToExplore(hero);
-		if (t.z == -1) //no safe tile to explore - we need to break!
+		for (auto obj : objs) //double loop, performance risk?
 		{
-			erase_if (objs, [&](const CGObjectInstance *obj) -> bool
-			{
-				switch (obj->ID.num)
-				{
-					case Obj::CARTOGRAPHER:
-					case Obj::SUBTERRANEAN_GATE:
-					//case Obj::MONOLITH1:
-					//case obj::MONOLITH2:
-					//case obj::MONOLITH3:
-					//case Obj::WHIRLPOOL:
-						return false; //do not erase
-						break;
-					default:
-						return true;
-				}
-			});
-			if (objs.size())
+			if (ai->isAccessibleForHero(obj->visitablePos(), h) && isSafeToVisit(h, obj->visitablePos()))
 			{
-				return sptr (Goals::VisitTile(objs.front()->visitablePos()).sethero(hero).setisAbstract(true));
+				ret.push_back (sptr (Goals::VisitTile(obj->visitablePos()).sethero(h)));
 			}
-			else
-				throw cannotFulfillGoalException("Cannot explore - no possible ways found!");
 		}
-		return sptr (Goals::VisitTile(t).sethero(hero));
-	}
-
-	auto hs = cb->getHeroesInfo();
-	int howManyHeroes = hs.size();
 
-	erase(hs, [](const CGHeroInstance *h)
-	{
-		return contains(ai->lockedHeroes, h);
-	});
-	if(hs.empty()) //all heroes are busy. buy new one
-	{
-		if (howManyHeroes < 3  && ai->findTownWithTavern()) //we may want to recruit second hero. TODO: make it smart finally
-			return sptr (Goals::RecruitHero());
-		else //find mobile hero with weakest army
-		{
-			hs = cb->getHeroesInfo();
-			erase_if(hs, [](const CGHeroInstance *h)
-			{
-				return !h->movement; //only hero with movement are of interest for us
-			});
-			if (hs.empty())
-			{
-				if (howManyHeroes < GameConstants::MAX_HEROES_PER_PLAYER)
-					return sptr (Goals::RecruitHero());
-				else
-					throw cannotFulfillGoalException("No heroes with remaining MPs for exploring!\n");
-			}
-			boost::sort(hs, compareMovement); //closer to what?
-		}
+		int3 t = whereToExplore(h);
+		if (t.z != -1) //no safe tile to explore - we need to break!
+		ret.push_back (sptr (Goals::VisitTile(t).sethero(h)));
 	}
+	if (!hero && ai->canRecruitAnyHero())//if hero is assigned to that goal, no need to buy another one yet
+		ret.push_back (sptr(Goals::RecruitHero()));
 
-	const CGHeroInstance *h = hs.front();
-
-	return sptr (sethero(h).setisAbstract(true));
+	if (ret.empty())
+		throw cannotFulfillGoalException("Cannot explore - no possible ways found!");
 
-	return iAmElementar(); //FIXME: how can this be called?
+	return ret;
 };
 
 float Explore::importanceWhenLocked() const

+ 1 - 1
AI/VCAI/Goals.h

@@ -229,7 +229,7 @@ class Explore : public CGoal<Explore>
 	public:
 	Explore() : CGoal (Goals::EXPLORE){};
 	Explore(HeroPtr h) : CGoal (Goals::EXPLORE){hero = h;};
-	TGoalVec getAllPossibleSubgoals() override {return TGoalVec();};
+	TGoalVec getAllPossibleSubgoals() override;
 	TSubgoal whatToDoToAchieve() override;
 	std::string completeMessage() const override;
 	float importanceWhenLocked() const override;