Răsfoiți Sursa

AI pathfinding loss evaluation

Andrii Danylchenko 4 ani în urmă
părinte
comite
1e4a086bb1

+ 11 - 7
AI/Nullkiller/Pathfinding/AINodeStorage.cpp

@@ -70,7 +70,7 @@ void AINodeStorage::initialize(const PathfinderOptions & options, const CGameSta
 	}
 }
 
-void AINodeStorage::reset()
+void AINodeStorage::clear()
 {
 	actors.clear();
 }
@@ -148,6 +148,7 @@ void AINodeStorage::resetTile(const int3 & coord, EPathfindingLayer layer, CGPat
 		heroNode.danger = 0;
 		heroNode.manaCost = 0;
 		heroNode.specialAction.reset();
+		heroNode.armyLoss = 0;
 		heroNode.update(coord, layer, accessibility);
 	}
 }
@@ -165,6 +166,7 @@ void AINodeStorage::commit(CDestinationNodeInfo & destination, const PathNodeInf
 		dstNode->action = destination.action;
 		dstNode->theNodeBefore = srcNode->theNodeBefore;
 		dstNode->manaCost = srcNode->manaCost;
+		dstNode->armyLoss = srcNode->armyLoss;
 
 		if(dstNode->specialAction && dstNode->actor)
 		{
@@ -213,7 +215,7 @@ const std::set<const CGHeroInstance *> AINodeStorage::getAllHeroes() const
 	for(auto actor : actors)
 	{
 		if(actor->hero)
-			heroes.insert(hero);
+			heroes.insert(actor->hero);
 	}
 
 	return heroes;
@@ -255,7 +257,7 @@ std::vector<CGPathNode *> AINodeStorage::calculateTeleportations(
 		}
 	}
 
-	if(hero->getPosition(false) == source.coord)
+	if(source.isInitialPosition)
 	{
 		calculateTownPortalTeleportations(source, neighbours);
 	}
@@ -270,6 +272,7 @@ void AINodeStorage::calculateTownPortalTeleportations(
 	SpellID spellID = SpellID::TOWN_PORTAL;
 	const CSpell * townPortal = spellID.toSpell();
 	auto srcNode = getAINode(source.node);
+	auto hero = srcNode->actor->hero;
 
 	if(hero->canCastThisSpell(townPortal) && hero->mana >= hero->getSpellCost(townPortal))
 	{
@@ -384,11 +387,10 @@ std::vector<AIPath> AINodeStorage::getChainInfo(const int3 & pos, bool isOnLand)
 {
 	std::vector<AIPath> paths;
 	auto chains = nodes[pos.x][pos.y][pos.z][isOnLand ? EPathfindingLayer::LAND : EPathfindingLayer::SAIL];
-	auto initialPos = hero->visitablePos();
 
 	for(const AIPathNode & node : chains)
 	{
-		if(node.action == CGPathNode::ENodeAction::UNKNOWN || !node.actor)
+		if(node.action == CGPathNode::ENodeAction::UNKNOWN || !node.actor || !node.actor->hero)
 		{
 			continue;
 		}
@@ -397,6 +399,7 @@ std::vector<AIPath> AINodeStorage::getChainInfo(const int3 & pos, bool isOnLand)
 		const AIPathNode * current = &node;
 
 		path.targetHero = node.actor->hero;
+		auto initialPos = path.targetHero->visitablePos();
 
 		while(current != nullptr && current->coord != initialPos)
 		{
@@ -412,7 +415,7 @@ std::vector<AIPath> AINodeStorage::getChainInfo(const int3 & pos, bool isOnLand)
 			current = getAINode(current->theNodeBefore);
 		}
 
-		path.targetObjectDanger = evaluateDanger(pos);
+		path.targetObjectDanger = evaluateDanger(pos, path.targetHero);
 
 		paths.push_back(path);
 	}
@@ -471,6 +474,7 @@ ChainActor::ChainActor(const CGHeroInstance * hero, int chainMask)
 	layer = hero->boat ? EPathfindingLayer::SAIL : EPathfindingLayer::LAND;
 	initialMovement = hero->movement;
 	initialTurn = 0;
+	armyValue = hero->getTotalStrength();
 
 	setupSpecialActors();
 }
@@ -500,7 +504,7 @@ void ChainActor::setupSpecialActors()
 		allActors.push_back(&specialActor);
 	}
 
-	for(int i = 0; i <= 8; i++)
+	for(int i = 0; i < 8; i++)
 	{
 		ChainActor * actor = allActors[i];
 

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

@@ -40,6 +40,7 @@ public:
 	EPathfindingLayer layer;
 	uint32_t initialMovement;
 	uint32_t initialTurn;
+	uint64_t armyValue;
 
 	ChainActor()
 	{
@@ -51,6 +52,7 @@ public:
 struct AIPathNode : public CGPathNode
 {
 	uint64_t danger;
+	uint64_t armyLoss;
 	uint32_t manaCost;
 	std::shared_ptr<const ISpecialAction> specialAction;
 	const ChainActor * actor;
@@ -93,7 +95,6 @@ private:
 	boost::multi_array<AIPathNode, 5> nodes;
 	const CPlayerSpecificInfoCallback * cb;
 	const VCAI * ai;
-	const CGHeroInstance * hero;
 	std::unique_ptr<FuzzyHelper> dangerEvaluator;
 	std::vector<std::shared_ptr<ChainActor>> actors;
 
@@ -137,9 +138,9 @@ public:
 
 	const std::set<const CGHeroInstance *> getAllHeroes() const;
 
-	void reset();
+	void clear();
 
-	uint64_t evaluateDanger(const int3 &  tile) const
+	uint64_t evaluateDanger(const int3 &  tile, const CGHeroInstance * hero) const
 	{
 		return dangerEvaluator->evaluateDanger(tile, hero, ai);
 	}

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

@@ -52,7 +52,7 @@ void AIPathfinder::updatePaths(std::vector<HeroPtr> heroes)
 
 	logAi->debug("Recalculate all paths");
 
-	storage.reset();
+	storage->clear();
 	storage->setHeroes(heroes, ai);
 
 		auto config = std::make_shared<AIPathfinding::AIPathfinderConfig>(cb, ai, storage);

+ 1 - 1
AI/Nullkiller/Pathfinding/Actions/ISpecialAction.h

@@ -13,7 +13,7 @@
 #include "../../AIUtility.h"
 #include "../../Goals/AbstractGoal.h"
 
-class AIPathNode;
+struct AIPathNode;
 
 class ISpecialAction
 {

+ 20 - 13
AI/Nullkiller/Pathfinding/Rules/AIMovementAfterDestinationRule.cpp

@@ -121,25 +121,32 @@ namespace AIPathfinding
 				return;
 			}
 
-			auto danger = nodeStorage->evaluateDanger(destination.coord);
+			auto hero = nodeStorage->getHero(source.node);
+			auto danger = nodeStorage->evaluateDanger(destination.coord, hero);
+			double actualArmyValue = srcNode->actor->armyValue - srcNode->armyLoss;
+			double ratio = (double)danger / actualArmyValue;
 
-			destination.node = battleNode;
-			nodeStorage->commit(destination, source);
+			uint64_t loss = (uint64_t)(actualArmyValue * ratio * ratio * ratio);
 
-			if(battleNode->danger < danger)
+			if(loss < actualArmyValue)
 			{
-				battleNode->danger = danger;
-			}
+				destination.node = battleNode;
+				nodeStorage->commit(destination, source);
+
+				battleNode->armyLoss += loss;
+
+				vstd::amax(battleNode->danger, danger);
 
-			battleNode->specialAction = std::make_shared<BattleAction>(destination.coord);
+				battleNode->specialAction = std::make_shared<BattleAction>(destination.coord);
 #ifdef VCMI_TRACE_PATHFINDER
-			logAi->trace(
-				"Begin bypass guard at destination with danger %s while moving %s -> %s",
-				std::to_string(danger),
-				source.coord.toString(),
-				destination.coord.toString());
+				logAi->trace(
+					"Begin bypass guard at destination with danger %s while moving %s -> %s",
+					std::to_string(danger),
+					source.coord.toString(),
+					destination.coord.toString());
 #endif
-			return;
+				return;
+			}
 		}
 
 		destination.blocked = true;