#include "StrategyManager.h"

using namespace MyBot;

void StrategyManager::setMyBuildStrategy(BuildStrategy newBuildStrategy)
{
	if (myCurrentBuildStrategy != newBuildStrategy) {
		myOldBuildStrategy = myCurrentBuildStrategy;
		myCurrentBuildStrategy = newBuildStrategy;

		//std::cout << "My BuildStrategy to " << myCurrentBuildStrategy << " from " << myOldBuildStrategy << " at FrameCount " << BWAPI::Broodwar->getFrameCount() << std::endl;
	}
}

void StrategyManager::setEnemyBuildStrategy(BuildStrategy newBuildStrategy)
{
	if (enemyCurrentBuildStrategy != newBuildStrategy) {
		enemyOldBuildStrategy = enemyCurrentBuildStrategy;
		enemyCurrentBuildStrategy = newBuildStrategy;

		//std::cout << "Enemy BuildStrategy to " << enemyCurrentBuildStrategy << " from " << enemyOldBuildStrategy << " at FrameCount " << BWAPI::Broodwar->getFrameCount() << std::endl;
	}
}

void StrategyManager::setMyCombatStrategy(CombatStrategy newCombatStrategy)
{
	if (myCurrentCombatStrategy != newCombatStrategy) {
		myOldCombatStrategy = myCurrentCombatStrategy;
		myCurrentCombatStrategy = newCombatStrategy;

		//std::cout << "My CombatStrategy to " << myCurrentCombatStrategy << " from " << myOldCombatStrategy << " at FrameCount " << BWAPI::Broodwar->getFrameCount() << std::endl;
	}
}

void StrategyManager::setEnemyCombatStrategy(CombatStrategy newCombatStrategy)
{
	if (enemyCurrentCombatStrategy != newCombatStrategy) {
		enemyOldCombatStrategy = enemyCurrentCombatStrategy;
		enemyCurrentCombatStrategy = newCombatStrategy;

		//std::cout << "Enemy CombatStrategy to " << enemyCurrentCombatStrategy << " from " << enemyOldCombatStrategy << " at FrameCount " << BWAPI::Broodwar->getFrameCount() << std::endl;
	}
}

