diff --git a/AI/VCAI/Fuzzy.cpp b/AI/VCAI/Fuzzy.cpp index 78523fe82..2c7a8b4d5 100644 --- a/AI/VCAI/Fuzzy.cpp +++ b/AI/VCAI/Fuzzy.cpp @@ -5,6 +5,8 @@ #include "../../lib/CObjectHandler.h" #include "../../lib/CCreatureHandler.h" #include "../../lib/VCMI_Lib.h" +//#include "Goals.h" +//#include "VCAI.h" /* * Fuzzy.cpp, part of VCMI engine @@ -25,6 +27,7 @@ class CGTownInstance; using namespace boost::assign; using namespace vstd; +//using namespace Goals; FuzzyHelper *fh; @@ -273,3 +276,22 @@ float FuzzyHelper::getTacticalAdvantage (const CArmedInstance *we, const CArmedI } return output; } + +//shared_ptr chooseSolution (std::vector> & vec) +//{ +// typedef std::pair, float> goalValue; +// std::vector values; +// +// for (auto g : vec) +// { +// values.push_back (std::make_pair(g, 66.6f)); +// } +// +// auto compareGoals = [&](const goalValue & lhs, const goalValue & rhs) -> bool +// { +// return lhs.second < rhs.second; +// }; +// +// boost::sort (values, compareGoals); +// return values.end()->first; +//} \ No newline at end of file diff --git a/AI/VCAI/Fuzzy.h b/AI/VCAI/Fuzzy.h index 135bbfecf..5f617f376 100644 --- a/AI/VCAI/Fuzzy.h +++ b/AI/VCAI/Fuzzy.h @@ -13,6 +13,9 @@ class VCAI; class CArmedInstance; +//class TSubgoal; +//class TGoalVec; +//class AbstractGoal; class FuzzyHelper { @@ -40,4 +43,8 @@ public: ui64 estimateBankDanger (int ID); float getTacticalAdvantage (const CArmedInstance *we, const CArmedInstance *enemy); //returns factor how many times enemy is stronger than us + + //FIXME: use Goals namespace + //Goals::TSubgoal chooseSolution (Goals::TGoalVec & vec); + //shared_ptr chooseSolution (std::vector> & vec); }; diff --git a/AI/VCAI/Goals.cpp b/AI/VCAI/Goals.cpp index d6f52cc2f..1cff26d52 100644 --- a/AI/VCAI/Goals.cpp +++ b/AI/VCAI/Goals.cpp @@ -196,6 +196,11 @@ TSubgoal FindObj::whatToDoToAchieve() else return sptr (Goals::Explore()); } +std::string GetObj::completeMessage() const +{ + return "hero " + hero.get()->name + " captured Object ID = " + boost::lexical_cast(objid); +} + TSubgoal GetObj::whatToDoToAchieve() { const CGObjectInstance * obj = cb->getObj(ObjectInstanceID(objid)); @@ -205,6 +210,11 @@ TSubgoal GetObj::whatToDoToAchieve() return sptr (Goals::VisitTile(pos)); } +std::string VisitHero::completeMessage() const +{ + return "hero " + hero.get()->name + " visited hero " + boost::lexical_cast(objid); +} + TSubgoal VisitHero::whatToDoToAchieve() { const CGObjectInstance * obj = cb->getObj(ObjectInstanceID(objid)); @@ -214,6 +224,7 @@ TSubgoal VisitHero::whatToDoToAchieve() if (hero && ai->isAccessibleForHero(pos, hero, true) && isSafeToVisit(hero, pos)) //enemy heroes can get reinforcements { + assert (hero->pos != pos); //don't try to visit yourself settile(pos).setisElementar(true); return sptr (*this); } @@ -278,6 +289,11 @@ TSubgoal ClearWayTo::whatToDoToAchieve() throw cannotFulfillGoalException("Cannot reach given tile!"); //how and when could this be used? } +std::string Explore::completeMessage() const +{ + return "Hero " + hero.get()->name + " completed exploration"; +}; + TSubgoal Explore::whatToDoToAchieve() { auto objs = ai->visitableObjs; //try to use buildings that uncover map @@ -403,6 +419,11 @@ TSubgoal RecruitHero::whatToDoToAchieve() return iAmElementar(); } +std::string VisitTile::completeMessage() const +{ + return "Hero " + hero.get()->name + " visited tile " + tile(); +} + TSubgoal VisitTile::whatToDoToAchieve() { if(!cb->isVisible(tile)) @@ -676,6 +697,11 @@ TSubgoal Invalid::whatToDoToAchieve() return iAmElementar(); } +std::string GatherArmy::completeMessage() const +{ + return "Hero " + hero.get()->name + " gathered army of value " + boost::lexical_cast(value); +}; + TSubgoal GatherArmy::whatToDoToAchieve() { //TODO: find hero if none set diff --git a/AI/VCAI/Goals.h b/AI/VCAI/Goals.h index e20d89304..223bd4cc6 100644 --- a/AI/VCAI/Goals.h +++ b/AI/VCAI/Goals.h @@ -23,6 +23,7 @@ namespace Goals { struct AbstractGoal; typedef std::shared_ptr TSubgoal; + typedef std::vector TGoalVec; enum EGoals { @@ -90,6 +91,7 @@ public: EGoals goalType; std::string name() const; + virtual std::string completeMessage() const {return "This goal is unspecified!";}; bool invalid() const; @@ -101,13 +103,8 @@ public: //TODO: make accept work for shared_ptr... somehow virtual void accept (VCAI * ai); //unhandled goal will report standard error - bool operator== (AbstractGoal &g) //TODO: virtualize - comparison returns true only for same subclasses + virtual bool operator== (AbstractGoal &g) //TODO: virtualize - comparison returns true only for same subclasses { - switch (goalType) - { - case EGoals::GET_OBJ: - return objid == g.objid; - } return false; } @@ -149,12 +146,12 @@ public: void accept (VCAI * ai) override { - ai->tryRealize(static_cast(*this)); + ai->tryRealize(static_cast(*this)); //casting enforces template instantiation } CGoal * clone() const override { - return new T(static_cast(*this)); + return new T(static_cast(*this)); //casting enforces template instantiation } TSubgoal iAmElementar() { @@ -209,6 +206,7 @@ class Explore : public CGoal Explore() : CGoal (Goals::EXPLORE){}; Explore(HeroPtr h) : CGoal (Goals::EXPLORE){hero = h;}; TSubgoal whatToDoToAchieve() override; + std::string completeMessage() const override; }; class GatherArmy : public CGoal { @@ -217,6 +215,7 @@ private: public: GatherArmy(int val) : CGoal (Goals::GATHER_ARMY){value = val;}; TSubgoal whatToDoToAchieve() override; + std::string completeMessage() const override; }; class BoostHero : public CGoal { @@ -257,17 +256,19 @@ public: }; class GetObj : public CGoal { - private: - GetObj() {}; // empty constructor not allowed - public: - GetObj(int Objid) : CGoal(Goals::GET_OBJ) {objid = Objid;}; +private: + GetObj() {}; // empty constructor not allowed +public: + GetObj(int Objid) : CGoal(Goals::GET_OBJ) {objid = Objid;}; TSubgoal whatToDoToAchieve() override; + bool operator== (GetObj &g) {return g.objid == objid;} + std::string completeMessage() const override; }; class FindObj : public CGoal { - private: - FindObj() {}; // empty constructor not allowed - public: +private: + FindObj() {}; // empty constructor not allowed +public: FindObj(int ID) : CGoal(Goals::FIND_OBJ) {objid = ID;}; FindObj(int ID, int subID) : CGoal(Goals::FIND_OBJ) {objid = ID; resID = subID;}; TSubgoal whatToDoToAchieve() override; @@ -279,6 +280,8 @@ private: public: VisitHero(int hid) : CGoal (Goals::VISIT_HERO){objid = hid;}; TSubgoal whatToDoToAchieve() override; + bool operator== (VisitHero &g) {return g.objid == objid;} + std::string completeMessage() const override; }; class GetArtOfType : public CGoal { @@ -296,12 +299,15 @@ private: public: VisitTile(int3 Tile) : CGoal (Goals::VISIT_TILE) {tile = Tile;}; TSubgoal whatToDoToAchieve() override; + bool operator== (VisitTile &g) {return g.tile == tile;} + std::string completeMessage() const override; }; class ClearWayTo : public CGoal { public: ClearWayTo(int3 Tile) : CGoal (Goals::CLEAR_WAY_TO) {tile = Tile;}; TSubgoal whatToDoToAchieve() override; + bool operator== (ClearWayTo &g) {return g.tile == tile;} }; class DigAtTile : public CGoal //elementar with hero on tile @@ -311,6 +317,7 @@ private: public: DigAtTile(int3 Tile) : CGoal (Goals::DIG_AT_TILE) {tile = Tile;}; TSubgoal whatToDoToAchieve() override; + bool operator== (DigAtTile &g) {return g.tile == tile;} }; class CIssueCommand : public CGoal diff --git a/AI/VCAI/VCAI.cpp b/AI/VCAI/VCAI.cpp index 2c7bfe187..acebf767c 100644 --- a/AI/VCAI/VCAI.cpp +++ b/AI/VCAI/VCAI.cpp @@ -1226,13 +1226,29 @@ void VCAI::setGoal(HeroPtr h, Goals::TSubgoal goal) void VCAI::completeGoal (Goals::TSubgoal goal) { + logAi->debugStream() << boost::format("Completing goal: %s") % goal->name(); if (const CGHeroInstance * h = goal->hero.get(true)) { auto it = lockedHeroes.find(h); if (it != lockedHeroes.end()) - if (it->second->goalType == goal->goalType) + if (it->second == goal) + { + logAi->debugStream() << boost::format("%s") % goal->completeMessage(); lockedHeroes.erase(it); //goal fulfilled, free hero + } } + else //complete goal for all heroes maybe? + { + for (auto p : lockedHeroes) + { + if (p.second == goal) + { + logAi->debugStream() << boost::format("%s") % goal->completeMessage(); + lockedHeroes.erase (lockedHeroes.find(p.first)); //is it safe? + } + } + } + } void VCAI::battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side) @@ -1407,6 +1423,7 @@ bool VCAI::moveHeroToTile(int3 dst, HeroPtr h) bool ret = false; if(startHpos == dst) { + //FIXME: this assertion fails also if AI moves onto defeated guarded object assert(cb->getVisitableObjs(dst).size() > 1); //there's no point in revisiting tile where there is no visitable object cb->moveHero(*h, CGHeroInstance::convertPosition(dst, true)); waitTillFree(); //movement may cause battle or blocking dialog @@ -1420,7 +1437,7 @@ bool VCAI::moveHeroToTile(int3 dst, HeroPtr h) { logAi->errorStream() << "Hero " << h->name << " cannot reach " << dst; //setGoal(h, INVALID); - completeGoal (sptr(Goals::VisitTile(int3(-1,-1,-1)).sethero(h))); //TODO: better mechanism to determine goal + completeGoal (sptr(Goals::VisitTile(dst).sethero(h))); //TODO: better mechanism to determine goal cb->recalculatePaths(); throw std::runtime_error("Wrong move order!"); }