瀏覽代碼

Some more logging for goal completion.

Stub of fuzzy goal selection.
DjWarmonger 12 年之前
父節點
當前提交
cedb3ea82a
共有 5 個文件被更改,包括 96 次插入17 次删除
  1. 22 0
      AI/VCAI/Fuzzy.cpp
  2. 7 0
      AI/VCAI/Fuzzy.h
  3. 26 0
      AI/VCAI/Goals.cpp
  4. 22 15
      AI/VCAI/Goals.h
  5. 19 2
      AI/VCAI/VCAI.cpp

+ 22 - 0
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<AbstractGoal> chooseSolution (std::vector<shared_ptr<AbstractGoal>> & vec)
+//{
+//	typedef std::pair<shared_ptr<AbstractGoal>, float> goalValue;
+//	std::vector <goalValue> 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;
+//}

+ 7 - 0
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<AbstractGoal> chooseSolution (std::vector<shared_ptr<AbstractGoal>> & vec);
 };

+ 26 - 0
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<std::string>(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<std::string>(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<std::string>(value);
+};
+
 TSubgoal GatherArmy::whatToDoToAchieve()
 {
 	//TODO: find hero if none set

+ 22 - 15
AI/VCAI/Goals.h

@@ -23,6 +23,7 @@ namespace Goals
 {
 	struct AbstractGoal;
 	typedef std::shared_ptr<Goals::AbstractGoal> TSubgoal;
+	typedef std::vector<TSubgoal> 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<T&>(*this));
+		ai->tryRealize(static_cast<T&>(*this)); //casting enforces template instantiation
 	}
 
 	CGoal<T> * clone() const override
 	{
-		return new T(static_cast<T const&>(*this));
+		return new T(static_cast<T const&>(*this)); //casting enforces template instantiation
 	}
 	TSubgoal iAmElementar()
 	{
@@ -209,6 +206,7 @@ class Explore : public CGoal<Explore>
 	Explore() : CGoal (Goals::EXPLORE){};
 	Explore(HeroPtr h) : CGoal (Goals::EXPLORE){hero = h;};
 	TSubgoal whatToDoToAchieve() override;
+	std::string completeMessage() const override;
 };
 class GatherArmy : public CGoal<GatherArmy>
 {
@@ -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<BoostHero>
 {
@@ -257,17 +256,19 @@ public:
 };
 class GetObj : public CGoal<GetObj>
 {
-	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<FindObj>
 {
-	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<GetArtOfType>
 {
@@ -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<ClearWayTo>
 {
 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<DigAtTile>
 	//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<CIssueCommand>

+ 19 - 2
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!");
 		}