1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-04-15 11:46:56 +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) 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 if(cb->getHeroesInfo().size() < cb->getTownsInfo().size() + 1
|| cb->getResourceAmount(Res::GOLD) > 10000) || cb->getResourceAmount(Res::GOLD) > 10000)

View File

@ -16,8 +16,14 @@ extern boost::thread_specific_ptr<VCAI> ai;
void DangerHitMapAnalyzer::updateHitMap() void DangerHitMapAnalyzer::updateHitMap()
{ {
if(upToDate)
return;
upToDate = true;
auto mapSize = cb->getMapSize(); auto mapSize = cb->getMapSize();
hitMap.resize(boost::extents[mapSize.x][mapSize.y][mapSize.z]); hitMap.resize(boost::extents[mapSize.x][mapSize.y][mapSize.z]);
enemyHeroAccessibleObjects.clear();
std::map<PlayerColor, std::vector<HeroPtr>> heroes; std::map<PlayerColor, std::vector<HeroPtr>> heroes;
@ -62,6 +68,17 @@ void DangerHitMapAnalyzer::updateHitMap()
node.fastestDanger.turn = turn; node.fastestDanger.turn = turn;
node.fastestDanger.hero = path.targetHero; 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); || 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]; const HitMapNode & info = hitMap[tile.x][tile.y][tile.z];
return info; 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: private:
boost::multi_array<HitMapNode, 3> hitMap; boost::multi_array<HitMapNode, 3> hitMap;
std::map<const CGHeroInstance *, int> enemyHeroTreatMAp; std::map<const CGHeroInstance *, std::set<const CGObjectInstance *>> enemyHeroAccessibleObjects;
bool upToDate;
public: public:
void updateHitMap(); void updateHitMap();
uint64_t enemyCanKillOurHeroesAlongThePath(const AIPath & path) const; 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(); lockedHeroes.clear();
dangerHitMap->updateHitMap(); dangerHitMap->reset();
} }
void Nullkiller::updateAiState() void Nullkiller::updateAiState()
{ {
ai->validateVisitableObjs(); ai->validateVisitableObjs();
dangerHitMap->updateHitMap();
// TODO: move to hero manager // TODO: move to hero manager
auto activeHeroes = ai->getMyHeroes(); auto activeHeroes = ai->getMyHeroes();

View File

@ -21,6 +21,7 @@
#include "../../../lib/filesystem/Filesystem.h" #include "../../../lib/filesystem/Filesystem.h"
#include "../VCAI.h" #include "../VCAI.h"
#include "../AIhelper.h" #include "../AIhelper.h"
#include "../Engine/Nullkiller.h"
#define MIN_AI_STRENGHT (0.5f) //lower when combat AI gets smarter #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 #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"); skillRewardVariable = engine->getInputVariable("skillReward");
rewardTypeVariable = engine->getInputVariable("rewardType"); rewardTypeVariable = engine->getInputVariable("rewardType");
closestHeroRatioVariable = engine->getInputVariable("closestHeroRatio"); closestHeroRatioVariable = engine->getInputVariable("closestHeroRatio");
strategicalValueVariable = engine->getInputVariable("strategicalValue");
value = engine->getOutputVariable("Value"); 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) float evaluateWitchHutSkillScore(const CGWitchHut * hut, const CGHeroInstance * hero, HeroRole role)
{ {
if(!hut->wasVisited(hero->tempOwner)) if(!hut->wasVisited(hero->tempOwner))
@ -336,8 +372,9 @@ float PriorityEvaluator::evaluate(Goals::TSubgoal task)
bool checkGold = danger == 0; bool checkGold = danger == 0;
uint64_t armyReward = getArmyReward(target, hero, checkGold); uint64_t armyReward = getArmyReward(target, hero, checkGold);
float skillReward = getSkillReward(target, hero, heroRole); float skillReward = getSkillReward(target, hero, heroRole);
float strategicalValue = getStrategicalValue(target);
double result = 0; 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 try
{ {
@ -350,6 +387,7 @@ float PriorityEvaluator::evaluate(Goals::TSubgoal task)
dangerVariable->setValue(danger); dangerVariable->setValue(danger);
rewardTypeVariable->setValue(rewardType); rewardTypeVariable->setValue(rewardType);
closestHeroRatioVariable->setValue(task->evaluationContext.closestWayRatio); closestHeroRatioVariable->setValue(task->evaluationContext.closestWayRatio);
strategicalValueVariable->setValue(strategicalValue);
engine->process(); engine->process();
//engine.process(VISIT_TILE); //TODO: Process only Visit_Tile //engine.process(VISIT_TILE); //TODO: Process only Visit_Tile

View File

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

View File

@ -1750,6 +1750,11 @@ void VCAI::addVisitableObj(const CGObjectInstance * obj)
auto teleportObj = dynamic_cast<const CGTeleport *>(obj); auto teleportObj = dynamic_cast<const CGTeleport *>(obj);
if(teleportObj) if(teleportObj)
CGTeleport::addToChannel(knownTeleportChannels, 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 const CGObjectInstance * VCAI::lookForArt(int aid) const