bool StrategyManager::isCompletedTask(StrategicTask task)
{
	bool isCompleted = false;

	bool isThereUnit = false;
	int myUnitCountAroundEnemyBaseLocation = 0;
	int enemyUnitCountAroundEnemyBaseLocation = 0;
	std::vector<ConstructionTask> * constructionQueue = ConstructionManager::Instance().getConstructionQueue();
	BWAPI::Unitset unitset1;
	BWAPI::Unitset unitset2;
	int count = 0;

	switch (task.taskGoal) {

		// 적군 종족을 알게 되었으면, Figure_Out_Enemy_Race 클리어
		case TaskGoalType::Figure_Out_Enemy_Race:
			if (InformationManager::Instance().enemyRace != BWAPI::Races::Unknown) {
				isCompleted = true;
			}
			break;

		// 적군 enemyMainBaseLocation 를 알게 되었으면, Figure_Out_Enemy_BaseLocation 클리어
		case TaskGoalType::Figure_Out_Enemy_BaseLocation:
			if (enemyMainBaseLocation != nullptr) {
				isCompleted = true;
			}
			break;

		case TaskGoalType::Scout_Enemy_MainBaseLocation: 
			/*
			if (enemyMainBaseLocation != nullptr) {
				// GridCell 의 timeLastVisited 은 직접 유닛이 지나간 자리여야 숫자가 바뀌므로, 체크하기에 부적절하다				
				if (baseLocationStatusMap[enemyMainBaseLocation].lastVisibleTime > 0 
					&& BWAPI::Broodwar->getFrameCount() - baseLocationStatusMap[enemyMainBaseLocation].lastVisibleTime < 20 * 60 * 2)
				{
					isCompleted =  true;
				}
			}
			*/
			break;
		case TaskGoalType::Scout_Enemy_First_Expansion: 
			/*
			if (enemyFirstExpansionBaseLocation != nullptr) {
				if (baseLocationStatusMap[enemyFirstExpansionBaseLocation].lastVisibleTime > 0
					&& BWAPI::Broodwar->getFrameCount() - baseLocationStatusMap[enemyFirstExpansionBaseLocation].lastVisibleTime < 20 * 60 * 2)
				{
					isCompleted =  true;
				}
			}
			*/
			break;
		case TaskGoalType::Scout_Enemy_Chokepoint: 
			/*
			if (enemyFirstChokepoint != nullptr) {
				if (chokepointStatusMap[enemyFirstChokepoint].lastVisibleTime > 0
					&& BWAPI::Broodwar->getFrameCount() - chokepointStatusMap[enemyFirstChokepoint].lastVisibleTime < 20 * 60 * 2)
				{
					isCompleted = true;
				}
			}
			*/
			break;
		case TaskGoalType::Scout_Enemy_Other_Expansion:
			break;
		case TaskGoalType::Scout_Empty_BaseLocations:
			break;

		case TaskGoalType::Eliminate_Enemy_Player:
			break;

		case TaskGoalType::Build_Unit_By_Limit:
			
			if (task.targetUnitType == BWAPI::UnitTypes::Zerg_Creep_Colony) {
				if (BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Zerg_Creep_Colony)
					+ BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Zerg_Sunken_Colony)
					>= task.targetCount) 
				{
					isCompleted = true;
				}
			}
			else {
				if (BWAPI::Broodwar->self()->completedUnitCount(task.targetUnitType) >= task.targetCount) {
					isCompleted = true;
				}
			}

			break;
		case TaskGoalType::Build_Tech:
			if (BWAPI::Broodwar->self()->hasResearched(task.targetTechType)) {
				
				isCompleted = true;
			}
			break;
		case TaskGoalType::Build_Upgrade:
			if (BWAPI::Broodwar->self()->getUpgradeLevel(task.targetUpgradeType) >= task.targetCount) {
				
				isCompleted = true;
			}
			break;

		case TaskGoalType::Build_Expansion_On_Ground:

			for (auto & baseLocation : InformationManager::Instance().getOccupiedBaseLocations(InformationManager::Instance().selfPlayer)){
				count++;
			}
			if (count >= task.targetCount) {
				isCompleted = true;
			}
			break;
		case TaskGoalType::Build_Expansion_On_Island: 
			for (auto & baseLocation : InformationManager::Instance().getOccupiedBaseLocations(InformationManager::Instance().selfPlayer)){
				count++;
			}
			if (count >= task.targetCount) {				
				isCompleted = true;
			}
			break;

		case TaskGoalType::Attack_Enemy_BaseLocation_With_Early_Zergling_Unit:
			// enemyMainBaseLocation 주위에 적 유닛이 하나도 없고, 아군 유닛이 10개 이상 있다면 완결. 성공
			if (enemyMainBaseLocation != nullptr) {
				for (auto & unit : BWAPI::Broodwar->getUnitsInRadius(enemyMainBaseLocation->getPosition(), 4 * TILE_SIZE)) {
					if (unit->getPlayer() == selfPlayer) {
						myUnitCountAroundEnemyBaseLocation++;
					}
					else if (unit->getPlayer() == enemyPlayer && unit->isFlying() == false) {
						enemyUnitCountAroundEnemyBaseLocation++;
					}
				}
				if (enemyUnitCountAroundEnemyBaseLocation == 0 && myUnitCountAroundEnemyBaseLocation > 10) {
					isCompleted = true;
				}
			}

			// 적이 너무 강해져도 완결. 실패
			if (Strategy_CombatTaskManager::Instance().isImpossibleToWinTheCombat()) {
				isCompleted = true;
			}

			// 시간이 많이 경과해도 완결
			if (BWAPI::Broodwar->getFrameCount() > 24 * 60 * 8) {
				isCompleted = true;
			}
			break;

		case TaskGoalType::Attack_Enemy_BaseLocation_With_Ground_Unit:
		case TaskGoalType::Attack_Enemy_BaseLocation_With_Mutalisk:
			// enemyMainBaseLocation 주위에 적 유닛이 하나도 없고, 아군 유닛이 10개 이상 있다면 완결
			if (enemyMainBaseLocation != nullptr) {
				for (auto & unit : BWAPI::Broodwar->getUnitsInRadius(enemyMainBaseLocation->getPosition(), 4 * TILE_SIZE)) {
					if (unit->getPlayer() == selfPlayer) {
						myUnitCountAroundEnemyBaseLocation++;
					}
					else if (unit->getPlayer() == enemyPlayer && unit->isFlying() == false) {
						enemyUnitCountAroundEnemyBaseLocation++;
					}
				}
				if (enemyUnitCountAroundEnemyBaseLocation == 0 && myUnitCountAroundEnemyBaseLocation > 10) {
					isCompleted = true;
				}
			}
			break;

		case TaskGoalType::AttackEnemyUnits: 
			break;

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

				if (enemyUnit == task.targetUnit
					&& enemyUnitInfo.lastHealth > 0 && enemyUnitInfo.isLastPositionValid == true)
				{
					isThereUnit = true;
					isCompleted = false;
					break;
				}
			}
			if (isThereUnit == false) {
				
				isCompleted = true;
			}
			break;

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

				if (enemyUnitInfo.type == task.targetUnitType
					&& enemyUnitInfo.lastHealth > 0 && enemyUnitInfo.isLastPositionValid == true)
				{
					isThereUnit = true;
					isCompleted = false;
					break;
				}
			}
			if (isThereUnit == false) {
				
				isCompleted = true;
			}
			break;

		case TaskGoalType::Transport_Defiler_Throuth_Overlord:
			break;
		case TaskGoalType::SlaughterEnemyWorkersWithZergling: 
			break;
		case TaskGoalType::SlaughterEnemyWorkersWithLurkerDrop: 
			break;
		case TaskGoalType::Spray_Plague_On_Enemy_Buildings:
			break;
		case TaskGoalType::Spray_Plague_On_Enemy_Units: 
			break;

		case TaskGoalType::Block_And_Hold_On_ChokePoint: 
			if (BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Zerg_Zergling) >= 12
				|| BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Zerg_Hydralisk) >= 6
				|| BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Zerg_Lurker) >= 4
				|| BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Zerg_Sunken_Colony) >= 3
				|| InformationManager::Instance().getOccupiedBaseLocations(InformationManager::Instance().selfPlayer).size() >= 3) {
				isCompleted = true;
			}
			break;
		case TaskGoalType::Defense_Position_With_Zergling:
			break;

		case TaskGoalType::Defense_Position_With_SunkenColonies:
			break;
		case TaskGoalType::Burrow_On_Position:
			for (auto & unit : BWAPI::Broodwar->self()->getUnits())
			{
				if (unit == nullptr || unit->exists() == false) continue;
				if (unit->isBurrowed()
					&& unit->getDistance(task.targetPosition) < 1 * TILE_SIZE)
				{
					isCompleted = true;
				}
			}
			break;
		case TaskGoalType::Burrow_On_Empty_BaseLocation:
			break;
		case TaskGoalType::Burrow_And_Ambush_Attack_With_Lurker:
			break;
		case TaskGoalType::Attack_Enemy_Worker_In_Main_Region:
			for (auto & it : InformationManager::Instance().getUnitAndUnitInfoMap(InformationManager::Instance().enemyPlayer)) {
				BWAPI::Unit enemyUnit = it.first;
				UnitInfo & enemyUnitInfo = it.second;

				if (BWTA::getRegion(enemyUnitInfo.lastPosition) == myMainBaseLocation->getRegion()
					|| BWTA::getRegion(enemyUnitInfo.lastPosition) == myFirstExpansionBaseLocation->getRegion())
				{
					if (enemyUnitInfo.lastHealth > 0 && enemyUnitInfo.isLastPositionValid == true) {
						if (enemyUnitInfo.type.isWorker()) {
							isThereUnit = true;
							isCompleted = false;
							break;
						}
					}
				}
			}
			if (isThereUnit == false) {
				
				isCompleted = true;
			}
			break;
		case TaskGoalType::Attack_Enemy_Dangerous_Building_In_Main_Region:
			for (auto & it : InformationManager::Instance().getUnitAndUnitInfoMap(InformationManager::Instance().enemyPlayer)) {
				BWAPI::Unit enemyUnit = it.first;
				UnitInfo & enemyUnitInfo = it.second;

				if (BWTA::getRegion(enemyUnitInfo.lastPosition) == myMainBaseLocation->getRegion()
					|| BWTA::getRegion(enemyUnitInfo.lastPosition) == myFirstExpansionBaseLocation->getRegion())
				{
					if (enemyUnitInfo.lastHealth > 0 && enemyUnitInfo.isLastPositionValid == true) {
						if (enemyUnitInfo.type.isBuilding()) {
							if (enemyUnitInfo.type == BWAPI::UnitTypes::Terran_Bunker
								|| enemyUnitInfo.type == BWAPI::UnitTypes::Terran_Refinery
								|| enemyUnitInfo.type == BWAPI::UnitTypes::Protoss_Pylon
								|| enemyUnitInfo.type == BWAPI::UnitTypes::Protoss_Photon_Cannon
								|| enemyUnitInfo.type == BWAPI::UnitTypes::Protoss_Assimilator
								|| enemyUnitInfo.type == BWAPI::UnitTypes::Zerg_Extractor
								|| enemyUnitInfo.type == BWAPI::UnitTypes::Zerg_Creep_Colony
								|| enemyUnitInfo.type == BWAPI::UnitTypes::Zerg_Nydus_Canal
								|| enemyUnitInfo.type == BWAPI::UnitTypes::Zerg_Sunken_Colony)
							{
								isThereUnit = true;
								isCompleted = false;
								break;
							}
						}
					}
				}
			}
			if (isThereUnit == false) {				
				isCompleted = true;
			}
			break;
		case TaskGoalType::Attack_Enemy_Ground_Unit_In_Our_Region:
			for (auto & it : InformationManager::Instance().getUnitAndUnitInfoMap(InformationManager::Instance().enemyPlayer)) {
				BWAPI::Unit enemyUnit = it.first;
				UnitInfo & enemyUnitInfo = it.second;

				if (enemyUnitInfo.type.isWorker() == false
					&& enemyUnitInfo.type.canAttack()
					&& enemyUnitInfo.type.isFlyer() == false
					&& enemyUnitInfo.lastHealth > 0
					&& enemyUnitInfo.isLastPositionValid == true)
				{
					for (BWTA::BaseLocation* baselocation : InformationManager::Instance().getOccupiedBaseLocations(InformationManager::Instance().selfPlayer)) {
						if (baselocation->getPosition().getDistance(enemyUnitInfo.lastPosition) < 16 * TILE_SIZE) {
							isThereUnit = true;
							break;
						}
					}
				}
			}
			if (isThereUnit == false) {				
				isCompleted = true;
			}
			break;

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

				if (BWTA::getRegion(enemyUnitInfo.lastPosition) == myMainBaseLocation->getRegion()
					|| BWTA::getRegion(enemyUnitInfo.lastPosition) == myFirstExpansionBaseLocation->getRegion())
				{
					if (enemyUnitInfo.type.canAttack()
						&& enemyUnitInfo.type.isFlyer() == true
						&& enemyUnitInfo.lastHealth > 0 && enemyUnitInfo.isLastPositionValid == true)
					{
						isThereUnit = true;
						break;
					}
				}
			}
			if (isThereUnit == false) {				
				isCompleted = true;
			}
			break;

		case TaskGoalType::Move_Every_Overlord_To_MainBaseLocation: 
			if (BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Zerg_Overlord) > 0
				&& BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Zerg_Spore_Colony) > 0) 
			{
				for (auto & unit : BWAPI::Broodwar->self()->getUnits()) {
					if (unit == nullptr || unit->exists() == false) continue;
					if (unit->getType() == BWAPI::UnitTypes::Zerg_Overlord) {
						unitset1.insert(unit);
					}
					else if (unit->getType() == BWAPI::UnitTypes::Zerg_Spore_Colony) {
						unitset2.insert(unit);
					}
				}

				for (auto & overlord : unitset1) {
					for (auto & sporeColony : unitset2) {
						if (overlord->getDistance(sporeColony) > 7 * TILE_SIZE) {

							isThereUnit = true;
							return false;
						}
					}
				}
			}
			break;
	}

	return isCompleted;
}

void StrategyManager::insertTask(StrategicTask newTask)
{
	// 이미 넣어져있는 StrategicTask 가 아닐 때
	if (taskList.find(newTask) == taskList.end()) {

		// 이미 완성된 StrategicTask 가 아닐 때
		if (isCompletedTask(newTask) == false) {
			
			// Build_Unit_Another 타스크는 긴급한 것이 아니라면, 빌드큐에 1개만 있게 한다
			if (newTask.taskGoal == TaskGoalType::Build_Unit_Another) {
				if (newTask.isUrgent == true) {
					taskList.insert(newTask);
				}
				else {
					if (BuildManager::Instance().buildQueue.getItemCount(newTask.targetUnitType) == 0
						&& ConstructionManager::Instance().getConstructionQueueItemCount(newTask.targetUnitType) == 0)
					{
						taskList.insert(newTask);
					}
				}
			}
			else {
				taskList.insert(newTask);
			}

			if (isToFindError) {
				std::cout << " insertTask " << StrategicTaskUtil::getTaskGoalTypeString(newTask.taskGoal).c_str() << " ";

				if (newTask.targetUnitType != BWAPI::UnitTypes::None)
					std::cout << newTask.targetUnitType.getName() << " ";
				if (newTask.targetTechType != BWAPI::TechTypes::None)
					std::cout << newTask.targetTechType.getName() << " ";
				if (newTask.targetUpgradeType != BWAPI::UpgradeTypes::None)
					std::cout << newTask.targetUpgradeType.getName() << " ";
				if (newTask.targetPosition != BWAPI::Positions::None)
					std::cout << newTask.targetPosition.x << "," << newTask.targetPosition.y << " ";
				if (newTask.targetUnit != nullptr)
					std::cout << "ID=" << newTask.targetUnit->getID() << " ";
				if (newTask.targetCount != 0)
					std::cout << newTask.targetCount << " ";

				std::cout << std::endl;
			}
		}
	}
}

