فهرست منبع

Nullkiller: turn limit for main heroes

Andrii Danylchenko 4 سال پیش
والد
کامیت
0ffc7c3b94

+ 20 - 0
AI/Nullkiller/Engine/Nullkiller.cpp

@@ -104,6 +104,7 @@ Goals::TTask Nullkiller::choseBestTask(Goals::TSubgoal behavior, int decompositi
 
 void Nullkiller::resetAiState()
 {
+	scanDepth = ScanDepth::SMALL;
 	playerID = ai->playerID;
 	lockedHeroes.clear();
 	dangerHitMap->reset();
@@ -140,6 +141,11 @@ void Nullkiller::updateAiState(int pass)
 	cfg.useHeroChain = true;
 	cfg.scoutTurnDistanceLimit = SCOUT_TURN_DISTANCE_LIMIT;
 
+	if(scanDepth != ScanDepth::FULL)
+	{
+		cfg.mainTurnDistanceLimit = MAIN_TURN_DISTANCE_LIMIT * ((int)scanDepth + 1);
+	}
+
 	pathfinder->updatePaths(activeHeroes, cfg);
 
 	armyManager->update();
@@ -215,6 +221,20 @@ void Nullkiller::makeTurn()
 		}
 
 		Goals::TTask bestTask = choseBestTask(bestTasks);
+		HeroPtr hero = bestTask->getHero();
+
+		if(bestTask->priority < NEXT_SCAN_MIN_PRIORITY
+			&& hero.validAndSet()
+			&& heroManager->getHeroRole(hero) == HeroRole::MAIN
+			&& scanDepth != ScanDepth::FULL)
+		{
+			logAi->trace(
+				"Goal %s has too low priority %f so increasing scan depth",
+				bestTask->toString(),
+				bestTask->priority);
+			scanDepth = (ScanDepth)((int)scanDepth + 1);
+			continue;
+		}
 
 		if(bestTask->priority < MIN_PRIORITY)
 		{

+ 11 - 0
AI/Nullkiller/Engine/Nullkiller.h

@@ -21,6 +21,7 @@
 
 const float MAX_GOLD_PEASURE = 0.3f;
 const float MIN_PRIORITY = 0.01f;
+const float NEXT_SCAN_MIN_PRIORITY = 0.4f;
 
 enum class HeroLockedReason
 {
@@ -33,12 +34,22 @@ enum class HeroLockedReason
 	HERO_CHAIN = 3
 };
 
+enum class ScanDepth
+{
+	SMALL = 0,
+
+	MEDIUM = 1,
+
+	FULL = 2
+};
+
 class Nullkiller
 {
 private:
 	const CGHeroInstance * activeHero;
 	int3 targetTile;
 	std::map<const CGHeroInstance *, HeroLockedReason> lockedHeroes;
+	ScanDepth scanDepth;
 
 public:
 	std::unique_ptr<DangerHitMapAnalyzer> dangerHitMap;

+ 1 - 2
AI/Nullkiller/Goals/AbstractGoal.h

@@ -74,7 +74,6 @@ namespace Goals
 	public:
 		bool operator==(const TSubgoal & rhs) const;
 		bool operator<(const TSubgoal & rhs) const;
-		//TODO: serialize?
 	};
 
 	typedef std::shared_ptr<ITask> TTask;
@@ -108,7 +107,6 @@ namespace Goals
 		const CGTownInstance *town; VSETTER(CGTownInstance *, town)
 		int bid; VSETTER(int, bid)
 		TSubgoal parent; VSETTER(TSubgoal, parent)
-		//EvaluationContext evaluationContext; VSETTER(EvaluationContext, evaluationContext)
 
 		AbstractGoal(EGoals goal = EGoals::INVALID)
 			: goalType(goal), hero()
@@ -185,6 +183,7 @@ namespace Goals
 		//TODO: make accept work for std::shared_ptr... somehow
 		virtual void accept(VCAI * ai) = 0; //unhandled goal will report standard error
 		virtual std::string toString() const = 0;
+		virtual HeroPtr getHero() const = 0;
 		virtual ~ITask() {}
 	};
 }

+ 3 - 4
AI/Nullkiller/Goals/CGoal.h

@@ -97,10 +97,9 @@ namespace Goals
 			return *((T *)this);
 		}
 
-		virtual bool isElementar() const override
-		{
-			return true;
-		}
+		virtual bool isElementar() const override { return true; }
+
+		virtual HeroPtr getHero() const override { return hero; }
 	};
 
 	class DLL_EXPORT Invalid : public ElementarGoal<Invalid>

