#include "Strategy_CombatTaskManager.h"

using namespace MyBot;


void Strategy_CombatTaskManager::updateUnitCount()
{
	// 적군 MainBaseLocation 을 향해 공격
	enemyCombatUnitCount = InformationManager::Instance().getNumUnits(InformationManager::Instance().getBasicCombatUnitType(InformationManager::Instance().enemyRace), InformationManager::Instance().enemyPlayer);
	enemyWorkerUnitCount = InformationManager::Instance().getNumUnits(InformationManager::Instance().getWorkerType(InformationManager::Instance().enemyRace), InformationManager::Instance().enemyPlayer);
	enemyZealotCount = InformationManager::Instance().getNumUnits(BWAPI::UnitTypes::Protoss_Zealot, InformationManager::Instance().enemyPlayer);
	enemyMarineCount = InformationManager::Instance().getNumUnits(BWAPI::UnitTypes::Terran_Marine, InformationManager::Instance().enemyPlayer);
	enemyZerglingCount = InformationManager::Instance().getNumUnits(BWAPI::UnitTypes::Zerg_Zergling, InformationManager::Instance().enemyPlayer);

	BWTA::BaseLocation * enemyMainBaseLocation = InformationManager::Instance().getMainBaseLocation(InformationManager::Instance().enemyPlayer);
	if (enemyMainBaseLocation != nullptr) {

		enemyWorkerUnitAroundEnemyBase = 0;
		enemyWorkerUnitAroundEnemyChokepoint = 0;
		enemyCombatUnitAroundEnemyBase = 0;
		enemyCombatUnitAroundEnemyChokepoint = 0;
		enemyBuildingAroundEnemyBase = 0;
		enemyBuildingAroundEnemyChokepoint = 0;
		enemyDefenseBuildingAroundEnemyBase = 0;
		enemyDefenseBuildingAroundEnemyChokepoint = 0;

		for (auto & it : InformationManager::Instance().getUnitAndUnitInfoMap(StrategyManager::Instance().enemyPlayer)) {
			BWAPI::Unit enemyUnit = it.first;
			UnitInfo & enemyUnitInfo = it.second;

			if (enemyUnitInfo.lastHealth == 0) {
				continue;
			}

			if (BWTA::getRegion(enemyUnitInfo.lastPosition) == enemyMainBaseLocation->getRegion()) {
				if (enemyUnitInfo.type.isWorker()) {
					enemyWorkerUnitAroundEnemyBase++;
				}
				if (enemyUnitInfo.type.isBuilding()) {
					enemyBuildingAroundEnemyBase++;
				}
				if (enemyUnitInfo.type.canAttack() && enemyUnitInfo.type.isWorker() == false && enemyUnitInfo.type.isBuilding() == false) {
					enemyCombatUnitAroundEnemyBase++;
				}
				if (enemyUnitInfo.type.canAttack() && enemyUnitInfo.type.isBuilding() == true) {
					enemyDefenseBuildingAroundEnemyBase++;
				}

			}
			else if (enemyUnitInfo.lastPosition.getDistance(StrategyManager::Instance().enemyFirstChokepoint->getCenter()) < 5 * TILE_SIZE)
			{
				if (enemyUnitInfo.type.isWorker()) {
					enemyWorkerUnitAroundEnemyChokepoint++;
				}
				if (enemyUnitInfo.type.isBuilding()) {
					enemyBuildingAroundEnemyChokepoint++;
				}
				if (enemyUnitInfo.type.canAttack() && enemyUnitInfo.type.isWorker() == false && enemyUnitInfo.type.isBuilding() == false) {
					enemyCombatUnitAroundEnemyChokepoint++;
				}
				if (enemyUnitInfo.type.canAttack() && enemyUnitInfo.type.isBuilding() == true) {
					enemyDefenseBuildingAroundEnemyChokepoint++;
				}
			}
		}
	}
}

int Strategy_CombatTaskManager::getNumberOfSameTargeting(BWAPI::Unit targetUnit)
{
	if (targetUnit == nullptr) {
		return 0;
	}
	else {
		int count = 0;

		for (auto it : attackerTargetMap) {
			if (it.second == targetUnit) {
				count++;
			}
		}
		return count;
	}

}


BWAPI::Unit Strategy_CombatTaskManager::getNearestEnemyWorker(BWAPI::Position from, int radius)
{
	BWAPI::Unit targetUnit = nullptr;
	double minDistanceToNearbyWorker = 1000000000;
	double tempDistanceToNearbyWorker = 0;
	for (auto & enemyUnit : BWAPI::Broodwar->getUnitsInRadius(from, radius)) {
		if (enemyUnit == nullptr || enemyUnit->exists() == false) continue;
		if (enemyUnit->getPlayer() == StrategyManager::Instance().enemyPlayer && enemyUnit->getType().isWorker()) {
			tempDistanceToNearbyWorker = from.getDistance(enemyUnit->getPosition());
			if (minDistanceToNearbyWorker > tempDistanceToNearbyWorker) {
				minDistanceToNearbyWorker = tempDistanceToNearbyWorker;
				targetUnit = enemyUnit;
			}
		}
	}

	return targetUnit;
}

BWAPI::Unit Strategy_CombatTaskManager::getNearestEnemyWorkerForMeleeAttack(BWAPI::Position from, int maxSameAttackerCount)
{
	BWAPI::Unit closestEnemyWorker = nullptr;

	// 가장 가까운 적 일꾼유닛 하나를 집중 공격
	double minDistanceToAttack = 1000000000;
	double tempDistanceToAttack;
	
	// 가급적 적 일꾼 1마리당 아군 저글링 3마리씩 공격하도록 한다
	for (auto & it : InformationManager::Instance().getUnitAndUnitInfoMap(InformationManager::Instance().enemyPlayer))
	{
		BWAPI::Unit enemyUnit = it.first;
		const UnitInfo & enemyUnitInfo = it.second;

		if (enemyUnitInfo.type == InformationManager::Instance().getWorkerType(InformationManager::Instance().enemyRace))
		{
			if (getNumberOfSameTargeting(enemyUnit) < maxSameAttackerCount) {
				tempDistanceToAttack = from.getDistance(enemyUnitInfo.lastPosition);
				if (tempDistanceToAttack < minDistanceToAttack) {
					minDistanceToAttack = tempDistanceToAttack;
					closestEnemyWorker = enemyUnit;
				}
			}
		}
	}

	if (closestEnemyWorker == nullptr) {
		// 그렇게 하기 힘들면, 그냥 가장 가까운 적 일꾼을 공격
		for (auto & it : InformationManager::Instance().getUnitAndUnitInfoMap(InformationManager::Instance().enemyPlayer))
		{
			BWAPI::Unit enemyUnit = it.first;
			const UnitInfo & enemyUnitInfo = it.second;

			if (enemyUnitInfo.type == InformationManager::Instance().getWorkerType(InformationManager::Instance().enemyRace))
			{
				tempDistanceToAttack = from.getDistance(enemyUnitInfo.lastPosition);
				if (tempDistanceToAttack < minDistanceToAttack) {
					minDistanceToAttack = tempDistanceToAttack;
					closestEnemyWorker = enemyUnit;
				}
			}
		}
	}

	return closestEnemyWorker;

}


BWAPI::Unit Strategy_CombatTaskManager::getNearestAndWeakestEnemyGroundCombatUnit(BWAPI::Position from)
{
	BWAPI::Unit targetUnit = nullptr;

	double minDistanceToAttack = 1000000000;
	double tempDistanceToAttack = 0;
	int minHitPointToAttack = INT_MAX;
	int tempHitPointToAttack = 0;

	// BWAPI::Broodwar->enemy()->getUnits 를 사용하면, 아군 가시거리내에 있지 않으면 조회안된다
	// 그래서, InformationManager::Instance().getUnitAndUnitInfoMap 을 사용해야 한다
	for (auto & it : InformationManager::Instance().getUnitAndUnitInfoMap(InformationManager::Instance().enemyPlayer))
	{
		BWAPI::Unit enemyUnit = it.first;
		const UnitInfo & enemyUnitInfo = it.second;

		if (enemyUnitInfo.type.canAttack() == true
			&& enemyUnitInfo.type.isWorker() == false 
			&& enemyUnitInfo.type.isBuilding() == false)
		{
			tempDistanceToAttack = from.getDistance(enemyUnitInfo.lastPosition);
			if (tempDistanceToAttack < minDistanceToAttack) {
				minDistanceToAttack = tempDistanceToAttack;

				targetUnit = enemyUnit;
			}
			else if (tempDistanceToAttack == minDistanceToAttack) {
				tempHitPointToAttack = enemyUnitInfo.lastHealth + enemyUnitInfo.lastShields;
				if (tempHitPointToAttack < minHitPointToAttack) {
					minHitPointToAttack = tempHitPointToAttack;

					targetUnit = enemyUnit;
				}
			}
		}
	}


	if (targetUnit == nullptr || targetUnit->exists() == false || targetUnit->getHitPoints() == 0 || targetUnit->isVisible() == false) {
		for (auto & enemyUnit : BWAPI::Broodwar->enemy()->getUnits())
		{
			if (enemyUnit == nullptr || enemyUnit->exists() == false) continue;
			if (enemyUnit->getType().canAttack() == true
				&& enemyUnit->getType().isWorker() == false
				&& enemyUnit->getType().isBuilding() == false)
			{
				tempDistanceToAttack = from.getDistance(enemyUnit->getPosition());
				if (tempDistanceToAttack < minDistanceToAttack) {
					minDistanceToAttack = tempDistanceToAttack;

					targetUnit = enemyUnit;
				}
				else if (tempDistanceToAttack == minDistanceToAttack) {
					tempHitPointToAttack = enemyUnit->getHitPoints() + enemyUnit->getShields();
					if (tempHitPointToAttack < minHitPointToAttack) {
						minHitPointToAttack = tempHitPointToAttack;

						targetUnit = enemyUnit;
					}
				}
			}
		}
	}

	return targetUnit;
}

