1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-08-15 20:03:15 +02:00

VCAI is now functional again!

Implemented Visitor pattern for double-dispatch (actually only goal type dispatch).
This commit is contained in:
DjWarmonger
2013-11-23 18:16:25 +00:00
parent e6bb39d3a4
commit 0ab7b498f5
4 changed files with 124 additions and 106 deletions

View File

@@ -18,6 +18,13 @@ extern boost::thread_specific_ptr<VCAI> ai;
using namespace vstd; using namespace vstd;
using namespace Goals; using namespace Goals;
TSubgoal Goals::sptr(const AbstractGoal & tmp)
{
shared_ptr<AbstractGoal> ptr;
ptr.reset(tmp.clone());
return ptr;
}
std::string Goals::AbstractGoal::name() const //TODO: virtualize std::string Goals::AbstractGoal::name() const //TODO: virtualize
{ {
switch (goalType) switch (goalType)
@@ -67,7 +74,11 @@ std::string Goals::AbstractGoal::name() const //TODO: virtualize
} }
} }
//TSubgoal AbstractGoal::whatToDoToAchieve()
//{
// logAi->debugStream() << boost::format("Decomposing goal of type %s") % name();
// return sptr (Goals::Explore());
//}
TSubgoal Win::whatToDoToAchieve() TSubgoal Win::whatToDoToAchieve()
{ {
@@ -780,11 +791,11 @@ TSubgoal GatherArmy::whatToDoToAchieve()
return sptr (Goals::Explore(hero)); //find dwelling. use current hero to prevent him from doing nothing. return sptr (Goals::Explore(hero)); //find dwelling. use current hero to prevent him from doing nothing.
} }
TSubgoal AbstractGoal::whatToDoToAchieve() //TSubgoal AbstractGoal::whatToDoToAchieve()
{ //{
logAi->debugStream() << boost::format("Decomposing goal of type %s") % name(); // logAi->debugStream() << boost::format("Decomposing goal of type %s") % name();
return sptr (Goals::Explore()); // return sptr (Goals::Explore());
} //}
TSubgoal AbstractGoal::goVisitOrLookFor(const CGObjectInstance *obj) TSubgoal AbstractGoal::goVisitOrLookFor(const CGObjectInstance *obj)
{ {
@@ -803,3 +814,8 @@ bool AbstractGoal::invalid() const
{ {
return goalType == INVALID; return goalType == INVALID;
} }
void AbstractGoal::accept (VCAI * ai)
{
ai->tryRealize(*this);
};

View File

@@ -17,6 +17,7 @@
* *
*/ */
struct HeroPtr; struct HeroPtr;
class VCAI;
namespace Goals namespace Goals
{ {
@@ -49,8 +50,8 @@ namespace Goals
}; };
//method chaining + clone pattern //method chaining + clone pattern
#define VSETTER(type, field) AbstractGoal & set ## field(const type &rhs) { field = rhs; return *this; }; #define VSETTER(type, field) virtual AbstractGoal & set ## field(const type &rhs) = 0;
#define OSETTER(type, field) CGoal<T> & set ## field(const type &rhs) { field = rhs; return *this; }; #define OSETTER(type, field) CGoal<T> & set ## field(const type &rhs) override { field = rhs; return *this; };
#if 0 #if 0
#define SETTER #define SETTER
@@ -84,6 +85,8 @@ public:
tile = int3(-1, -1, -1); tile = int3(-1, -1, -1);
town = nullptr; town = nullptr;
} }
virtual ~AbstractGoal(){};
virtual AbstractGoal * clone() const = 0;
EGoals goalType; EGoals goalType;
std::string name() const; std::string name() const;
@@ -94,7 +97,9 @@ public:
static TSubgoal lookForArtSmart(int aid); //checks non-standard ways of obtaining art (merchants, quests, etc.) static TSubgoal lookForArtSmart(int aid); //checks non-standard ways of obtaining art (merchants, quests, etc.)
static TSubgoal tryRecruitHero(); static TSubgoal tryRecruitHero();
virtual TSubgoal whatToDoToAchieve(); virtual TSubgoal whatToDoToAchieve() = 0;
//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 bool operator== (AbstractGoal &g) //TODO: virtualize - comparison returns true only for same subclasses
{ {
@@ -107,11 +112,11 @@ public:
} }
template <typename Handler> void serialize(Handler &h, const int version) //template <typename Handler> void serialize(Handler &h, const int version)
{ //{
h & goalType & isElementar & isAbstract & priority; // h & goalType & isElementar & isAbstract & priority;
h & value & resID & objid & aid & tile & hero & town & bid; // h & value & resID & objid & aid & tile & hero & town & bid;
} //}
}; };
template <typename T> class CGoal : public AbstractGoal template <typename T> class CGoal : public AbstractGoal
@@ -128,7 +133,7 @@ public:
tile = int3(-1, -1, -1); tile = int3(-1, -1, -1);
town = nullptr; town = nullptr;
} }
//virtual TSubgoal whatToDoToAchieve() override; //virtual TSubgoal whatToDoToAchieve() override; //can't have virtual and template class at once
OSETTER(bool, isElementar) OSETTER(bool, isElementar)
OSETTER(bool, isAbstract) OSETTER(bool, isAbstract)
@@ -141,25 +146,31 @@ public:
OSETTER(HeroPtr, hero) OSETTER(HeroPtr, hero)
OSETTER(CGTownInstance *, town) OSETTER(CGTownInstance *, town)
OSETTER(int, bid) OSETTER(int, bid)
shared_ptr<CGoal<T>> iAmElementar()
void accept (VCAI * ai) override
{ {
return make_shared<CGoal<T>> (setisElementar(true)); ai->tryRealize(static_cast<T&>(*this));
}
CGoal<T> * clone() const override
{
return new T(static_cast<T const&>(*this));
}
TSubgoal iAmElementar()
{
setisElementar(true);
shared_ptr<AbstractGoal> ptr;
ptr.reset(clone());
return ptr;
} }
template <typename Handler> void serialize(Handler &h, const int version) template <typename Handler> void serialize(Handler &h, const int version)
{ {
h & static_cast<AbstractGoal&>(*this); h & goalType & isElementar & isAbstract & priority;
h & value & resID & objid & aid & tile & hero & town & bid;
} }
}; };
//There seems to be some ambiguity on these two, template function keeps form consitent TSubgoal sptr(const AbstractGoal & tmp);
template <typename T> shared_ptr<CGoal<T>> sptr(const CGoal<T> & tmp)
{
return make_shared<CGoal<T>> (tmp);
}
template <typename T> shared_ptr<CGoal<T>> sptr(const T & obj)
{
return make_shared<CGoal<T>> (obj);
}
class Invalid : public CGoal<Invalid> class Invalid : public CGoal<Invalid>
{ {
@@ -190,6 +201,7 @@ class Build : public CGoal<Build>
public: public:
Build() : CGoal (Goals::BUILD){}; Build() : CGoal (Goals::BUILD){};
TSubgoal whatToDoToAchieve() override; TSubgoal whatToDoToAchieve() override;
void accept (const VCAI *);
}; };
class Explore : public CGoal<Explore> class Explore : public CGoal<Explore>
{ {

View File

@@ -19,12 +19,13 @@
extern FuzzyHelper *fh; extern FuzzyHelper *fh;
class CGVisitableOPW; class CGVisitableOPW;
class TSubgoal;
const double SAFE_ATTACK_CONSTANT = 1.5; const double SAFE_ATTACK_CONSTANT = 1.5;
const int GOLD_RESERVE = 10000; //when buying creatures we want to keep at least this much gold (10000 so at least we'll be able to reach capitol) const int GOLD_RESERVE = 10000; //when buying creatures we want to keep at least this much gold (10000 so at least we'll be able to reach capitol)
using namespace vstd; using namespace vstd;
//extern Goals::TSubgoal sptr(const Goals::AbstractGoal & tmp);
//#define sptr(x) Goals::sptr(x)
//one thread may be turn of AI and another will be handling a side effect for AI2 //one thread may be turn of AI and another will be handling a side effect for AI2
boost::thread_specific_ptr<CCallback> cb; boost::thread_specific_ptr<CCallback> cb;
@@ -258,7 +259,7 @@ void VCAI::heroVisit(const CGHeroInstance *visitor, const CGObjectInstance *visi
markObjectVisited (visitedObj); markObjectVisited (visitedObj);
erase_if_present(reservedObjs, visitedObj); //unreserve objects erase_if_present(reservedObjs, visitedObj); //unreserve objects
erase_if_present(reservedHeroesMap[visitor], visitedObj); erase_if_present(reservedHeroesMap[visitor], visitedObj);
completeGoal (Goals::GetObj(visitedObj->id.getNum()).sethero(visitor)); //we don't need to visit in anymore completeGoal (sptr(Goals::GetObj(visitedObj->id.getNum()).sethero(visitor))); //we don't need to visit in anymore
} }
status.heroVisit(visitedObj, start); status.heroVisit(visitedObj, start);
@@ -312,8 +313,8 @@ void VCAI::heroExchangeStarted(ObjectInstanceID hero1, ObjectInstanceID hero2, Q
else if (canGetArmy (secondHero, firstHero)) else if (canGetArmy (secondHero, firstHero))
pickBestCreatures (secondHero, firstHero); pickBestCreatures (secondHero, firstHero);
completeGoal(Goals::AbstractGoal(Goals::VISIT_HERO).sethero(firstHero)); //TODO: what if we were visited by other hero in the meantime? completeGoal(sptr(Goals::VisitHero(firstHero->id.getNum()))); //TODO: what if we were visited by other hero in the meantime?
completeGoal(Goals::AbstractGoal(Goals::VISIT_HERO).sethero(secondHero)); completeGoal(sptr(Goals::VisitHero(secondHero->id.getNum())));
//TODO: exchange artifacts //TODO: exchange artifacts
answerQuery(query, 0); answerQuery(query, 0);
@@ -668,7 +669,7 @@ void VCAI::makeTurn()
ui64 averageDanger = totalDanger / std::max(dangerousObjects, 1); ui64 averageDanger = totalDanger / std::max(dangerousObjects, 1);
if (dangerousObjects && averageDanger > h->getHeroStrength()) if (dangerousObjects && averageDanger > h->getHeroStrength())
{ {
setGoal (h, Goals::GatherArmy(averageDanger * SAFE_ATTACK_CONSTANT).sethero(h).setisAbstract(true)); setGoal (h, sptr(Goals::GatherArmy(averageDanger * SAFE_ATTACK_CONSTANT).sethero(h).setisAbstract(true)));
} }
} }
} }
@@ -724,10 +725,10 @@ void VCAI::makeTurnInternal()
//finally, continue our abstract long-term goals //finally, continue our abstract long-term goals
//heroes tend to die in the process and loose their goals, unsafe to iterate it //heroes tend to die in the process and loose their goals, unsafe to iterate it
std::vector<std::pair<HeroPtr, Goals::AbstractGoal> > safeCopy; std::vector<std::pair<HeroPtr, Goals::TSubgoal> > safeCopy;
boost::copy(lockedHeroes, std::back_inserter(safeCopy)); boost::copy(lockedHeroes, std::back_inserter(safeCopy));
typedef std::pair<HeroPtr, Goals::AbstractGoal> TItrType; typedef std::pair<HeroPtr, Goals::TSubgoal> TItrType;
auto lockedHeroesSorter = [](TItrType h1, TItrType h2) -> bool auto lockedHeroesSorter = [](TItrType h1, TItrType h2) -> bool
{ {
@@ -741,7 +742,7 @@ void VCAI::makeTurnInternal()
if (it->first && it->first->tempOwner == playerID && vstd::contains(lockedHeroes, it->first)) //make sure hero still has his goal if (it->first && it->first->tempOwner == playerID && vstd::contains(lockedHeroes, it->first)) //make sure hero still has his goal
{ {
cb->setSelection(*it->first); cb->setSelection(*it->first);
striveToGoal (make_shared<Goals::AbstractGoal>(it->second)); striveToGoal (it->second);
} }
safeCopy.erase(it); safeCopy.erase(it);
} }
@@ -1214,29 +1215,22 @@ void VCAI::wander(HeroPtr h)
} }
} }
void VCAI::setGoal(HeroPtr h, const Goals::AbstractGoal &goal) void VCAI::setGoal(HeroPtr h, Goals::TSubgoal goal)
{ //TODO: check for presence? { //TODO: check for presence?
if (goal.invalid()) if (goal->invalid())
erase_if_present(lockedHeroes, h); erase_if_present(lockedHeroes, h);
else else
lockedHeroes[h] = Goals::AbstractGoal(goal).setisElementar(false); //always evaluate goals before realizing lockedHeroes[h] = goal;
goal->setisElementar(false); //always evaluate goals before realizing
} }
void VCAI::setGoal(HeroPtr h, Goals::EGoals goalType) void VCAI::completeGoal (Goals::TSubgoal goal)
{ {
if (goalType == Goals::INVALID) if (const CGHeroInstance * h = goal->hero.get(true))
erase_if_present(lockedHeroes, h);
else
lockedHeroes[h] = Goals::AbstractGoal(goalType).setisElementar(false); //always evaluate goals before realizing;
}
void VCAI::completeGoal (const Goals::AbstractGoal &goal)
{
if (const CGHeroInstance * h = goal.hero.get(true))
{ {
auto it = lockedHeroes.find(h); auto it = lockedHeroes.find(h);
if (it != lockedHeroes.end()) if (it != lockedHeroes.end())
if (it->second.goalType == goal.goalType) if (it->second->goalType == goal->goalType)
lockedHeroes.erase(it); //goal fulfilled, free hero lockedHeroes.erase(it); //goal fulfilled, free hero
} }
} }
@@ -1426,7 +1420,7 @@ bool VCAI::moveHeroToTile(int3 dst, HeroPtr h)
{ {
logAi->errorStream() << "Hero " << h->name << " cannot reach " << dst; logAi->errorStream() << "Hero " << h->name << " cannot reach " << dst;
//setGoal(h, INVALID); //setGoal(h, INVALID);
completeGoal (Goals::AbstractGoal(Goals::VISIT_TILE).sethero(h)); completeGoal (sptr(Goals::VisitTile(int3(-1,-1,-1)).sethero(h))); //TODO: better mechanism to determine goal
cb->recalculatePaths(); cb->recalculatePaths();
throw std::runtime_error("Wrong move order!"); throw std::runtime_error("Wrong move order!");
} }
@@ -1483,12 +1477,12 @@ bool VCAI::moveHeroToTile(int3 dst, HeroPtr h)
logAi->debugStream() << boost::format("Hero %s moved from %s to %s. Returning %d.") % h->name % startHpos % h->visitablePos() % ret; logAi->debugStream() << boost::format("Hero %s moved from %s to %s. Returning %d.") % h->name % startHpos % h->visitablePos() % ret;
return ret; return ret;
} }
void VCAI::tryRealize(Goals::Explore g) void VCAI::tryRealize(Goals::Explore & g)
{ {
throw cannotFulfillGoalException("EXPLORE is not a elementar goal!"); throw cannotFulfillGoalException("EXPLORE is not a elementar goal!");
} }
void VCAI::tryRealize(Goals::RecruitHero g) void VCAI::tryRealize(Goals::RecruitHero & g)
{ {
if(const CGTownInstance *t = findTownWithTavern()) if(const CGTownInstance *t = findTownWithTavern())
{ {
@@ -1498,38 +1492,39 @@ void VCAI::tryRealize(Goals::RecruitHero g)
} }
} }
void VCAI::tryRealize(Goals::VisitTile g) void VCAI::tryRealize(Goals::VisitTile & g)
{ {
//cb->recalculatePaths(); //cb->recalculatePaths();
if(!g.hero->movement) if(!g.hero->movement)
throw cannotFulfillGoalException("Cannot visit tile: hero is out of MPs!"); throw cannotFulfillGoalException("Cannot visit tile: hero is out of MPs!");
if(g.tile == g.hero->visitablePos() && cb->getVisitableObjs(g.hero->visitablePos()).size() < 2) if(g.tile == g.hero->visitablePos() && cb->getVisitableObjs(g.hero->visitablePos()).size() < 2)
{ {
logAi->warnStream() << boost::format("Why do I want to move hero %s to tile %s? Already standing on that tile! ") % g.hero->name % g.tile; logAi->warnStream() << boost::format("Why do I want to move hero %s to tile %s? Already standing on that tile! ")
throw goalFulfilledException (g); % g.hero->name % g.tile;
throw goalFulfilledException (sptr(g));
} }
//if(!g.isBlockedBorderGate(g.tile)) //if(!g.isBlockedBorderGate(g.tile))
//{ //{
if (ai->moveHeroToTile(g.tile, g.hero.get())) if (ai->moveHeroToTile(g.tile, g.hero.get()))
{ {
throw goalFulfilledException (g); throw goalFulfilledException (sptr(g));
} }
//} //}
//else //else
// throw cannotFulfillGoalException("There's a blocked gate!, we should never be here"); //CLEAR_WAY_TO should get keymaster tent // throw cannotFulfillGoalException("There's a blocked gate!, we should never be here"); //CLEAR_WAY_TO should get keymaster tent
} }
void VCAI::tryRealize(Goals::VisitHero g) void VCAI::tryRealize(Goals::VisitHero & g)
{ {
if(!g.hero->movement) if(!g.hero->movement)
throw cannotFulfillGoalException("Cannot visit tile: hero is out of MPs!"); throw cannotFulfillGoalException("Cannot visit tile: hero is out of MPs!");
if (ai->moveHeroToTile(g.tile, g.hero.get())) if (ai->moveHeroToTile(g.tile, g.hero.get()))
{ {
throw goalFulfilledException (g); throw goalFulfilledException (sptr(g));
} }
} }
void VCAI::tryRealize(Goals::BuildThis g) void VCAI::tryRealize(Goals::BuildThis & g)
{ {
const CGTownInstance *t = g.town; const CGTownInstance *t = g.town;
@@ -1558,22 +1553,22 @@ void VCAI::tryRealize(Goals::BuildThis g)
throw cannotFulfillGoalException("Cannot build a given structure!"); throw cannotFulfillGoalException("Cannot build a given structure!");
} }
void VCAI::tryRealize(Goals::DigAtTile g) void VCAI::tryRealize(Goals::DigAtTile & g)
{ {
assert(g.hero->visitablePos() == g.tile); //surely we want to crash here? assert(g.hero->visitablePos() == g.tile); //surely we want to crash here?
if (g.hero->diggingStatus() == CGHeroInstance::CAN_DIG) if (g.hero->diggingStatus() == CGHeroInstance::CAN_DIG)
{ {
cb->dig(g.hero.get()); cb->dig(g.hero.get());
setGoal(g.hero, Goals::INVALID); // finished digging setGoal(g.hero, sptr(Goals::Invalid())); // finished digging
} }
else else
{ {
ai->lockedHeroes[g.hero] = g; //hero who tries to dig shouldn't do anything else ai->lockedHeroes[g.hero] = sptr(g); //hero who tries to dig shouldn't do anything else
throw cannotFulfillGoalException("A hero can't dig!\n"); throw cannotFulfillGoalException("A hero can't dig!\n");
} }
} }
void VCAI::tryRealize(Goals::CollectRes g) void VCAI::tryRealize(Goals::CollectRes & g)
{ {
if(cb->getResourceAmount(static_cast<Res::ERes>(g.resID)) >= g.value) if(cb->getResourceAmount(static_cast<Res::ERes>(g.resID)) >= g.value)
throw cannotFulfillGoalException("Goal is already fulfilled!"); throw cannotFulfillGoalException("Goal is already fulfilled!");
@@ -1608,20 +1603,20 @@ void VCAI::tryRealize(Goals::CollectRes g)
} }
} }
void VCAI::tryRealize(Goals::Build g) void VCAI::tryRealize(Goals::Build & g)
{ {
performTypicalActions(); //TODO: separate build and wander performTypicalActions(); //TODO: separate build and wander
throw cannotFulfillGoalException("BUILD has been realized as much as possible."); throw cannotFulfillGoalException("BUILD has been realized as much as possible.");
} }
void VCAI::tryRealize(Goals::Invalid g) void VCAI::tryRealize(Goals::Invalid & g)
{ {
throw cannotFulfillGoalException("I don't know how to fulfill this!"); throw cannotFulfillGoalException("I don't know how to fulfill this!");
} }
void VCAI::tryRealize(Goals::AbstractGoal g) void VCAI::tryRealize(Goals::AbstractGoal & g)
{ {
logAi->debugStream() << boost::format("Attempting realizing goal with code %s") % g.name(); logAi->debugStream() << boost::format("Attempting realizing goal with code %s") % g.name();
throw cannotFulfillGoalException("Unknown type of goal !"); throw cannotFulfillGoalException("Unknown type of goal !");
} }
const CGTownInstance * VCAI::findTownWithTavern() const const CGTownInstance * VCAI::findTownWithTavern() const
@@ -1641,7 +1636,7 @@ std::vector<HeroPtr> VCAI::getUnblockedHeroes() const
for(auto h : lockedHeroes) for(auto h : lockedHeroes)
{ {
//if (!h.second.invalid()) //we can use heroes without valid goal //if (!h.second.invalid()) //we can use heroes without valid goal
if (h.second.goalType == Goals::DIG_AT_TILE || !h.first->movement) //experiment: use all heroes that have movement left, TODO: unlock heroes that couldn't realize their goals if (h.second->goalType == Goals::DIG_AT_TILE || !h.first->movement) //experiment: use all heroes that have movement left, TODO: unlock heroes that couldn't realize their goals
erase_if_present(ret, h.first); erase_if_present(ret, h.first);
} }
return ret; return ret;
@@ -1674,19 +1669,15 @@ void VCAI::endTurn()
logAi->debugStream() << "Player " << static_cast<int>(playerID.getNum()) << " ended turn"; logAi->debugStream() << "Player " << static_cast<int>(playerID.getNum()) << " ended turn";
} }
bool VCAI::fulfillsGoal (Goals::AbstractGoal &goal, Goals::AbstractGoal &mainGoal) bool VCAI::fulfillsGoal (Goals::TSubgoal goal, Goals::TSubgoal mainGoal)
{ {
if (mainGoal.goalType == Goals::GET_OBJ && goal.goalType == Goals::VISIT_TILE) //deduce that GET_OBJ was completed by visiting object's tile if (mainGoal->goalType == Goals::GET_OBJ && goal->goalType == Goals::VISIT_TILE) //deduce that GET_OBJ was completed by visiting object's tile
{ //TODO: more universal mechanism { //TODO: more universal mechanism
if (cb->getObj(ObjectInstanceID(mainGoal.objid))->visitablePos() == goal.tile) if (cb->getObj(ObjectInstanceID(mainGoal->objid))->visitablePos() == goal->tile)
return true; return true;
} }
return false; return false;
} }
bool VCAI::fulfillsGoal (Goals::AbstractGoal &goal, const Goals::AbstractGoal &mainGoal)
{
return fulfillsGoal (goal, const_cast<Goals::AbstractGoal&>(mainGoal));
}
void VCAI::striveToGoal(Goals::TSubgoal ultimateGoal) void VCAI::striveToGoal(Goals::TSubgoal ultimateGoal)
{ {
@@ -1732,11 +1723,11 @@ void VCAI::striveToGoal(Goals::TSubgoal ultimateGoal)
{ {
if (maxGoals) if (maxGoals)
{ {
setGoal(goal->hero, *goal.get()); setGoal(goal->hero, goal);
} }
else else
{ {
setGoal(goal->hero, Goals::INVALID); // we seemingly don't know what to do with hero setGoal(goal->hero, sptr(Goals::Invalid())); // we seemingly don't know what to do with hero
} }
} }
@@ -1747,7 +1738,7 @@ void VCAI::striveToGoal(Goals::TSubgoal ultimateGoal)
break; break;
} }
else else
tryRealize(*goal); goal->accept(this);
boost::this_thread::interruption_point(); boost::this_thread::interruption_point();
} }
@@ -1758,8 +1749,8 @@ void VCAI::striveToGoal(Goals::TSubgoal ultimateGoal)
} }
catch(goalFulfilledException &e) catch(goalFulfilledException &e)
{ {
completeGoal (*goal); completeGoal (goal);
if (fulfillsGoal (*goal, *ultimateGoal.get()) || maxGoals > 98) //completed goal was main goal //TODO: find better condition if (fulfillsGoal (goal, ultimateGoal) || maxGoals > 98) //completed goal was main goal //TODO: find better condition
return; return;
} }
catch(std::exception &e) catch(std::exception &e)
@@ -1802,7 +1793,7 @@ void VCAI::striveToGoal(Goals::TSubgoal ultimateGoal)
std::runtime_error e("Too many subgoals, don't know what to do"); std::runtime_error e("Too many subgoals, don't know what to do");
throw (e); throw (e);
} }
tryRealize(*goal); goal->accept(this);
boost::this_thread::interruption_point(); boost::this_thread::interruption_point();
} }
catch(boost::thread_interrupted &e) catch(boost::thread_interrupted &e)
@@ -1812,8 +1803,8 @@ void VCAI::striveToGoal(Goals::TSubgoal ultimateGoal)
} }
catch(goalFulfilledException &e) catch(goalFulfilledException &e)
{ {
completeGoal (*goal); //FIXME: deduce that we have realized GET_OBJ goal completeGoal (goal); //FIXME: deduce that we have realized GET_OBJ goal
if (fulfillsGoal (*goal, *abstractGoal) || maxGoals > 98) //completed goal was main goal if (fulfillsGoal (goal, abstractGoal) || maxGoals > 98) //completed goal was main goal
return; return;
} }
catch(std::exception &e) catch(std::exception &e)
@@ -2119,8 +2110,8 @@ void VCAI::checkHeroArmy (HeroPtr h)
auto it = lockedHeroes.find(h); auto it = lockedHeroes.find(h);
if (it != lockedHeroes.end()) if (it != lockedHeroes.end())
{ {
if (it->second.goalType == Goals::GATHER_ARMY && it->second.value <= h->getArmyStrength()) if (it->second->goalType == Goals::GATHER_ARMY && it->second->value <= h->getArmyStrength())
completeGoal(Goals::GatherArmy(it->second.value).sethero(h)); completeGoal(sptr(Goals::GatherArmy(it->second->value).sethero(h)));
} }
} }
@@ -2627,7 +2618,7 @@ int3 SectorMap::firstTileToGet(HeroPtr h, crint3 dst)
if(!preds[dst]) if(!preds[dst])
{ {
write("test.txt"); write("test.txt");
ai->completeGoal (Goals::Explore(h)); //if we can't find the way, seemingly all tiles were explored ai->completeGoal (sptr(Goals::Explore(h))); //if we can't find the way, seemingly all tiles were explored
//TODO: more organized way? //TODO: more organized way?
throw cannotFulfillGoalException(boost::str(boost::format("Cannot find connection between sectors %d and %d") % src->id % dst->id)); throw cannotFulfillGoalException(boost::str(boost::format("Cannot find connection between sectors %d and %d") % src->id % dst->id));
} }

