1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

NKAI: configurable object graph

This commit is contained in:
Andrii Danylchenko 2024-03-08 14:39:16 +02:00
parent 5f8a157c6d
commit 6245adb9a4
8 changed files with 55 additions and 30 deletions

View File

@ -373,7 +373,11 @@ void AIGateway::objectRemoved(const CGObjectInstance * obj, const PlayerColor &
return;
nullkiller->memory->removeFromMemory(obj);
nullkiller->baseGraph->removeObject(obj);
if(nullkiller->baseGraph && nullkiller->settings->isObjectGraphAllowed())
{
nullkiller->baseGraph->removeObject(obj);
}
if(obj->ID == Obj::HERO && obj->tempOwner == playerID)
{

View File

@ -178,8 +178,11 @@ Goals::TGoalVec CaptureObjectsBehavior::decompose() const
#endif
const int3 pos = objToVisit->visitablePos();
bool useObjectGraph = ai->nullkiller->settings->isObjectGraphAllowed()
&& ai->nullkiller->getScanDepth() != ScanDepth::SMALL;
auto paths = ai->nullkiller->pathfinder->getPathInfo(pos, useObjectGraph);
auto paths = ai->nullkiller->pathfinder->getPathInfo(pos, true);
std::vector<std::shared_ptr<ExecuteHeroChain>> waysToVisitObj;
std::shared_ptr<ExecuteHeroChain> closestWay;
@ -210,7 +213,7 @@ Goals::TGoalVec CaptureObjectsBehavior::decompose() const
{
captureObjects(ai->nullkiller->objectClusterizer->getNearbyObjects());
if(tasks.empty())
if(tasks.empty() || ai->nullkiller->getScanDepth() != ScanDepth::SMALL)
captureObjects(ai->nullkiller->objectClusterizer->getFarObjects());
}

View File

@ -42,7 +42,7 @@ Goals::TGoalVec ClusterBehavior::decompose() const
Goals::TGoalVec ClusterBehavior::decomposeCluster(std::shared_ptr<ObjectCluster> cluster) const
{
auto center = cluster->calculateCenter();
auto paths = ai->nullkiller->pathfinder->getPathInfo(center->visitablePos(), true);
auto paths = ai->nullkiller->pathfinder->getPathInfo(center->visitablePos(), ai->nullkiller->settings->isObjectGraphAllowed());
auto blockerPos = cluster->blocker->visitablePos();
std::vector<AIPath> blockerPaths;

View File

@ -443,6 +443,10 @@ void DefenceBehavior::evaluateRecruitingHero(Goals::TGoalVec & tasks, const HitM
heroToDismiss = town->garrisonHero.get();
}
}
// avoid dismissing one weak hero in order to recruit another.
if(heroToDismiss && heroToDismiss->getArmyStrength() + 500 > hero->getArmyStrength())
continue;
}
else if(ai->nullkiller->heroManager->heroCapReached())
{

View File

@ -125,7 +125,7 @@ void Nullkiller::resetAiState()
dangerHitMap->reset();
useHeroChain = true;
if(!baseGraph)
if(!baseGraph && ai->nullkiller->settings->isObjectGraphAllowed())
{
baseGraph = std::make_unique<ObjectGraph>();
baseGraph->updateGraph(this);
@ -172,20 +172,24 @@ void Nullkiller::updateAiState(int pass, bool fast)
cfg.useHeroChain = useHeroChain;
cfg.allowBypassObjects = true;
if(scanDepth == ScanDepth::SMALL)
if(scanDepth == ScanDepth::SMALL || settings->isObjectGraphAllowed())
{
cfg.mainTurnDistanceLimit = ai->nullkiller->settings->getMainHeroTurnDistanceLimit();
cfg.mainTurnDistanceLimit = settings->getMainHeroTurnDistanceLimit();
}
if(scanDepth != ScanDepth::ALL_FULL)
if(scanDepth != ScanDepth::ALL_FULL || settings->isObjectGraphAllowed())
{
cfg.scoutTurnDistanceLimit = ai->nullkiller->settings->getScoutHeroTurnDistanceLimit();
cfg.scoutTurnDistanceLimit =settings->getScoutHeroTurnDistanceLimit();
}
boost::this_thread::interruption_point();
pathfinder->updatePaths(activeHeroes, cfg);
pathfinder->updateGraphs(activeHeroes);
if(settings->isObjectGraphAllowed())
{
pathfinder->updateGraphs(activeHeroes);
}
boost::this_thread::interruption_point();
@ -299,7 +303,8 @@ void Nullkiller::makeTurn()
// TODO: better to check turn distance here instead of priority
if((heroRole != HeroRole::MAIN || bestTask->priority < SMALL_SCAN_MIN_PRIORITY)
&& scanDepth == ScanDepth::MAIN_FULL)
&& scanDepth == ScanDepth::MAIN_FULL
&& !settings->isObjectGraphAllowed())
{
useHeroChain = false;
scanDepth = ScanDepth::SMALL;
@ -312,22 +317,25 @@ void Nullkiller::makeTurn()
if(bestTask->priority < MIN_PRIORITY)
{
auto heroes = cb->getHeroesInfo();
auto hasMp = vstd::contains_if(heroes, [](const CGHeroInstance * h) -> bool
{
return h->movementPointsRemaining() > 100;
});
if(hasMp && scanDepth != ScanDepth::ALL_FULL)
if(!settings->isObjectGraphAllowed())
{
logAi->trace(
"Goal %s has too low priority %f so increasing scan depth to full.",
taskDescription,
bestTask->priority);
auto heroes = cb->getHeroesInfo();
auto hasMp = vstd::contains_if(heroes, [](const CGHeroInstance * h) -> bool
{
return h->movementPointsRemaining() > 100;
});
scanDepth = ScanDepth::ALL_FULL;
useHeroChain = false;
continue;
if(hasMp && scanDepth != ScanDepth::ALL_FULL)
{
logAi->trace(
"Goal %s has too low priority %f so increasing scan depth to full.",
taskDescription,
bestTask->priority);
scanDepth = ScanDepth::ALL_FULL;
useHeroChain = false;
continue;
}
}
logAi->trace("Goal %s has too low priority. It is not worth doing it. Ending turn.", taskDescription);

View File

@ -27,7 +27,8 @@ namespace NKAI
mainHeroTurnDistanceLimit(10),
scoutHeroTurnDistanceLimit(5),
maxGoldPreasure(0.3f),
maxpass(30)
maxpass(30),
allowObjectGraph(false)
{
ResourcePath resource("config/ai/nkai/nkai-settings", EResType::JSON);
@ -74,5 +75,10 @@ namespace NKAI
{
maxGoldPreasure = node.Struct()["maxGoldPreasure"].Float();
}
if(!node.Struct()["allowObjectGraph"].isNull())
{
allowObjectGraph = node.Struct()["allowObjectGraph"].Bool();
}
}
}

View File

@ -26,6 +26,7 @@ namespace NKAI
int scoutHeroTurnDistanceLimit;
int maxpass;
float maxGoldPreasure;
bool allowObjectGraph;
public:
Settings();
@ -35,6 +36,7 @@ namespace NKAI
int getMaxRoamingHeroes() const { return maxRoamingHeroes; }
int getMainHeroTurnDistanceLimit() const { return mainHeroTurnDistanceLimit; }
int getScoutHeroTurnDistanceLimit() const { return scoutHeroTurnDistanceLimit; }
bool isObjectGraphAllowed() const { return allowObjectGraph; }
private:
void loadFromMod(const std::string & modName, const ResourcePath & resource);

View File

@ -12,7 +12,7 @@
#define NKAI_PATHFINDER_TRACE_LEVEL 0
#define NKAI_GRAPH_TRACE_LEVEL 0
#define NKAI_TRACE_LEVEL 0
#define NKAI_TRACE_LEVEL 1
#include "../../../lib/pathfinder/CGPathNode.h"
#include "../../../lib/pathfinder/INodeStorage.h"
@ -27,11 +27,9 @@ namespace NKAI
{
namespace AIPathfinding
{
const int BUCKET_COUNT = 5;
const int BUCKET_COUNT = 5;
const int BUCKET_SIZE = 3;
const int NUM_CHAINS = BUCKET_COUNT * BUCKET_SIZE;
const int THREAD_COUNT = 8;
const int CHAIN_MAX_DEPTH = 4;
}