void StrategyManager::eraseTask(StrategicTask targetTask)
{
	for (auto it = taskList.begin(); it != taskList.end();) {
		if ((*it) == targetTask) {
			//std::cout << " eraseTask " << StrategicTaskUtil::getTaskGoalTypeString(targetTask.taskGoal).c_str() << std::endl;
			it = taskList.erase(it);
			return;
		}
		else {
			++it;
		}
	}
}

void StrategyManager::clearCompletedTask()
{
	for (auto it = taskList.begin(); it != taskList.end();) {
		if (isCompletedTask((*it))) {

			//std::cout << "completedTask will be erased : " << StrategicTaskUtil::toString(*it) << std::endl;

			// 완료된 타스크를 수행하던 부대 해체 목록에 추가
			switch ((*it).taskGoal) {
			case TaskGoalType::Figure_Out_Enemy_Race:
				break;
			case TaskGoalType::Figure_Out_Enemy_BaseLocation:
				break;
			case TaskGoalType::Scout_Enemy_MainBaseLocation:
				break;
			case TaskGoalType::Scout_Enemy_First_Expansion:
				break;
			case TaskGoalType::Scout_Enemy_Chokepoint:
				break;
			case TaskGoalType::Scout_Enemy_Other_Expansion:
				break;
			case TaskGoalType::Scout_Empty_BaseLocations:
				break;
			case TaskGoalType::Eliminate_Enemy_Player:
				break;

			case TaskGoalType::Build_Unit_By_Limit:
				break;
			case TaskGoalType::Build_Tech:
				break;
			case TaskGoalType::Build_Upgrade:
				break;

			case TaskGoalType::Build_Expansion_On_Ground:
				Strategy_ExpansionTaskManager::Instance().setCompleted();
				breakUpSquad(&newExpansionSetupSquad);
				break;
			case TaskGoalType::Build_Expansion_On_Island:
				break;

				
			case TaskGoalType::Attack_Enemy_BaseLocation_With_Early_Zergling_Unit:
				breakUpSquad(&mainCombatZerglingSquad);
				break;
			case TaskGoalType::Attack_Enemy_BaseLocation_With_Ground_Unit:
				break;
			case TaskGoalType::Attack_Enemy_BaseLocation_With_Mutalisk:
				break;
			case TaskGoalType::AttackEnemyUnits:
				break;
			case TaskGoalType::Kill_Unit_Urgently:
				break;

			case TaskGoalType::Kill_Some_UnitType:
				break;

			case TaskGoalType::Transport_Defiler_Throuth_Overlord:
				break;
			case TaskGoalType::SlaughterEnemyWorkersWithZergling:
				break;
			case TaskGoalType::SlaughterEnemyWorkersWithLurkerDrop:
				break;
			case TaskGoalType::Spray_Plague_On_Enemy_Buildings:
				break;
			case TaskGoalType::Spray_Plague_On_Enemy_Units:
				break;

			case TaskGoalType::Block_And_Hold_On_ChokePoint:
				breakUpSquad(&mainChokepointBlockingSquad);
				break;
			case TaskGoalType::Defense_Position_With_Zergling:
				break;

			case TaskGoalType::Defense_Position_With_SunkenColonies:
				break;
			case TaskGoalType::Burrow_On_Empty_BaseLocation:
				breakUpSquad(&multiObstructLurkerSquad);
				break;
			case TaskGoalType::Burrow_And_Ambush_Attack_With_Lurker:
				breakUpSquad(&ambushCombatLurkerSquad);
				break;
			case TaskGoalType::Attack_Enemy_Worker_In_Main_Region:
				breakUpSquad(&mainBaseClearSquad1);
				break;
			case TaskGoalType::Attack_Enemy_Dangerous_Building_In_Main_Region:
				breakUpSquad(&mainBaseClearSquad2);
				break;
			case TaskGoalType::Attack_Enemy_Ground_Unit_In_Our_Region:
				breakUpSquad(&mainBaseDefenseSquad);
				break;
			case TaskGoalType::Kill_Enemy_Air_Unit_In_Main_Region:
				break;

			case TaskGoalType::Move_Every_Overlord_To_MainBaseLocation:
				break;
			}

			// 완료된 타스크 삭제
			it = taskList.erase(it);
		}
		else {
			++it;
		}
	}
}