BWAPI::Position Strategy_CombatTaskManager::getNearestEnemyUnitToGroundAttack(BWAPI::Position from)
{
	BWAPI::Position targetPosition = BWAPI::Positions::None;

	// 가장 가까운 적 공격유닛 하나씩 집중 공격
	double minDistanceToAttack = 1000000000;
	double tempDistanceToAttack = 0;
	int minHitPointToAttack = INT_MAX;
	int tempHitPointToAttack = 0;

	// BWAPI::Broodwar->enemy()->getUnits 를 사용하면, 아군 가시거리내에 있지 않으면 조회안된다
	// 그래서, InformationManager::Instance().getUnitAndUnitInfoMap 을 사용해야 한다
	for (auto & it : InformationManager::Instance().getUnitAndUnitInfoMap(InformationManager::Instance().enemyPlayer))
	{
		BWAPI::Unit enemyUnit = it.first;
		const UnitInfo & enemyUnitInfo = it.second;

		if (enemyUnitInfo.type.isFlyer() == false)
		{
			// 건물이 공중에 떴으면 패스
			if (enemyUnit != nullptr && enemyUnit->exists() && enemyUnit->isFlying() == true) {
				continue;
			}

			tempDistanceToAttack = from.getDistance(enemyUnitInfo.lastPosition);
			if (tempDistanceToAttack < minDistanceToAttack) {
				minDistanceToAttack = tempDistanceToAttack;

				targetPosition = enemyUnitInfo.lastPosition;
			}
			else if (tempDistanceToAttack == minDistanceToAttack) {
				tempHitPointToAttack = enemyUnitInfo.lastHealth + enemyUnitInfo.lastShields;
				if (tempHitPointToAttack < minHitPointToAttack) {
					minHitPointToAttack = tempHitPointToAttack;

					targetPosition = enemyUnitInfo.lastPosition;
				}
			}
		}
	}

	return targetPosition;
}

bool Strategy_CombatTaskManager::isThereHealthyFriendUnitAround(BWAPI::Position from, int radius)
{
bool result = false;
for (auto & closeUnit : BWAPI::Broodwar->getUnitsInRadius(from, radius)) {
	if (closeUnit->getPlayer() == StrategyManager::Instance().selfPlayer
		&& closeUnit->getHitPoints() > 10)
	{
		result = true;
		break;
	}
}

return result;
}


BWAPI::Position Strategy_CombatTaskManager::getFarthestMineralPosition(BWAPI::Position from, BWTA::BaseLocation* baselocation)
{
	BWAPI::Position targetPosition;

	double maxDistance = 0;
	double tempDistance = 0;
	for (auto & mineral : baselocation->getStaticMinerals()) {

		tempDistance = from.getDistance(mineral->getInitialPosition());
		if (maxDistance < tempDistance) {
			maxDistance = tempDistance;
			targetPosition = mineral->getInitialPosition();
		}
	}

	return targetPosition;
}


bool Strategy_CombatTaskManager::isAllMineralExplored(BWTA::BaseLocation* baselocation)
{
	bool isAllMineralExplored = true;
	for (auto & mineral : baselocation->getStaticMinerals()) {
		if (BWAPI::Broodwar->isExplored(mineral->getTilePosition()) == false) {
			isAllMineralExplored = false;
		}
	}

	return isAllMineralExplored;
}

BWAPI::Unit Strategy_CombatTaskManager::getEnemyUnitAroundEnemyChokepointClosestToEnemyFirstExpansionLocation()
{
	BWAPI::Unit targetUnit = nullptr;

	if (StrategyManager::Instance().enemyFirstChokepoint != nullptr) {

		double minDistance = 1000000000;
		double tempDistance = 0;

		for (auto & it : InformationManager::Instance().getUnitAndUnitInfoMap(StrategyManager::Instance().enemyPlayer)) {
			BWAPI::Unit enemyUnit = it.first;
			UnitInfo & enemyUnitInfo = it.second;

			if (enemyUnitInfo.lastHealth == 0) {
				continue;
			}

			if (enemyUnitInfo.lastPosition.getDistance(StrategyManager::Instance().enemyFirstChokepoint->getCenter()) < 4 * TILE_SIZE)
			{
				tempDistance = enemyUnitInfo.lastPosition.getDistance(StrategyManager::Instance().enemyFirstExpansionBaseLocation->getPosition());
				if (minDistance > tempDistance) {
					minDistance = tempDistance;
					targetUnit = enemyUnitInfo.unit;
				}
			}
		}
	}

	return targetUnit;

}

BWAPI::Unit Strategy_CombatTaskManager::getMostUrgentEnemyUnit()
{
	BWAPI::Unit mostUrgentTarget = nullptr;

	int minPriority = 10000;
	int tempPriority = 0;

	for (auto & it : InformationManager::Instance().getUnitAndUnitInfoMap(StrategyManager::Instance().enemyPlayer)) {
		BWAPI::Unit enemyUnit = it.first;
		UnitInfo & enemyUnitInfo = it.second;

		if (enemyUnitInfo.lastHealth == 0) {
			continue;
		}

		if (enemyUnit != nullptr && enemyUnit->exists() && enemyUnit->getHitPoints() > 0 && enemyUnit->isVisible()) {

			if (BWTA::getRegion(enemyUnit->getPosition()) == BWTA::getRegion(StrategyManager::Instance().enemyMainBaseLocation->getPosition())
				|| BWTA::getRegion(enemyUnit->getPosition()) == BWTA::getRegion(StrategyManager::Instance().enemyFirstExpansionBaseLocation->getPosition()))
			{
				tempPriority = 10;

				if (enemyUnit->getType() == BWAPI::UnitTypes::Protoss_Photon_Cannon) {
					if (enemyUnit->isCompleted()) {
						if (enemyUnit->getHitPoints() < 30) {
							tempPriority = 1;
						}
						else {
							tempPriority = 9;
						}
					}
					else {
						tempPriority = 1;
					}
				}
				else if (enemyUnit->getType() == BWAPI::UnitTypes::Protoss_Forge){
					if (enemyUnit->isCompleted()) {
						tempPriority = 7;
					}
					else {
						tempPriority = 4;
					}
				}
				else if (enemyUnit->getType() == BWAPI::UnitTypes::Protoss_Pylon){
					if (enemyUnit->isCompleted()) {
						if (enemyUnit->getHitPoints() < 30) {
							tempPriority = 1;
						}
						else {
							tempPriority = 3;
						}
					}
					else {
						tempPriority = 5;
					}
				}
				else if (enemyUnit->getType() == BWAPI::UnitTypes::Protoss_Shield_Battery){
					tempPriority = 6;
				}
				else if (enemyUnit->getType() == BWAPI::UnitTypes::Protoss_Gateway){
					tempPriority = 8;
				}

				else if (enemyUnit->getType() == BWAPI::UnitTypes::Terran_SCV){
					if (enemyUnit->isConstructing()) {
						tempPriority = 1;
					}
				}
				else if (enemyUnit->getType() == BWAPI::UnitTypes::Terran_Supply_Depot){
					if (enemyUnit->isCompleted()) {
						tempPriority = 3;
					}
					else {
						tempPriority = 5;
					}
				}
				else if (enemyUnit->getType() == BWAPI::UnitTypes::Terran_Bunker){
					if (enemyUnit->isCompleted()) {
						tempPriority = 9;
					}
					else {
						tempPriority = 4;
					}
				}
				else if (enemyUnit->getType() == BWAPI::UnitTypes::Terran_Barracks){
					tempPriority = 8;
				}

				else if (enemyUnit->getType() == BWAPI::UnitTypes::Zerg_Creep_Colony){
					if (enemyUnit->isCompleted()) {
						tempPriority = 5;
					}
					else {
						tempPriority = 2;
					}
				}
				else if (enemyUnit->getType() == BWAPI::UnitTypes::Zerg_Sunken_Colony){
					if (enemyUnit->isCompleted()) {
						tempPriority = 7;
					}
					else {
						tempPriority = 1;
					}
				}
				else if (enemyUnit->getType() == BWAPI::UnitTypes::Zerg_Spawning_Pool){
					tempPriority = 9;
				}

				if (minPriority > tempPriority) {
					minPriority = tempPriority;
					mostUrgentTarget = enemyUnit;
				}
			}
		}
	}

	return mostUrgentTarget;
}

