Pārlūkot izejas kodu

BattleAI: fast targets optimization

Andrii Danylchenko 2 gadi atpakaļ
vecāks
revīzija
ba9998ac66

+ 6 - 1
AI/BattleAI/BattleAI.cpp

@@ -507,7 +507,12 @@ void CBattleAI::attemptCastingSpell()
 	{
 		spells::BattleCast temp(cb.get(), hero, spells::Mode::HERO, spell);
 
-		for(auto & target : temp.findPotentialTargets())
+		if(!spell->isDamage() && spell->getTargetType() == spells::AimType::LOCATION)
+			continue;
+		
+		const bool FAST = true;
+
+		for(auto & target : temp.findPotentialTargets(FAST))
 		{
 			PossibleSpellcast ps;
 			ps.dest = target;

+ 4 - 2
AI/BattleAI/BattleExchangeVariant.cpp

@@ -600,6 +600,8 @@ void BattleExchangeEvaluator::updateReachabilityMap(HypotheticBattle & hb)
 			if(unit->isTurret())
 				continue;
 
+			auto unitSpeed = unit->speed(turn);
+
 			if(turnBattle.battleCanShoot(unit))
 			{
 				for(BattleHex hex = BattleHex::TOP_LEFT; hex.isValid(); hex = hex + 1)
@@ -614,7 +616,7 @@ void BattleExchangeEvaluator::updateReachabilityMap(HypotheticBattle & hb)
 
 			for(BattleHex hex = BattleHex::TOP_LEFT; hex.isValid(); hex = hex + 1)
 			{
-				bool reachable = unitReachability.distances[hex] <= unit->speed(turn);
+				bool reachable = unitReachability.distances[hex] <= unitSpeed;
 
 				if(!reachable && unitReachability.accessibility[hex] == EAccessibility::ALIVE_STACK)
 				{
@@ -624,7 +626,7 @@ void BattleExchangeEvaluator::updateReachabilityMap(HypotheticBattle & hb)
 					{
 						for(BattleHex neighbor : hex.neighbouringTiles())
 						{
-							reachable = unitReachability.distances[neighbor] <= unit->speed(turn);
+							reachable = unitReachability.distances[neighbor] <= unitSpeed;
 
 							if(reachable) break;
 						}

+ 0 - 11
AI/BattleAI/PotentialTargets.cpp

@@ -84,17 +84,6 @@ PotentialTargets::PotentialTargets(const battle::Unit * attacker, const Hypothet
 	{
 		return lhs.damageDiff() > rhs.damageDiff();
 	});
-
-	if (!possibleAttacks.empty())
-	{
-		auto & bestAp = possibleAttacks[0];
-
-		logGlobal->debug("Battle AI best: %s -> %s at %d from %d, affects %d units: d:%lld a:%lld c:%lld s:%lld",
-			bestAp.attack.attacker->unitType()->getJsonKey(),
-			state.battleGetUnitByPos(bestAp.dest)->unitType()->getJsonKey(),
-			(int)bestAp.dest, (int)bestAp.from, (int)bestAp.affectedUnits.size(),
-			bestAp.defenderDamageReduce, bestAp.attackerDamageReduce, bestAp.collateralDamageReduce, bestAp.shootersBlockedDmg);
-	}
 }
 
 int64_t PotentialTargets::bestActionValue() const

+ 56 - 9
lib/spells/BattleSpellMechanics.cpp

@@ -590,7 +590,7 @@ std::vector<AimType> BattleSpellMechanics::getTargetTypes() const
 	return ret;
 }
 
-std::vector<Destination> BattleSpellMechanics::getPossibleDestinations(size_t index, AimType aimType, const Target & current) const
+std::vector<Destination> BattleSpellMechanics::getPossibleDestinations(size_t index, AimType aimType, const Target & current, bool fast) const
 {
 	//TODO: BattleSpellMechanics::getPossibleDestinations
 
@@ -602,19 +602,66 @@ std::vector<Destination> BattleSpellMechanics::getPossibleDestinations(size_t in
 	switch(aimType)
 	{
 	case AimType::CREATURE:
+	{
+		auto stacks = battle()->battleGetAllStacks();
+
+		for(auto stack : stacks)
+		{
+			Target tmp = current;
+			tmp.emplace_back(stack->getPosition());
+
+			detail::ProblemImpl ignored;
+
+			if(canBeCastAt(tmp, ignored))
+				ret.emplace_back(stack->getPosition());
+		}
+
+		break;
+	}
+
 	case AimType::LOCATION:
-		for(int i = 0; i < GameConstants::BFIELD_SIZE; i++)
+		if(fast)
+		{
+			auto stacks = battle()->battleGetAllStacks();
+			std::set<BattleHex> hexesToCheck;
+
+			for(auto stack : stacks)
+			{
+				hexesToCheck.insert(stack->getPosition());
+
+				for(auto adjacent : stack->getPosition().neighbouringTiles())
+					hexesToCheck.insert(adjacent);
+			}
+
+			for(auto hex : hexesToCheck)
+			{
+				if(hex.isAvailable())
+				{
+					Target tmp = current;
+					tmp.emplace_back(hex);
+
+					detail::ProblemImpl ignored;
+
+					if(canBeCastAt(tmp, ignored))
+						ret.emplace_back(hex);
+				}
+			}
+		}
+		else
 		{
-			BattleHex dest(i);
-			if(dest.isAvailable())
+			for(int i = 0; i < GameConstants::BFIELD_SIZE; i++)
 			{
-				Target tmp = current;
-				tmp.emplace_back(dest);
+				BattleHex dest(i);
+				if(dest.isAvailable())
+				{
+					Target tmp = current;
+					tmp.emplace_back(dest);
 
-				detail::ProblemImpl ignored;
+					detail::ProblemImpl ignored;
 
-				if(canBeCastAt(tmp, ignored))
-					ret.emplace_back(dest);
+					if(canBeCastAt(tmp, ignored))
+						ret.emplace_back(dest);
+				}
 			}
 		}
 		break;

+ 1 - 1
lib/spells/BattleSpellMechanics.h

@@ -50,7 +50,7 @@ public:
 	/// Returns vector of all possible destinations for specified aim type
 	/// index - ???
 	/// current - ???
-	std::vector<Destination> getPossibleDestinations(size_t index, AimType aimType, const Target & current) const override final;
+	std::vector<Destination> getPossibleDestinations(size_t index, AimType aimType, const Target & current, bool fast) const override final;
 
 	/// Returns true if spell can be cast on unit
 	bool isReceptive(const battle::Unit * target) const override;

+ 3 - 3
lib/spells/ISpellMechanics.cpp

@@ -326,7 +326,7 @@ bool BattleCast::castIfPossible(ServerCallback * server, Target target)
 	return false;
 }
 
-std::vector<Target> BattleCast::findPotentialTargets() const
+std::vector<Target> BattleCast::findPotentialTargets(bool fast) const
 {
 	//TODO: for more than 2 destinations per target much more efficient algorithm is required
 
@@ -354,7 +354,7 @@ std::vector<Target> BattleCast::findPotentialTargets() const
 			if(previous.empty())
 			{
 				Target empty;
-				destinations = m->getPossibleDestinations(index, targetTypes.at(index), empty);
+				destinations = m->getPossibleDestinations(index, targetTypes.at(index), empty, fast);
 
 				for(auto & destination : destinations)
 				{
@@ -367,7 +367,7 @@ std::vector<Target> BattleCast::findPotentialTargets() const
 			{
 				for(const Target & current : previous)
 				{
-					destinations = m->getPossibleDestinations(index, targetTypes.at(index), current);
+					destinations = m->getPossibleDestinations(index, targetTypes.at(index), current, fast);
 
 					for(auto & destination : destinations)
 					{

+ 2 - 2
lib/spells/ISpellMechanics.h

@@ -139,7 +139,7 @@ public:
 	///cast with silent check for permitted cast
 	bool castIfPossible(ServerCallback * server, Target target);
 
-	std::vector<Target> findPotentialTargets() const;
+	std::vector<Target> findPotentialTargets(bool fast = false) const;
 
 private:
 	///spell school level
@@ -199,7 +199,7 @@ public:
 
 	virtual std::vector<AimType> getTargetTypes() const = 0;
 
-	virtual std::vector<Destination> getPossibleDestinations(size_t index, AimType aimType, const Target & current) const = 0;
+	virtual std::vector<Destination> getPossibleDestinations(size_t index, AimType aimType, const Target & current, bool fast = false) const = 0;
 
 	virtual const Spell * getSpell() const = 0;
 

+ 1 - 1
test/mock/mock_spells_Mechanics.h

@@ -34,7 +34,7 @@ public:
 
 	MOCK_CONST_METHOD1(isReceptive, bool(const battle::Unit * ));
 	MOCK_CONST_METHOD0(getTargetTypes, std::vector<AimType>());
-	MOCK_CONST_METHOD3(getPossibleDestinations, std::vector<Destination>(size_t, AimType, const Target &));
+	MOCK_CONST_METHOD4(getPossibleDestinations, std::vector<Destination>(size_t, AimType, const Target &, bool));
 
 	MOCK_CONST_METHOD0(getSpell, const Spell *());