1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-04-11 11:31:52 +02:00

Nullkiller AI: add strategical value fuzzy variable

This commit is contained in:
Andrii Danylchenko 2021-05-16 14:13:35 +03:00 committed by Andrii Danylchenko
parent e6eb9ccc03
commit 66ed1a2901
7 changed files with 91 additions and 7 deletions

View File

@ -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)

View File

@ -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;
}

View File

@ -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();
};

View File

@ -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();

View File

@ -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

View File

@ -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;

View File

@ -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