bool Strategy_CombatTaskManager::isImpossibleToWinTheCombat()
{
	bool isImpossibleToWin = false;

	int dangerousUnitCount = 0;

	for (auto & it : InformationManager::Instance().getUnitAndUnitInfoMap(StrategyManager::Instance().enemyPlayer)) {
		BWAPI::Unit enemyUnit = it.first;
		UnitInfo & enemyUnitInfo = it.second;

		if (enemyUnitInfo.lastHealth == 0) {
			continue;
		}

		if (enemyUnitInfo.completed == true && enemyUnitInfo.lastHealth > 0) {

			if (enemyUnitInfo.type.canAttack() && enemyUnitInfo.type.isWorker() == false) {
				dangerousUnitCount++;
			}

			if (enemyUnitInfo.type == BWAPI::UnitTypes::Terran_Vulture
				|| enemyUnitInfo.type == BWAPI::UnitTypes::Terran_Siege_Tank_Tank_Mode
				|| enemyUnitInfo.type == BWAPI::UnitTypes::Protoss_Dragoon
				|| enemyUnitInfo.type == BWAPI::UnitTypes::Zerg_Hydralisk)
			{
				dangerousUnitCount+=3;
			}

			if (enemyUnitInfo.type == BWAPI::UnitTypes::Protoss_Photon_Cannon
				|| enemyUnitInfo.type == BWAPI::UnitTypes::Zerg_Sunken_Colony)
			{
				dangerousUnitCount+=10;
			}

		}
	}

	if (dangerousUnitCount >= 10) {
		isImpossibleToWin = true;
	}

	return isImpossibleToWin;
}

bool Strategy_CombatTaskManager::isEasyToKillEnemyCombatUnitsWithZergling()
{
	Squad* currentSquad = &StrategyManager::Instance().mainCombatZerglingSquad;

	bool isEnemyHasLittleCombatUnit = true;
	if (enemyMarineCount > (int)(currentSquad->unitset.size() / 3)
		|| enemyZealotCount > (int)(currentSquad->unitset.size() / 4)
		|| enemyZerglingCount > (int)(currentSquad->unitset.size()))
	{
		isEnemyHasLittleCombatUnit = false;
	}

	return isEnemyHasLittleCombatUnit;
}


bool Strategy_CombatTaskManager::isTimeToStartAttack() 
{
	int necessaryNumberOfZergling = 12;
	int necessaryNumberOfHydralisk = 12;
	int necessaryNumberOfLurker = 4;
	int necessaryNumberOfUltralisk = 0;
	int necessaryNumberOfQueen = 1;
	int necessaryNumberOfDefiler = 1;

	// 공격 전략에 따라 
	if (StrategyManager::Instance().myCurrentCombatStrategy == CombatStrategy::Zerg_Combat_4Drone_Zergling_Rush) 
	{
		return true;
	}

	if (StrategyManager::Instance().myCurrentCombatStrategy == CombatStrategy::Zerg_Combat_Front_Ground_Rush) 
	{
		if (StrategyManager::Instance().myCurrentBuildStrategy == BuildStrategy::Zerg_Build_Zergling_Only) {
			necessaryNumberOfZergling = 20;
			necessaryNumberOfHydralisk = 0;
			necessaryNumberOfLurker = 0;
			necessaryNumberOfUltralisk = 0;
			necessaryNumberOfQueen = 0;
			necessaryNumberOfDefiler = 0;
		}
		else if (StrategyManager::Instance().myCurrentBuildStrategy == BuildStrategy::Zerg_Build_Zergling_Hydralisk) {
			necessaryNumberOfZergling = 20;
			necessaryNumberOfHydralisk = 16;
			necessaryNumberOfLurker = 0;
			necessaryNumberOfUltralisk = 0;
			necessaryNumberOfQueen = 0;
			necessaryNumberOfDefiler = 0;
		}
		else if (StrategyManager::Instance().myCurrentBuildStrategy == BuildStrategy::Zerg_Build_Zergling_Hydralisk_Defiler) {
			necessaryNumberOfZergling = 20;
			necessaryNumberOfHydralisk = 24;
			necessaryNumberOfLurker = 0;
			necessaryNumberOfUltralisk = 0;
			necessaryNumberOfQueen = 0;
			necessaryNumberOfDefiler = 2;
		}
		else if (StrategyManager::Instance().myCurrentBuildStrategy == BuildStrategy::Zerg_Build_Zergling_Hydralisk_Lurker) {
			necessaryNumberOfZergling = 20;
			necessaryNumberOfHydralisk = 16;
			necessaryNumberOfLurker = 4;
			necessaryNumberOfUltralisk = 0;
			necessaryNumberOfQueen = 0;
			necessaryNumberOfDefiler = 0;
		}
		else if (StrategyManager::Instance().myCurrentBuildStrategy == BuildStrategy::Zerg_Build_Zergling_Hydralisk_Lurker_Defiler) {
			necessaryNumberOfZergling = 20;
			necessaryNumberOfHydralisk = 24;
			necessaryNumberOfLurker = 8;
			necessaryNumberOfUltralisk = 0;
			necessaryNumberOfQueen = 0;
			necessaryNumberOfDefiler = 2;
		}
		else if (StrategyManager::Instance().myCurrentBuildStrategy == BuildStrategy::Zerg_Build_Zergling_Lurker_Defiler) {
			necessaryNumberOfZergling = 32;
			necessaryNumberOfHydralisk = 0;
			necessaryNumberOfLurker = 8;
			necessaryNumberOfUltralisk = 0;
			necessaryNumberOfQueen = 0;
			necessaryNumberOfDefiler = 2;
		}
		else if (StrategyManager::Instance().myCurrentBuildStrategy == BuildStrategy::Zerg_Build_Zergling_Lurker_Mutalisk) {
			necessaryNumberOfZergling = 20;
			necessaryNumberOfHydralisk = 0;
			necessaryNumberOfLurker = 8;
			necessaryNumberOfUltralisk = 0;
			necessaryNumberOfQueen = 0;
			necessaryNumberOfDefiler = 0;
		}
		else {
			necessaryNumberOfZergling = 20;
			necessaryNumberOfHydralisk = 24;
			necessaryNumberOfLurker = 8;
			necessaryNumberOfUltralisk = 0;
			necessaryNumberOfQueen = 0;
			necessaryNumberOfDefiler = 0;
		}

	}
	else if (StrategyManager::Instance().myCurrentCombatStrategy == CombatStrategy::Zerg_Combat_Front_Defense_Mutalisk_BackRush) 
	{
		necessaryNumberOfZergling = 20;
		necessaryNumberOfHydralisk = 16;
		necessaryNumberOfLurker = 4;
		necessaryNumberOfUltralisk = 0;
		necessaryNumberOfQueen = 0;
		necessaryNumberOfDefiler = 0;
	}

	// 유닛 종류별로 최소 숫자 이상 있으면
	if ((int)(StrategyManager::Instance().mainCombatZerglingSquad.unitset.size()) >= necessaryNumberOfZergling
		&& (int)(StrategyManager::Instance().mainCombatHydraliskSquad.unitset.size()) >= necessaryNumberOfHydralisk
		&& (int)(StrategyManager::Instance().mainCombatLurkerSquad.unitset.size()) >= necessaryNumberOfLurker
		&& (int)(StrategyManager::Instance().mainCombatUltraliskSquad.unitset.size()) >= necessaryNumberOfHydralisk
		&& (int)(StrategyManager::Instance().mainCombatQueenSquad.unitset.size()) >= necessaryNumberOfQueen
		&& (int)(StrategyManager::Instance().mainCombatDefilerSquad.unitset.size()) >= necessaryNumberOfDefiler)
	{

		if (necessaryNumberOfQueen > 0) {
			bool isQueenHasEnoughEnergy = false;
			for (auto & unit : BWAPI::Broodwar->self()->getUnits()) {
				if (unit != nullptr && unit->exists() && unit->getType() == BWAPI::UnitTypes::Zerg_Queen && unit->getEnergy() >= 100) {
					isQueenHasEnoughEnergy = true;
					return false;
					break;
				}
			}
		}

		if (necessaryNumberOfDefiler > 0) {
			bool isDefilerHasEnoughEnergy = false;
			for (auto & unit : BWAPI::Broodwar->self()->getUnits()) {
				if (unit != nullptr && unit->exists() && unit->getType() == BWAPI::UnitTypes::Zerg_Defiler && unit->getEnergy() >= 100) {
					isDefilerHasEnoughEnergy = true;
					return false;
					break;
				}
			}
		}
		return true;
	}
	else if (StrategyManager::Instance().mainCombatZerglingSquad.unitset.size()
		+ StrategyManager::Instance().mainCombatHydraliskSquad.unitset.size()
		+ StrategyManager::Instance().mainCombatLurkerSquad.unitset.size() > 30) 
	{
		return true;
	}

	return false;
}