void StrategyManager::setInitialSquad()
{
	reservedSquad.squadName = "reservedSquad";		///< 예비 부대

	mainCombatZerglingSquad.squadName = "mainCombatZerglingSquad";		///< 메인 공격 저글링 부대 : 본진 / 앞마당 공격
	mainCombatHydraliskSquad.squadName = "mainCombatHydraliskSquad";		///< 메인 공격 히드라 부대 : 본진 / 앞마당 공격
	mainCombatLurkerSquad.squadName = "mainCombatLurkerSquad";		///< 메인 공격 럴커 부대 : 본진 / 앞마당 공격
	mainCombatMutaliskSquad.squadName = "mainCombatMutaliskSquad";		///< 메인 공격 뮤탈/디바우어러/가디언 부대 : 본진 / 앞마당 공격
	mainCombatScourgeSquad.squadName = "mainCombatScourgeSquad";		///< 메인 공격 스커지 부대 : 본진 / 앞마당 공격
	mainCombatOverlordSquad.squadName = "mainCombatOverlordSquad";		///< 메인 공격 오버로드 부대 : 오버로드
	mainCombatQueenSquad.squadName = "mainCombatQueenSquad";			///< 메인 공격 퀸 부대 : 퀸
	mainCombatDefilerSquad.squadName = "mainCombatDefilerSquad";		///< 메인 공격 디파일러 부대 : 디파일러, 먹이용 저글링, 전담 오버로드들
	mainCombatUltraliskSquad.squadName = "mainCombatUltraliskSquad";		///< 메인 공격 울트라 부대 : 본진 / 앞마당 공격

	reinforceMainCombatMutaliskSquad.squadName = "reinforceMainCombatMutaliskSquad";		///< 메인 공격 뮤탈 증원 부대

	subCombatSquad.squadName = "subCombatSquad";				///< 서브 공격 부대 : 멀티 공격
	subCombatOverlordSquad.squadName = "subCombatOverlordSquad";		///< 서브 공격 지원 부대 : 오버로드. 

	subCombatReinforceSquad.squadName = "subCombatReinforceSquad";		///< 서브 증원 부대

	dropAttackSquad.squadName = "dropAttackSquad";				///< 드랍부대 : 히드라, 럴커. 전담 오버로드
	ambushCombatLurkerSquad.squadName = "ambushCombatLurkerSquad";		///< 매복부대 : 럴커. 전담 오버로드

	mainBaseDefenseSquad.squadName = "mainBaseDefenseSquad";				///< 주력 방어 부대 : 히드라, 뮤탈

	mainBaseClearSquad1.squadName = "mainBaseClearSquad1";			///< 본진에 들어온 적 정찰유닛, 벙커 등을 긴급공격하는 부대 : 저글링, 일꾼 등
	mainBaseClearSquad2.squadName = "mainBaseClearSquad2";			///< 본진에 들어온 적 정찰유닛, 벙커 등을 긴급공격하는 부대 : 저글링, 일꾼 등
	mainChokepointBlockingSquad.squadName = "mainChokepointBlockingSquad";
	mainBasePatrolSquad.squadName = "mainBasePatrolSquad";			///< 본진 주변 패트롤 부대 : 저글링, 스커지, 오버로드

	firstExpansionDefenseSquad.squadName = "firstExpansionDefenseSquad";	///< 앞마당 방어 부대 : 히드라, 뮤탈
	firstExpansionPatrolSquad.squadName = "firstExpansionPatrolSquad";	///< 앞마당 주변 패트롤 부대 : 저글링, 스커지, 오버로드

	secondExpansionDefenseSquad.squadName = "secondExpansionDefenseSquad";	///< 멀티 방어 부대 : 히드라, 뮤탈
	secondExpansionPatrolSquad.squadName = "secondExpansionPatrolSquad";	///< 멀티 주변 패트롤 부대 : 저글링, 스커지, 오버로드

	scoutDroneSquad.squadName = "scoutDroneSquad";				///< 정찰 드론 부대 : 초반에만 운용. 지상 정찰. 
	scoutOverlordSquad1.squadName = "scoutOverlordSquad1";			///< 정찰 오버로드 부대 : 초반에만 운용. 공중 정찰. 
	scoutOverlordSquad2.squadName = "scoutOverlordSquad2";			///< 정찰 오버로드 부대 : 초반에만 운용. 공중 정찰. 
	scoutOverlordSquad3.squadName = "scoutOverlordSquad3";			///< 정찰 오버로드 부대 : 초반에만 운용. 공중 정찰. 
	scoutOverlordSquad4.squadName = "scoutOverlordSquad4";			///< 정찰 오버로드 부대 : 초반에만 운용. 공중 정찰. 
	scoutOverlordSquad5.squadName = "scoutOverlordSquad5";			///< 정찰 오버로드 부대 : 초반에만 운용. 공중 정찰. 
	scoutZerglingSquad.squadName = "scoutZerglingSquad";			///< 정찰 저글링 부대 : 지상 정찰
	scoutScourgeSquad.squadName = "scoutScourgeSquad";			///< 정찰 스커지 부대 : 공중 정찰
	scoutQueenSquad.squadName = "scoutQueenSquad";				///< 정찰 퀸 부대 : 공중 정찰
	
	multiObstructZerglingSquad.squadName = "multiObstructZerglingSquad";				///< 멀티 체크 및 견제 부대 : 저글링 -> 버로우
	multiObstructLurkerSquad.squadName = "multiObstructLurkerSquad";				///< 멀티 체크 및 견제 부대 : 저글링 -> 버로우

	newExpansionSetupSquad.squadName = "newExpansionSetupSquad";

	allMySquadList.insert(&reservedSquad);				///< 예비 부대

	allMySquadList.insert(&mainCombatZerglingSquad);		///< 메인 공격 저글링 부대 : 본진 / 앞마당 공격
	allMySquadList.insert(&mainCombatHydraliskSquad);		///< 메인 공격 히드라 부대 : 본진 / 앞마당 공격
	allMySquadList.insert(&mainCombatLurkerSquad);		///< 메인 공격 럴커 부대 : 본진 / 앞마당 공격
	allMySquadList.insert(&mainCombatMutaliskSquad);		///< 메인 공격 뮤탈/디바우어러/가디언 부대 : 본진 / 앞마당 공격
	allMySquadList.insert(&mainCombatScourgeSquad);		///< 메인 공격 스커지 부대 : 본진 / 앞마당 공격
	allMySquadList.insert(&mainCombatOverlordSquad);		///< 메인 공격 오버로드 부대 : 오버로드
	allMySquadList.insert(&mainCombatQueenSquad);			///< 메인 공격 퀸 부대 : 퀸
	allMySquadList.insert(&mainCombatDefilerSquad);		///< 메인 공격 디파일러 부대 : 디파일러, 먹이용 저글링, 전담 오버로드들
	allMySquadList.insert(&mainCombatUltraliskSquad);		///< 메인 공격 울트라 부대 : 본진 / 앞마당 공격

	allMySquadList.insert(&reinforceMainCombatMutaliskSquad);		///< 메인 공격 뮤탈 증원 부대

	allMySquadList.insert(&subCombatSquad);				///< 서브 공격 부대 : 멀티 공격
	allMySquadList.insert(&subCombatOverlordSquad);		///< 서브 공격 지원 부대 : 오버로드. 

	allMySquadList.insert(&subCombatReinforceSquad);		///< 서브 증원 부대

	allMySquadList.insert(&dropAttackSquad);				///< 드랍부대 : 히드라, 럴커. 전담 오버로드
	allMySquadList.insert(&ambushCombatLurkerSquad);		///< 매복부대 : 럴커. 전담 오버로드

	allMySquadList.insert(&mainBaseDefenseSquad);				///< 주력 방어 부대 : 히드라, 뮤탈

	allMySquadList.insert(&mainBaseClearSquad1);			///< 본진에 들어온 적 정찰유닛 을 긴급공격하는 부대 : 저글링, 일꾼 등
	allMySquadList.insert(&mainBaseClearSquad2);			///< 본진에 들어온 적 벙커 등을 긴급공격하는 부대 : 저글링, 일꾼 등
	allMySquadList.insert(&mainChokepointBlockingSquad);	///< 본진에 들어온 적 벙커 등을 긴급공격하는 부대 : 저글링, 일꾼 등
	allMySquadList.insert(&mainBasePatrolSquad);			///< 본진 주변 패트롤 부대 : 저글링, 스커지, 오버로드

	allMySquadList.insert(&firstExpansionDefenseSquad);	///< 앞마당 방어 부대 : 히드라, 뮤탈
	allMySquadList.insert(&firstExpansionPatrolSquad);	///< 앞마당 주변 패트롤 부대 : 저글링, 스커지, 오버로드

	allMySquadList.insert(&secondExpansionDefenseSquad);	///< 멀티 방어 부대 : 히드라, 뮤탈
	allMySquadList.insert(&secondExpansionPatrolSquad);	///< 멀티 주변 패트롤 부대 : 저글링, 스커지, 오버로드

	allMySquadList.insert(&scoutDroneSquad);				///< 정찰 드론 부대 : 초반에만 운용. 지상 정찰. 
	allMySquadList.insert(&scoutOverlordSquad1);			///< 정찰 오버로드 부대 : 초반에만 운용. 공중 정찰. 
	allMySquadList.insert(&scoutOverlordSquad2);			///< 정찰 오버로드 부대 : 초반에만 운용. 공중 정찰. 
	allMySquadList.insert(&scoutOverlordSquad3);			///< 정찰 오버로드 부대 : 초반에만 운용. 공중 정찰. 
	allMySquadList.insert(&scoutOverlordSquad4);			///< 정찰 오버로드 부대 : 초반에만 운용. 공중 정찰. 
	allMySquadList.insert(&scoutOverlordSquad5);			///< 정찰 오버로드 부대 : 초반에만 운용. 공중 정찰. 
	allMySquadList.insert(&scoutZerglingSquad);			///< 정찰 저글링 부대 : 지상 정찰
	allMySquadList.insert(&scoutScourgeSquad);			///< 정찰 스커지 부대 : 공중 정찰
	allMySquadList.insert(&scoutQueenSquad);				///< 정찰 퀸 부대 : 공중 정찰
	allMySquadList.insert(&multiObstructZerglingSquad);				///< 멀티 체크 및 견제 부대 : 저글링 -> 버로우
	allMySquadList.insert(&multiObstructLurkerSquad);				///< 멀티 체크 및 견제 부대 : 저글링 -> 버로우

}


std::string StrategyManager::getSquadInfo(Squad* squad)
{
	std::string str = "no squad";
	if (squad == nullptr) {
		return str;
	}

	str += squad->squadName;
	str += " ";
	str += std::to_string(squad->unitset.size());
}

void StrategyManager::moveUnitBetweenSquad(Squad* from, Squad* to, BWAPI::UnitType unitType, int count, BWAPI::Unit unit)
{
	for (auto it = from->unitset.begin(); it != from->unitset.end() && count > 0; ) {
		if (*it == nullptr) {
			++it;
		}
		else if (unitType != BWAPI::UnitTypes::None && (*it)->getType() != unitType) {
			++it;
		}
		else {
			// 특정 유닛 지정시
			if (unit != nullptr) {
				if ((*it) == unit)
				{
					to->addUnit(*it);
					it = from->removeUnit(it);
					//to->unitset.insert(*it);
					//it = from->unitset.erase(it);
					count--;
				}
				else {
					++it;
				}
			}
			// 특정 유닛 미지정시
			else {
				// TODO : 그중에서도 HitPoint 가 많이 남아있는 유닛을 선택
				//if ((*it)->getHitPoints() >= (*it)->getType().maxHitPoints() * 0.2) {
				if ((*it)->getHitPoints() >= (*it)->getType().maxHitPoints() * 0.2) {
					to->addUnit(*it);
					it = from->removeUnit(it);
					//to->unitset.insert(*it);
					//it = from->unitset.erase(it);
					count--;
				}
				else {
					++it;
				}
			}
		}
	}
}



void StrategyManager::breakUpSquad(Squad* targetSquad)
{
	for (auto it = targetSquad->unitset.begin(); it != targetSquad->unitset.end();) {

		if (*it == nullptr || (*it)->exists() == false || (*it)->getHitPoints() <= 0) {
			it = targetSquad->unitset.erase(it);
		}
		else {
			reservedSquad.unitset.insert(*it);

			if ((*it)->getType().isWorker()) {
				WorkerManager::Instance().setIdleWorker(*it);
			}
			/*
			if ((*it)->isAttackFrame() || (*it)->isAttacking()) {

			}
			else {
				if ((*it)->canStop()){
					(*it)->stop();
				}
			}
			*/

			it = targetSquad->unitset.erase(it);
		}
	}

	targetSquad->unitMissionMap.clear();
	targetSquad->unitTargetMap.clear();
}

/*
void StrategyManager::breakUpSquadsThatHasNoTask()
{
	for (Squad* squad : allMySquadList) {

		if (squad == &reservedSquad) continue;

		if (squad->unitset.size() > 0) {

			if (squad->assignedTaskList.size() == 0) {

				breakUpSquad(squad);
			}
		}
	}
}
*/

