Browse Source

Try to reduce amount of time AI spends on pathfinding

Ivan Savenko 10 months ago
parent
commit
1caab5100a

+ 4 - 0
AI/Nullkiller/AIGateway.cpp

@@ -97,6 +97,8 @@ void AIGateway::heroMoved(const TryMoveHero & details, bool verbose)
 	if(!hero)
 		validateObject(details.id); //enemy hero may have left visible area
 
+	nullkiller->invalidatePathfinderData();
+
 	const int3 from = hero ? hero->convertToVisitablePos(details.start) : (details.start - int3(0,1,0));
 	const int3 to   = hero ? hero->convertToVisitablePos(details.end)   : (details.end   - int3(0,1,0));
 
@@ -358,6 +360,7 @@ void AIGateway::newObject(const CGObjectInstance * obj)
 {
 	LOG_TRACE(logAi);
 	NET_EVENT_HANDLER;
+	nullkiller->invalidatePathfinderData();
 	if(obj->isVisitable())
 		addVisitableObj(obj);
 }
@@ -582,6 +585,7 @@ void AIGateway::yourTurn(QueryID queryID)
 {
 	LOG_TRACE_PARAMS(logAi, "queryID '%i'", queryID);
 	NET_EVENT_HANDLER;
+	nullkiller->invalidatePathfinderData();
 	status.addQuery(queryID, "YourTurn");
 	requestActionASAP([=](){ answerQuery(queryID, 0); });
 	status.startedTurn();

+ 14 - 3
AI/Nullkiller/Engine/Nullkiller.cpp

@@ -37,6 +37,7 @@ Nullkiller::Nullkiller()
 	: activeHero(nullptr)
 	, scanDepth(ScanDepth::MAIN_FULL)
 	, useHeroChain(true)
+	, pathfinderInvalidated(false)
 	, memory(std::make_unique<AIMemory>())
 {
 
@@ -239,6 +240,11 @@ void Nullkiller::resetAiState()
 	}
 }
 
+void Nullkiller::invalidatePathfinderData()
+{
+	pathfinderInvalidated = true;
+}
+
 void Nullkiller::updateAiState(int pass, bool fast)
 {
 	boost::this_thread::interruption_point();
@@ -253,7 +259,10 @@ void Nullkiller::updateAiState(int pass, bool fast)
 	decomposer->reset();
 	buildAnalyzer->update();
 
-	if(!fast)
+	if (!pathfinderInvalidated)
+		logAi->trace("Skipping paths regeneration - up to date");
+
+	if(!fast && pathfinderInvalidated)
 	{
 		memory->removeInvisibleObjects(cb.get());
 
@@ -304,11 +313,13 @@ void Nullkiller::updateAiState(int pass, bool fast)
 		boost::this_thread::interruption_point();
 
 		objectClusterizer->clusterize();
+
+		pathfinderInvalidated = false;
 	}
 
 	armyManager->update();
 
-	logAi->debug("AI state updated in %ld", timeElapsed(start));
+	logAi->debug("AI state updated in %ld ms", timeElapsed(start));
 }
 
 bool Nullkiller::isHeroLocked(const CGHeroInstance * hero) const
@@ -379,7 +390,7 @@ void Nullkiller::makeTurn()
 
 		Goals::TTask bestTask = taskptr(Goals::Invalid());
 