bool Strategy_CombatTaskManager::isTimeToRetreatFromCombat()
{
	// 공격 유닛 숫자가 10 미만으로 떨어지면 후퇴
	if (StrategyManager::Instance().mainCombatZerglingSquad.unitset.size()
		+ StrategyManager::Instance().mainCombatHydraliskSquad.unitset.size()
		+ StrategyManager::Instance().mainCombatLurkerSquad.unitset.size() < 10 ) 
	{
		return true;
	}

	return false;
}


BWTA::BaseLocation* Strategy_CombatTaskManager::getWeakestEnemyBaseLocationForGroundCombatUnit()
{
	BWTA::BaseLocation* targetBaseLocation = nullptr;

	// 적 제2,제3멀티가 있으면 거기를 공격
	for (BWTA::BaseLocation * baseLocation : InformationManager::Instance().getOccupiedBaseLocations(InformationManager::Instance().enemyPlayer)) {
		if (StrategyManager::Instance().enemyMainBaseLocation != baseLocation
			&& StrategyManager::Instance().enemyFirstExpansionBaseLocation != baseLocation) {
			targetBaseLocation = baseLocation;
			break;
		}
	}

	// 적 본진과 앞마당이 있으면 앞마당을 공격
	if (targetBaseLocation == nullptr) {
		for (BWTA::BaseLocation * baseLocation : InformationManager::Instance().getOccupiedBaseLocations(InformationManager::Instance().enemyPlayer)) {
			if (StrategyManager::Instance().enemyFirstExpansionBaseLocation == baseLocation) {
				targetBaseLocation = baseLocation;
			}
		}
	}

	// 적 본진만 있으면 본진을 공격
	if (targetBaseLocation == nullptr) {
		targetBaseLocation = StrategyManager::Instance().enemyMainBaseLocation;
	}

	return targetBaseLocation;

}

int Strategy_CombatTaskManager::getMyUnitCount(BWAPI::Position from, int radius)
{
	int count = 0;
	for (auto & unit : BWAPI::Broodwar->getUnitsInRadius(from, radius)) {
		if (unit->getPlayer() == InformationManager::Instance().selfPlayer) {
			if (unit->getType().isWorker() == false) {
				count++;
			}
		}
	}
	return count;
}

BWAPI::Position Strategy_CombatTaskManager::getAssemblePositionForGroundAttack(BWAPI::Position from, BWAPI::Position to)
{
	if (from.isValid() == false || to.isValid() == false) {
		return BWAPI::Positions::None;
	}

	BWAPI::Position targetPosition = BWAPI::Positions::None;
	BWAPI::TilePosition targetTilePosition = BWAPI::TilePositions::None;

	/*
	std::list<BWTA::Chokepoint*> chokepointList = BWTA::getShortestPath2(
		BWAPI::TilePosition(StrategyManager::Instance().frontlinePosition.x / TILE_SIZE, StrategyManager::Instance().frontlinePosition.y / TILE_SIZE),
		BWAPI::TilePosition(finalTargetPosition));

	while (chokepointList.size() > 2) {
		chokepointList.pop_front();
	}
	BWTA::Chokepoint* targetChokepoint = chokepointList.front();
	targetPosition = targetChokepoint->getCenter();
	*/

	std::vector<BWAPI::TilePosition> tileVector = BWTA::getShortestPath( BWAPI::TilePosition(from), BWAPI::TilePosition(to));

	if (tileVector.size() > 60) {
		targetTilePosition = tileVector[tileVector.size() - 30];
	}
	else {
		targetTilePosition = tileVector[tileVector.size() / 2];
	}
	targetPosition = BWAPI::Position(targetTilePosition);

	return targetPosition;

}

int Strategy_CombatTaskManager::getAttractionToAttackWithMutalisk(BWTA::BaseLocation* baseLocation)
{
	if (baseLocation == nullptr) {
		return 0;
	}

	int workerCount = 0;
	int resourceDepotCount = 0;
	int buildingCount = 0;

	for (auto & it : InformationManager::Instance().getUnitAndUnitInfoMap(InformationManager::Instance().enemyPlayer)) {
		BWAPI::Unit enemyUnit = it.first;
		UnitInfo & enemyUnitInfo = it.second;

		if (enemyUnitInfo.type.isBuilding() && BWTA::getRegion(enemyUnitInfo.lastPosition) == BWTA::getRegion(baseLocation->getPosition())) {
			if (enemyUnitInfo.type.canAttack() == false) {
				buildingCount++;
			}
		}
		if (enemyUnitInfo.lastPosition.getDistance(baseLocation->getPosition()) <= 8 * TILE_SIZE) {
			if (enemyUnitInfo.type.isResourceDepot()) {
				resourceDepotCount++;
			}
			else if (enemyUnitInfo.type.isWorker()) {
				workerCount++;
			}
		}		
	}

	return workerCount + resourceDepotCount + buildingCount;
}

