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:
parent
e6eb9ccc03
commit
66ed1a2901
@ -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)
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
@ -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();
|
||||||
};
|
};
|
||||||
|
@ -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();
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user