Browse Source

Rewritten VCAI::pickBestCreatures. Should fix the compilation error ( http://forum.vcmi.eu/viewtopic.php?p=6605#6605 ).

Michał W. Urbańczyk 13 years ago
parent
commit
76eb0ed429
3 changed files with 42 additions and 47 deletions
  1. 32 47
      AI/VCAI/VCAI.cpp
  2. 8 0
      CCallback.cpp
  3. 2 0
      CCallback.h

+ 32 - 47
AI/VCAI/VCAI.cpp

@@ -863,6 +863,10 @@ void VCAI::makeTurnInternal()
 	blockedHeroes.clear();
 	saving = 0;
 
+	//it looks messy here, but it's better to have armed heroes before attempting realizing goals
+	BOOST_FOREACH(const CGTownInstance *t, cb->getTownsInfo())
+		moveCreaturesToHero(t);
+
 	try
 	{
 		striveToGoal(CGoal(WIN));
@@ -901,7 +905,7 @@ void VCAI::performObjectInteraction(const CGObjectInstance * obj, const CGHeroIn
 
 void VCAI::moveCreaturesToHero(const CGTownInstance * t)
 {
-	if(t->visitingHero)
+	if(t->visitingHero && t->armedGarrison())
 	{
 		pickBestCreatures (t->visitingHero, t);
 	}
@@ -909,56 +913,37 @@ void VCAI::moveCreaturesToHero(const CGTownInstance * t)
 
 void VCAI::pickBestCreatures(const CArmedInstance * army, const CArmedInstance * source)
 {
-	if (army->stacksCount() == GameConstants::ARMY_SIZE) //try merging our army first
-	{
-		for (int i = 0; i < GameConstants::ARMY_SIZE; ++i)
-		{
-			if (const CStackInstance *s = army->getStackPtr(i))
-			{
-				for (int j = 0; j < GameConstants::ARMY_SIZE; ++j)
-				{
-					if (i != j && army->mergableStacks(std::pair<TSlot, TSlot>(i, j)))
-					{
-						cb->mergeStacks (army, army, j, i);
-						break;
-					}
-				}
-			}
-		}
-	}
+	//TODO - what if source is a hero (the last stack problem) -> it'd good to create a single stack of weakest cre
+	const CArmedInstance *armies[] = {army, source};
+	//we calculate total strength for each creature type available in armies
+	std::map<const CCreature*, int> creToPower;
+	BOOST_FOREACH(auto armyPtr, armies)
+		BOOST_FOREACH(auto &i, armyPtr->Slots())
+			creToPower[i.second->type] += i.second->getPower(); 
+	//TODO - consider more than just power (ie morale penalty, hero specialty in certain stacks, etc)
 
-	for (int i = 0; i < GameConstants::ARMY_SIZE; ++i)
+	std::vector<const CCreature *> bestArmy; //types that'll be in final dst army
+	for (int i = 0; i < GameConstants::ARMY_SIZE; i++) //pick the creatures from which we can get most power, as many as dest can fit
 	{
-		if(const CStackInstance *s = source->getStackPtr(i))
-		{
-			//find d
-			int dstSlot = army->getSlotFor(s->type);
-			if(dstSlot >= 0)
-			{
-				if (army->hasStackAtSlot(dstSlot))
-					cb->mergeStacks(source, army, i, dstSlot);
-				else 
-					cb->swapCreatures(source, army, i, dstSlot);
-			}
-			else //exchange poorest stack with stronger one
+		typedef const std::pair<const CCreature*, int> &CrePowerPair;
+		auto creIt = boost::max_element(creToPower, [](CrePowerPair lhs, CrePowerPair rhs)
 			{
-				TSlot weakestStack = 0;
-				for (int j = 1; j < GameConstants::ARMY_SIZE; ++j)
-				{
-					const CStackInstance *p = army->getStackPtr(j);
-					const CStackInstance *w = army->getStackPtr(weakestStack);
-					if (p && w)
-					{
-						if (p->getPower() < w->getPower())
-							weakestStack = j;
-					}
-				}
-				if (const CStackInstance *w = army->getStackPtr(weakestStack))
-					if (w->getPower() < s->getPower())
-						cb->swapCreatures(source, army, i, weakestStack);
-			}
-		}
+				return lhs.second < rhs.second;
+			});
+		bestArmy.push_back(creIt->first);
+		creToPower.erase(creIt);
+		if(creToPower.empty())
+			break;
 	}
+	
+	//foreach best type -> iterate over slots in both armies and if it's the appropriate type, send it to the slot where it belongs
+	for (int i = 0; i < bestArmy.size(); i++) //i-th strongest creature type will go to i-th slot
+		BOOST_FOREACH(auto armyPtr, armies) 
+			for (int j = 0; j < GameConstants::ARMY_SIZE; j++)
+				if(armyPtr->getCreature(j) == bestArmy[i]  &&  (i != j || armyPtr != army)) //it's a searched creature not in dst slot
+						cb->mergeOrSwapStacks(armyPtr, army, j, i);
+
+	//TODO - having now strongest possible army, we may want to think about arranging stacks
 }
 
 void VCAI::recruitCreatures(const CGDwelling * d)

+ 8 - 0
CCallback.cpp

@@ -403,6 +403,14 @@ void CCallback::validatePaths()
 	}
 }
 
+int CCallback::mergeOrSwapStacks(const CArmedInstance *s1, const CArmedInstance *s2, int p1, int p2)
+{
+	if(s1->getCreature(p1) == s2->getCreature(p2))
+		return mergeStacks(s1, s2, p1, p2);
+	else
+		return swapCreatures(s1, s2, p1, p2);
+}
+
 CBattleCallback::CBattleCallback(CGameState *GS, int Player, CClient *C )
 {
 	gs = GS;

+ 2 - 0
CCallback.h

@@ -60,6 +60,7 @@ public:
 	virtual void selectionMade(int selection, int asker) =0;
 	virtual int swapCreatures(const CArmedInstance *s1, const CArmedInstance *s2, int p1, int p2)=0;//swaps creatures between two possibly different garrisons // TODO: AI-unsafe code - fix it!
 	virtual int mergeStacks(const CArmedInstance *s1, const CArmedInstance *s2, int p1, int p2)=0;//joins first stack to the second (creatures must be same type)
+	virtual int mergeOrSwapStacks(const CArmedInstance *s1, const CArmedInstance *s2, int p1, int p2) =0; //first goes to the second
 	virtual int splitStack(const CArmedInstance *s1, const CArmedInstance *s2, int p1, int p2, int val)=0;//split creatures from the first stack
 	//virtual bool swapArtifacts(const CGHeroInstance * hero1, ui16 pos1, const CGHeroInstance * hero2, ui16 pos2)=0; //swaps artifacts between two given heroes
 	virtual bool swapArtifacts(const IArtifactSetBase * src, ui16 pos1, const IArtifactSetBase * dest, ui16 pos2)=0;
@@ -121,6 +122,7 @@ public:
 	bool teleportHero(const CGHeroInstance *who, const CGTownInstance *where);
 	void selectionMade(int selection, int asker);
 	int swapCreatures(const CArmedInstance *s1, const CArmedInstance *s2, int p1, int p2);
+	int mergeOrSwapStacks(const CArmedInstance *s1, const CArmedInstance *s2, int p1, int p2); //first goes to the second
 	int mergeStacks(const CArmedInstance *s1, const CArmedInstance *s2, int p1, int p2); //first goes to the second
 	int splitStack(const CArmedInstance *s1, const CArmedInstance *s2, int p1, int p2, int val);
 	bool dismissHero(const CGHeroInstance * hero);