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

Nullkiller: rough implementation of capture objects and recruit hero behaviors

This commit is contained in:
Andrii Danylchenko 2021-05-15 19:23:11 +03:00 committed by Andrii Danylchenko
parent 9c85e26d3c
commit eee145c486
11 changed files with 331 additions and 20 deletions

View File

@ -123,14 +123,14 @@ TResource AIhelper::allGold() const
return resourceManager->allGold();
}
Goals::TGoalVec AIhelper::howToVisitTile(const int3 & tile) const
Goals::TGoalVec AIhelper::howToVisitTile(const int3 & tile, bool allowGatherArmy) const
{
return pathfindingManager->howToVisitTile(tile);
return pathfindingManager->howToVisitTile(tile, allowGatherArmy);
}
Goals::TGoalVec AIhelper::howToVisitObj(ObjectIdRef obj) const
Goals::TGoalVec AIhelper::howToVisitObj(ObjectIdRef obj, bool allowGatherArmy) const
{
return pathfindingManager->howToVisitObj(obj);
return pathfindingManager->howToVisitObj(obj, allowGatherArmy);
}
Goals::TGoalVec AIhelper::howToVisitTile(const HeroPtr & hero, const int3 & tile, bool allowGatherArmy) const

View File

@ -57,8 +57,8 @@ public:
Goals::TGoalVec howToVisitTile(const HeroPtr & hero, const int3 & tile, bool allowGatherArmy = true) const override;
Goals::TGoalVec howToVisitObj(const HeroPtr & hero, ObjectIdRef obj, bool allowGatherArmy = true) const override;
Goals::TGoalVec howToVisitTile(const int3 & tile) const override;
Goals::TGoalVec howToVisitObj(ObjectIdRef obj) const override;
Goals::TGoalVec howToVisitTile(const int3 & tile, bool allowGatherArmy = true) const override;
Goals::TGoalVec howToVisitObj(ObjectIdRef obj, bool allowGatherArmy = true) const override;
std::vector<AIPath> getPathsToTile(const HeroPtr & hero, const int3 & tile) const override;
void updatePaths(std::vector<HeroPtr> heroes) override;
void updatePaths(const HeroPtr & hero) override;

View File

@ -4,10 +4,7 @@
class Behavior
{
};
class CaptureObjectBehavior : public Behavior
{
public:
virtual Goals::TGoalVec getTasks() = 0;
virtual std::string toString() const = 0;
};

View File