int StrategyManager::getUnitNumberInSquad(Squad* targetSquad, BWAPI::UnitType targetUnitType)
{
	if (targetUnitType == BWAPI::UnitTypes::None) {
		return targetSquad->unitset.size();
	}
	else {
		int count = 0;

		for (auto & unit : targetSquad->unitset) {
			if (unit->getType() == targetUnitType) {
				count++;
			}
		}
		return count;
	}
}


void StrategyManager::clearDeadUnitInSquad()
{
	for (Squad* squad : allMySquadList) {

		for (auto it = squad->unitset.begin(); it != squad->unitset.end();) {
			if (*it == nullptr || (*it)->exists() == false || (*it)->getHitPoints() <= 0) {
				it = squad->unitset.erase(it);
			}
			else {
				++it;
			}
		}
	}
}


void StrategyManager::cancelScoutDroneSquad()
{
	isToScoutWithWorker = false;
	if (scoutDroneSquad.unitset.size() > 0) {
		for (auto & unit : scoutDroneSquad.unitset) {
			WorkerManager::Instance().setIdleWorker(unit);
			CommandUtil::move(unit, myMainBaseLocation->getPosition());
		}
		breakUpSquad(&scoutDroneSquad);
	}
}

void StrategyManager::cancelScoutOverlordSquad()
{
	isToScoutWithOverlord = false;
	if (scoutOverlordSquad1.unitset.size() > 0) {
		breakUpSquad(&scoutOverlordSquad1);
	}
	if (scoutOverlordSquad2.unitset.size() > 0) {
		breakUpSquad(&scoutOverlordSquad2);
	}
	if (scoutOverlordSquad3.unitset.size() > 0) {
		breakUpSquad(&scoutOverlordSquad3);
	}
	if (scoutOverlordSquad4.unitset.size() > 0) {
		breakUpSquad(&scoutOverlordSquad4);
	}
	if (scoutOverlordSquad5.unitset.size() > 0) {
		breakUpSquad(&scoutOverlordSquad5);
	}
}

int StrategyManager::getMainCombatUnitCount()
{
	return BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Zerg_Zergling)
		+ BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Zerg_Hydralisk)
		+ BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Zerg_Mutalisk)
		+ BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Zerg_Ultralisk)
		+ BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Zerg_Devourer)
		+ BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Zerg_Guardian);
}


/*
void StrategyManager::executeUnitControl()
{
	for (auto & unit : BWAPI::Broodwar->self()->getUnits())
	{
		if (unit == nullptr || unit->exists() == false) continue;
		// 건물 및 일꾼은 제외
		if (unit->getType().isBuilding() || unit->getType().isWorker()) continue;

		auto & it = unitMissionMap.find(unit);
		if (it != unitMissionMap.end())
		{
			if (unitMissionMap[unit].missionType == MissionType::Move)
			{
				std::cout << "m";

				if (unitMissionMap[unit].targetUnit != nullptr) {
					if (unitMissionMap[unit].targetUnit->isVisible() == false
						|| unit->getDistance(unitMissionMap[unit].targetUnit->getPosition()) < 3 * TILE_SIZE) {
						setUnitMission(unit, Mission(MissionType::Wait, nullptr, BWAPI::Positions::None));
					}
					else {
						CommandUtil::rightClick(unit, unitMissionMap[unit].targetUnit);
					}
				}
				else if (unitMissionMap[unit].targetPosition != BWAPI::Positions::None) {

					//std::cout << unit->getType().getName() << " " << unit->getID()
					//<< " missionType " << unitMissionMap[unit].missionType
					//<< " currentPosition " << unit->getTilePosition().x << "," << unit->getTilePosition().y
					//<< " targetPosition " << unitMissionMap[unit].position.x / 32 << "," << unitMissionMap[unit].position.y / 32
					//<< " targetIsExplored " << BWAPI::Broodwar->isExplored(BWAPI::TilePosition(unitMissionMap[unit].position))
					//<< " distance " << unit->getDistance(unitMissionMap[unit].position)
					//<< std::endl;

					// getDistance는 Position 단위. 5타일 거리 내로 접근하면 임무완료
					if (unit->getDistance(unitMissionMap[unit].targetPosition) < 5 * TILE_SIZE) {
						setUnitMission(unit, Mission(MissionType::Wait, nullptr, BWAPI::Positions::None));
					}
					else {
						CommandUtil::move(unit, unitMissionMap[unit].targetPosition);
					}
				}
			}
			else if (unitMissionMap[unit].missionType == MissionType::Attack)
			{
				std::cout << "k";

				if (unitMissionMap[unit].targetUnit != nullptr) {
					if (unitMissionMap[unit].targetUnit->isVisible()) {
						CommandUtil::attackUnit(unit, unitMissionMap[unit].targetUnit);
					}
					else if (unitMissionMap[unit].targetPosition != BWAPI::Positions::None) {
						CommandUtil::move(unit, unitMissionMap[unit].targetPosition);
					}
				}
				else if (unitMissionMap[unit].targetPosition != BWAPI::Positions::None) {
					CommandUtil::attackMove(unit, unitMissionMap[unit].targetPosition);
				}
			}
			else if (unitMissionMap[unit].missionType == MissionType::AttackMove)
			{
				std::cout << "l";

				if (unitMissionMap[unit].targetUnit != nullptr) {
					if (unitMissionMap[unit].targetUnit->isVisible()) {
						CommandUtil::attackMove(unit, unitMissionMap[unit].targetUnit->getPosition());
					}
					else if (unitMissionMap[unit].targetPosition != BWAPI::Positions::None) {
						CommandUtil::attackMove(unit, unitMissionMap[unit].targetPosition);
					}
				}
				else if (unitMissionMap[unit].targetPosition != BWAPI::Positions::None) {
					CommandUtil::attackMove(unit, unitMissionMap[unit].targetPosition);
				}
			}
			else if (unitMissionMap[unit].missionType == MissionType::MoveRoundAboutWay)
			{
				std::cout << "r";
				if (unit->isIdle()) {
					if (unit->getDistance(BWAPI::Position(0, 0)) > 8 * TILE_SIZE) {
						CommandUtil::attackMove(unit, BWAPI::Position(0, 0));
					}
					else {
						if (unitMissionMap[unit].targetUnit != nullptr) {
							if (unitMissionMap[unit].targetUnit->isVisible()) {
								CommandUtil::attackMove(unit, unitMissionMap[unit].targetUnit->getPosition());
							}
							else if (unitMissionMap[unit].targetPosition != BWAPI::Positions::None) {
								CommandUtil::attackMove(unit, unitMissionMap[unit].targetPosition);
							}
						}
						else if (unitMissionMap[unit].targetPosition != BWAPI::Positions::None) {
							CommandUtil::attackMove(unit, unitMissionMap[unit].targetPosition);
						}
					}
				}

			}
			else if (unitMissionMap[unit].missionType == MissionType::Parasite)
			{
				std::cout << "x";

				if (unitMissionMap[unit].targetUnit != nullptr) {
					if (unitMissionMap[unit].targetUnit->isVisible()) {
						unit->useTech(BWAPI::TechTypes::Parasite, unitMissionMap[unit].targetUnit);
					}
					else if (unitMissionMap[unit].targetPosition != BWAPI::Positions::None) {
						CommandUtil::move(unit, unitMissionMap[unit].targetPosition);
					}
				}
				else if (unitMissionMap[unit].targetPosition != BWAPI::Positions::None) {
					CommandUtil::move(unit, unitMissionMap[unit].targetPosition);
				}
			}
			else if (unitMissionMap[unit].missionType == MissionType::Ensnare)
			{
				std::cout << "x";

				if (unitMissionMap[unit].targetUnit != nullptr) {
					if (unitMissionMap[unit].targetUnit->isVisible()) {
						unit->useTech(BWAPI::TechTypes::Ensnare, unitMissionMap[unit].targetUnit);
					}
					else if (unitMissionMap[unit].targetPosition != BWAPI::Positions::None) {
						CommandUtil::move(unit, unitMissionMap[unit].targetPosition);
					}
				}
				else if (unitMissionMap[unit].targetPosition != BWAPI::Positions::None) {
					CommandUtil::move(unit, unitMissionMap[unit].targetPosition);
				}
			}
			else if (unitMissionMap[unit].missionType == MissionType::Spawn_Broodlings)
			{
				std::cout << "x";

				if (unitMissionMap[unit].targetUnit != nullptr) {
					if (unitMissionMap[unit].targetUnit->isVisible()) {
						unit->useTech(BWAPI::TechTypes::Spawn_Broodlings, unitMissionMap[unit].targetUnit);
					}
					else if (unitMissionMap[unit].targetPosition != BWAPI::Positions::None) {
						CommandUtil::move(unit, unitMissionMap[unit].targetPosition);
					}
				}
				else if (unitMissionMap[unit].targetPosition != BWAPI::Positions::None) {
					CommandUtil::move(unit, unitMissionMap[unit].targetPosition);
				}
			}
			else if (unitMissionMap[unit].missionType == MissionType::Attack_BaseLocation)
			{
				if (unitMissionMap[unit].targetPosition != BWAPI::Positions::None) {

					if (unit->canAttack()) {
						CommandUtil::attackMove(unit, unitMissionMap[unit].targetPosition);
					}
					else {
						CommandUtil::move(unit, unitMissionMap[unit].targetPosition);
					}

					if (InformationManager::Instance().enemyRace == BWAPI::Races::Protoss)
					{
					}
					else if (InformationManager::Instance().enemyRace == BWAPI::Races::Terran)
					{

					}
					else if (InformationManager::Instance().enemyRace == BWAPI::Races::Zerg)
					{
					}
				}
			}
			else if (unitMissionMap[unit].missionType == MissionType::Burrow)
			{
				if (unit->canBurrow()) {
					unit->burrow();
				}
			}
			else if (unitMissionMap[unit].missionType == MissionType::Eliminate_BaseLocation) {
				if (unitMissionMap[unit].targetPosition != BWAPI::Positions::None) {
					CommandUtil::attackMove(unit, unitMissionMap[unit].targetPosition);
				}
			}

		}
	}
}
*/