int Strategy_CombatTaskManager::getDifficultyToAttackWithMutalisk(BWTA::BaseLocation* baseLocation)
{
	if (baseLocation == nullptr) {
		return 10000;
	}

	// 공격 갈지 말지 판단
	bool isTooStrongThisEnemy = false;

	Squad* currentSquad = &StrategyManager::Instance().mainCombatMutaliskSquad;
	
	int defenseBuildingTurretCount = 0;
	int defenseBuildingBunkerCount = 0;
	int defenseBuildingCannonCount = 0;
	int defenseBuildingSporeCount = 0;
	int airCombatUnitMarineCount = 0;
	int airCombatUnitGoliathCount = 0;
	int airCombatUnitWraithCount = 0;
	int airCombatUnitDragoonCount = 0;
	int airCombatUnitCorsairCount = 0;
	int airCombatUnitHydraliskCount = 0;
	int airCombatUnitMutaliskCount = 0;

	for (auto & it : InformationManager::Instance().getUnitAndUnitInfoMap(InformationManager::Instance().enemyPlayer)) {
		BWAPI::Unit enemyUnit = it.first;
		UnitInfo & enemyUnitInfo = it.second;
		
		// 사정거리
		// 포톤, 터렛, 스포어콜로니 7
		// 드라군 4 + 2
		// 마린 4 + 1
		// 히드라 4 + 1
		//unit->getType().groundWeapon().maxRange
		if (enemyUnitInfo.lastPosition.getDistance(baseLocation->getPosition()) <= 8 * TILE_SIZE) {

			if (enemyUnitInfo.type == BWAPI::UnitTypes::Protoss_Photon_Cannon) {
				defenseBuildingCannonCount++;
			}
			else if (enemyUnitInfo.type == BWAPI::UnitTypes::Terran_Missile_Turret)
			{
				defenseBuildingTurretCount++;
			}
			// 벙커는 2배로 계산
			else if (enemyUnitInfo.type == BWAPI::UnitTypes::Terran_Bunker) {
				defenseBuildingBunkerCount++;
			}
			else if (enemyUnitInfo.type == BWAPI::UnitTypes::Zerg_Spore_Colony) {
				defenseBuildingSporeCount++;
			}
		}
		else if (enemyUnitInfo.lastPosition.getDistance(baseLocation->getPosition()) <= 8 * TILE_SIZE) {
			if (enemyUnitInfo.type == BWAPI::UnitTypes::Protoss_Dragoon){
				airCombatUnitGoliathCount++;
			}
			else if (enemyUnitInfo.type == BWAPI::UnitTypes::Zerg_Hydralisk){
				airCombatUnitHydraliskCount++;
			}
			else if (enemyUnitInfo.type == BWAPI::UnitTypes::Zerg_Mutalisk){
				airCombatUnitMutaliskCount++;
			}
			else if (enemyUnitInfo.type == BWAPI::UnitTypes::Terran_Marine){
				airCombatUnitMarineCount++;
			}
			else if (enemyUnitInfo.type == BWAPI::UnitTypes::Terran_Wraith){
				airCombatUnitWraithCount++;
			}
			else if (enemyUnitInfo.type == BWAPI::UnitTypes::Terran_Goliath)
			{
				airCombatUnitGoliathCount++;
			}
			else if (enemyUnitInfo.type == BWAPI::UnitTypes::Protoss_Corsair) {
				airCombatUnitCorsairCount++;
			}
		}
	}

	// TODO : 머신러닝 적용?
	// 뮤탈 8마리 - 터렛 3개
	// 뮤탈 12마리 - 터렛 4개
	if ((int)(currentSquad->unitset.size()) < 8) {
		if (defenseBuildingTurretCount > 0
			|| defenseBuildingBunkerCount > 0
			|| defenseBuildingCannonCount > 0
			|| defenseBuildingSporeCount > 0
			|| airCombatUnitMarineCount > 0
			|| airCombatUnitGoliathCount > 0
			|| airCombatUnitWraithCount > 0
			|| airCombatUnitDragoonCount > 0
			|| airCombatUnitCorsairCount > 0
			|| airCombatUnitHydraliskCount > 0
			|| airCombatUnitMutaliskCount > 0)
		{
			isTooStrongThisEnemy = true;
		}
	}
	else if ((int)(currentSquad->unitset.size()) <= 10) {
		if (defenseBuildingTurretCount > 2
			|| defenseBuildingBunkerCount > 0
			|| defenseBuildingCannonCount > 2
			|| defenseBuildingSporeCount > 2
			|| airCombatUnitMarineCount > 3
			|| airCombatUnitGoliathCount > 3
			|| airCombatUnitWraithCount > 3
			|| airCombatUnitDragoonCount > 2
			|| airCombatUnitCorsairCount > 2
			|| airCombatUnitHydraliskCount > 3
			|| airCombatUnitMutaliskCount > 4)
		{
			isTooStrongThisEnemy = true;
		}
	}
	else if ((int)(currentSquad->unitset.size()) <= 12) {
		if (defenseBuildingTurretCount > 3
			|| defenseBuildingBunkerCount > 2
			|| defenseBuildingCannonCount > 3
			|| defenseBuildingSporeCount > 3
			|| airCombatUnitMarineCount > 5
			|| airCombatUnitGoliathCount > 3
			|| airCombatUnitWraithCount > 4
			|| airCombatUnitDragoonCount > 3
			|| airCombatUnitCorsairCount > 3
			|| airCombatUnitHydraliskCount > 4
			|| airCombatUnitMutaliskCount > 6)
		{
			isTooStrongThisEnemy = true;
		}
	}
	else if ((int)(currentSquad->unitset.size()) <= 14) {
		if (defenseBuildingTurretCount > 3
			|| defenseBuildingBunkerCount > 3
			|| defenseBuildingCannonCount > 4
			|| defenseBuildingSporeCount > 3
			|| airCombatUnitMarineCount > 6
			|| airCombatUnitGoliathCount > 4
			|| airCombatUnitWraithCount > 5
			|| airCombatUnitDragoonCount > 4
			|| airCombatUnitCorsairCount > 4
			|| airCombatUnitHydraliskCount > 6
			|| airCombatUnitMutaliskCount > 8)
		{
			isTooStrongThisEnemy = true;
		}
	}
	else if ((int)(currentSquad->unitset.size()) > 14) {
		isTooStrongThisEnemy = false;
	}

	int difficulty = defenseBuildingTurretCount + defenseBuildingBunkerCount + defenseBuildingCannonCount + defenseBuildingSporeCount
		+ airCombatUnitMarineCount + airCombatUnitGoliathCount + airCombatUnitWraithCount + airCombatUnitDragoonCount
		+ airCombatUnitCorsairCount + airCombatUnitHydraliskCount + airCombatUnitMutaliskCount;

	if (isTooStrongThisEnemy) {
		return 10000;
	}
	else {
		return difficulty;
	}
}

BWTA::BaseLocation* Strategy_CombatTaskManager::getWeakestEnemyBaseLocationForMutalisk()
{
	BWTA::BaseLocation * targetBaseLocation = nullptr;

	int minDefense = 1000000000;
	int tempDefense = 0;
	for (BWTA::BaseLocation * baseLocation : InformationManager::Instance().getOccupiedBaseLocations(InformationManager::Instance().enemyPlayer)) {
		int attraction = getAttractionToAttackWithMutalisk(baseLocation);
		if (attraction > 0) {
			tempDefense = getDifficultyToAttackWithMutalisk(baseLocation);
			if (tempDefense < 10000) {
				// 가까운 적진을 공격?
				//tempDistance = currentSquad->unitset.getPosition().getDistance(baseLocation->getPosition());
				// 공격하기 쉬운 적진을 공격
				if (minDefense > tempDefense) {
					minDefense = tempDefense;
					targetBaseLocation = baseLocation;
				}
			}
		}
	}

	return targetBaseLocation;
}

BWAPI::Position Strategy_CombatTaskManager::getTargetPositionInMapToAttackWithMutalisk()
{
	BWAPI::Position targetPosition = BWAPI::Positions::None;
	int targetUnitPriority = 10000;

	int targetUnitSearchRadius = 8 * TILE_SIZE;

	// 보이는 적 유닛들 중에서 검색
	for (auto & enemyUnit : BWAPI::Broodwar->enemy()->getUnits()) {
		if (enemyUnit == nullptr || enemyUnit->exists() == false) continue;

		bool isOutOfEnemyBaseLocationUnit = true;
		for (BWTA::BaseLocation * baseLocation : InformationManager::Instance().getOccupiedBaseLocations(InformationManager::Instance().enemyPlayer)) {
			if (BWTA::getRegion(baseLocation->getPosition()) == BWTA::getRegion(enemyUnit->getPosition())) {
				isOutOfEnemyBaseLocationUnit = false;
				break;
			}
		}

		if (isOutOfEnemyBaseLocationUnit) {
			int airAttackUnitCount = 0;
			for (auto & unit : BWAPI::Broodwar->getUnitsInRadius(enemyUnit->getPosition(), targetUnitSearchRadius)) {
				if (unit->getPlayer() == InformationManager::Instance().enemyPlayer) {
					BWAPI::WeaponType weaponType = unit->getType().airWeapon();
					if (weaponType != BWAPI::WeaponTypes::None && weaponType.targetsAir()) {
						airAttackUnitCount++;
					}
				}
			}

			if (airAttackUnitCount <= 2) {

				int currentUnitPriority = (enemyUnit->getType().mineralPrice() + enemyUnit->getType().gasPrice()) * (-1);

				if (targetUnitPriority > currentUnitPriority) {
					targetUnitPriority = currentUnitPriority;
					targetPosition = enemyUnit->getPosition();
				}
			}
		}
	}

	return targetPosition;
}


