Kaynağa Gözat

revert Nullkiller to develop code

Mircea TheHonestCTO 4 ay önce
ebeveyn
işleme
2223f38c1e

+ 97 - 0
AI/Nullkiller/Goals/Build.cpp

@@ -0,0 +1,97 @@
+/*
+* Build.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 "Build.h"
+#include "BuildThis.h"
+#include "../AIGateway.h"
+#include "../AIUtility.h"
+#include "../AIhelper.h"
+#include "../FuzzyHelper.h"
+#include "../ResourceManager.h"
+#include "../BuildingManager.h"
+#include "../../../lib/mapping/CMap.h" //for victory conditions
+#include "../../../lib/CPathfinder.h"
+#include "../../../lib/StringConstants.h"
+
+namespace Nullkiller
+{
+
+extern boost::thread_specific_ptr<CCallback> cb;
+extern boost::thread_specific_ptr<AIGateway> ai;
+extern FuzzyHelper * fh;
+
+using namespace Goals;
+
+TGoalVec Build::getAllPossibleSubgoals()
+{
+	TGoalVec ret;
+
+	for(const CGTownInstance * t : cb->getTownsInfo())
+	{
+		//start fresh with every town
+		ai->ah->getBuildingOptions(t);
+		auto immediateBuilding = ai->ah->immediateBuilding();
+		auto expensiveBuilding = ai->ah->expensiveBuilding();
+
+		//handling for early town development to save money and focus on income
+		if(!t->hasBuilt(ai->ah->getMaxPossibleGoldBuilding(t)) && expensiveBuilding.has_value())
+		{
+			auto potentialBuilding = expensiveBuilding.value();
+			switch(expensiveBuilding.value().bid)
+			{
+			case BuildingID::TOWN_HALL:
+			case BuildingID::CITY_HALL:
+			case BuildingID::CAPITOL:
+			case BuildingID::FORT:
+			case BuildingID::CITADEL:
+			case BuildingID::CASTLE:
+				//If above buildings are next to be bought, but no money... do not buy anything else, try to gather resources for these. Simple but has to suffice for now.
+				auto goal = ai->ah->whatToDo(potentialBuilding.price, sptr(BuildThis(potentialBuilding.bid, t).setpriority(2.25)));
+				ret.push_back(goal);
+				return ret;
+				break;
+			}
+		}
+
+		if(immediateBuilding.has_value())
+		{
+			ret.push_back(sptr(BuildThis(immediateBuilding.value().bid, t).setpriority(2))); //prioritize buildings we can build quick
+		}
+		else //try build later
+		{
+			if(expensiveBuilding.has_value())
+			{
+				auto potentialBuilding = expensiveBuilding.value(); //gather resources for any we can't afford
+				auto goal = ai->ah->whatToDo(potentialBuilding.price, sptr(BuildThis(potentialBuilding.bid, t).setpriority(0.5)));
+				ret.push_back(goal);
+			}
+		}
+	}
+
+	if(ret.empty())
+		throw cannotFulfillGoalException("BUILD has been realized as much as possible.");
+	else
+		return ret;
+}
+
+TSubgoal Build::whatToDoToAchieve()
+{
+	return fh->chooseSolution(getAllPossibleSubgoals());
+}
+
+bool Build::fulfillsMe(TSubgoal goal)
+{
+	if(goal->goalType == BUILD || goal->goalType == BUILD_STRUCTURE)
+		return (!town || town == goal->town); //building anything will do, in this town if set
+	else
+		return false;
+}
+
+}

+ 42 - 0
AI/Nullkiller/Goals/Build.h

@@ -0,0 +1,42 @@
+/*
+* Build.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 "CGoal.h"
+
+namespace Nullkiller
+{
+
+struct HeroPtr;
+class AIGateway;
+class FuzzyHelper;
+
+namespace Goals
+{
+	class DLL_EXPORT Build : public CGoal<Build>
+	{
+	public:
+		Build()
+			: CGoal(Goals::BUILD)
+		{
+			priority = 1;
+		}
+		TGoalVec getAllPossibleSubgoals() override;
+		TSubgoal whatToDoToAchieve() override;
+		bool fulfillsMe(TSubgoal goal) override;
+
+		bool operator==(const Build & other) const override
+		{
+			return true;
+		}
+	};
+}
+
+}

+ 214 - 0
AI/Nullkiller/Goals/GatherArmy.cpp

@@ -0,0 +1,214 @@
+/*
+* GatherArmy.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 "Goals.h"
+#include "../AIGateway.h"
+#include "../AIUtility.h"
+#include "../AIhelper.h"
+#include "../FuzzyHelper.h"
+#include "../ResourceManager.h"
+#include "../BuildingManager.h"
+#include "../../../lib/mapping/CMap.h" //for victory conditions
+#include "../../../lib/CPathfinder.h"
+#include "../../../lib/StringConstants.h"
+
+namespace Nullkiller
+{
+
+extern boost::thread_specific_ptr<CCallback> cb;
+extern boost::thread_specific_ptr<AIGateway> ai;
+extern FuzzyHelper * fh;
+
+using namespace Goals;
+
+bool GatherArmy::operator==(const GatherArmy & other) const
+{
+	return other.hero.h == hero.h || town == other.town;
+}
+
+std::string GatherArmy::completeMessage() const
+{
+	return "Hero " + hero.get()->name + " gathered army of value " + std::to_string(value);
+}
+
+TSubgoal GatherArmy::whatToDoToAchieve()
+{
+	//TODO: find hero if none set
+	assert(hero.h);
+
+	return fh->chooseSolution(getAllPossibleSubgoals()); //find dwelling. use current hero to prevent him from doing nothing.
+}
+
+TGoalVec GatherArmy::getAllPossibleSubgoals()
+{
+	//get all possible towns, heroes and dwellings we may use
+	TGoalVec ret;
+
+	if(!hero.validAndSet())
+	{
+		return ret;
+	}
+
+	//TODO: include evaluation of monsters gather in calculation
+	for(auto t : cb->getTownsInfo())
+	{
+		auto waysToVisit = ai->ah->howToVisitObj(hero, t);
+
+		if(waysToVisit.size())
+		{
+			//grab army from town
+			if(!t->visitingHero && ai->ah->howManyReinforcementsCanGet(hero.get(), t))
+			{
+				if(!vstd::contains(ai->townVisitsThisWeek[hero], t))
+					vstd::concatenate(ret, waysToVisit);
+			}
+
+			//buy army in town
+			if (!t->visitingHero || t->visitingHero == hero.get(true))
+			{
+				std::vector<int> values = {
+					value,
+					(int)ai->ah->howManyReinforcementsCanBuy(t->getUpperArmy(), t),
+					(int)ai->ah->howManyReinforcementsCanBuy(hero.get(), t) };
+
+				int val = *std::min_element(values.begin(), values.end());
+
+				if (val)
+				{
+					auto goal = sptr(BuyArmy(t, val).sethero(hero));
+
+					if(!ai->ah->containsObjective(goal)) //avoid loops caused by reserving same objective twice
+						ret.push_back(goal);
+					else
+						logAi->debug("Can not buy army, because of ai->ah->containsObjective");
+				}
+			}
+			//build dwelling
+			//TODO: plan building over multiple turns?
+			//auto bid = ah->canBuildAnyStructure(t, std::vector<BuildingID>(unitsSource, unitsSource + ARRAY_COUNT(unitsSource)), 8 - cb->getDate(Date::DAY_OF_WEEK));
+
+			//Do not use below code for now, rely on generic Build. Code below needs to know a lot of town/resource context to do more good than harm
+			/*auto bid = ai->ah->canBuildAnyStructure(t, std::vector<BuildingID>(unitsSource, unitsSource + ARRAY_COUNT(unitsSource)), 1);
+			if (bid.has_value())
+			{
+				auto goal = sptr(BuildThis(bid.get(), t).setpriority(priority));
+				if (!ai->ah->containsObjective(goal)) //avoid loops caused by reserving same objective twice
+					ret.push_back(goal);
+				else
+					logAi->debug("Can not build a structure, because of ai->ah->containsObjective");
+			}*/
+		}
+	}
+
+	auto otherHeroes = cb->getHeroesInfo();
+	auto heroDummy = hero;
+	vstd::erase_if(otherHeroes, [heroDummy](const CGHeroInstance * h)
+	{
+		if(h == heroDummy.h)
+			return true;
+		else if(!ai->isAccessibleForHero(heroDummy->visitablePos(), h, true))
+			return true;
+		else if(!ai->ah->canGetArmy(heroDummy.h, h)) //TODO: return actual aiValue
+			return true;
+		else if(ai->getGoal(h)->goalType == GATHER_ARMY)
+			return true;
+		else
+		   return false;
+	});
+
+	for(auto h : otherHeroes)
+	{
+		// Go to the other hero if we are faster
+		if(!vstd::contains(ai->visitedHeroes[hero], h))
+		{
+			vstd::concatenate(ret, ai->ah->howToVisitObj(hero, h, false));
+		}
+
+		// Go to the other hero if we are faster
+		if(!vstd::contains(ai->visitedHeroes[h], hero))
+		{
+			vstd::concatenate(ret, ai->ah->howToVisitObj(h, hero.get(), false));
+		}
+	}
+
+	std::vector<const CGObjectInstance *> objs;
+	for(auto obj : ai->visitableObjs)
+	{
+		if(obj->ID == Obj::CREATURE_GENERATOR1)
+		{
+			auto relationToOwner = cb->getPlayerRelations(obj->getOwner(), ai->playerID);
+
+			//Use flagged dwellings only when there are available creatures that we can afford
+			if(relationToOwner == PlayerRelations::SAME_PLAYER)
+			{
+				auto dwelling = dynamic_cast<const CGDwelling *>(obj);
+
+				ui32 val = std::min((ui32)value, (ui32)ai->ah->howManyReinforcementsCanBuy(hero.get(), dwelling));
+
+				if(val)
+				{
+					for(auto & creLevel : dwelling->creatures)
+					{
+						if(creLevel.first)
+						{
+							for(auto & creatureID : creLevel.second)
+							{
+								auto creature = VLC->creh->creatures[creatureID];
+								if(ai->ah->freeResources().canAfford(creature->getFullRecruitCost()))
+									objs.push_back(obj); //TODO: reserve resources?
+							}
+						}
+					}
+				}
+			}
+		}
+	}
+
+	for(auto h : cb->getHeroesInfo())
+	{
+		for(auto obj : objs)
+		{
+			//find safe dwelling
+			if(ai->isGoodForVisit(obj, h))
+			{
+				vstd::concatenate(ret, ai->ah->howToVisitObj(h, obj));
+			}
+		}
+	}
+
+	if(ai->canRecruitAnyHero() && ai->ah->freeGold() > GameConstants::HERO_GOLD_COST) //this is not stupid in early phase of game
+	{
+		if(auto t = ai->findTownWithTavern())
+		{
+			for(auto h : cb->getAvailableHeroes(t)) //we assume that all towns have same set of heroes
+			{
+				if(h && h->getTotalStrength() > 500) //do not buy heroes with single creatures for GatherArmy
+				{
+					ret.push_back(sptr(RecruitHero()));
+					break;
+				}
+			}
+		}
+	}
+
+	if(ret.empty())
+	{
+		const bool allowGatherArmy = false;
+
+		if(hero == ai->primaryHero())
+			ret.push_back(sptr(Explore(allowGatherArmy)));
+		else
+			throw cannotFulfillGoalException("No ways to gather army");
+	}
+
+	return ret;
+}
+
+}

+ 43 - 0
AI/Nullkiller/Goals/GatherArmy.h

@@ -0,0 +1,43 @@
+/*
+* GatherArmy.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 "CGoal.h"
+
+namespace Nullkiller
+{
+
+struct HeroPtr;
+class AIGateway;
+class FuzzyHelper;
+
+namespace Goals
+{
+	class DLL_EXPORT GatherArmy : public CGoal<GatherArmy>
+	{
+	public:
+		GatherArmy()
+			: CGoal(Goals::GATHER_ARMY)
+		{
+		}
+		GatherArmy(int val)
+			: CGoal(Goals::GATHER_ARMY)
+		{
+			value = val;
+			priority = 2.5;
+		}
+		TGoalVec getAllPossibleSubgoals() override;
+		TSubgoal whatToDoToAchieve() override;
+		std::string completeMessage() const override;
+		bool operator==(const GatherArmy & other) const override;
+	};
+}
+
+}