-		while(true)
+		for(int j = 1; j <= settings->getMaxPriorityPass() && cb->getPlayerStatus(playerID) == EPlayerStatus::INGAME; j++)
 		{
 			bestTasks.clear();
 

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

@@ -78,6 +78,7 @@ private:
 	AIGateway * gateway;
 	bool openMap;
 	bool useObjectGraph;
+	bool pathfinderInvalidated;
 
 public:
 	static std::unique_ptr<ObjectGraph> baseGraph;
@@ -121,6 +122,7 @@ public:
 	bool isOpenMap() const { return openMap; }
 	bool isObjectGraphAllowed() const { return useObjectGraph; }
 	bool handleTrading();
+	void invalidatePathfinderData();
 
 private:
 	void resetAiState();

+ 4 - 2
AI/Nullkiller/Engine/Settings.cpp

@@ -32,7 +32,8 @@ namespace NKAI
 		retreatThresholdRelative(0.3),
 		retreatThresholdAbsolute(10000),
 		safeAttackRatio(1.1),
-		maxpass(10),
+		maxPass(10),
+		maxPriorityPass(10),
 		pathfinderBucketsCount(1),
 		pathfinderBucketSize(32),
 		allowObjectGraph(true),
@@ -48,7 +49,8 @@ namespace NKAI
 		maxRoamingHeroes = node["maxRoamingHeroes"].Integer();
 		mainHeroTurnDistanceLimit = node["mainHeroTurnDistanceLimit"].Integer();
 		scoutHeroTurnDistanceLimit = node["scoutHeroTurnDistanceLimit"].Integer();
-		maxpass = node["maxpass"].Integer();
+		maxPass = node["maxPass"].Integer();
+		maxPriorityPass = node["maxPriorityPass"].Integer();
 		pathfinderBucketsCount = node["pathfinderBucketsCount"].Integer();
 		pathfinderBucketSize = node["pathfinderBucketSize"].Integer();
 		maxGoldPressure = node["maxGoldPressure"].Float();

+ 4 - 2
AI/Nullkiller/Engine/Settings.h

@@ -24,7 +24,8 @@ namespace NKAI
 		int maxRoamingHeroes;
 		int mainHeroTurnDistanceLimit;
 		int scoutHeroTurnDistanceLimit;
-		int maxpass;
+		int maxPass;
+		int maxPriorityPass;
 		int pathfinderBucketsCount;
 		int pathfinderBucketSize;
 		float maxGoldPressure;
@@ -41,7 +42,8 @@ namespace NKAI
 	public:
 		explicit Settings(int difficultyLevel);
 
-		int getMaxPass() const { return maxpass; }
+		int getMaxPass() const { return maxPass; }
+		int getMaxPriorityPass() const { return maxPriorityPass; }
 		float getMaxGoldPressure() const { return maxGoldPressure; }
 		float getRetreatThresholdRelative() const { return retreatThresholdRelative; }
 		float getRetreatThresholdAbsolute() const { return retreatThresholdAbsolute; }

+ 2 - 2
AI/Nullkiller/Pathfinding/AIPathfinder.cpp

@@ -106,7 +106,7 @@ void AIPathfinder::updatePaths(const std::map<const CGHeroInstance *, HeroRole>
 
 	if(!pathfinderSettings.useHeroChain)
 	{
-		logAi->trace("Recalculated paths in %ld", timeElapsed(start));
+		logAi->trace("Recalculated paths in %ld ms", timeElapsed(start));
 
 		return;
 	}
@@ -141,7 +141,7 @@ void AIPathfinder::updatePaths(const std::map<const CGHeroInstance *, HeroRole>
 		}
 	} while(storage->increaseHeroChainTurnLimit());
 
-	logAi->trace("Recalculated paths in %ld", timeElapsed(start));
+	logAi->trace("Recalculated paths in %ld ms", timeElapsed(start));
 }
 
 void AIPathfinder::updateGraphs(

+ 29 - 24
config/ai/nkai/nkai-settings.json

@@ -33,17 +33,18 @@
 	
 	
 	"pawn" : {
-		"maxRoamingHeroes" : 4, //H3 value: 3,
-		"maxpass" : 30,
+		"maxRoamingHeroes" : 3, //H3 value: 3,
+		"maxPass" : 30,
+		"maxPriorityPass" : 10,
 		"mainHeroTurnDistanceLimit" : 10,
 		"scoutHeroTurnDistanceLimit" : 5,
 		"maxGoldPressure" : 0.3,
 		"updateHitmapOnTileReveal" : false,
 		"useTroopsFromGarrisons" : true,
 		"openMap": true,
-		"allowObjectGraph": false,
-		"pathfinderBucketsCount" : 1, // old value: 3,
-		"pathfinderBucketSize" : 32, // old value: 7,
+		"allowObjectGraph": true,
+		"pathfinderBucketsCount" : 4, // old value: 3,
+		"pathfinderBucketSize" : 8, // old value: 7,
 		"retreatThresholdRelative" : 0,
 		"retreatThresholdAbsolute" : 0,
 		"safeAttackRatio" : 1.1,
@@ -52,17 +53,18 @@
 	},
 	
 	"knight" : {
-		"maxRoamingHeroes" : 6, //H3 value: 3,
-		"maxpass" : 30,
+		"maxRoamingHeroes" : 3, //H3 value: 3,
+		"maxPass" : 30,
+		"maxPriorityPass" : 10,
 		"mainHeroTurnDistanceLimit" : 10,
 		"scoutHeroTurnDistanceLimit" : 5,
 		"maxGoldPressure" : 0.3,
 		"updateHitmapOnTileReveal" : false,
 		"useTroopsFromGarrisons" : true,
 		"openMap": true,
-		"allowObjectGraph": false,
-		"pathfinderBucketsCount" : 1, // old value: 3,
-		"pathfinderBucketSize" : 32, // old value: 7,
+		"allowObjectGraph": true,
+		"pathfinderBucketsCount" : 4, // old value: 3,
+		"pathfinderBucketSize" : 8, // old value: 7,
 		"retreatThresholdRelative" : 0.1,
 		"retreatThresholdAbsolute" : 5000,
 		"safeAttackRatio" : 1.1,
@@ -71,17 +73,18 @@
 	},
 	
 	"rook" : {
-		"maxRoamingHeroes" : 8, //H3 value: 4
-		"maxpass" : 30,
+		"maxRoamingHeroes" : 4, //H3 value: 4
+		"maxPass" : 30,
+		"maxPriorityPass" : 10,
 		"mainHeroTurnDistanceLimit" : 10,
 		"scoutHeroTurnDistanceLimit" : 5,
 		"maxGoldPressure" : 0.3,
 		"updateHitmapOnTileReveal" : false,
 		"useTroopsFromGarrisons" : true,
 		"openMap": true,
-		"allowObjectGraph": false,
-		"pathfinderBucketsCount" : 1, // old value: 3,
-		"pathfinderBucketSize" : 32, // old value: 7,
+		"allowObjectGraph": true,
+		"pathfinderBucketsCount" : 4, // old value: 3,
+		"pathfinderBucketSize" : 8, // old value: 7,
 		"retreatThresholdRelative" : 0.3,
 		"retreatThresholdAbsolute" : 10000,
 		"safeAttackRatio" : 1.1,
@@ -90,17 +93,18 @@
 	},
 	
 	"queen" : {
-		"maxRoamingHeroes" : 8, //H3 value: 5
-		"maxpass" : 30,
+		"maxRoamingHeroes" : 6, //H3 value: 5
+		"maxPass" : 30,
+		"maxPriorityPass" : 10,
 		"mainHeroTurnDistanceLimit" : 10,
 		"scoutHeroTurnDistanceLimit" : 5,
 		"maxGoldPressure" : 0.3,
 		"updateHitmapOnTileReveal" : false,
 		"useTroopsFromGarrisons" : true,
 		"openMap": true,
-		"allowObjectGraph": false,
-		"pathfinderBucketsCount" : 1, // old value: 3,
-		"pathfinderBucketSize" : 32, // old value: 7,
+		"allowObjectGraph": true,
+		"pathfinderBucketsCount" : 4, // old value: 3,
+		"pathfinderBucketSize" : 8, // old value: 7,
 		"retreatThresholdRelative" : 0.3,
 		"retreatThresholdAbsolute" : 10000,
 		"safeAttackRatio" : 1.1,
@@ -110,16 +114,17 @@
 	
 	"king" : {
 		"maxRoamingHeroes" : 8, //H3 value: 6
-		"maxpass" : 30,
+		"maxPass" : 30,
+		"maxPriorityPass" : 10,
 		"mainHeroTurnDistanceLimit" : 10,
 		"scoutHeroTurnDistanceLimit" : 5,
 		"maxGoldPressure" : 0.3,
 		"updateHitmapOnTileReveal" : false,
 		"useTroopsFromGarrisons" : true,
 		"openMap": true,
-		"allowObjectGraph": false,
-		"pathfinderBucketsCount" : 1, // old value: 3,
-		"pathfinderBucketSize" : 32, // old value: 7,
+		"allowObjectGraph": true,
+		"pathfinderBucketsCount" : 4, // old value: 3,
+		"pathfinderBucketSize" : 8, // old value: 7,
 		"retreatThresholdRelative" : 0.3,
 		"retreatThresholdAbsolute" : 10000,
 		"safeAttackRatio" : 1.1,