void Strategy_CombatTaskManager::moveMutaliskSquad(BWAPI::Position finalTargetPosition, bool isToAttackBaseLocation)
{
	Squad* currentSquad = &StrategyManager::Instance().mainCombatMutaliskSquad;

	int minRadiusForMove = 20 * TILE_SIZE;

	BWAPI::TilePosition finalTargetTilePosition = BWAPI::TilePosition(finalTargetPosition);
	// 뮤탈이 일점사 공격할 대상
	BWAPI::Unit targetUnit = nullptr;

	// 적 지상유닛이 주로 다니는 길
	std::vector<BWAPI::TilePosition> mainGroundPath = BWTA::getShortestPath(StrategyManager::Instance().enemyMainBaseLocation->getTilePosition(),
		StrategyManager::Instance().myFirstExpansionBaseLocation->getTilePosition());
	

	// 각각의 뮤탈에게 명령 내리는 방식
	for (auto & unit : currentSquad->unitset) {

		if (unit == nullptr || unit->exists() == false || unit->getType().canAttack() == false) {
			continue;
		}

		Mission* unitMission = currentSquad->getUnitMission(unit);
		BWAPI::Position currentUnitPosition = unit->getPosition();
		BWAPI::TilePosition currentUnitTilePosition = unit->getTilePosition();

		BWAPI::Position tempPosition = BWAPI::Positions::None;
		BWAPI::Position targetPosition = BWAPI::Positions::None;

		bool hasCommanded = false;

		// 최종 목적지가 BaseLocation 인 경우, 
		if (isToAttackBaseLocation) {

			// 최종 목적지 근처의 BaseLocation 을 targetPosition 으로 삼는다
			double minDistance = 1000000000;
			double tempDistance = 0;

			int minDangerLevel = 1000000000;
			int tempDangerLevel = 0;

			for (auto & it : StrategyManager::Instance().baseLocationStatusMap) {
				BWTA::BaseLocation* baselocation = it.first;
				LocationInfo& locationInfo = it.second;

				// 적군의 점령지역이 아닌 BaseLocation
				if (it.second.locationStatus == LocationStatus::Enemy_MainBase
					|| it.second.locationStatus == LocationStatus::Enemy_Occupied)
				{
					continue;
				}

				// 적군의 앞마당이 아닌 BaseLocation
				if (baselocation == StrategyManager::Instance().enemyFirstExpansionBaseLocation) {
					continue;
				}

				// 현재 위치에서 바로 최종 목적지로 가는 것보다, BaseLocation 에서 가는 것이 더 가까운 곳 : 거리가 동일하면 문제됨
				//if (currentUnitPosition.getDistance(finalTargetPosition) < baselocation->getPosition().getDistance(finalTargetPosition)) {
				//	continue;
				//}

				// 가는 길이 적 대공유닛들에 의해 위협받지 않는 BaseLocation 
				BWAPI::TilePosition tempTilePosition = baselocation->getTilePosition();
				int tempDangerLevel = StrategyManager::Instance().confidenceMapForMutalisk->getDangerLevelToFlyer(currentUnitTilePosition, BWAPI::TilePosition(tempTilePosition));

				if (tempDangerLevel > 4000) {
					continue;
				}
				
				// 그런 곳들 중 finalTargetPosition 에서 가장 가까운 BaseLocation
				tempDistance = baselocation->getPosition().getDistance(finalTargetPosition);
				if (minDistance > tempDistance) {
					minDistance = tempDistance;
					tempPosition = baselocation->getPosition();
				}
			}

			// 그런 BaseLocation 이 있고, 현재 위치에서 바로 최종 목적지로 가는 것보다, BaseLocation 에서 가는 것이 더 가까우면 해당 BaseLocation 으로 이동
			if (tempPosition != BWAPI::Positions::None && unit->getDistance(finalTargetPosition) > tempPosition.getDistance(finalTargetPosition)) {
				targetPosition = tempPosition;
			}
			// 그런 BaseLocation 이 없다면, 적 대공유닛들에 의해 모든 경로가 위협받고 있거나, 이미 최종 목적지로부터 가장 가까운 BaseLocation 에 도착했다는 것
			else {

				tempPosition = finalTargetPosition;

				// 최종 목적지와의 거리가 가까워졌으면 targetPosition 은 최종 목적지가 된다

				// 최종 목적지와의 거리가 멀면  targetPosition 을 지도 끝 가장자리로 수정하여 지도 끝을 따라 이동하게 한다
				/*
				if (currentUnitPosition.getDistance(finalTargetPosition) > 10 * TILE_SIZE) {

					double angle = (double)(BWAPI::Broodwar->mapHeight()) / (double)(BWAPI::Broodwar->mapWidth());
					
					if (currentUnitPosition.y > angle * (double)currentUnitPosition.x) {
						if (currentUnitPosition.y < BWAPI::Broodwar->mapHeight() - angle * (double)currentUnitPosition.x) {
							//BWAPI::Broodwar->drawTextMap(currentUnitPosition.x * TILE_SIZE, currentUnitPosition.y * TILE_SIZE, "Left");
							tempPosition.x = TILE_SIZE;
						}
						else {
							//BWAPI::Broodwar->drawTextMap(currentUnitPosition.x * TILE_SIZE, currentUnitPosition.y * TILE_SIZE, "Down");
							tempPosition.y = (BWAPI::Broodwar->mapHeight() - 1) * TILE_SIZE;
						}
					}
					else {
						if (currentUnitPosition.y < BWAPI::Broodwar->mapHeight() - angle * (double)currentUnitPosition.x) {
							//BWAPI::Broodwar->drawTextMap(currentUnitPosition.x * TILE_SIZE, currentUnitPosition.y * TILE_SIZE, "Upper");
							tempPosition.y = TILE_SIZE;
						}
						else {
							//BWAPI::Broodwar->drawTextMap(currentUnitPosition.x * TILE_SIZE, currentUnitPosition.y * TILE_SIZE, "Right");
							tempPosition.x = (BWAPI::Broodwar->mapWidth() - 1) * TILE_SIZE;
						}
					}
				}
				*/

				targetPosition = tempPosition;
			}
		}
		// 최종 목적지가 BaseLocation 가 아닌 경우 (특정 유닛 혹은 건물을 공격하러 가거나,  safe position 으로 이동하는 경우) 
		else {
			targetPosition = finalTargetPosition;
		}


		// 목적지까지 가는 직선경로가 안전한지 (거의 피해없이 갈 수 있겠는지, 쉽게 이길 수 있겠는지) 체크한다
		// TODO : 현재 위치를 중심점으로 하는 원을 그려서 각도를 45도씩 바꿔보며 안전한 우회 중간목적지를 찾는다
		/*
		BWAPI::Position midPosition = targetPosition;
		int tempDangerLevel = 0;
		double theta = 0;
		double distance = 0;
		for (int i = 0; i < 100; i++) {

			if (i != 0) {
				midPosition = BWAPI::Position(targetPosition.x + rand() % (20 * TILE_SIZE) - 10 * TILE_SIZE, targetPosition.y + rand() % (20 * TILE_SIZE) - 10 * TILE_SIZE);
			}

			if (midPosition.isValid()) {
				tempDangerLevel = StrategyManager::Instance().confidenceMapForMutalisk->getDangerLevelToFlyer(currentUnitTilePosition, BWAPI::TilePosition(midPosition));
				if (tempDangerLevel < 4000) {
					targetPosition = midPosition;
					break;
				}
			}	
		}
		*/

		// 안전한 곳이 없거나
		// 목적지와 거리가 아주 가까운 경우 (사정거리 3 Tile) 이길 수 있겠는지 판단해봐서
		// 이길 수 있겠다면 싸우고, 
		// 이길 수 없겠다면 지금까지 우회 중간 목적지 중 그나마 가장 안전성이 높은 곳으로 이동한다

		// 최종목적지와 다른 Region 이면
		if (BWTA::getRegion(unit->getPosition()) != BWTA::getRegion(finalTargetPosition)) {
		//if (currentUnitPosition.getDistance(finalTargetPosition) > 7 * TILE_SIZE) {
			
			if (targetPosition != BWAPI::Positions::None) {
				currentSquad->setUnitMission(unit, Mission(MissionType::MovePoint, targetPosition));
			}
		}
		// 최종목적지와 같은 Region 이면  일점사 공격을 하게 한다
		else {
			targetUnit = getAttractiveUnitToAttackForMutalisk(unit);

			if (targetUnit != nullptr) {
				currentSquad->setUnitMission(unit, Mission(MissionType::Attack, targetUnit));
			}
			else {
				currentSquad->setUnitMission(unit, Mission(MissionType::AttackMove, targetPosition));
			}
		}
	}
}

BWAPI::Unit Strategy_CombatTaskManager::getAttractiveUnitToAttackForMutalisk(BWAPI::Unit mutalisk)
{
	if (mutalisk == nullptr) {
		return nullptr;
	}

	// 같은 리전 내에 있는, 가장 우선순위가 높은 (Priority 숫자가 작은) 유닛의 위치를 찾는다

	BWAPI::Unit targetUnit = nullptr;

	int minPriority = 1000000000;
	int tempPriority = 0;
	double minDistance = 1000000000;
	double tempDistance = 0;

	for (auto & enemyUnit : BWAPI::Broodwar->enemy()->getUnits()) {

		if (enemyUnit == nullptr || enemyUnit->exists() == false || enemyUnit->isVisible() == false || enemyUnit->getHitPoints() <= 0) {
			continue;
		}
		if (enemyUnit->getPlayer() != StrategyManager::Instance().enemyPlayer) {
			continue;
		}
		if (BWTA::getRegion(mutalisk->getPosition()) != BWTA::getRegion(enemyUnit->getPosition())) {
			continue;
		}

		// 우선순위가 높은 유닛을 먼저 공격한다
		tempPriority = getAttackPriority(enemyUnit);

		if (minPriority > tempPriority) {
			minPriority = tempPriority;
			targetUnit = enemyUnit;
		}
		else if (minPriority == tempPriority) {
			tempDistance = enemyUnit->getDistance(mainCombatMutaliskSquadCenterPosition);
			if (minDistance > tempDistance) {
				minDistance = tempDistance;
				targetUnit = enemyUnit;
			}
		}
	}

	return targetUnit;
}

BWAPI::Position Strategy_CombatTaskManager::getTargetPositionToAttackWithMutalisk()
{
	BWAPI::Position targetPosition = BWAPI::Positions::None;

	int targetUnitSearchRadius = 8 * TILE_SIZE;

	int minPriority = 1000000000;
	int tempPriority = 0;

	double minDistance = 1000000000;
	double tempDistance = 0;

	// 보이는 적 유닛들 중에서 검색
	for (auto & enemyUnit : BWAPI::Broodwar->enemy()->getUnits()) {
		if (enemyUnit == nullptr || enemyUnit->exists() == false) continue;

		// 우선순위가 높은 유닛을 먼저 공격한다
		tempPriority = getAttackPriority(enemyUnit);

		if (minPriority > tempPriority) {
			minPriority = tempPriority;
			targetPosition = enemyUnit->getPosition();
		}
		else if (minPriority == tempPriority) {
			tempDistance = enemyUnit->getDistance(mainCombatMutaliskSquadCenterPosition);
			if (minDistance > tempDistance) {
				minDistance = tempDistance;
				targetPosition = enemyUnit->getPosition();
			}
		}
	}

	return targetPosition;

}