+ 5 - 9
AI/Nullkiller/Pathfinding/AINodeStorage.cpp

@@ -108,7 +108,8 @@ void AINodeStorage::clear()
 	heroChainPass = EHeroChainPass::INITIAL;
 	heroChainTurn = 0;
 	heroChainMaxTurns = 1;
-	scoutTurnDistanceLimit = 255;
+	turnDistanceLimit[HeroRole::MAIN] = 255;
+	turnDistanceLimit[HeroRole::SCOUT] = 255;
 }
 
 const AIPathNode * AINodeStorage::getAINode(const CGPathNode * node) const
@@ -703,15 +704,10 @@ bool AINodeStorage::isDistanceLimitReached(const PathNodeInfo & source, CDestina
 	
 	auto aiNode = getAINode(destination.node);
 	
-	if(heroChainPass == EHeroChainPass::FINAL)
+	if(heroChainPass != EHeroChainPass::CHAIN
+		&& destination.node->turns > turnDistanceLimit[aiNode->actor->heroRole])
 	{
-		if(aiNode->actor->heroRole == HeroRole::SCOUT && destination.node->turns > scoutTurnDistanceLimit)
-			return true;
-	}
-	else if(heroChainPass == EHeroChainPass::INITIAL)
-	{
-		if(aiNode->actor->heroRole == HeroRole::SCOUT && destination.node->turns > scoutTurnDistanceLimit)
-			return true;
+		return true;
 	}
 
 	return false;

+ 4 - 2
AI/Nullkiller/Pathfinding/AINodeStorage.h

@@ -13,6 +13,7 @@
 #define PATHFINDER_TRACE_LEVEL 0
 #define AI_TRACE_LEVEL 0
 #define SCOUT_TURN_DISTANCE_LIMIT 3
+#define MAIN_TURN_DISTANCE_LIMIT 5
 
 #include "../../../lib/CPathfinder.h"
 #include "../../../lib/mapObjects/CGHeroInstance.h"
@@ -147,7 +148,7 @@ private:
 	int heroChainTurn;
 	int heroChainMaxTurns;
 	PlayerColor playerID;
-	uint8_t scoutTurnDistanceLimit;
+	uint8_t turnDistanceLimit[2];
 
 public:
 	/// more than 1 chain layer for each hero allows us to have more than 1 path to each tile so we can chose more optimal one.	
@@ -204,7 +205,8 @@ public:
 	std::vector<AIPath> getChainInfo(const int3 & pos, bool isOnLand) const;
 	bool isTileAccessible(const HeroPtr & hero, const int3 & pos, const EPathfindingLayer layer) const;
 	void setHeroes(std::map<const CGHeroInstance *, HeroRole> heroes);
-	void setScoutTurnDistanceLimit(uint8_t distanceLimit) { scoutTurnDistanceLimit = distanceLimit; }
+	void setScoutTurnDistanceLimit(uint8_t distanceLimit) { turnDistanceLimit[HeroRole::SCOUT] = distanceLimit; }
+	void setMainTurnDistanceLimit(uint8_t distanceLimit) { turnDistanceLimit[HeroRole::MAIN] = distanceLimit; }
 	void setTownsAndDwellings(
 		const std::vector<const CGTownInstance *> & towns,
 		const std::set<const CGObjectInstance *> & visitableObjs);

+ 1 - 0
AI/Nullkiller/Pathfinding/AIPathfinder.cpp

@@ -56,6 +56,7 @@ void AIPathfinder::updatePaths(std::map<const CGHeroInstance *, HeroRole> heroes
 	storage->clear();
 	storage->setHeroes(heroes);
 	storage->setScoutTurnDistanceLimit(pathfinderSettings.scoutTurnDistanceLimit);
+	storage->setMainTurnDistanceLimit(pathfinderSettings.mainTurnDistanceLimit);
 
 	if(pathfinderSettings.useHeroChain)
 	{

+ 3 - 1
AI/Nullkiller/Pathfinding/AIPathfinder.h

@@ -19,10 +19,12 @@ struct PathfinderSettings
 {
 	bool useHeroChain;
 	uint8_t scoutTurnDistanceLimit;
+	uint8_t mainTurnDistanceLimit;
 
 	PathfinderSettings()
 		:useHeroChain(false),
-		scoutTurnDistanceLimit(255)
+		scoutTurnDistanceLimit(255),
+		mainTurnDistanceLimit(255)
 	{ }
 };