From 0e328ab3c2ad64d49d6f08a3195626eb387336d9 Mon Sep 17 00:00:00 2001 From: Andrii Danylchenko Date: Sat, 15 May 2021 21:54:28 +0300 Subject: [PATCH] AI: hero chain stabilisation --- AI/Nullkiller/Pathfinding/AINodeStorage.cpp | 30 ++++++++++----- AI/Nullkiller/Pathfinding/AINodeStorage.h | 4 +- AI/Nullkiller/Pathfinding/AIPathfinder.cpp | 5 +++ AI/Nullkiller/Pathfinding/Actors.cpp | 37 +++++++++---------- AI/Nullkiller/Pathfinding/Actors.h | 9 +++++ .../Pathfinding/Rules/AIPreviousNodeRule.cpp | 8 ---- 6 files changed, 55 insertions(+), 38 deletions(-) diff --git a/AI/Nullkiller/Pathfinding/AINodeStorage.cpp b/AI/Nullkiller/Pathfinding/AINodeStorage.cpp index b62d5653e..25f2371af 100644 --- a/AI/Nullkiller/Pathfinding/AINodeStorage.cpp +++ b/AI/Nullkiller/Pathfinding/AINodeStorage.cpp @@ -172,6 +172,12 @@ void AINodeStorage::commit(CDestinationNodeInfo & destination, const PathNodeInf { commit(dstNode, srcNode, destination.action, destination.turn, destination.movementLeft, destination.cost); + if(srcNode->specialAction || srcNode->chainOther) + { + // there is some action on source tile which should be performed before we can bypass it + destination.node->theNodeBefore = source.node; + } + if(dstNode->specialAction && dstNode->actor) { dstNode->specialAction->applyOnDestination(dstNode->actor->hero, destination, source, dstNode, srcNode); @@ -183,7 +189,7 @@ void AINodeStorage::commit(CDestinationNodeInfo & destination, const PathNodeInf source.coord.toString(), destination.coord.toString(), destination.cost, - dstNode->actor->hero->name, + dstNode->actor->toString(), dstNode->actor->chainMask); #endif }); @@ -251,13 +257,19 @@ bool AINodeStorage::calculateHeroChain() for(AIPathNode & node : chains) { + if(node.coord.x == 60 && node.coord.y == 56 && node.actor) + logAi->trace(node.actor->toString()); + if(node.turns <= heroChainMaxTurns && node.action != CGPathNode::ENodeAction::UNKNOWN) buffer.push_back(&node); } for(AIPathNode * node : buffer) { - addHeroChain(node, buffer); + if(node->actor->hero) + { + addHeroChain(node, buffer); + } } }); @@ -277,9 +289,9 @@ void AINodeStorage::addHeroChain(AIPathNode * srcNode, std::vector #ifdef VCMI_TRACE_PATHFINDER_EX logAi->trace( "Thy exchange %s[%i] -> %s[%i] at %s", - node->actor->hero->name, + node->actor->toString(), node->actor->chainMask, - srcNode->actor->hero->name, + srcNode->actor->toString(), srcNode->actor->chainMask, srcNode->coord.toString()); #endif @@ -299,9 +311,9 @@ void AINodeStorage::addHeroChain(AIPathNode * carrier, AIPathNode * other) #ifdef VCMI_TRACE_PATHFINDER_EX logAi->trace( "Exchange allowed %s[%i] -> %s[%i] at %s", - other->actor->hero->name, + other->actor->toString(), other->actor->chainMask, - carrier->actor->hero->name, + carrier->actor->toString(), carrier->actor->chainMask, carrier->coord.toString()); #endif @@ -344,8 +356,8 @@ void AINodeStorage::addHeroChain(AIPathNode * carrier, AIPathNode * other) logAi->trace( "Chain accepted at %s %s -> %s, mask %i, cost %f", chainNode->coord.toString(), - other->actor->hero->name, - chainNode->actor->hero->name, + other->actor->toString(), + chainNode->actor->toString(), chainNode->actor->chainMask, chainNode->cost); #endif @@ -430,7 +442,7 @@ void AINodeStorage::setHeroes(std::vector heroes, const VCAI * _ai) void AINodeStorage::setTownsAndDwellings( const std::vector & towns, - const std::vector & visitableObjs) + const std::set & visitableObjs) { for(auto town : towns) { diff --git a/AI/Nullkiller/Pathfinding/AINodeStorage.h b/AI/Nullkiller/Pathfinding/AINodeStorage.h index f6c510982..2910a9733 100644 --- a/AI/Nullkiller/Pathfinding/AINodeStorage.h +++ b/AI/Nullkiller/Pathfinding/AINodeStorage.h @@ -85,7 +85,7 @@ private: public: /// more than 1 chain layer for each hero allows us to have more than 1 path to each tile so we can chose more optimal one. - static const int NUM_CHAINS = 3 * GameConstants::MAX_HEROES_PER_PLAYER; + static const int NUM_CHAINS = 5 * GameConstants::MAX_HEROES_PER_PLAYER; AINodeStorage(const int3 & sizes); ~AINodeStorage(); @@ -116,7 +116,7 @@ public: void setHeroes(std::vector heroes, const VCAI * ai); void setTownsAndDwellings( const std::vector & towns, - const std::vector & visitableObjs); + const std::set & visitableObjs); const CGHeroInstance * getHero(const CGPathNode * node) const; const std::set getAllHeroes() const; void clear(); diff --git a/AI/Nullkiller/Pathfinding/AIPathfinder.cpp b/AI/Nullkiller/Pathfinding/AIPathfinder.cpp index 66d75e5c3..0d9cd1176 100644 --- a/AI/Nullkiller/Pathfinding/AIPathfinder.cpp +++ b/AI/Nullkiller/Pathfinding/AIPathfinder.cpp @@ -56,6 +56,11 @@ void AIPathfinder::updatePaths(std::vector heroes, bool useHeroChain) storage->clear(); storage->setHeroes(heroes, ai); + if(useHeroChain) + { + storage->setTownsAndDwellings(cb->getTownsInfo(), ai->visitableObjs); + } + auto config = std::make_shared(cb, ai, storage); do { diff --git a/AI/Nullkiller/Pathfinding/Actors.cpp b/AI/Nullkiller/Pathfinding/Actors.cpp index a66ec1a3e..1fd237991 100644 --- a/AI/Nullkiller/Pathfinding/Actors.cpp +++ b/AI/Nullkiller/Pathfinding/Actors.cpp @@ -16,23 +16,6 @@ #include "../../../lib/mapping/CMap.h" #include "../../../lib/mapObjects/MapObjects.h" -class ExchangeAction : public ISpecialAction -{ -private: - const CGHeroInstance * target; - const CGHeroInstance * source; - -public: - ExchangeAction(const CGHeroInstance * target, const CGHeroInstance * source) - :target(target), source(source) - { } - - virtual Goals::TSubgoal whatToDo(const HeroPtr & hero) const override - { - return Goals::sptr(Goals::VisitHero(target->id.getNum()).sethero(hero)); - } -}; - ChainActor::ChainActor(const CGHeroInstance * hero, uint64_t chainMask) :hero(hero), isMovable(true), chainMask(chainMask), creatureSet(hero), baseActor(this), carrierParent(nullptr), otherParent(nullptr) @@ -60,6 +43,11 @@ ChainActor::ChainActor(const CGObjectInstance * obj, const CCreatureSet * creatu armyValue = creatureSet->getArmyStrength(); } +std::string ChainActor::toString() const +{ + return hero->name; +} + HeroActor::HeroActor(const CGHeroInstance * hero, uint64_t chainMask, const VCAI * ai) :ChainActor(hero, chainMask) { @@ -213,7 +201,8 @@ DwellingActor::DwellingActor(const CGDwelling * dwelling, uint64_t chainMask, bo dwelling, getDwellingCreatures(dwelling, waitForGrowth), chainMask, - getInitialTurn(waitForGrowth, dayOfWeek)) + getInitialTurn(waitForGrowth, dayOfWeek)), + dwelling(dwelling) { } @@ -230,6 +219,11 @@ int DwellingActor::getInitialTurn(bool waitForGrowth, int dayOfWeek) return 8 - dayOfWeek; } +std::string DwellingActor::toString() const +{ + return dwelling->typeName + dwelling->visitablePos().toString(); +} + CCreatureSet * DwellingActor::getDwellingCreatures(const CGDwelling * dwelling, bool waitForGrowth) { CCreatureSet * dwellingCreatures = new CCreatureSet(); @@ -259,6 +253,11 @@ CCreatureSet * DwellingActor::getDwellingCreatures(const CGDwelling * dwelling, } TownGarrisonActor::TownGarrisonActor(const CGTownInstance * town, uint64_t chainMask) - :ChainActor(town, town->getUpperArmy(), chainMask, 0) + :ChainActor(town, town->getUpperArmy(), chainMask, 0), town(town) { +} + +std::string TownGarrisonActor::toString() const +{ + return town->name; } \ No newline at end of file diff --git a/AI/Nullkiller/Pathfinding/Actors.h b/AI/Nullkiller/Pathfinding/Actors.h index 598812460..9b8a976c5 100644 --- a/AI/Nullkiller/Pathfinding/Actors.h +++ b/AI/Nullkiller/Pathfinding/Actors.h @@ -48,6 +48,7 @@ public: ChainActor(){} virtual bool canExchange(const ChainActor * other) const; + virtual std::string toString() const; ChainActor * exchange(const ChainActor * other) const { return exchange(this, other); } void setBaseActor(HeroActor * base); @@ -102,9 +103,13 @@ protected: class DwellingActor : public ChainActor { +private: + const CGDwelling * dwelling; + public: DwellingActor(const CGDwelling * dwelling, uint64_t chainMask, bool waitForGrowth, int dayOfWeek); ~DwellingActor(); + virtual std::string toString() const override; protected: int getInitialTurn(bool waitForGrowth, int dayOfWeek); @@ -113,6 +118,10 @@ protected: class TownGarrisonActor : public ChainActor { +private: + const CGTownInstance * town; + public: TownGarrisonActor(const CGTownInstance * town, uint64_t chainMask); + virtual std::string toString() const override; }; \ No newline at end of file diff --git a/AI/Nullkiller/Pathfinding/Rules/AIPreviousNodeRule.cpp b/AI/Nullkiller/Pathfinding/Rules/AIPreviousNodeRule.cpp index 04666b041..68ebf7a54 100644 --- a/AI/Nullkiller/Pathfinding/Rules/AIPreviousNodeRule.cpp +++ b/AI/Nullkiller/Pathfinding/Rules/AIPreviousNodeRule.cpp @@ -35,13 +35,5 @@ namespace AIPathfinding #endif return; } - - auto srcNode = nodeStorage->getAINode(source.node); - - if(srcNode->specialAction || srcNode->chainOther) - { - // there is some action on source tile which should be performed before we can bypass it - destination.node->theNodeBefore = source.node; - } } }