int Strategy_CombatTaskManager::getAttackPriority(BWAPI::Unit enemyUnit)
{
	if (enemyUnit == nullptr || enemyUnit->exists() == false) return 10000;

	// 먼저 일꾼 근처 방어 건물 / 유닛
	// 사정거리
	// 포톤, 터렛, 스포어콜로니 7
	// 드라군 4 + 2
	// 마린 4 + 1
	// 히드라 4 + 1
	//unit->getType().groundWeapon().maxRange

	int currentUnitPriority = 99;

	int minDamagePerSecond = 1000000000;
	int tempDamagePerSecond = 0;

	BWAPI::TilePosition enemyUnitTilePosition = enemyUnit->getTilePosition();
	ConfidenceMapCell & enemyCell = StrategyManager::Instance().confidenceMapForMutalisk->GetCell(enemyUnitTilePosition);
	tempDamagePerSecond = enemyCell.airDamagePerSecond;

	// 건설중인 일꾼이 최우선순위
	if (enemyUnit->getType().isWorker()) {
		if (enemyUnit->isConstructing()) {
			currentUnitPriority = 1;
		}
		else {
			currentUnitPriority = 15;
		}
	}
	else if (enemyUnit->getType() == BWAPI::UnitTypes::Protoss_High_Templar
		|| enemyUnit->getType() == BWAPI::UnitTypes::Zerg_Defiler
		|| enemyUnit->getType() == BWAPI::UnitTypes::Terran_Science_Vessel)
	{
		currentUnitPriority = 0;
	}
	else if (enemyUnit->getType().isBuilding()
		&& enemyUnit->isCompleted() == false
		&& (enemyUnit->getType() == BWAPI::UnitTypes::Protoss_Forge
		|| enemyUnit->getType() == BWAPI::UnitTypes::Protoss_Photon_Cannon
		|| enemyUnit->getType() == BWAPI::UnitTypes::Protoss_Templar_Archives
		|| enemyUnit->getType() == BWAPI::UnitTypes::Protoss_Stargate
		|| enemyUnit->getType() == BWAPI::UnitTypes::Terran_Engineering_Bay
		|| enemyUnit->getType() == BWAPI::UnitTypes::Terran_Missile_Turret
		|| enemyUnit->getType() == BWAPI::UnitTypes::Terran_Bunker
		|| enemyUnit->getType() == BWAPI::UnitTypes::Terran_Starport
		|| enemyUnit->getType() == BWAPI::UnitTypes::Zerg_Creep_Colony
		|| enemyUnit->getType() == BWAPI::UnitTypes::Zerg_Evolution_Chamber
		|| enemyUnit->getType() == BWAPI::UnitTypes::Zerg_Spire
		|| enemyUnit->getType() == BWAPI::UnitTypes::Zerg_Spore_Colony)) {
		currentUnitPriority = 2;
	}
	else if (enemyUnit->getType() == BWAPI::UnitTypes::Protoss_Photon_Cannon
		|| enemyUnit->getType() == BWAPI::UnitTypes::Terran_Missile_Turret) {
		currentUnitPriority = 10;
	}
	else if (enemyUnit->getType() == BWAPI::UnitTypes::Protoss_Dragoon
		|| enemyUnit->getType() == BWAPI::UnitTypes::Zerg_Hydralisk
		|| enemyUnit->getType() == BWAPI::UnitTypes::Zerg_Mutalisk
		|| enemyUnit->getType() == BWAPI::UnitTypes::Terran_Marine
		|| enemyUnit->getType() == BWAPI::UnitTypes::Terran_Wraith
		|| enemyUnit->getType() == BWAPI::UnitTypes::Terran_Goliath) {
		currentUnitPriority = 5;
	}
	else if (enemyUnit->getType() == BWAPI::UnitTypes::Protoss_Forge
		|| enemyUnit->getType() == BWAPI::UnitTypes::Terran_Engineering_Bay
		|| enemyUnit->getType() == BWAPI::UnitTypes::Zerg_Evolution_Chamber)
	{
		currentUnitPriority = 30;
	}
	else if (enemyUnit->getType() == BWAPI::UnitTypes::Terran_Bunker
		|| enemyUnit->getType() == BWAPI::UnitTypes::Zerg_Spore_Colony) {
		currentUnitPriority = 80;
	}
	else if (enemyUnit->getType() == BWAPI::UnitTypes::Protoss_Corsair
		|| enemyUnit->getType() == BWAPI::UnitTypes::Protoss_Archon
		|| enemyUnit->getType() == BWAPI::UnitTypes::Protoss_Carrier
		|| enemyUnit->getType() == BWAPI::UnitTypes::Zerg_Devourer
		|| enemyUnit->getType() == BWAPI::UnitTypes::Terran_Battlecruiser) {
		currentUnitPriority = 80;
	}
	else if (enemyUnit->getType().isBuilding()) {
		currentUnitPriority = 90;
	}
	else {
		currentUnitPriority = 50;
	}

	// 공중 유닛을 공격할 수 있는 유닛들이 주위에 있으면 가급적 미룬다
	if (tempDamagePerSecond > 1500) {
		currentUnitPriority += 30;
	}

	return currentUnitPriority;
}


