浏览代码

Nullkiller AI: add strategical value fuzzy variable

Andrii Danylchenko 4 年之前
父节点
当前提交
66ed1a2901

+ 1 - 1
AI/Nullkiller/Behaviors/RecruitHeroBehavior.cpp

@@ -35,7 +35,7 @@ Goals::TGoalVec RecruitHeroBehavior::getTasks()
 
 	for(auto town : towns)
 	{
-		if(!town->garrisonHero && ai->canRecruitAnyHero(town))
+		if(!town->garrisonHero && !town->visitingHero && ai->canRecruitAnyHero(town))
 		{
 			if(cb->getHeroesInfo().size() < cb->getTownsInfo().size() + 1
 				|| cb->getResourceAmount(Res::GOLD) > 10000)

+ 38 - 2
AI/Nullkiller/Engine/DangerHitMapAnalyzer.cpp

@@ -16,8 +16,14 @@ extern boost::thread_specific_ptr<VCAI> ai;
 
 void DangerHitMapAnalyzer::updateHitMap()
 {
+	if(upToDate)
+		return;
+
+	upToDate = true;
+
 	auto mapSize = cb->getMapSize();
 	hitMap.resize(boost::extents[mapSize.x][mapSize.y][mapSize.z]);
+	enemyHeroAccessibleObjects.clear();
 
 	std::map<PlayerColor, std::vector<HeroPtr>> heroes;
 
@@ -62,6 +68,17 @@ void DangerHitMapAnalyzer::updateHitMap()
 					node.fastestDanger.turn = turn;
 					node.fastestDanger.hero = path.targetHero;
 				}
+
+				if(turn == 0)
+				{
+					auto objects = cb->getVisitableObjs(pos, false);
+					
+					for(auto obj : objects)
+					{
+						if(cb->getPlayerRelations(obj->tempOwner, ai->playerID) != PlayerRelations::ENEMIES)
+							enemyHeroAccessibleObjects[path.targetHero].insert(obj);
+					}
+				}
 			}
 		});
 	}
@@ -77,10 +94,29 @@ uint64_t DangerHitMapAnalyzer::enemyCanKillOurHeroesAlongThePath(const AIPath &
 		|| info.maximumDanger.turn <= turn && !isSafeToVisit(path.targetHero, path.heroArmy, info.maximumDanger.danger);
 }
 
-const HitMapNode & DangerHitMapAnalyzer::getObjectTreat(const CGObjectInstance * town) const
+const HitMapNode & DangerHitMapAnalyzer::getObjectTreat(const CGObjectInstance * obj) const
 {
-	auto tile = town->visitablePos();
+	auto tile = obj->visitablePos();
 	const HitMapNode & info = hitMap[tile.x][tile.y][tile.z];
 
 	return info;
 }
+
+const std::set<const CGObjectInstance *> empty = {};
+
+const std::set<const CGObjectInstance *> & DangerHitMapAnalyzer::getOneTurnAccessibleObjects(const CGHeroInstance * enemy) const
+{
+	auto result = enemyHeroAccessibleObjects.find(enemy);
+	
+	if(result == enemyHeroAccessibleObjects.end())
+	{
+		return empty;
+	}
+
+	return result->second;
+}
+
+void DangerHitMapAnalyzer::reset()
+{
+	upToDate = false;
+}

+ 5 - 2
AI/Nullkiller/Engine/DangerHitMapAnalyzer.h

@@ -42,10 +42,13 @@ class DangerHitMapAnalyzer
 {
 private:
 	boost::multi_array<HitMapNode, 3> hitMap;
-	std::map<const CGHeroInstance *, int> enemyHeroTreatMAp;
+	std::map<const CGHeroInstance *, std::set<const CGObjectInstance *>> enemyHeroAccessibleObjects;
+	bool upToDate;
 
 public:
 	void updateHitMap();
 	uint64_t enemyCanKillOurHeroesAlongThePath(const AIPath & path) const;
-	const HitMapNode & getObjectTreat(const CGObjectInstance * town) const;
+	const HitMapNode & getObjectTreat(const CGObjectInstance * obj) const;
+	const std::set<const CGObjectInstance *> & getOneTurnAccessibleObjects(const CGHeroInstance * enemy) const;
+	void reset();
 };

+ 2 - 1
AI/Nullkiller/Engine/Nullkiller.cpp