View File

@@ -128,7 +128,7 @@ public:
//std::vector<const CGObjectInstance *> visitedThisWeek; //only OPWs //std::vector<const CGObjectInstance *> visitedThisWeek; //only OPWs
std::map<HeroPtr, std::vector<const CGTownInstance *> > townVisitsThisWeek; std::map<HeroPtr, std::vector<const CGTownInstance *> > townVisitsThisWeek;
std::map<HeroPtr, Goals::AbstractGoal> lockedHeroes; //TODO: allow non-elementar objectives std::map<HeroPtr, Goals::TSubgoal> lockedHeroes; //TODO: allow non-elementar objectives
std::map<HeroPtr, std::vector<const CGObjectInstance *> > reservedHeroesMap; //objects reserved by specific heroes std::map<HeroPtr, std::vector<const CGObjectInstance *> > reservedHeroesMap; //objects reserved by specific heroes
std::vector<const CGObjectInstance *> visitableObjs; std::vector<const CGObjectInstance *> visitableObjs;
@@ -147,16 +147,17 @@ public:
VCAI(void); VCAI(void);
~VCAI(void); ~VCAI(void);
void tryRealize(Goals::AbstractGoal g); //TODO: use only smart pointers?
void tryRealize(Goals::Explore g); void tryRealize(Goals::Explore & g);
void tryRealize(Goals::RecruitHero g); void tryRealize(Goals::RecruitHero & g);
void tryRealize(Goals::VisitTile g); void tryRealize(Goals::VisitTile & g);
void tryRealize(Goals::VisitHero g); void tryRealize(Goals::VisitHero & g);
void tryRealize(Goals::BuildThis g); void tryRealize(Goals::BuildThis & g);
void tryRealize(Goals::DigAtTile g); void tryRealize(Goals::DigAtTile & g);
void tryRealize(Goals::CollectRes g); void tryRealize(Goals::CollectRes & g);
void tryRealize(Goals::Build g); void tryRealize(Goals::Build & g);
void tryRealize(Goals::Invalid g); void tryRealize(Goals::Invalid & g);
void tryRealize(Goals::AbstractGoal & g);
int3 explorationBestNeighbour(int3 hpos, int radius, HeroPtr h); int3 explorationBestNeighbour(int3 hpos, int radius, HeroPtr h);
int3 explorationNewPoint(int radius, HeroPtr h, std::vector<std::vector<int3> > &tiles); int3 explorationNewPoint(int radius, HeroPtr h, std::vector<std::vector<int3> > &tiles);
@@ -234,12 +235,10 @@ public:
void striveToGoal(Goals::TSubgoal ultimateGoal); void striveToGoal(Goals::TSubgoal ultimateGoal);
void endTurn(); void endTurn();
void wander(HeroPtr h); void wander(HeroPtr h);
void setGoal(HeroPtr h, const Goals::AbstractGoal &goal); void setGoal(HeroPtr h, Goals::TSubgoal goal);
void setGoal(HeroPtr h, Goals::EGoals goalType = Goals::INVALID); void completeGoal (Goals::TSubgoal goal); //safely removes goal from reserved hero
void completeGoal (const Goals::AbstractGoal &goal); //safely removes goal from reserved hero
void striveToQuest (const QuestInfo &q); void striveToQuest (const QuestInfo &q);
bool fulfillsGoal (Goals::AbstractGoal &goal, Goals::AbstractGoal &mainGoal); bool fulfillsGoal (Goals::TSubgoal goal, Goals::TSubgoal mainGoal);
bool fulfillsGoal (Goals::AbstractGoal &goal, const Goals::AbstractGoal &mainGoal); //TODO: something smarter
void recruitHero(const CGTownInstance * t, bool throwing = false); void recruitHero(const CGTownInstance * t, bool throwing = false);
std::vector<const CGObjectInstance *> getPossibleDestinations(HeroPtr h); std::vector<const CGObjectInstance *> getPossibleDestinations(HeroPtr h);
@@ -291,7 +290,7 @@ public:
template <typename Handler> void serializeInternal(Handler &h, const int version) template <typename Handler> void serializeInternal(Handler &h, const int version)
{ {
h & knownSubterraneanGates & townVisitsThisWeek & lockedHeroes & reservedHeroesMap; h & knownSubterraneanGates & townVisitsThisWeek;// & lockedHeroes & reservedHeroesMap; //FIXME: cannot instantiate abstract class
h & visitableObjs & alreadyVisited & reservedObjs; h & visitableObjs & alreadyVisited & reservedObjs;
h & saving & status & battlename; h & saving & status & battlename;
@@ -320,9 +319,9 @@ public:
class goalFulfilledException : public std::exception class goalFulfilledException : public std::exception
{ {
public: public:
Goals::AbstractGoal goal; Goals::TSubgoal goal;
explicit goalFulfilledException(Goals::AbstractGoal Goal) : goal(Goal) explicit goalFulfilledException(Goals::TSubgoal Goal) : goal(Goal)
{ {
} }
@@ -332,7 +331,7 @@ public:
const char *what() const throw () override const char *what() const throw () override
{ {
return goal.name().c_str(); return goal->name().c_str();
} }
}; };