@ -0,0 +1,116 @@
/*
* Goals.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "../VCAI.h"
#include "../AIhelper.h"
#include "CaptureObjectsBehavior.h"
#include "../AIUtility.h"
#include "lib/mapping/CMap.h" //for victory conditions
#include "lib/CPathfinder.h"
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<VCAI> ai;
extern FuzzyHelper * fh;
using namespace Goals;
std::string CaptureObjectsBehavior::toString() const {
return "Capture objects";
}
Goals::TGoalVec CaptureObjectsBehavior::getTasks() {
Goals::TGoalVec tasks;
auto captureObjects = [&](std::vector<const CGObjectInstance*> objs) -> void {
if (objs.empty()) {
return;
}
for (auto objToVisit : objs) {
if(!shouldVisitObject(objToVisit))
continue;
const int3 pos = objToVisit->visitablePos();
logAi->trace("considering object %s %s", objToVisit->getObjectName(), pos.toString());
Goals::TGoalVec waysToVisitObj = ai->ah->howToVisitObj(objToVisit, false);
vstd::erase_if(waysToVisitObj, [objToVisit](Goals::TSubgoal goal) -> bool
{
return !goal->hero.validAndSet()
|| !shouldVisit(goal->hero, objToVisit)
|| goal->evaluationContext.danger * 1.5 > goal->hero->getTotalStrength();
});
if(waysToVisitObj.empty())
continue;
Goals::TSubgoal closestWay = *vstd::minElementByFun(waysToVisitObj, [](Goals::TSubgoal goal) -> float {
return goal->evaluationContext.movementCost;
});
for(Goals::TSubgoal way : waysToVisitObj)
{
if(!way->hero->movement)
continue;
way->accept(fh);
auto closestWayRatio = way->evaluationContext.movementCost / closestWay->evaluationContext.movementCost;
way->setpriority(way->priority / closestWayRatio);
tasks.push_back(way);
}
}
};
if (specificObjects) {
captureObjects(objectsToCapture);
}
else {
captureObjects(std::vector<const CGObjectInstance*>(ai->visitableObjs.begin(), ai->visitableObjs.end()));
}
return tasks;
}
bool CaptureObjectsBehavior::shouldVisitObject(ObjectIdRef obj) const
{
const CGObjectInstance* objInstance = obj;
if (!objInstance || objectTypes.size() && !vstd::contains(objectTypes, objInstance->ID.num)) {
return false;
}
if (!objInstance || objectSubTypes.size() && !vstd::contains(objectSubTypes, objInstance->subID)) {
return false;
}
const int3 pos = objInstance->visitablePos();
if (vstd::contains(ai->alreadyVisited, objInstance)) {
return false;
}
auto playerRelations = cb->getPlayerRelations(ai->playerID, objInstance->tempOwner);
if (playerRelations != PlayerRelations::ENEMIES && !isWeeklyRevisitable(objInstance)) {
return false;
}
//it may be hero visiting this obj
//we don't try visiting object on which allied or owned hero stands
// -> it will just trigger exchange windows and AI will be confused that obj behind doesn't get visited
const CGObjectInstance * topObj = cb->getTopObj(obj->visitablePos());
if (topObj->ID == Obj::HERO && cb->getPlayerRelations(ai->playerID, topObj->tempOwner) != PlayerRelations::ENEMIES)
return false;
else
return true; //all of the following is met
}

View File

@ -0,0 +1,60 @@
/*
* Goals.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include "lib/VCMI_Lib.h"
#include "Behavior.h"
#include "../AIUtility.h"
class CaptureObjectsBehavior : public Behavior {
private:
std::vector<int> objectTypes;
std::vector<int> objectSubTypes;
std::vector<const CGObjectInstance *> objectsToCapture;
bool specificObjects;
public:
CaptureObjectsBehavior()
{
objectTypes = std::vector<int>();
specificObjects = false;
}
CaptureObjectsBehavior(std::vector<const CGObjectInstance *> objectsToCapture)
{
this->objectsToCapture = objectsToCapture;
specificObjects = true;
}
CaptureObjectsBehavior(const CGObjectInstance * objectToCapture)
{
objectsToCapture = std::vector<const CGObjectInstance *>();
objectsToCapture.push_back(objectToCapture);
specificObjects = true;
}
virtual Goals::TGoalVec getTasks() override;
virtual std::string toString() const override;
CaptureObjectsBehavior & ofType(int type) {
objectTypes.push_back(type);
return *this;
}
CaptureObjectsBehavior & ofType(int type, int subType) {
objectTypes.push_back(type);
objectSubTypes.push_back(subType);
return *this;
}
private:
bool shouldVisitObject(ObjectIdRef obj) const;
};

View File

@ -0,0 +1,45 @@
/*
* Goals.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "RecruitHeroBehavior.h"
#include "../VCAI.h"
#include "../AIhelper.h"
#include "../AIUtility.h"
#include "../Goals/RecruitHero.h"
#include "lib/mapping/CMap.h" //for victory conditions
#include "lib/CPathfinder.h"
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<VCAI> ai;
extern FuzzyHelper * fh;
using namespace Goals;
std::string RecruitHeroBehavior::toString() const
{
return "Recruit hero";
}
Goals::TGoalVec RecruitHeroBehavior::getTasks()
{
Goals::TGoalVec tasks;
if(ai->canRecruitAnyHero())
{
if(cb->getDate(Date::DAY) == 1
|| cb->getHeroesInfo().size() < cb->getTownsInfo().size() + 1
|| cb->getResourceAmount(Res::GOLD) > 10000)
{
tasks.push_back(Goals::sptr(Goals::RecruitHero()));
}
}
return tasks;
}

View File

@ -0,0 +1,26 @@
/*
* Goals.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include "lib/VCMI_Lib.h"
#include "Behavior.h"
#include "../AIUtility.h"
class RecruitHeroBehavior : public Behavior
{
public:
RecruitHeroBehavior()
{
}
virtual Goals::TGoalVec getTasks() override;
virtual std::string toString() const override;
};

View File

@ -54,6 +54,8 @@ set(VCAI_SRCS
Goals/CompleteQuest.cpp
Engine/Nullkiller.cpp
Behaviors/Behavior.cpp
Behaviors/CaptureObjectsBehavior.cpp
Behaviors/RecruitHeroBehavior.cpp
main.cpp
VCAI.cpp
)
@ -111,6 +113,8 @@ set(VCAI_HEADERS
Goals/Goals.h
Engine/Nullkiller.h
Behaviors/Behavior.h
Behaviors/CaptureObjectsBehavior.h
Behaviors/RecruitHeroBehavior.h
VCAI.h
)

View File

@ -1,8 +1,71 @@
#include "StdInc.h"
#include "Nullkiller.h"
#include "../VCAI.h"
#include "../Behaviors/CaptureObjectsBehavior.h"
#include "../Behaviors/RecruitHeroBehavior.h"
#include "../Goals/Invalid.h"
extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<VCAI> ai;
Goals::TSubgoal choseBestTask(Goals::TGoalVec tasks)
{
Goals::TSubgoal bestTask = *vstd::maxElementByFun(tasks, [](Goals::TSubgoal goal) -> float
{
return goal->priority;
});
return bestTask;
}
Goals::TSubgoal choseBestTask(Behavior & behavior)
{
auto tasks = behavior.getTasks();
if(tasks.empty())
{
logAi->trace("Behavior %s found no tasks", behavior.toString());
return Goals::sptr(Goals::Invalid());
}
return choseBestTask(tasks);
}
void Nullkiller::makeTurn()
{
while(true)
{
Goals::TGoalVec bestTasks = {
choseBestTask(CaptureObjectsBehavior()),
choseBestTask(RecruitHeroBehavior())
};
Goals::TSubgoal bestTask = choseBestTask(bestTasks);
if(bestTask->invalid())
{
logAi->trace("No goals found. Ending turn.");
return;
}
logAi->debug("Trying to realize %s (value %2.3f)", bestTask->name(), bestTask->priority);
try
{
bestTask->accept(ai.get());
}
catch(goalFulfilledException &)
{
logAi->trace(bestTask->completeMessage());
}
catch(std::exception & e)
{
logAi->debug("Failed to realize subgoal of type %s, I will stop.", bestTask->name());
logAi->debug("The error message was: %s", e.what());
return;
}
}
}

View File

@ -32,7 +32,7 @@ void PathfindingManager::setAI(VCAI * AI)
ai = AI;
}
Goals::TGoalVec PathfindingManager::howToVisitTile(const int3 & tile) const
Goals::TGoalVec PathfindingManager::howToVisitTile(const int3 & tile, bool allowGatherArmy) const
{
Goals::TGoalVec result;
@ -41,13 +41,13 @@ Goals::TGoalVec PathfindingManager::howToVisitTile(const int3 & tile) const
for(auto hero : heroes)
{
vstd::concatenate(result, howToVisitTile(hero, tile));
vstd::concatenate(result, howToVisitTile(hero, tile, allowGatherArmy));
}
return result;
}
Goals::TGoalVec PathfindingManager::howToVisitObj(ObjectIdRef obj) const
Goals::TGoalVec PathfindingManager::howToVisitObj(ObjectIdRef obj, bool allowGatherArmy) const
{
Goals::TGoalVec result;
@ -56,7 +56,7 @@ Goals::TGoalVec PathfindingManager::howToVisitObj(ObjectIdRef obj) const
for(auto hero : heroes)
{
vstd::concatenate(result, howToVisitObj(hero, obj));
vstd::concatenate(result, howToVisitObj(hero, obj, allowGatherArmy));
}
return result;

View File

@ -24,8 +24,8 @@ public:
virtual void updatePaths(const HeroPtr & hero) = 0;
virtual Goals::TGoalVec howToVisitTile(const HeroPtr & hero, const int3 & tile, bool allowGatherArmy = true) const = 0;
virtual Goals::TGoalVec howToVisitObj(const HeroPtr & hero, ObjectIdRef obj, bool allowGatherArmy = true) const = 0;
virtual Goals::TGoalVec howToVisitTile(const int3 & tile) const = 0;
virtual Goals::TGoalVec howToVisitObj(ObjectIdRef obj) const = 0;
virtual Goals::TGoalVec howToVisitTile(const int3 & tile, bool allowGatherArmy = true) const = 0;
virtual Goals::TGoalVec howToVisitObj(ObjectIdRef obj, bool allowGatherArmy = true) const = 0;
virtual std::vector<AIPath> getPathsToTile(const HeroPtr & hero, const int3 & tile) const = 0;
};
@ -44,8 +44,8 @@ public:
Goals::TGoalVec howToVisitTile(const HeroPtr & hero, const int3 & tile, bool allowGatherArmy = true) const override;
Goals::TGoalVec howToVisitObj(const HeroPtr & hero, ObjectIdRef obj, bool allowGatherArmy = true) const override;
Goals::TGoalVec howToVisitTile(const int3 & tile) const override;
Goals::TGoalVec howToVisitObj(ObjectIdRef obj) const override;
Goals::TGoalVec howToVisitTile(const int3 & tile, bool allowGatherArmy = true) const override;
Goals::TGoalVec howToVisitObj(ObjectIdRef obj, bool allowGatherArmy = true) const override;
std::vector<AIPath> getPathsToTile(const HeroPtr & hero, const int3 & tile) const override;
void updatePaths(std::vector<HeroPtr> heroes) override;
void updatePaths(const HeroPtr & hero) override;