@@ -67,12 +67,13 @@ void Nullkiller::resetAiState()
 {
 	lockedHeroes.clear();
 
-	dangerHitMap->updateHitMap();
+	dangerHitMap->reset();
 }
 
 void Nullkiller::updateAiState()
 {
 	ai->validateVisitableObjs();
+	dangerHitMap->updateHitMap();
 
 	// TODO: move to hero manager
 	auto activeHeroes = ai->getMyHeroes();

+ 39 - 1
AI/Nullkiller/Engine/PriorityEvaluator.cpp

@@ -21,6 +21,7 @@
 #include "../../../lib/filesystem/Filesystem.h"
 #include "../VCAI.h"
 #include "../AIhelper.h"
+#include "../Engine/Nullkiller.h"
 
 #define MIN_AI_STRENGHT (0.5f) //lower when combat AI gets smarter
 #define UNGUARDED_OBJECT (100.0f) //we consider unguarded objects 100 times weaker than us
@@ -58,6 +59,7 @@ void PriorityEvaluator::initVisitTile()
 	skillRewardVariable = engine->getInputVariable("skillReward");
 	rewardTypeVariable = engine->getInputVariable("rewardType");
 	closestHeroRatioVariable = engine->getInputVariable("closestHeroRatio");
+	strategicalValueVariable = engine->getInputVariable("strategicalValue");
 	value = engine->getOutputVariable("Value");
 }
 
@@ -190,6 +192,40 @@ uint64_t getArmyReward(const CGObjectInstance * target, const CGHeroInstance * h
 	}
 }
 
+float getStrategicalValue(const CGObjectInstance * target);
+
+float getEnemyHeroStrategicalValue(const CGHeroInstance * enemy)
+{
+	auto objectsUnderTreat = ai->nullkiller->dangerHitMap->getOneTurnAccessibleObjects(enemy);
+	float objectValue = 0;
+
+	for(auto obj : objectsUnderTreat)
+	{
+		objectValue += getStrategicalValue(obj);
+	}
+
+	return objectValue + enemy->level / 15.0f;
+}
+
+float getStrategicalValue(const CGObjectInstance * target)
+{
+	if(!target)
+		return 0;
+
+	switch(target->ID)
+	{
+	case Obj::TOWN:
+		return target->tempOwner == PlayerColor::NEUTRAL ? 0.5 : 1;
+
+	case Obj::HERO:
+		return cb->getPlayerRelations(target->tempOwner, ai->playerID) == PlayerRelations::ENEMIES
+			? getEnemyHeroStrategicalValue(dynamic_cast<const CGHeroInstance *>(target))
+			: 0;
+	default:
+		return 0;
+	}
+}
+
 float evaluateWitchHutSkillScore(const CGWitchHut * hut, const CGHeroInstance * hero, HeroRole role)
 {
 	if(!hut->wasVisited(hero->tempOwner))
@@ -336,8 +372,9 @@ float PriorityEvaluator::evaluate(Goals::TSubgoal task)
 	bool checkGold = danger == 0;
 	uint64_t armyReward = getArmyReward(target, hero, checkGold);
 	float skillReward = getSkillReward(target, hero, heroRole);
+	float strategicalValue = getStrategicalValue(target);
 	double result = 0;
-	int rewardType = (goldReward > 0 ? 1 : 0) + (armyReward > 0 ? 1 : 0) + (skillReward > 0 ? 1 : 0);
+	int rewardType = (goldReward > 0 ? 1 : 0) + (armyReward > 0 ? 1 : 0) + (skillReward > 0 ? 1 : 0) + (strategicalValue > 0 ? 1 : 0);
 	
 	try
 	{
@@ -350,6 +387,7 @@ float PriorityEvaluator::evaluate(Goals::TSubgoal task)
 		dangerVariable->setValue(danger);
 		rewardTypeVariable->setValue(rewardType);
 		closestHeroRatioVariable->setValue(task->evaluationContext.closestWayRatio);
+		strategicalValueVariable->setValue(strategicalValue);
 
 		engine->process();
 		//engine.process(VISIT_TILE); //TODO: Process only Visit_Tile

+ 1 - 0
AI/Nullkiller/Engine/PriorityEvaluator.h

@@ -35,6 +35,7 @@ private:
 	fl::InputVariable * armyRewardVariable;
 	fl::InputVariable * dangerVariable;
 	fl::InputVariable * skillRewardVariable;
+	fl::InputVariable * strategicalValueVariable;
 	fl::InputVariable * rewardTypeVariable;
 	fl::InputVariable * closestHeroRatioVariable;
 	fl::OutputVariable * value;

+ 5 - 0
AI/Nullkiller/VCAI.cpp

@@ -1750,6 +1750,11 @@ void VCAI::addVisitableObj(const CGObjectInstance * obj)
 	auto teleportObj = dynamic_cast<const CGTeleport *>(obj);
 	if(teleportObj)
 		CGTeleport::addToChannel(knownTeleportChannels, teleportObj);
+
+	if(obj->ID == Obj::HERO && cb->getPlayerRelations(obj->tempOwner, playerID) == PlayerRelations::ENEMIES)
+	{
+		if(nullkiller) nullkiller->dangerHitMap->reset();
+	}
 }
 
 const CGObjectInstance * VCAI::lookForArt(int aid) const