BWAPI::Position StrategyManager::getSafePosition(BWAPI::Position desiredPosition)
{
	// targetPosition 근처, 바다 혹은 길이 없는 곳, 언덕 위 등 안전한 곳 중에서도 가장 가까운 곳

	double closestDistance = 1000000000;
	double tempDistance;

	BWAPI::Position targetPosition = desiredPosition;

	// 안전한 아군 점령지역
	for (BWTA::BaseLocation * baseLocation : InformationManager::Instance().getOccupiedBaseLocations(InformationManager::Instance().selfPlayer)) {
		tempDistance = desiredPosition.getDistance(baseLocation->getPosition());
		if (tempDistance < closestDistance) {
			closestDistance = tempDistance;
			targetPosition = BWAPI::Position(baseLocation->getPosition());
		}
	}

	// 안전한 섬
	if (closestDistance > 30 * TILE_SIZE) {
		closestDistance = 1000000000;
		for (auto & safePosition : *StrategyManager::Instance().safeLevel9Positions){
			tempDistance = desiredPosition.getDistance(BWAPI::Position(safePosition));
			if (tempDistance < closestDistance) {
				closestDistance = tempDistance;
				targetPosition = BWAPI::Position(safePosition);
			}
		}
	}

	// 안전한 곳이 너무 멀리 있으면 덜 안전한 곳이라도 일단 가까운 곳 중에서 찾아서 이동
	if (closestDistance > 30 * TILE_SIZE) {
		closestDistance = 1000000000;
		for (auto & safePosition : *StrategyManager::Instance().safeLevel5Positions){
			tempDistance = desiredPosition.getDistance(BWAPI::Position(safePosition));
			if (tempDistance < closestDistance) {
				closestDistance = tempDistance;
				targetPosition = BWAPI::Position(safePosition);
			}
		}
	}

	return BWAPI::Position(targetPosition);
}

BWAPI::Position StrategyManager::getSafePositionForUnit(BWAPI::Unit unit, BWAPI::Position desiredPosition)
{
	// desiredPosition 이 BWAPI::Positions::None 일 경우, unit 현재 위치 근처에서 가장 안전한 곳
	if (desiredPosition == BWAPI::Positions::None) {
		desiredPosition = unit->getPosition();
	}

// TODO : unit 의 현재 위치에서 desiredPosition 으로 가는데 있어 가장 안전한 곳

return getSafePosition(desiredPosition);
}

bool StrategyManager::isPossibleToGo(BWTA::BaseLocation* from, BWTA::BaseLocation* to)
{
	std::cout << " isPossible? ";

	bool isPossible = false;
	if (from == nullptr || to == nullptr) {
		return isPossible;
	}

	// TODO : theMap.GetPath 를 쓰면 에러발생
	/*
	int length = -1;
	const CPPath & Path = theMap.GetPath(from->getPosition(), to->getPosition(), &length);
	if (Path.size() == 0) {
	std::cout << " isIsland or same area ";
	return false;
	}
	else {
	bool isPossible = true;
	if (!Path.empty())						// no ChokePoint between a and b:
	{
	const ChokePoint * cpPrevious = nullptr;
	for (const ChokePoint * cp : Path)
	{
	if (cp->Blocked() || cp->IsPseudo()) {
	isPossible = false;
	std::cout << " isImpossible ";
	break;
	}
	}
	}
	return isPossible;
	}
	*/

	return isPossible;
}

void StrategyManager::clearFakeMineral() {

	if (isFakeMineralCleared == true) return;

	BWAPI::TilePosition fakeMineralPosition = getNearestFakeMineralPosition(myMainBaseLocation->getTilePosition());

	if (fakeMineralPosition == BWAPI::TilePositions::None) {
		isFakeMineralCleared = true;
		std::cout << "There is no fake mineral" << std::endl;
	}
	else {

		if (fakeMineralClearWorker == nullptr || fakeMineralClearWorker->exists() == false || fakeMineralClearWorker->getHitPoints() <= 0) {
			BWAPI::Unit unit = WorkerManager::Instance().getClosestMineralWorkerTo(BWAPI::Position(fakeMineralPosition.x * TILE_SIZE, fakeMineralPosition.y * TILE_SIZE));
			if (unit != nullptr) {
				fakeMineralClearWorker = unit;
				WorkerManager::Instance().setScoutWorker(unit);
			}
		}

		if (fakeMineralClearWorker != nullptr) {

			if (BWAPI::Broodwar->isVisible(fakeMineralPosition) == false || BWAPI::Broodwar->isExplored(fakeMineralPosition) == false ) {
				CommandUtil::move(fakeMineralClearWorker, BWAPI::Position(fakeMineralPosition.x * TILE_SIZE, fakeMineralPosition.y * TILE_SIZE));
			}
			else {

				BWAPI::Unit fakeMineral = nullptr;
				for (auto & unit : BWAPI::Broodwar->getUnitsOnTile(fakeMineralPosition)) {

					//std::cout << unit->getID() << " " << unit->getType().getName().c_str() << std::endl;
					if (unit->getType() == BWAPI::UnitTypes::Resource_Mineral_Field ||
						unit->getType() == BWAPI::UnitTypes::Resource_Mineral_Field_Type_2 || 
						unit->getType() == BWAPI::UnitTypes::Resource_Mineral_Field_Type_3) 
					{
						fakeMineral = unit;
					}
				}

				if (fakeMineral != nullptr) {
					if (fakeMineral->exists()) {
						if (fakeMineralClearWorker->isIdle()) {
							CommandUtil::rightClick(fakeMineralClearWorker, fakeMineral);
						}
					}
				}
				else {
					WorkerManager::Instance().setIdleWorker(fakeMineralClearWorker);
					fakeMineralClearWorker = nullptr;
					isFakeMineralCleared = true;
					std::cout << "isFakeMineralCleared" << std::endl;
				}
			}
		}
	}
}

BWAPI::TilePosition StrategyManager::getNearestFakeMineralPosition(BWAPI::TilePosition fromPosition){

	BWAPI::Unit targetMineral = nullptr;

	if (BWAPI::Broodwar->mapFileName().find("Destination") != std::string::npos) {
		
		BWAPI::TilePosition m1(40,120);
		BWAPI::TilePosition m2(54,6);

		if (fromPosition.getDistance(m1) < fromPosition.getDistance(m2)) {
			return m1;
		}
		else {
			return m2;
		}
	}
	else if (BWAPI::Broodwar->mapFileName().find("Heartbreak") != std::string::npos) {
		BWAPI::TilePosition m1(119, 3);
		BWAPI::TilePosition m2(6, 91);

		if (fromPosition.getDistance(m1) < fromPosition.getDistance(m2)) {
			return m1;
		}
		else {
			return m2;
		}
	}

	return BWAPI::TilePositions::None;
}

BWAPI::TilePosition StrategyManager::getNearestBaseLocationPositionBlockedByFakeMineral(BWAPI::TilePosition fromPosition){

	BWAPI::Unit targetMineral = nullptr;

	if (BWAPI::Broodwar->mapFileName().find("Destination") != std::string::npos) {

		BWAPI::TilePosition m1(86, 6);
		BWAPI::TilePosition m2(6, 119);

		if (fromPosition.getDistance(m1) < fromPosition.getDistance(m2)) {
			return m1;
		}
		else {
			return m2;
		}
	}
	else if (BWAPI::Broodwar->mapFileName().find("Heartbreak") != std::string::npos) {
		BWAPI::TilePosition m1(105, 6);
		BWAPI::TilePosition m2(19, 87);

		if (fromPosition.getDistance(m1) < fromPosition.getDistance(m2)) {
			return m1;
		}
		else {
			return m2;
		}
	}

	return BWAPI::TilePositions::None;
}