void Strategy_CombatTaskManager::swarmTest()
{
	/*
	// Swarm AI
	// 한줄로 한마리씩 이동하는 것 방지
	for (auto & unit : squad) {

		// 유닛이 사망해서 없어진 경우는 제거
		if (!unit->exists()) continue;

		BWAPI::Unitset enemyUnits;
		MapGrid::Instance().getUnitsNear(enemyUnits, unit->getPosition(), 10 * TILE_SIZE, false, true);

		// 공격이 임박한 유닛은 공격시킨다
		if (unit->isAttacking() || enemyUnits.size() > 0) {
			if (unit->canAttack()) {
				Micro::SmartAttackMove(unit, targetAttackPosition);
			}
			else {
				Micro::SmartMove(unit, targetAttackPosition);
			}
		}
		// 이동중인 유닛에 대해서
		else {
			// 유닛이 정지해있는 경우는 이동시킨다
			if (unit->getVelocityX() == 0 && unit->getVelocityY() == 0) { // isMoving() == false) { 
				if (unit->canAttack()) {
					Micro::SmartAttackMove(unit, targetAttackPosition);
				}
				else {
					Micro::SmartMove(unit, targetAttackPosition);
				}
			}
			// 유닛이 이동중이면 이동 방향을 조정한다
			else {
				BWAPI::Position unitCurrentPosition = unit->getPosition();				// pixel 단위. 현재 위치
				double unitVelocityX = unit->getVelocityX();							// pixels in frame
				double unitVelocityY = unit->getVelocityY();
				double unitVelocityAngle = std::atan2(unitVelocityY * (-1.0), unitVelocityX + 0.0001); // 라디안 단위. Y축이 거꾸로
				double unitVelocityLength = std::sqrt(unitVelocityX*unitVelocityX + unitVelocityY*unitVelocityY);

				// TODO : neighbor  는 건물이 아닌, 같은 공격유닛들 중에서 정해야한다
				// neighbor 는 반경 8 타일 로 정한다
				BWAPI::Unitset neighborUnits;
				neighborUnits = BWAPI::Broodwar->getUnitsInRadius(unitCurrentPosition, 8 * TILE_SIZE, BWAPI::Filter::IsOwned && !BWAPI::Filter::IsBuilding);
				//MapGrid::Instance().getUnitsNear(neighborUnits, unitCurrentPosition, 8 * TILE_SIZE, true, false);

				if (neighborUnits.size() == 0) continue;

				std::pair<double, double> unitNextProperPosition;

				// 지상유닛의 경우, 주위 유닛들과의 충돌을 피한다 
				// 다른 유닛들과 충돌하게 될거라면, 방향을 바꾼다
				if (true) {
					if (!unit->isFlying()) {

						std::pair<double, double> unitNextAnticipatedPosition;					// pixel 단위. 8 frame 후 위치. 

						// 주위 유닛들과 충돌하게 될거라면, 방향을 시계방향으로 30도씩 바꿔본다 (0도, 15도, -15도, 30도, -30도, ..., 90도, -90도) //, 135도, -135도, 180도)
						// 방향을 다 바꿔봐도 항상 충돌할 것이라면, 정지한다
						bool properDirectionFound = true;
						bool willCollide = false;
						double angleMultiply = 0;

						while (true) {

							// 모든 neighbor 와 충돌하지 않는다면 properDirectionFound = true 가 된다
							properDirectionFound = true;
							for (auto & neighbor : neighborUnits) {

								if (unit == neighbor
									|| neighbor->getType().isFlyer()
									|| (neighbor->getType().isBuilding() && neighbor->isFlying())) {
									continue;
								}

								//for (double i = 1; i < 8; i += 1.0) {
								double i = 8;
								unitNextAnticipatedPosition.first = unitCurrentPosition.x + unitVelocityLength * i * cos(unitVelocityAngle + (M_PI / 6.0)*angleMultiply);
								unitNextAnticipatedPosition.second = unitCurrentPosition.y - unitVelocityLength * i * sin(unitVelocityAngle + (M_PI / 6.0)*angleMultiply);

								if (unitNextAnticipatedPosition.first >= neighbor->getLeft() && unitNextAnticipatedPosition.first <= neighbor->getRight()
									&& unitNextAnticipatedPosition.second >= neighbor->getTop() && unitNextAnticipatedPosition.second <= neighbor->getBottom())
								{
									//std::cout << "Swarm move : unit " << unit->getID() << " (" << unit->getTilePosition().x << ", " << unit->getTilePosition().y 
									//	<< ") will collide with " << neighbor->getID() << " at (" << (double)(unitNextAnticipatedPosition.first / 32.0) << ", " << (double)(unitNextAnticipatedPosition.second / 32.0) << ")" << std::endl;

									willCollide = true;
									properDirectionFound = false;
									//break;
								}
								//}

								if (willCollide) {
									break;
								}
							}

							if (properDirectionFound) {
								break;
							}

							if (angleMultiply == 0) angleMultiply = 1;
							else if (angleMultiply == 1) angleMultiply = -1;
							else if (angleMultiply == -1) angleMultiply = 2;
							else if (angleMultiply == 2) angleMultiply = -2;
							else if (angleMultiply == -2) angleMultiply = 3;
							else if (angleMultiply == 3) angleMultiply = -3;
							//else if (angleMultiply == -3) angleMultiply = 4;
							//else if (angleMultiply == 4) angleMultiply = -4;
							//else if (angleMultiply == -4) angleMultiply = 5;
							//else if (angleMultiply == 5) angleMultiply = -5;
							//else if (angleMultiply == -5) angleMultiply = 6;
							//else if (angleMultiply == 6) angleMultiply = -6;
							else {
								break;
							}
						}

						// 충돌할 것 같으면 충돌을 회피할 수 있는 곳으로 이동한다
						if (willCollide == true) {
							if (properDirectionFound == true) {

								unitNextProperPosition.first = unitCurrentPosition.x + unitVelocityLength*cos(unitVelocityAngle + (M_PI / 12.0)*angleMultiply) * 24.0; // 곱하기 를 하는 이유는 너무 짧은 타겟위치면 금방 도달하니까
								unitNextProperPosition.second = unitCurrentPosition.y - unitVelocityLength*sin(unitVelocityAngle + (M_PI / 12.0)*angleMultiply) * 24.0;

								//std::cout << "Swarm move : unit " << unit->getID() << " (" << unit->getTilePosition().x << ", " << unit->getTilePosition().y << 
								//	") change Target To (" << (double)(unitNextProperPosition.first / 32.0) << ", " << (double)(unitNextProperPosition.second / 32.0) << ")" << std::endl;
								BWAPI::Broodwar->drawCircleMap(unit->getPosition(), 30, BWAPI::Colors::Orange);
								if (unit->canAttack()) {
									Micro::SmartAttackMove(unit, BWAPI::Position((int)unitNextProperPosition.first, (int)unitNextProperPosition.second));
								}
								else {
									Micro::SmartMove(unit, BWAPI::Position((int)unitNextProperPosition.first, (int)unitNextProperPosition.second));
								}
							}
							// 모든 방향으로 이동해도 다 충돌하면, 그냥 stop 한다
							else {
								//std::cout << "Swarm move : unit " << unit->getID() << " (" << unit->getTilePosition().x << ", " << unit->getTilePosition().y << 
								//	" will collide -> stop" << std::endl;
								unit->stop();
							}
						}
					}
				}

				// 주위 유닛들과 비슷한 방향 (비슷한 각도) 으로 이동하도록 조정한다
				if (false) {
					double averageVelocityX = 0;
					double averageVelocityY = 0;
					for (auto & neighbor : neighborUnits) {
						averageVelocityX += neighbor->getVelocityX();
						averageVelocityY += neighbor->getVelocityY();
					}
					averageVelocityX /= neighborUnits.size();
					averageVelocityY /= neighborUnits.size();

					unitNextProperPosition.first = unitCurrentPosition.x + unitVelocityX + averageVelocityX * 0.1;
					unitNextProperPosition.second = unitCurrentPosition.y + unitVelocityY + averageVelocityY * 0.1;
				}

				// targetAttackPosition 쪽으로 가장 앞서 나가있고 neighbor 유닛들의 무게중심 으로부터 너무 멀리 떨어진 유닛은 
				// neighbor 유닛들의 무게중심 쪽으로 이동시켜서, 다함께 몰려 가도록 한다
				if (true) {

					BWAPI::Position centerOfNeighborUnits = neighborUnits.getPosition();
					double unitDistanceToTargetAttackPosition = unit->getDistance(targetAttackPosition);

					bool isFrontier = true;
					for (auto & neighbor : neighborUnits) {
						if (neighbor->getDistance(targetAttackPosition) < unitDistanceToTargetAttackPosition) {
							isFrontier = false;
						}
					}

					// neighbor 유닛들 중에서 가장 앞서 나가있고,
					if (isFrontier) {

						// neighbor 유닛들의 무게중심 으로부터 6 타일 이상 멀리 떨어져있거나, 
						// neighborUnits 규모에 따라 neighborUnits 1~10 면 4타일, 10~20이면 6타일 정도 멀리 떨어져있으면
						double tileDistanceFromCenter = unit->getDistance(centerOfNeighborUnits) / TILE_SIZE;
						if (tileDistanceFromCenter > 6 || tileDistanceFromCenter > (neighborUnits.size() + 10.0) / 6.0) {

							// neighbor 유닛들의 무게중심 에서 unit 위치까지 그린 직선을 60도 혹은 -60도 회전한 위치로 이동시킨다
							// neighbor 유닛들의 무게중심 으로 이동시키거나, 정지시키는 방법보다는 더 나은 듯
							double unitVectorX = unit->getPosition().x - centerOfNeighborUnits.x;
							double unitVectorY = unit->getPosition().y - centerOfNeighborUnits.y;
							double unitVectorAngle = std::atan2(unitVectorY * (-1.0), unitVectorX + 0.0001); // 라디안 단위. Y축이 거꾸로
							double unitVectorLength = std::max(std::sqrt(unitVectorX*unitVectorX + unitVectorY*unitVectorY), 3.0 * TILE_SIZE);
							unitNextProperPosition.first = centerOfNeighborUnits.x + unitVectorLength*cos(unitVectorAngle + (M_PI / 3.0) * (rand() % 2 == 0 ? 1.0 : -1.0));
							unitNextProperPosition.second = centerOfNeighborUnits.y - unitVectorLength*sin(unitVectorAngle + (M_PI / 3.0) * (rand() % 2 == 0 ? 1.0 : -1.0));

							//std::cout << "Swarm move : " << unit->getType().getName() << " " << unit->getID() << " (" << unit->getTilePosition().x << ", " << unit->getTilePosition().y 
							//	<< ") is too far from centerOfNeighborUnits (" << (double)(centerOfNeighborUnits.x / 32.0) << ", " << (double)(centerOfNeighborUnits.y / 32.0)
							//	<< ") [size=" << neighborUnits.size() 
							//	<< "] so move to (" << (double)(unitNextProperPosition.first / 32.0) << ", " << (double)(unitNextProperPosition.second / 32.0) << ")" << std::endl;
							BWAPI::Broodwar->drawCircleMap(unit->getPosition(), 30, BWAPI::Colors::Yellow);

							if (unit->canAttack()) {
								Micro::SmartAttackMove(unit, BWAPI::Position((int)unitNextProperPosition.first, (int)unitNextProperPosition.second));
								//Micro::SmartAttackMove(unit, centerOfNeighborUnits);
								//unit->stop();
							}
							else {
								Micro::SmartMove(unit, BWAPI::Position((int)unitNextProperPosition.first, (int)unitNextProperPosition.second));
								//Micro::SmartMove(unit, centerOfNeighborUnits);
								//unit->stop();
							}
						}
					}
				}
			}
		}
	}
	*/
}