BWTA::BaseLocation* StrategyManager::getMyNextExpansionLocation(TaskGoalType taskGoalType)
{
	BWTA::BaseLocation* targetBaseLocation = nullptr;

	int dangerousLevel = 0;

	// 적 본진 위치를 아직 모르는 게임 초반에는, 적 본진 위치를 임시적으로 랜덤하게 정함. 
	// 결국 getMyNextExpansionLocation 결과는 아군 본진 앞마당이 선택될 것임
	BWTA::BaseLocation* enemyMainBaseLocationTemporal = nullptr;
	if (enemyMainBaseLocation == nullptr) {
		while (enemyMainBaseLocationTemporal == nullptr) {
			for (BWTA::BaseLocation* startLocation : BWTA::getStartLocations()) {
				if (rand() % 4 == 0) {
					enemyMainBaseLocationTemporal = startLocation;
					break;
				}
			}
		}
	}

	// TODO : 아군 본진으로부터의 거리, 적군 본진으로부터의 거리 뿐만 아니라
	// 아군 멀티로부터의 거리, 적군 멀티로부터의 거리 등 고려
	int minDangerousLevel = INT_MAX;
	for (auto & it : baseLocationStatusMap) {
		BWTA::BaseLocation* baseLocation = it.first;
		LocationInfo& locationInfo = it.second;

		//std::cout << " check ExpansionLocation " << baseLocation->getTilePosition().x << "," << baseLocation->getTilePosition().y;

		if (it.second.locationStatus == LocationStatus::My_MainBase
			|| it.second.locationStatus == LocationStatus::My_Occupied
			|| it.second.locationStatus == LocationStatus::Enemy_MainBase
			|| it.second.locationStatus == LocationStatus::Enemy_Occupied)
		{
			continue;
		}

		// 섬 지역 / 육상경로 있는 지역
		if (taskGoalType == TaskGoalType::Build_Expansion_On_Island
			&& baseLocation->isIsland() == false) {
			continue;
		}

		if (taskGoalType == TaskGoalType::Build_Expansion_On_Ground
			&& baseLocation->isIsland() == true) {
			continue;
		}

		if (baseLocation->isIsland()) {
			dangerousLevel = (int)(baseLocation->getAirDistance(myMainBaseLocation) - baseLocation->getAirDistance(enemyMainBaseLocation));
		}
		else {
			dangerousLevel = (int)(baseLocation->getGroundDistance(myMainBaseLocation) - baseLocation->getGroundDistance(enemyMainBaseLocation));
		}

		// 미네랄 멀티 지역은 비선호
		if (baseLocation->isMineralOnly()) {
			dangerousLevel += 10000;
			//dangerousLevel += 10 * TILE_SIZE;
		}

		// 지도 정 가운데 지역은 비선호
		if (std::abs(baseLocation->getTilePosition().x - BWAPI::Broodwar->mapWidth()) < 10
			&& std::abs(baseLocation->getTilePosition().x - BWAPI::Broodwar->mapWidth()) < 10) {
			dangerousLevel += 10000;
			//dangerousLevel += 10 * TILE_SIZE;
		}

		// fakeMineral에 막혀있는 경우, 해당 지역은 다음에 확장
		if (isFakeMineralCleared == false) {
			BWAPI::TilePosition fakeBaseLocationPosition = getNearestBaseLocationPositionBlockedByFakeMineral(myMainBaseLocation->getTilePosition());
			if (fakeBaseLocationPosition == baseLocation->getTilePosition()) {
				dangerousLevel += 100000;
			}
		}

		locationInfo.lastDangerousLevel = dangerousLevel;

		if (minDangerousLevel > dangerousLevel) {
			minDangerousLevel = dangerousLevel;
			targetBaseLocation = baseLocation;
		}
	}

	return targetBaseLocation;

}

std::vector<BWTA::BaseLocation*> getEnemyNextExpansionLocaion()
{
	std::vector<BWTA::BaseLocation*> baseList;
	return baseList;
}

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

		// 오버로드는 느리기 때문에, 유닛이나 건물이 보이기만해도 도망가야 한다
		if (enemyUnitInfo.type == BWAPI::UnitTypes::Protoss_Dragoon
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Protoss_Archon
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Protoss_Corsair
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Protoss_Carrier
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Terran_Marine
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Terran_Medic
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Terran_Firebat
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Terran_Goliath
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Terran_Wraith
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Terran_Valkyrie
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Terran_Battlecruiser
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Terran_Science_Vessel
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Terran_Missile_Turret
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Zerg_Spore_Colony
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Zerg_Hydralisk
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Zerg_Mutalisk
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Zerg_Scourge

			|| enemyUnitInfo.type == BWAPI::UnitTypes::Terran_Barracks
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Terran_Refinery
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Terran_Factory
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Terran_Engineering_Bay
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Terran_Bunker
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Terran_Missile_Turret
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Terran_Starport
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Protoss_Cybernetics_Core
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Protoss_Forge
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Protoss_Photon_Cannon
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Protoss_Assimilator
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Protoss_Citadel_of_Adun
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Protoss_Templar_Archives
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Protoss_Stargate
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Zerg_Hydralisk_Den
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Zerg_Lair
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Zerg_Evolution_Chamber
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Zerg_Spire)
		{
			return true;
		}
	}
	return false;
}

bool StrategyManager::isVeryDangerousToScoutWithDrone()
{
	if (BWAPI::Broodwar->getFrameCount() > 24 * 60 * 5) {
		return true;
	}

	for (auto & it : InformationManager::Instance().getUnitAndUnitInfoMap(InformationManager::Instance().enemyPlayer)) {
		BWAPI::Unit enemyUnit = it.first;
		UnitInfo & enemyUnitInfo = it.second;
		
		// TODO : 건설 시작 후 건설 완료될 시점 쯤 해서 위험해진다
		// TODO : 유닛 훈련 시작하면 완료될 시점 쯤 해서 위험해진다
		if (enemyUnitInfo.type == BWAPI::UnitTypes::Protoss_Zealot
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Protoss_Dark_Templar
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Protoss_Dark_Templar
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Protoss_Archon
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Protoss_Scout
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Protoss_Carrier
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Terran_Marine
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Terran_Firebat
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Terran_Vulture
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Terran_Siege_Tank_Siege_Mode
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Terran_Siege_Tank_Tank_Mode
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Terran_Goliath
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Terran_Wraith
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Terran_Valkyrie
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Terran_Battlecruiser
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Zerg_Hydralisk
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Zerg_Mutalisk
			
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Terran_Bunker
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Terran_Factory
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Terran_Starport
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Protoss_Photon_Cannon
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Zerg_Hydralisk_Den
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Zerg_Spire)
		{
			return true;
		}

		if (enemyUnitInfo.type == BWAPI::UnitTypes::Terran_Barracks
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Protoss_Gateway)
		{
			if (enemyUnit != nullptr && enemyUnit->isCompleted() == true) {
				return true;
			}
		}		
	}
	return false;
}

bool StrategyManager::isVeryDangerousToEveryOverlord()
{
	if (BWAPI::Broodwar->getFrameCount() > 24 * 60 * 10) {
		return true;
	}

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

		if (enemyUnitInfo.type == BWAPI::UnitTypes::Protoss_Stargate
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Protoss_Corsair
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Protoss_Scout
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Protoss_Carrier
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Terran_Starport
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Terran_Wraith
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Terran_Valkyrie
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Terran_Battlecruiser
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Terran_Science_Vessel
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Zerg_Spire
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Zerg_Mutalisk
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Zerg_Devourer
			|| enemyUnitInfo.type == BWAPI::UnitTypes::Zerg_Scourge)
		{
			return true;
		}
	}
	return false;

}

void StrategyManager::updateSafePositions() {

	// TODO : 완전한 바다 한가운데는 아니지만
	// 상대방이 점령한 지역이 아닌 지역은 바다 처럼 안전한 지역이라고 볼수 있고, 이를 기준으로 safeLevel9Positions 를 계산할 수 있음

	auto & theMap = BWEM::Map::Instance();

	BWAPI::WalkPosition w;
	BWAPI::WalkPosition wt;
	for (int y = 0; y < theMap.WalkSize().y; ++y) {
		for (int x = 0; x < theMap.WalkSize().x; ++x)
		{
			w.x = x;
			w.y = y;

			const MiniTile & miniTile = theMap.GetMiniTile(w, check_t::no_check);

			if (miniTile.Sea()) {

				safeLevel1Positions->insert(w);
				//std::cout << "safeLevel1Positions insert " << w.x << "," << w.y << std::endl;

				// 반경 4 TilePosition (16 WalkPosition) 이내에 Walkable  가 5% 미만이면 조금 안전한 타일. 언덕 경계면.. 일단 여기로 대피하는 것도 좋은 선택
				int numWalkable = 0;
				for (int dy = -16; dy <= 16; dy++) {
					for (int dx = -16; dx <= 16; dx++) {

						wt.x = x + dx;
						wt.y = y + dy;

						if (theMap.Valid(wt)) {

							if (wt.getDistance(w) < 4 * TILE_SIZE) {
								if (theMap.GetMiniTile(wt).Walkable()){
									numWalkable++;
								}
							}

						}
					}
					if (numWalkable > 32 * 32 * 0.05) break;

				}

				if (numWalkable <= 32 * 32 * 0.05) {
					safeLevel5Positions->insert(w);
					//std::cout << "safeLevel5Positions insert " << w.x << "," << w.y << std::endl;
					//const BWEM::Area * nearestArea = theMap.GetNearestArea(BWAPI::TilePosition(WalkPosition(x, y)));
				}

				// 반경 7 TilePosition (28 WalkPosition) 이내에 Walkable  가 5% 미만이면 아주 안전한 타일. 바다 한가운데.. 
				numWalkable = 0;
				for (int dy = -28; dy <= 28; dy++) {
					for (int dx = -28; dx <= 28; dx++) {

						wt.x = x + dx;
						wt.y = y + dy;

						if (theMap.Valid(wt)) {

							if (wt.getDistance(w) < 7 * TILE_SIZE) {
								if (theMap.GetMiniTile(wt).Walkable()){
									numWalkable++;
								}
							}

						}
					}
					if (numWalkable > 28 * 28 * 0.05) break;

				}

				if (numWalkable <= 28 * 28 * 0.05) {
					safeLevel9Positions->insert(w);
					//std::cout << "safeLevel9Positions insert " << w.x << "," << w.y << std::endl;
					//const BWEM::Area * nearestArea = theMap.GetNearestArea(BWAPI::TilePosition(WalkPosition(x, y)));
				}

			}
		}
	}

}


void StrategyManager::loadGameRecordList()
{
	// 과거의 게임에서 bwapi-data\write 폴더에 기록했던 파일은 대회 서버가 bwapi-data\read 폴더로 옮겨놓습니다
	// 따라서, 파일 로딩은 bwapi-data\read 폴더로부터 하시면 됩니다
	std::string gameRecordFileName = Config::Files::ReadDirectory + Config::Files::LogFilename;

	FILE *file;
	errno_t err;

	if ((err = fopen_s(&file, gameRecordFileName.c_str(), "r")) != 0)
	{
		std::cout << "loadGameRecord failed. Could not open file :" << gameRecordFileName.c_str() << std::endl;
	}
	else
	{
		std::cout << "loadGameRecordList from file: " << gameRecordFileName.c_str() << std::endl;

		char line[4096];
		while (fgets(line, sizeof line, file) != nullptr)
		{
			std::stringstream ss(line);

			GameRecord tempGameRecord;
			ss >> tempGameRecord.mapName;
			ss >> tempGameRecord.myName;
			ss >> tempGameRecord.myRace;
			//ss >> tempGameRecord.myBuildStrategy;
			//ss >> tempGameRecord.myCombatStrategy;
			ss >> tempGameRecord.myWinCount;
			ss >> tempGameRecord.myLoseCount;
			ss >> tempGameRecord.enemyName;
			ss >> tempGameRecord.enemyRace;
			ss >> tempGameRecord.enemyRealRace;
			//ss >> tempGameRecord.enemyBuildStrategy;
			//ss >> tempGameRecord.enemyCombatStrategy;
			ss >> tempGameRecord.gameStartedTime;
			ss >> tempGameRecord.gameFrameCount;

			gameRecordList.push_back(tempGameRecord);
		}

		fclose(file);

		//std::cout << "loadGameRecordList resultSize: " << gameRecordList.size() << std::endl;
	}
}

void StrategyManager::saveGameRecordList(bool isWinner)
{
	// 이번 게임의 파일 저장은 bwapi-data\write 폴더에 하시면 됩니다.
	// bwapi-data\write 폴더에 저장된 파일은 대회 서버가 다음 경기 때 bwapi-data\read 폴더로 옮겨놓습니다
	std::string gameRecordFileName = Config::Files::WriteDirectory + Config::Files::LogFilename;

	// thisGameRecord 초기화
	std::string mapName = BWAPI::Broodwar->mapFileName();
	std::replace(mapName.begin(), mapName.end(), ' ', '_');
	std::string enemyName = BWAPI::Broodwar->enemy()->getName();
	std::replace(enemyName.begin(), enemyName.end(), ' ', '_');
	std::string myName = BWAPI::Broodwar->self()->getName();
	std::replace(myName.begin(), myName.end(), ' ', '_');

	/// 이번 게임에 대한 기록
	GameRecord				thisGameRecord;
	thisGameRecord.mapName = mapName;
	thisGameRecord.enemyName = enemyName;
	thisGameRecord.enemyRace = BWAPI::Broodwar->enemy()->getRace().c_str();
	thisGameRecord.enemyRealRace = InformationManager::Instance().enemyRace.c_str();
	thisGameRecord.myName = myName;
	thisGameRecord.myRace = BWAPI::Broodwar->self()->getRace().c_str();
	thisGameRecord.gameStartedTime = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
	thisGameRecord.gameFrameCount = BWAPI::Broodwar->getFrameCount();
	thisGameRecord.myWinCount = 0;
	thisGameRecord.myLoseCount = 0;
	if (isWinner) {
		thisGameRecord.myWinCount = 1;
		thisGameRecord.myLoseCount = 0;
	}
	else {
		thisGameRecord.myWinCount = 0;
		thisGameRecord.myLoseCount = 1;
	}
	// 이번 게임 기록을 전체 게임 기록에 추가
	gameRecordList.push_back(thisGameRecord);

	// 전체 게임 기록 write
	std::stringstream ss;
	for (GameRecord gameRecord : gameRecordList) {
		ss << gameRecord.mapName << " "
			<< gameRecord.myName << " "
			<< gameRecord.myRace << " "
			<< gameRecord.myWinCount << " "
			<< gameRecord.myLoseCount << " "
			<< gameRecord.enemyName << " "
			<< gameRecord.enemyRace << " "
			<< gameRecord.enemyRealRace << " "
			<< gameRecord.gameStartedTime << " "
			<< gameRecord.gameFrameCount << "\n";

	}
	Logger::overwriteToFile(gameRecordFileName, ss.str());
}


void StrategyManager::saveGameLog()
{
	// 100 프레임 (5초) 마다 1번씩 로그를 기록합니다
	// 참가팀 당 용량 제한이 있고, 타임아웃도 있기 때문에 자주 하지 않는 것이 좋습니다
	// 로그는 봇 개발 시 디버깅 용도로 사용하시는 것이 좋습니다
	if (BWAPI::Broodwar->getFrameCount() % 100 != 0) {
		return;
	}

	std::string gameLogFileName = Config::Files::WriteDirectory + Config::BotInfo::BotName + "_LastGameLog.dat";

	std::string mapName = BWAPI::Broodwar->mapFileName();
	std::replace(mapName.begin(), mapName.end(), ' ', '_');
	std::string enemyName = BWAPI::Broodwar->enemy()->getName();
	std::replace(enemyName.begin(), enemyName.end(), ' ', '_');
	std::string myName = BWAPI::Broodwar->self()->getName();
	std::replace(myName.begin(), myName.end(), ' ', '_');

	std::stringstream ss;
	ss << mapName << " "
		<< myName << " "
		<< BWAPI::Broodwar->self()->getRace().c_str() << " "
		<< enemyName << " "
		<< InformationManager::Instance().enemyRace.c_str() << " "
		<< BWAPI::Broodwar->getFrameCount() << " "
		<< BWAPI::Broodwar->self()->supplyUsed() << " "
		<< BWAPI::Broodwar->self()->supplyTotal() << " "
		<< "\n";

	Logger::appendTextToFile(gameLogFileName, ss.str());
}


bool StrategyManager::isDefenseEnough()
{
	bool isDefenseOK = false;

	UnitData & enemyUnitData = InformationManager::Instance().getUnitData(StrategyManager::Instance().enemyPlayer);

	// TODO : 방어가 충분히 갖춰져있는지 머신러닝 이용해서 판단
	if (BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Zerg_Sunken_Colony) >= 3)
	{
		isDefenseOK = true;
	}

	if (enemyUnitData.getNumUnits(BWAPI::UnitTypes::Protoss_Zealot) * 2 < BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Zerg_Zergling)
		|| enemyUnitData.getNumUnits(BWAPI::UnitTypes::Terran_Marine) < BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Zerg_Zergling)
		|| enemyUnitData.getNumUnits(BWAPI::UnitTypes::Zerg_Zergling) < BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Zerg_Zergling)
		|| BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Zerg_Zergling) >= 24
		|| BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Zerg_Hydralisk) >= 12
		|| BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Zerg_Lurker) >= 4
		|| BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Zerg_Sunken_Colony) >= 3
		)
	{
		isDefenseOK = true;
	}

	return isDefenseOK;
}
