#include "InformationManager.h"

#include "Bases.h"
#include "MapTools.h"
#include "ProductionManager.h"
#include "Random.h"
#include "UnitUtil.h"

using namespace UAlbertaBot;

InformationManager::InformationManager()
    : _self(BWAPI::Broodwar->self())
    , _enemy(BWAPI::Broodwar->enemy())
	
	, _weHaveCombatUnits(false)
	, _enemyHasCombatUnits(false)
	, _enemyHasStaticAntiAir(false)
	, _enemyHasAntiAir(false)
	, _enemyHasAirTech(false)
	, _enemyHasCloakTech(false)
	, _enemyCloakedUnitsSeen(false)
	, _enemyHasMobileCloakTech(false)
	, _enemyHasOverlordHunters(false)
	, _enemyHasStaticDetection(false)
	, _enemyHasMobileDetection(_enemy->getRace() == BWAPI::Races::Zerg)
	, _enemyHasSiegeMode(false)
{
	initializeTheBases();
	initializeRegionInformation();
}

// This fills in _theBases with neutral bases. An event will place our resourceDepot.
void InformationManager::initializeTheBases()
{
	for (BWTA::BaseLocation * base : BWTA::getBaseLocations())
	{
		Base * knownBase = Bases::Instance().getBaseAtTilePosition(base->getTilePosition());
		if (knownBase)
		{
			_theBases[base] = knownBase;
		}
		else
		{
			_theBases[base] = new Base(base->getTilePosition());
		}
	}
}

// Set up _mainBaseLocations and _occupiedLocations.
void InformationManager::initializeRegionInformation()
{
	_mainBaseLocations[_self] = BWTA::getStartLocation(_self);
	_mainBaseLocations[_enemy] = BWTA::getStartLocation(_enemy);

	// push that region into our occupied vector
	updateOccupiedRegions(BWTA::getRegion(_mainBaseLocations[_self]->getTilePosition()), _self);
}

// A base is inferred to exist at the given position, without having been seen.
// Only enemy bases can be inferred; we see our own.
// Adjust its value to match. It is not reserved.
void InformationManager::baseInferred(BWTA::BaseLocation * base)
{
	if (_theBases[base]->owner != _self)
	{
		_theBases[base]->setOwner(nullptr, _enemy);
	}
}

// The given resource depot has been created or discovered.
// Adjust its value to match. It is not reserved.
// This accounts for the theoretical case that it might be neutral.
void InformationManager::baseFound(BWAPI::Unit depot)
{
	UAB_ASSERT(depot && depot->getType().isResourceDepot(), "bad args");

	for (BWTA::BaseLocation * base : BWTA::getBaseLocations())
	{
		if (closeEnough(base->getTilePosition(), depot->getTilePosition()))
		{
			baseFound(base, depot);
			return;
		}
	}
}

// Set a base where the base and depot are both known.
// The depot must be at or near the base location; this is not checked.
void InformationManager::baseFound(BWTA::BaseLocation * base, BWAPI::Unit depot)
{
	UAB_ASSERT(base && depot && depot->getType().isResourceDepot(), "bad args");

	_theBases[base]->setOwner(depot, depot->getPlayer());
}

// Something that may be a base was just destroyed.
// If it is, update the value to match.
// If the lost base was our main, choose a new one if possible.
void InformationManager::baseLost(BWAPI::TilePosition basePosition)
{
	for (BWTA::BaseLocation * base : BWTA::getBaseLocations())
	{
		if (closeEnough(base->getTilePosition(), basePosition))
		{
			baseLost(base);
			return;
		}
	}
}

// A base was lost and is now unowned.
// If the lost base was our main, choose a new one if possible.
void InformationManager::baseLost(BWTA::BaseLocation * base)
{
	UAB_ASSERT(base, "bad args");

	_theBases[base]->setOwner(nullptr, BWAPI::Broodwar->neutral());
	if (base == getMyMainBaseLocation())
	{
		chooseNewMainBase();        // our main was lost, choose a new one
	}
}

// Our main base has been destroyed. Choose a new one if possible.
// Otherwise we'll keep trying to build in the old one, where the enemy may still be.
void InformationManager::chooseNewMainBase()
{
	BWTA::BaseLocation * oldMain = getMyMainBaseLocation();

	// Choose a base we own which is as far away from the old main as possible.
	// Maybe that will be safer.
	double newMainDist = 0.0;
	BWTA::BaseLocation * newMain = nullptr;

	for (BWTA::BaseLocation * base : BWTA::getBaseLocations())
	{
		if (_theBases[base]->owner == _self)
		{
			double dist = base->getAirDistance(oldMain);
			if (dist > newMainDist)
			{
				newMainDist = dist;
				newMain = base;
			}
		}
	}

	// If we didn't find a new main base, we're in deep trouble. We may as well keep the old one.
	// By decree, we always have a main base, even if it is unoccupied. It simplifies the rest.
	if (newMain)
	{
		_mainBaseLocations[_self] = newMain;
	}
}

// With some probability, randomly choose a base as the new "main" base.
void InformationManager::maybeChooseNewMainBase()
{
	// 1. If out of book, decide randomly whether to choose a new base.
	if (ProductionManager::Instance().isOutOfBook() && Random::Instance().index(2) == 0)
	{
		// 2. List my bases.
		std::vector<BWTA::BaseLocation *> myBases;
		for (BWTA::BaseLocation * base : BWTA::getBaseLocations())
		{
			if (_theBases[base]->owner == _self &&
				_theBases[base]->resourceDepot &&
				_theBases[base]->resourceDepot->isCompleted())
			{
				 myBases.push_back(base);
			}
		}

		// 3. Choose one, if there is a choice.
		if (myBases.size() > 1)
		{
			_mainBaseLocations[_self] = myBases.at(Random::Instance().index(myBases.size()));
		}
	}
}

// The given unit was just created or morphed.
// If it is a resource depot for our new base, record it.
// NOTE: It is a base only if it's in the right position according to BWTA.
// A resource depot will not be recorded if it is offset by too much.
// NOTE: This records the initial depot at the start of the game.
// There's no need to take special action to record the starting base.
void InformationManager::maybeAddBase(BWAPI::Unit unit)
{
	if (unit->getType().isResourceDepot())
	{
		baseFound(unit);
	}
}

// The two possible base positions are close enough together
// that we can say they are "the same place" as a base.
bool InformationManager::closeEnough(BWAPI::TilePosition a, BWAPI::TilePosition b)
{
	return abs(a.x - b.x) <= 2 && abs(a.y - b.y) <= 2;
}

void InformationManager::update()
{
	updateUnitInfo();
	updateGoneFromLastPosition();
	updateBaseLocationInfo();
	updateTheBases();
	updateTheirTargets();
	////////++
	Bases::Instance().updateEnemyStart();
	////////__
}

void InformationManager::updateUnitInfo() 
{
	_unitData[_enemy].removeBadUnits();
	_unitData[_self].removeBadUnits();

	for (const auto unit : _enemy->getUnits())
	{
		updateUnit(unit);
	}

	// Remove destroyed pylons from _ourPylons.
	for (auto pylon = _ourPylons.begin(); pylon != _ourPylons.end(); ++pylon)
	{
		if (!(*pylon)->exists())
		{
			pylon = _ourPylons.erase(pylon);
		}
	}

	bool anyNewPylons = false;

	for (const auto unit : _self->getUnits())
	{
		updateUnit(unit);

		// Add newly-ccompleted pylons to _ourPylons, and notify BuildingManager.
		if (unit->getType() == BWAPI::UnitTypes::Protoss_Pylon &&
			unit->isCompleted() &&
			!_ourPylons.contains(unit))
		{
			_ourPylons.insert(unit);
			anyNewPylons = true;
		}
	}

	if (anyNewPylons)
	{
		BuildingManager::Instance().unstall();
	}
}

void InformationManager::updateBaseLocationInfo() 
{
	_occupiedRegions[_self].clear();
	_occupiedRegions[_enemy].clear();
	
	// In the early game, look for enemy overlords as evidence of the enemy base.
	enemyBaseLocationFromOverlordSighting();

	// if we haven't found the enemy main base location yet
	if (!_mainBaseLocations[_enemy]) 
	{
		// how many start locations have we explored
		size_t exploredStartLocations = 0;
		bool baseFound = false;

		// an unexplored base location holder
		BWTA::BaseLocation * unexplored = nullptr;

		for (BWTA::BaseLocation * startLocation : BWTA::getStartLocations()) 
		{
			if (isEnemyBuildingInRegion(BWTA::getRegion(startLocation->getTilePosition()))) 
			{
				updateOccupiedRegions(BWTA::getRegion(startLocation->getTilePosition()), _enemy);

				// On a competition map, our base and the enemy base will never be in the same region.
				// If we find an enemy building in our region, it's a proxy.
				if (startLocation != BWTA::getStartLocation(_self))
				{
					if (Config::Debug::DrawScoutInfo)
					{
						BWAPI::Broodwar->printf("Enemy base seen");
					}

					baseFound = true;
					_mainBaseLocations[_enemy] = startLocation;
					baseInferred(startLocation);
				}
			}

			if (enemyStartLocationExplored(startLocation)) 
			{
				// Count the explored bases.
				++exploredStartLocations;
			} 
			else 
			{
				// Remember the unexplored base. It may be the only one.
				unexplored = startLocation;
			}
		}

		// if we've explored every start location except one, it's the enemy
		if (!baseFound && exploredStartLocations + 1 == BWTA::getStartLocations().size())
		{
            if (Config::Debug::DrawScoutInfo)
            {
                BWAPI::Broodwar->printf("Enemy base found by elimination");
            }
			
			_mainBaseLocations[_enemy] = unexplored;
			baseInferred(unexplored);
			updateOccupiedRegions(BWTA::getRegion(unexplored->getTilePosition()), _enemy);
		}
	// otherwise we do know it, so push it back
	}
	else 
	{
		updateOccupiedRegions(BWTA::getRegion(_mainBaseLocations[_enemy]->getTilePosition()), _enemy);
	}

	// The enemy occupies a region if it has a building there.
	for (const auto & kv : _unitData[_enemy].getUnits())
	{
		const UnitInfo & ui(kv.second);

		if (ui.type.isBuilding() && !ui.goneFromLastPosition)
		{
			updateOccupiedRegions(BWTA::getRegion(ui.lastPosition), _enemy);
		}
	}

	// We occupy a region if we have a building there.
	for (const auto & kv : _unitData[_self].getUnits())
	{
		const UnitInfo & ui(kv.second);

		if (ui.type.isBuilding() && !ui.goneFromLastPosition)
		{
			updateOccupiedRegions(BWTA::getRegion(BWAPI::TilePosition(ui.lastPosition)), _self);
		}
	}
}

// If the opponent is zerg and it's early in the game, we may be able to infer the enemy
// base's location by seeing the first overlord.
// NOTE This doesn't quite extract all the information from an overlord sighting. In principle,
//      we might be able to exclude a base location without being sure which remaining base is
//      the enemy base. Steamhammer doesn't provide a way to exclude bases.
void InformationManager::enemyBaseLocationFromOverlordSighting()
{
	// If we already know the base location, there's no need to try to infer it.
	if (_mainBaseLocations[_enemy])
	{
		return;
	}
	
	const int now = BWAPI::Broodwar->getFrameCount();

	if (_enemy->getRace() != BWAPI::Races::Zerg || now > 5 * 60 * 24)
	{
		return;
	}

	for (const auto unit : _enemy->getUnits())
	{
		if (unit->getType() != BWAPI::UnitTypes::Zerg_Overlord)
		{
			continue;
		}

		// What bases could the overlord be from? Can we narrow it down to 1 possibility?
		BWTA::BaseLocation * possibleEnemyBase = nullptr;
		int countPossibleBases = 0;
		for (BWTA::BaseLocation * base : BWTA::getStartLocations())
		{
			if (enemyStartLocationExplored(base))
			{
				// We've already seen this base, and the enemy is not there.
				continue;
			}

			// Assume the overlord came from this base.
			// Where did the overlord start from? It starts offset from the hatchery in a specific way.
			BWAPI::Position overlordStartPos;
			overlordStartPos.x = base->getPosition().x + ((base->getPosition().x < 32 * BWAPI::Broodwar->mapWidth() / 2) ? +99 : -99);
			overlordStartPos.y = base->getPosition().y + ((base->getPosition().y < 32 * BWAPI::Broodwar->mapHeight() / 2) ? +65 : -65);

			// How far could it have traveled from there?
			double maxDistance = double(now) * (BWAPI::UnitTypes::Zerg_Overlord).topSpeed();
			if (maxDistance >= double(unit->getDistance(overlordStartPos)))
			{
				// It could have started from this base.
				possibleEnemyBase = base;
				++countPossibleBases;
			}
		}
		if (countPossibleBases == 1)
		{
			// Success.
			_mainBaseLocations[_enemy] = possibleEnemyBase;
			baseInferred(possibleEnemyBase);
			updateOccupiedRegions(BWTA::getRegion(possibleEnemyBase->getTilePosition()), _enemy);
			return;
		}
	}
}

// We're scouting in the early game. Have we seen whether the enemy base is here?
// To turn the scout around as early as possible if the base is empty, we check
// each corner of the resource depot spot.
// TODO If the enemy is zerg, we can be a little quicker by looking for creep.
// TODO If we see a mineral patch that has been mined, that should be a base.
bool InformationManager::enemyStartLocationExplored(BWTA::BaseLocation * base) const
{
	BWAPI::TilePosition tile = base->getTilePosition();
	return
		BWAPI::Broodwar->isExplored(tile) ||
		BWAPI::Broodwar->isExplored(tile + BWAPI::TilePosition(3, 2)) ||
		BWAPI::Broodwar->isExplored(tile + BWAPI::TilePosition(0, 2)) ||
		BWAPI::Broodwar->isExplored(tile + BWAPI::TilePosition(3, 0));
}

// _theBases is not always correctly updated by the event-driven methods.
// Look for conflicting information and make corrections.
void InformationManager::updateTheBases()
{
	for (BWTA::BaseLocation * base : BWTA::getBaseLocations())
	{
		// If we can see the tile where the resource depot would be.
		if (BWAPI::Broodwar->isVisible(base->getTilePosition()))
		{
			BWAPI::Unitset units = BWAPI::Broodwar->getUnitsOnTile(base->getTilePosition());
			BWAPI::Unit depot = nullptr;
			for (const auto unit : units)
			{
				if (unit->getType().isResourceDepot())
				{
					depot = unit;
					break;
				}
			}
			if (depot)
			{
				// The base is occupied.
				baseFound(base, depot);
			}
			else
			{
				// The base is empty.
				baseLost(base);
			}
		}
		else
		{
			// We don't see anything. It's definitely not our base.
			if (_theBases[base]->owner == _self)
			{
				baseLost(base->getTilePosition());
			}
		}
	}
}

void InformationManager::updateOccupiedRegions(BWTA::Region * region, BWAPI::Player player) 
{
	// if the region is valid (flying buildings may be in nullptr regions)
	if (region)
	{
		// add it to the list of occupied regions
		_occupiedRegions[player].insert(region);
	}
}

// If we can see the last known location of a remembered unit and the unit is not there,
// set the unit's goneFromLastPosition flag (unless it is burrowed or burrowing).
void InformationManager::updateGoneFromLastPosition()
{
	// We don't need to check every frame.
	// 1. The game supposedly only resets visible tiles when frame % 100 == 99.
	// 2. If the unit has only been gone from its location for a short time, it probably
	//    didn't go far (though it might have been recalled or gone through a nydus).
	// On the other hand, burrowed units can disappear from view more quickly.
	// 3. Detection is updated immediately, so we might overlook having detected
	//    a burrowed unit if we don't update often enough.
	// 4. We also might miss a unit in the process of burrowing.
	// All in all, we should check fairly often.
	if (BWAPI::Broodwar->getFrameCount() % 6 == 5)
	{
		_unitData[_enemy].updateGoneFromLastPosition();
	}

	if (Config::Debug::DrawHiddenEnemies)
	{
		for (const auto & kv : _unitData[_enemy].getUnits())
		{
			const UnitInfo & ui(kv.second);

			// Units that are out of sight range.
			if (ui.unit && !ui.unit->isVisible())
			{
				if (ui.goneFromLastPosition)
				{
					// Draw a small X.
					BWAPI::Broodwar->drawLineMap(
						ui.lastPosition + BWAPI::Position(-2, -2),
						ui.lastPosition + BWAPI::Position(2, 2),
						BWAPI::Colors::Red);
					BWAPI::Broodwar->drawLineMap(
						ui.lastPosition + BWAPI::Position(2, -2),
						ui.lastPosition + BWAPI::Position(-2, 2),
						BWAPI::Colors::Red);
				}
				else
				{
					// Draw a small circle.
					BWAPI::Color color = ui.burrowed ? BWAPI::Colors::Yellow : BWAPI::Colors::Green;
					BWAPI::Broodwar->drawCircleMap(ui.lastPosition, 4, color);
				}
			}

			// Units that are in sight range but undetected.
			if (ui.unit && ui.unit->isVisible() && !ui.unit->isDetected())
			{
				// Draw a larger circle.
				BWAPI::Broodwar->drawCircleMap(ui.lastPosition, 8, BWAPI::Colors::Purple);

				BWAPI::Broodwar->drawTextMap(ui.lastPosition + BWAPI::Position(10, 6),
					"%c%s", white, UnitTypeName(ui.type).c_str());
			}
		}
	}
}

// For each of our units, keep track of which enemies are targeting it.
// It changes frequently, so this is updated every frame.
void InformationManager::updateTheirTargets()
{
	_theirTargets.clear();

	// We only know the targets for visible enemy units.
	for (BWAPI::Unit enemy : _enemy->getUnits())
	{
		BWAPI::Unit target = enemy->getOrderTarget();
		if (target && target->getPlayer() == _self && (target->getType() == BWAPI::UnitTypes::Terran_Vulture_Spider_Mine || UnitUtil::AttackOrder(enemy)))
		{
			_theirTargets[target].insert(enemy);
			//BWAPI::Broodwar->drawLineMap(enemy->getPosition(), target->getPosition(), BWAPI::Colors::Yellow);
		}
	}
}

bool InformationManager::isEnemyBuildingInRegion(BWTA::Region * region) 
{
	// invalid regions aren't considered the same, but they will both be null
	if (!region)
	{
		return false;
	}

	for (const auto & kv : _unitData[_enemy].getUnits())
	{
		const UnitInfo & ui(kv.second);
		if (ui.type.isBuilding() && !ui.goneFromLastPosition)
		{
			if (BWTA::getRegion(BWAPI::TilePosition(ui.lastPosition)) == region) 
			{
				return true;
			}
		}
	}

	return false;
}

const UIMap & InformationManager::getUnitInfo(BWAPI::Player player) const
{
	return getUnitData(player).getUnits();
}

std::set<BWTA::Region *> & InformationManager::getOccupiedRegions(BWAPI::Player player)
{
	return _occupiedRegions[player];
}

BWTA::BaseLocation * InformationManager::getMainBaseLocation(BWAPI::Player player)
{
	return _mainBaseLocations[player];
}

// Guaranteed non-null. If we have no bases left, it is our start location.
BWTA::BaseLocation * InformationManager::getMyMainBaseLocation()
{
	UAB_ASSERT(_mainBaseLocations[_self], "no base location");
	return _mainBaseLocations[_self];
}

// Null until the enemy base is located.
BWTA::BaseLocation * InformationManager::getEnemyMainBaseLocation()
{
	return _mainBaseLocations[_enemy];
}

int InformationManager::getAir2GroundSupply(BWAPI::Player player) const
{
	int supply = 0;

	for (const auto & kv : getUnitData(player).getUnits())
	{
		const UnitInfo & ui(kv.second);

		if (ui.type.isFlyer() && UnitUtil::TypeCanAttackGround(ui.type))
		{
			supply += ui.type.supplyRequired();
		}
	}

	return supply;
}

void InformationManager::drawExtendedInterface()
{
    if (!Config::Debug::DrawUnitHealthBars)
    {
        return;
    }

    int verticalOffset = -10;

    // draw enemy units
    for (const auto & kv : getUnitData(_enemy).getUnits())
	{
        const UnitInfo & ui(kv.second);

		BWAPI::UnitType type(ui.type);
        int hitPoints = ui.lastHP;
        int shields = ui.lastShields;

        const BWAPI::Position & pos = ui.lastPosition;

        int left    = pos.x - type.dimensionLeft();
        int right   = pos.x + type.dimensionRight();
        int top     = pos.y - type.dimensionUp();
        int bottom  = pos.y + type.dimensionDown();

        if (!BWAPI::Broodwar->isVisible(BWAPI::TilePosition(ui.lastPosition)))
        {
            BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, top), BWAPI::Position(right, bottom), BWAPI::Colors::Grey, false);
            BWAPI::Broodwar->drawTextMap(BWAPI::Position(left + 3, top + 4), "%s %c",
				ui.type.getName().c_str(),
				ui.goneFromLastPosition ? 'X' : ' ');
        }
        
        if (!type.isResourceContainer() && type.maxHitPoints() > 0)
        {
            double hpRatio = (double)hitPoints / (double)type.maxHitPoints();
        
            BWAPI::Color hpColor = BWAPI::Colors::Green;
            if (hpRatio < 0.66) hpColor = BWAPI::Colors::Orange;
            if (hpRatio < 0.33) hpColor = BWAPI::Colors::Red;

            int ratioRight = left + (int)((right-left) * hpRatio);
            int hpTop = top + verticalOffset;
            int hpBottom = top + 4 + verticalOffset;

            BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, hpTop), BWAPI::Position(right, hpBottom), BWAPI::Colors::Grey, true);
            BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, hpTop), BWAPI::Position(ratioRight, hpBottom), hpColor, true);
            BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, hpTop), BWAPI::Position(right, hpBottom), BWAPI::Colors::Black, false);

            int ticWidth = 3;

            for (int i(left); i < right-1; i+=ticWidth)
            {
                BWAPI::Broodwar->drawLineMap(BWAPI::Position(i, hpTop), BWAPI::Position(i, hpBottom), BWAPI::Colors::Black);
            }
        }

        if (!type.isResourceContainer() && type.maxShields() > 0)
        {
            double shieldRatio = (double)shields / (double)type.maxShields();
        
            int ratioRight = left + (int)((right-left) * shieldRatio);
            int hpTop = top - 3 + verticalOffset;
            int hpBottom = top + 1 + verticalOffset;

            BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, hpTop), BWAPI::Position(right, hpBottom), BWAPI::Colors::Grey, true);
            BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, hpTop), BWAPI::Position(ratioRight, hpBottom), BWAPI::Colors::Blue, true);
            BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, hpTop), BWAPI::Position(right, hpBottom), BWAPI::Colors::Black, false);

            int ticWidth = 3;

            for (int i(left); i < right-1; i+=ticWidth)
            {
                BWAPI::Broodwar->drawLineMap(BWAPI::Position(i, hpTop), BWAPI::Position(i, hpBottom), BWAPI::Colors::Black);
            }
        }
    }

    // draw neutral units and our units
    for (const auto & unit : BWAPI::Broodwar->getAllUnits())
    {
        if (unit->getPlayer() == _enemy)
        {
            continue;
        }

        const BWAPI::Position & pos = unit->getPosition();

        int left    = pos.x - unit->getType().dimensionLeft();
        int right   = pos.x + unit->getType().dimensionRight();
        int top     = pos.y - unit->getType().dimensionUp();
        int bottom  = pos.y + unit->getType().dimensionDown();

        //BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, top), BWAPI::Position(right, bottom), BWAPI::Colors::Grey, false);

        if (!unit->getType().isResourceContainer() && unit->getType().maxHitPoints() > 0)
        {
            double hpRatio = (double)unit->getHitPoints() / (double)unit->getType().maxHitPoints();
        
            BWAPI::Color hpColor = BWAPI::Colors::Green;
            if (hpRatio < 0.66) hpColor = BWAPI::Colors::Orange;
            if (hpRatio < 0.33) hpColor = BWAPI::Colors::Red;

            int ratioRight = left + (int)((right-left) * hpRatio);
            int hpTop = top + verticalOffset;
            int hpBottom = top + 4 + verticalOffset;

            BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, hpTop), BWAPI::Position(right, hpBottom), BWAPI::Colors::Grey, true);
            BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, hpTop), BWAPI::Position(ratioRight, hpBottom), hpColor, true);
            BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, hpTop), BWAPI::Position(right, hpBottom), BWAPI::Colors::Black, false);

            int ticWidth = 3;

            for (int i(left); i < right-1; i+=ticWidth)
            {
                BWAPI::Broodwar->drawLineMap(BWAPI::Position(i, hpTop), BWAPI::Position(i, hpBottom), BWAPI::Colors::Black);
            }
        }

        if (!unit->getType().isResourceContainer() && unit->getType().maxShields() > 0)
        {
            double shieldRatio = (double)unit->getShields() / (double)unit->getType().maxShields();
        
            int ratioRight = left + (int)((right-left) * shieldRatio);
            int hpTop = top - 3 + verticalOffset;
            int hpBottom = top + 1 + verticalOffset;

            BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, hpTop), BWAPI::Position(right, hpBottom), BWAPI::Colors::Grey, true);
            BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, hpTop), BWAPI::Position(ratioRight, hpBottom), BWAPI::Colors::Blue, true);
            BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, hpTop), BWAPI::Position(right, hpBottom), BWAPI::Colors::Black, false);

            int ticWidth = 3;

            for (int i(left); i < right-1; i+=ticWidth)
            {
                BWAPI::Broodwar->drawLineMap(BWAPI::Position(i, hpTop), BWAPI::Position(i, hpBottom), BWAPI::Colors::Black);
            }
        }

        if (unit->getType().isResourceContainer() && unit->getInitialResources() > 0)
        {
            
            double mineralRatio = (double)unit->getResources() / (double)unit->getInitialResources();
        
            int ratioRight = left + (int)((right-left) * mineralRatio);
            int hpTop = top + verticalOffset;
            int hpBottom = top + 4 + verticalOffset;

            BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, hpTop), BWAPI::Position(right, hpBottom), BWAPI::Colors::Grey, true);
            BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, hpTop), BWAPI::Position(ratioRight, hpBottom), BWAPI::Colors::Cyan, true);
            BWAPI::Broodwar->drawBoxMap(BWAPI::Position(left, hpTop), BWAPI::Position(right, hpBottom), BWAPI::Colors::Black, false);

            int ticWidth = 3;

            for (int i(left); i < right-1; i+=ticWidth)
            {
                BWAPI::Broodwar->drawLineMap(BWAPI::Position(i, hpTop), BWAPI::Position(i, hpBottom), BWAPI::Colors::Black);
            }
        }
    }
}

void InformationManager::drawUnitInformation(int x, int y) 
{
	if (!Config::Debug::DrawEnemyUnitInfo)
    {
        return;
    }

	char color = white;

	BWAPI::Broodwar->drawTextScreen(x, y-10, "\x03 Self Loss:\x04 Minerals: \x1f%d \x04Gas: \x07%d", _unitData[_self].getMineralsLost(), _unitData[_self].getGasLost());
    BWAPI::Broodwar->drawTextScreen(x, y, "\x03 Enemy Loss:\x04 Minerals: \x1f%d \x04Gas: \x07%d", _unitData[_enemy].getMineralsLost(), _unitData[_enemy].getGasLost());
	BWAPI::Broodwar->drawTextScreen(x, y+10, "\x04 Enemy: %s", _enemy->getName().c_str());
	BWAPI::Broodwar->drawTextScreen(x, y+20, "\x04 UNIT NAME");
	BWAPI::Broodwar->drawTextScreen(x+140, y+20, "\x04#");
	BWAPI::Broodwar->drawTextScreen(x+160, y+20, "\x04X");

	int yspace = 0;

	// for each unit in the queue
	for (BWAPI::UnitType t : BWAPI::UnitTypes::allUnitTypes()) 
	{
		int numUnits = _unitData[_enemy].getNumUnits(t);
		int numDeadUnits = _unitData[_enemy].getNumDeadUnits(t);

		if (numUnits > 0) 
		{
			if (t.isDetector())			{ color = purple; }		
			else if (t.canAttack())		{ color = red; }		
			else if (t.isBuilding())	{ color = yellow; }
			else						{ color = white; }

			BWAPI::Broodwar->drawTextScreen(x, y+40+((yspace)*10), " %c%s", color, t.getName().c_str());
			BWAPI::Broodwar->drawTextScreen(x+140, y+40+((yspace)*10), "%c%d", color, numUnits);
			BWAPI::Broodwar->drawTextScreen(x+160, y+40+((yspace++)*10), "%c%d", color, numDeadUnits);
		}
	}
}

void InformationManager::maybeClearNeutral(BWAPI::Unit unit)
{
	if (unit && unit->getPlayer() == BWAPI::Broodwar->neutral() && unit->getType().isBuilding())
	{
		Bases::Instance().clearNeutral(unit);
	}
}

void InformationManager::maybeAddStaticDefense(BWAPI::Unit unit)
{
	if (unit && unit->getPlayer() == _self && UnitUtil::IsStaticDefense(unit->getType()) && unit->isCompleted())
	{
		_staticDefense.insert(unit);
	}
}

void InformationManager::updateUnit(BWAPI::Unit unit)
{
    if (unit->getPlayer() == _self || unit->getPlayer() == _enemy)
    {
		_unitData[unit->getPlayer()].updateUnit(unit);
	}
}

void InformationManager::onUnitDestroy(BWAPI::Unit unit) 
{ 
	if (unit->getPlayer() == _self || unit->getPlayer() == _enemy)
	{
		_unitData[unit->getPlayer()].removeUnit(unit);

		// If it may be a base, remove that base.
		if (unit->getType().isResourceDepot())
		{
			baseLost(unit->getTilePosition());
		}

		// If it is our static defense, remove it.
		if (unit->getPlayer() == _self && UnitUtil::IsStaticDefense(unit->getType()))
		{
			_staticDefense.erase(unit);
		}
	}
	else
	{
		// Should be neutral.
		Bases::Instance().clearNeutral(unit);
	}
}

// Only returns units expected to be completed.
// A building is considered completed if it was last seen uncompleted and is now out of sight.
// NOTE It could be more accurate if ui.completed were ui.completionTime or something similar.
void InformationManager::getNearbyForce(std::vector<UnitInfo> & unitsOut, BWAPI::Position p, BWAPI::Player player, int radius) 
{
	for (const auto & kv : getUnitData(player).getUnits())
	{
		const UnitInfo & ui(kv.second);

		// if it's a combat unit we care about
		// and it's finished! 
		if (UnitUtil::IsCombatSimUnit(ui) && !ui.goneFromLastPosition &&
			(ui.completed || ui.type.isBuilding() && !ui.unit->isVisible()))
		{
			if (ui.type == BWAPI::UnitTypes::Terran_Medic)
			{
				// Spellcasters that the combat simulator is able to simulate.
				if (ui.lastPosition.getDistance(p) <= (radius + 64))
				{
					unitsOut.push_back(ui);
				}
			}
			else
			{
				// Non-spellcasters, aka units with weapons that have a range.

				// Determine its attack range, in the worst case.
				int range = UnitUtil::GetMaxAttackRange(ui.type);

				// Include it if it can attack into the radius we care about (with fudge factor).
				if (range && ui.lastPosition.getDistance(p) <= (radius + range + 32))
				{
					unitsOut.push_back(ui);
				}
			}
		}
		// NOTE FAP does not support detectors.
		// else if (ui.type.isDetector() && ui.lastPosition.getDistance(p) <= (radius + 250))
        // {
		//	unitsOut.push_back(ui);
        // }
	}
}

int InformationManager::getNumUnits(BWAPI::UnitType t, BWAPI::Player player) const
{
	return getUnitData(player).getNumUnits(t);
}

bool InformationManager::isBaseReserved(Base * base)
{
	return base->isReserved();
}

void InformationManager::reserveBase(Base * base)
{
	base->reserve();
}

void InformationManager::unreserveBase(Base * base)
{
	base->unreserve();
}

void InformationManager::unreserveBase(BWAPI::TilePosition baseTilePosition)
{
	for (Base * base : Bases::Instance().getBases())
	{
		if (closeEnough(base->getTilePosition(), baseTilePosition))
		{
			base->unreserve();
			return;
		}
	}

	UAB_ASSERT(false, "trying to unreserve a non-base @ %d,%d", baseTilePosition.x, baseTilePosition.y);
}

// We have complated combat units (excluding workers).
// This is a latch, initially false and set true forever when we get our first combat units.
bool InformationManager::weHaveCombatUnits()
{
	// Latch: Once we have combat units, pretend we always have them.
	if (_weHaveCombatUnits)
	{
		return true;
	}

	for (const auto u : _self->getUnits())
	{
		if (!u->getType().isWorker() &&
			!u->getType().isBuilding() &&
			u->isCompleted() &&
			u->getType() != BWAPI::UnitTypes::Zerg_Larva &&
			u->getType() != BWAPI::UnitTypes::Zerg_Overlord)
		{
			_weHaveCombatUnits = true;
			return true;
		}
	}

	return false;
}

// Enemy has complated combat units (excluding workers).
bool InformationManager::enemyHasCombatUnits()
{
	// Latch: Once they're known to have the tech, they always have it.
	if (_enemyHasCombatUnits)
	{
		return true;
	}

	for (const auto & kv : getUnitData(_enemy).getUnits())
	{
		const UnitInfo & ui(kv.second);

		if (!ui.type.isWorker() &&
			!ui.type.isBuilding() &&
			ui.completed &&
			ui.type != BWAPI::UnitTypes::Zerg_Larva &&
			ui.type != BWAPI::UnitTypes::Zerg_Overlord)
		{
			_enemyHasCombatUnits = true;
			return true;
		}
	}

	return false;
}

// Enemy has spore colonies, photon cannons, or turrets.
bool InformationManager::enemyHasStaticAntiAir()
{
	// Latch: Once they're known to have the tech, they always have it.
	if (_enemyHasStaticAntiAir)
	{
		return true;
	}

	for (const auto & kv : getUnitData(_enemy).getUnits())
	{
		const UnitInfo & ui(kv.second);

		if (ui.type == BWAPI::UnitTypes::Terran_Missile_Turret ||
			ui.type == BWAPI::UnitTypes::Protoss_Photon_Cannon ||
			ui.type == BWAPI::UnitTypes::Zerg_Spore_Colony)
		{
			_enemyHasStaticAntiAir = true;
			return true;
		}
	}

	return false;
}

// Enemy has mobile units that can shoot up, or the tech to produce them.
bool InformationManager::enemyHasAntiAir()
{
	// Latch: Once they're known to have the tech, they always have it.
	if (_enemyHasAntiAir)
	{
		return true;
	}

	for (const auto & kv : getUnitData(_enemy).getUnits())
	{
		const UnitInfo & ui(kv.second);

		if (
			// For terran, anything other than SCV, command center, depot is a hit.
			// Surely nobody makes ebay before barracks!
			(_enemy->getRace() == BWAPI::Races::Terran &&
			ui.type != BWAPI::UnitTypes::Terran_SCV &&
			ui.type != BWAPI::UnitTypes::Terran_Command_Center &&
			ui.type != BWAPI::UnitTypes::Terran_Supply_Depot)

			||

			// Otherwise, any mobile unit that has an air weapon.
			(!ui.type.isBuilding() && UnitUtil::TypeCanAttackAir(ui.type))

			||

			// Or a building for making such a unit.
            // The cyber core only counts once it is finished, other buildings earlier.
			ui.type == BWAPI::UnitTypes::Protoss_Cybernetics_Core && ui.completed ||
			ui.type == BWAPI::UnitTypes::Protoss_Stargate ||
			ui.type == BWAPI::UnitTypes::Protoss_Fleet_Beacon ||
			ui.type == BWAPI::UnitTypes::Protoss_Arbiter_Tribunal ||
			ui.type == BWAPI::UnitTypes::Zerg_Hydralisk_Den ||
			ui.type == BWAPI::UnitTypes::Zerg_Spire ||
			ui.type == BWAPI::UnitTypes::Zerg_Greater_Spire

			)
		{
			_enemyHasAntiAir = true;
			return true;
		}
	}

	return false;
}

// Enemy has air units or air-producing tech.
// Overlords and lifted buildings are excluded.
// A queen's nest is not air tech--it's usually a prerequisite for hive
// rather than to make queens. So we have to see a queen for it to count.
// Protoss robo fac and terran starport are taken to imply air units.
bool InformationManager::enemyHasAirTech()
{
	// Latch: Once they're known to have the tech, they always have it.
	if (_enemyHasAirTech)
	{
		return true;
	}

	for (const auto & kv : getUnitData(_enemy).getUnits())
	{
		const UnitInfo & ui(kv.second);

		if ((ui.type.isFlyer() && ui.type != BWAPI::UnitTypes::Zerg_Overlord) ||
			ui.type == BWAPI::UnitTypes::Terran_Starport ||
			ui.type == BWAPI::UnitTypes::Terran_Control_Tower ||
			ui.type == BWAPI::UnitTypes::Terran_Science_Facility ||
			ui.type == BWAPI::UnitTypes::Terran_Covert_Ops ||
			ui.type == BWAPI::UnitTypes::Terran_Physics_Lab ||
			ui.type == BWAPI::UnitTypes::Protoss_Stargate ||
			ui.type == BWAPI::UnitTypes::Protoss_Arbiter_Tribunal ||
			ui.type == BWAPI::UnitTypes::Protoss_Fleet_Beacon ||
			ui.type == BWAPI::UnitTypes::Protoss_Robotics_Facility ||
			ui.type == BWAPI::UnitTypes::Protoss_Robotics_Support_Bay ||
			ui.type == BWAPI::UnitTypes::Protoss_Observatory ||
			ui.type == BWAPI::UnitTypes::Zerg_Spire ||
			ui.type == BWAPI::UnitTypes::Zerg_Greater_Spire)
		{
			_enemyHasAirTech = true;
			return true;
		}
	}

	return false;
}

// This test is good for "can I benefit from detection?"
// NOTE The enemySeenBurrowing() call also sets _enemyHasCloakTech .
bool InformationManager::enemyHasCloakTech()
{
	// Latch: Once they're known to have the tech, they always have it.
	if (_enemyHasCloakTech)
	{
		return true;
	}

	for (const auto & kv : getUnitData(_enemy).getUnits())
	{
		const UnitInfo & ui(kv.second);

		if (ui.type.hasPermanentCloak() ||                             // DT, observer
			ui.type.isCloakable() ||                                   // wraith, ghost
			ui.type == BWAPI::UnitTypes::Terran_Vulture_Spider_Mine ||
			ui.type == BWAPI::UnitTypes::Protoss_Citadel_of_Adun ||    // assume DT
			ui.type == BWAPI::UnitTypes::Protoss_Templar_Archives ||   // assume DT
			ui.type == BWAPI::UnitTypes::Protoss_Observatory ||
			ui.type == BWAPI::UnitTypes::Protoss_Arbiter_Tribunal ||
			ui.type == BWAPI::UnitTypes::Protoss_Arbiter ||
			ui.type == BWAPI::UnitTypes::Zerg_Lurker ||
			ui.type == BWAPI::UnitTypes::Zerg_Lurker_Egg ||
			ui.unit->isBurrowed())
		{
			_enemyHasCloakTech = true;
			return true;
		}
	}

	return false;
}

// This test means more "can I be SURE that I will benefit from detection?"
// It only counts actual cloaked units, not merely the tech for them,
// and does not worry about observers.
// NOTE The enemySeenBurrowing() call also sets _enemyCloakedUnitsSeen.
// NOTE If they have cloaked units, they have cloak tech. Set all appropriate flags.
bool InformationManager::enemyCloakedUnitsSeen()
{
	// Latch: Once they're known to have the tech, they always have it.
	if (_enemyCloakedUnitsSeen)
	{
		return true;
	}

	for (const auto & kv : getUnitData(_enemy).getUnits())
	{
		const UnitInfo & ui(kv.second);

		if (ui.type.isCloakable() ||                                    // wraith, ghost
			ui.type == BWAPI::UnitTypes::Terran_Vulture_Spider_Mine ||
			ui.type == BWAPI::UnitTypes::Protoss_Dark_Templar ||
			ui.type == BWAPI::UnitTypes::Protoss_Arbiter ||
			ui.type == BWAPI::UnitTypes::Zerg_Lurker ||
			ui.type == BWAPI::UnitTypes::Zerg_Lurker_Egg ||
			ui.unit->isBurrowed())
		{
			_enemyHasCloakTech = true;
			_enemyCloakedUnitsSeen = true;
			_enemyHasMobileCloakTech = true;
			return true;
		}
	}

	return false;
}

// This test is better for "do I need detection to live?"
// It doesn't worry about spider mines, observers, or burrowed units except lurkers.
// NOTE If they have cloaked units, they have cloak tech. Set all appropriate flags.
bool InformationManager::enemyHasMobileCloakTech()
{
	// Latch: Once they're known to have the tech, they always have it.
	if (_enemyHasMobileCloakTech)
	{
		return true;
	}

	for (const auto & kv : getUnitData(_enemy).getUnits())
	{
		const UnitInfo & ui(kv.second);

		if (ui.type.isCloakable() ||                                   // wraith, ghost
			ui.type == BWAPI::UnitTypes::Protoss_Dark_Templar ||
			ui.type == BWAPI::UnitTypes::Protoss_Citadel_of_Adun ||    // assume DT
			ui.type == BWAPI::UnitTypes::Protoss_Templar_Archives ||   // assume DT
			ui.type == BWAPI::UnitTypes::Protoss_Arbiter_Tribunal ||
			ui.type == BWAPI::UnitTypes::Protoss_Arbiter ||
			ui.type == BWAPI::UnitTypes::Zerg_Lurker ||
			ui.type == BWAPI::UnitTypes::Zerg_Lurker_Egg)
		{
			_enemyHasCloakTech = true;
			_enemyHasMobileCloakTech = true;
			return true;
		}
	}

	return false;
}

// Enemy has cloaked wraiths or arbiters.
bool InformationManager::enemyHasAirCloakTech()
{
	for (const auto & kv : getUnitData(_enemy).getUnits())
	{
		const UnitInfo & ui(kv.second);

		// We have to see a wraith that is cloaked to be sure.
		if (ui.type == BWAPI::UnitTypes::Terran_Wraith &&
			ui.unit->isVisible() && !ui.unit->isDetected())
		{
			_enemyHasCloakTech = true;
			_enemyHasMobileCloakTech = true;
			_enemyHasAirCloakTech = true;
			return true;
		}

		if (ui.type == BWAPI::UnitTypes::Protoss_Arbiter_Tribunal ||
			ui.type == BWAPI::UnitTypes::Protoss_Arbiter)
		{
			_enemyHasCloakTech = true;
			_enemyHasMobileCloakTech = true;
			_enemyHasAirCloakTech = true;
			return true;
		}
	}

	return false;
}

// Enemy has air units good for hunting down overlords.
// A stargate counts, but not a fleet beacon or arbiter tribunal.
// A starport does not count; it may well be for something else.
bool InformationManager::enemyHasOverlordHunters()
{
	// Latch: Once they're known to have the tech, they always have it.
	if (_enemyHasOverlordHunters)
	{
		return true;
	}

	for (const auto & kv : getUnitData(_enemy).getUnits())
	{
		const UnitInfo & ui(kv.second);

		if (ui.type == BWAPI::UnitTypes::Terran_Wraith ||
			ui.type == BWAPI::UnitTypes::Terran_Valkyrie ||
			ui.type == BWAPI::UnitTypes::Terran_Battlecruiser ||
			ui.type == BWAPI::UnitTypes::Protoss_Corsair ||
			ui.type == BWAPI::UnitTypes::Protoss_Scout ||
			ui.type == BWAPI::UnitTypes::Protoss_Carrier ||
			ui.type == BWAPI::UnitTypes::Protoss_Stargate ||
			ui.type == BWAPI::UnitTypes::Zerg_Spire ||
			ui.type == BWAPI::UnitTypes::Zerg_Greater_Spire ||
			ui.type == BWAPI::UnitTypes::Zerg_Mutalisk ||
			ui.type == BWAPI::UnitTypes::Zerg_Scourge)
		{
			_enemyHasOverlordHunters = true;
			_enemyHasAirTech = true;
			return true;
		}
	}

	return false;
}

void InformationManager::enemySeenBurrowing()
{
	_enemyHasCloakTech = true;
	_enemyCloakedUnitsSeen = true;
}

// Enemy has spore colonies, photon cannons, turrets, or spider mines.
// It's the same as enemyHasStaticAntiAir() except for spider mines.
// Spider mines only catch cloaked ground units, so this routine is not for countering wraiths.
bool InformationManager::enemyHasStaticDetection()
{
	// Latch: Once they're known to have the tech, they always have it.
	if (_enemyHasStaticDetection)
	{
		return true;
	}

	if (enemyHasStaticAntiAir())
	{
		_enemyHasStaticDetection = true;
		return true;
	}

	for (const auto & kv : getUnitData(_enemy).getUnits())
	{
		const UnitInfo & ui(kv.second);

		if (ui.type == BWAPI::UnitTypes::Terran_Vulture_Spider_Mine)
		{
			_enemyHasStaticDetection = true;
			return true;
		}
	}

	return false;
}

// Enemy has overlords, observers, comsat, or science vessels.
bool InformationManager::enemyHasMobileDetection()
{
	// Latch: Once they're known to have the tech, they always have it.
	if (_enemyHasMobileDetection)
	{
		return true;
	}

	// If the enemy is zerg, they have overlords.
	// If they went random, we may not have known until now.
	if (_enemy->getRace() == BWAPI::Races::Zerg)
	{
		_enemyHasMobileDetection = true;
		return true;
	}

	for (const auto & kv : getUnitData(_enemy).getUnits())
	{
		const UnitInfo & ui(kv.second);

		if (ui.type == BWAPI::UnitTypes::Terran_Comsat_Station ||
			ui.type == BWAPI::UnitTypes::Terran_Science_Facility ||
			ui.type == BWAPI::UnitTypes::Terran_Science_Vessel ||
			ui.type == BWAPI::UnitTypes::Protoss_Observatory ||
			ui.type == BWAPI::UnitTypes::Protoss_Observer)
		{
			_enemyHasMobileDetection = true;
			return true;
		}
	}

	return false;
}

bool InformationManager::enemyHasSiegeMode()
{
	// Only terran can get siege mode. Ignore the possibility of protoss mind control.
	if (_enemy->getRace() != BWAPI::Races::Terran)
	{
		return false;
	}

	// Latch: Once they're known to have the tech, they always have it.
	if (_enemyHasSiegeMode)
	{
		return true;
	}

	for (const auto & kv : getUnitData(_enemy).getUnits())
	{
		const UnitInfo & ui(kv.second);

		// If the tank is in the process of sieging, it is still in tank mode.
		// If it is unsieging, it is still in siege mode.
		if (ui.type == BWAPI::UnitTypes::Terran_Siege_Tank_Siege_Mode ||
			ui.unit->isVisible() && ui.unit->getOrder() == BWAPI::Orders::Sieging)
		{
			_enemyHasStaticAntiAir = true;
			return true;
		}
	}

	return false;
}

// Our nearest static defense building that can hit ground, by air distance.
// Null if none.
// NOTE This assumes that we never put medics or SCVs into a bunker.
BWAPI::Unit InformationManager::nearestGroundStaticDefense(BWAPI::Position pos) const
{
	int closestDist = 999999;
	BWAPI::Unit closest = nullptr;
	for (BWAPI::Unit building : _staticDefense)
	{
		if (building->getType() == BWAPI::UnitTypes::Terran_Bunker && !building->getLoadedUnits().empty() ||
			building->getType() == BWAPI::UnitTypes::Protoss_Photon_Cannon ||
			building->getType() == BWAPI::UnitTypes::Zerg_Sunken_Colony)
		{
			int dist = building->getDistance(pos);
			if (dist < closestDist)
			{
				closestDist = dist;
				closest = building;
			}
		}
	}
	return closest;
}

// Our nearest static defense building that can hit air, by air distance.
// Null if none.
// NOTE This assumes that we only put marines into a bunker: If it is loaded, it can shoot air.
// If we ever put firebats or SCVs or medics into a bunker, we'll have to do a fancier check.
BWAPI::Unit InformationManager::nearestAirStaticDefense(BWAPI::Position pos) const
{
	int closestDist = 999999;
	BWAPI::Unit closest = nullptr;
	for (BWAPI::Unit building : _staticDefense)
	{
		if (building->getType() == BWAPI::UnitTypes::Terran_Missile_Turret ||
			building->getType() == BWAPI::UnitTypes::Terran_Bunker && !building->getLoadedUnits().empty() ||
			building->getType() == BWAPI::UnitTypes::Protoss_Photon_Cannon || 
			building->getType() == BWAPI::UnitTypes::Zerg_Spore_Colony)
		{
			int dist = building->getDistance(pos);
			if (dist < closestDist)
			{
				closestDist = dist;
				closest = building;
			}
		}
	}
	return closest;
}

// Our nearest shield battery, by air distance.
// Null if none.
BWAPI::Unit InformationManager::nearestShieldBattery(BWAPI::Position pos) const
{
	if (_self->getRace() == BWAPI::Races::Protoss)
	{
		int closestDist = 999999;
		BWAPI::Unit closest = nullptr;
		for (BWAPI::Unit building : _staticDefense)
		{
			if (building->getType() == BWAPI::UnitTypes::Protoss_Shield_Battery)
			{
				int dist = building->getDistance(pos);
				if (dist < closestDist)
				{
					closestDist = dist;
					closest = building;
				}
			}
		}
		return closest;
	}
	return nullptr;
}

// Zerg specific calculation: How many scourge hits are needed
// to kill the enemy's known air fleet?
// This counts individual units--you get 2 scourge per egg.
// One scourge does 110 normal damage.
// NOTE This ignores air armor, which might make a difference in rare cases.
int InformationManager::nScourgeNeeded()
{
	int count = 0;

	for (const auto & kv : getUnitData(_enemy).getUnits())
	{
		const UnitInfo & ui(kv.second);

		// A few unit types should not usually be scourged. Skip them.
		if (ui.type.isFlyer() &&
			ui.type != BWAPI::UnitTypes::Zerg_Overlord &&
			ui.type != BWAPI::UnitTypes::Zerg_Scourge &&
			ui.type != BWAPI::UnitTypes::Protoss_Interceptor)
		{
			int hp = ui.type.maxHitPoints() + ui.type.maxShields();      // assume the worst
			count += (hp + 109) / 110;
		}
	}

	return count;
}

const UnitData & InformationManager::getUnitData(BWAPI::Player player) const
{
	return _unitData.find(player)->second;
}

// Return the set of enemy units targeting a given one of our units.
const BWAPI::Unitset &	InformationManager::getEnemyFireteam(BWAPI::Unit ourUnit) const
{
	auto it = _theirTargets.find(ourUnit);
	if (it != _theirTargets.end())
	{
		return (*it).second;
	}
	return EmptyUnitSet;
}

///////////////////////++
void  InformationManager::setHasInitialized(bool a)
{
	if (a)
	{
		hasInitialized = true;
	}
	else
	{
		hasInitialized = false;
	}
}

void  InformationManager::initializePosition()
{
	Base * myStaringBase = Bases::Instance().myStartingBase();
	hasInitialized = false;

	if (BWAPI::Broodwar->mapFileName() == "(2)Destination.scx")
	{
		//上面
		int dist = myStaringBase->getDistance(BWAPI::Position(1149, 233));
		if (dist < 1000)
		{
			supplyPoint = BWAPI::Position(1506, 215);
		    barracksPoint = BWAPI::Position(1545, 266);
			bunkerPoint = BWAPI::Position(1574, 378);

			chokePoint1 = BWAPI::Position(1481, 399);
			chokePoint2 = BWAPI::Position(1988, 828);
			chokePoint3 = BWAPI::Position(400, 1136);
			chokePoint4 = BWAPI::Position(1646, 650);

			frontLine1 = BWAPI::Position(1482, 1360);
			frontLine2 = BWAPI::Position(1590, 2448);
			frontLine3 = BWAPI::Position(1520, 2989);
			hasInitialized = true;
		}
		else
		{
			supplyPoint = BWAPI::Position(1474, 3856);
			barracksPoint = BWAPI::Position(1412, 3769);
			bunkerPoint = BWAPI::Position(1411, 3701);

			chokePoint1 = BWAPI::Position(1589, 3793);
			chokePoint2 = BWAPI::Position(1069, 3275);
			chokePoint3 = BWAPI::Position(2625, 2961);
			chokePoint4 = BWAPI::Position(1411, 3433);

			frontLine1 = BWAPI::Position(1570, 2590);
			frontLine2 = BWAPI::Position(1582, 1733);
			frontLine3 = BWAPI::Position(1620, 1100);
			hasInitialized = true;
		}
	}
	else if (BWAPI::Broodwar->mapFileName() == "(2)Benzene.scx")
	{
		int dist = myStaringBase->getDistance(BWAPI::Position(351, 3129));
		//左边基地
		if (dist < 1000)
		{
			supplyPoint = BWAPI::Position(737, 2572);
			barracksPoint = BWAPI::Position(578, 2640);
			bunkerPoint = BWAPI::Position(738, 2639);

			chokePoint1 = BWAPI::Position(518, 2671);
			chokePoint2 = BWAPI::Position(371, 1958);
			chokePoint3 = BWAPI::Position(1988, 685);
			frontLine1 = BWAPI::Position(889, 1365);
			frontLine2 = BWAPI::Position(1987, 1901);
			frontLine3 = BWAPI::Position(2754, 1779);
			hasInitialized = true;
		}
		//右边
		else
		{
			supplyPoint = BWAPI::Position(3265, 972);
			barracksPoint = BWAPI::Position(3362, 884);
			bunkerPoint = BWAPI::Position(3266, 877);

			chokePoint1 = BWAPI::Position(3442, 860);
			chokePoint2 = BWAPI::Position(3728, 1456);
			chokePoint3 = BWAPI::Position(2264, 2712);
			frontLine1 = BWAPI::Position(3330, 1996);
			frontLine2 = BWAPI::Position(1987, 1901);
			frontLine3 = BWAPI::Position(1388, 1821);
			hasInitialized = true;
		}
	}
	else if (BWAPI::Broodwar->mapFileName() == "(2)HeartbreakRidge.scx")
	{
		int dist = myStaringBase->getDistance(BWAPI::Position(297, 1244));
		//出生点在地图的左边
		if (dist < 1000)
		{
			supplyPoint = BWAPI::Position(544, 1711);
			barracksPoint = BWAPI::Position(419, 1685);
			bunkerPoint = BWAPI::Position(322, 1712);

			chokePoint1 = BWAPI::Position(434, 1640);
			chokePoint2 = BWAPI::Position(825, 2248);
			chokePoint3 = BWAPI::Position(1211, 2965);
			frontLine1 = BWAPI::Position(1152, 2008);
			frontLine2 = BWAPI::Position(2104, 1501);
			frontLine3 = BWAPI::Position(2980, 947);
			hasInitialized = true;
		}
		else
		{
			supplyPoint = BWAPI::Position(3713, 1392);
			barracksPoint = BWAPI::Position(3555, 1365);
			bunkerPoint = BWAPI::Position(3459, 1360);

			chokePoint1 = BWAPI::Position(3652, 1485);
			chokePoint2 = BWAPI::Position(3306, 848);
			chokePoint3 = BWAPI::Position(2814, 94);
			frontLine1 = BWAPI::Position(2980, 947);
			frontLine2 = BWAPI::Position(2104, 1501);
			frontLine3 = BWAPI::Position(1152, 2008);
			hasInitialized = true;
		}
	}
	else if (BWAPI::Broodwar->mapFileName() == "(3)Aztec.scx")
	{
		//左一基地
		if (myStaringBase->getDistance(BWAPI::Position(312, 2692)) < 1000)
		{/*
			supplyPoint = BWAPI::Position(98, 2096);
			barracksPoint = BWAPI::Position(194, 2006);
			bunkerPoint = BWAPI::Position(101, 2033);
			*/
			supplyPoint = BWAPI::Position(577, 1774);
			barracksPoint = BWAPI::Position(608, 1875);
			bunkerPoint = BWAPI::Position(578, 1968);
			chokePoint1 = BWAPI::Position(490, 1839);


			//chokePoint1 = BWAPI::Position(130, 2022);
			chokePoint2 = BWAPI::Position(632, 1865);
			chokePoint3 = BWAPI::Position(1150, 628);
			frontLine1 = BWAPI::Position(850, 1780);

			frontLine2 = BWAPI::Position(frontLine1.x + 1, frontLine1.y);
			frontLine3 = BWAPI::Position(frontLine1.x, frontLine1.y + 1);;

			//假如敌方的start基地已知，设置3条阵线
			if (Bases::Instance().enemyStart())
			{
				BWAPI::Position enemyBasePosition = Bases::Instance().enemyStart()->getPosition();
				if (enemyBasePosition.y < 1000)
				{
					frontLine2 = BWAPI::Position(2060, 1449);
					frontLine3 = BWAPI::Position(3090, 822);
				}
				else
				{
					frontLine2 = BWAPI::Position(1700, 2473);
					frontLine3 = BWAPI::Position(2721, 3357);
				}
				hasInitialized = true;
			}
		}
		//左二
		else if (myStaringBase->getDistance(BWAPI::Position(2279, 224)) < 1000)
		{/*
			supplyPoint = BWAPI::Position(3009, 207);
			barracksPoint = BWAPI::Position(2978, 280);
			bunkerPoint = BWAPI::Position(2882, 336);
			*/
			supplyPoint = BWAPI::Position(2917, 592);
			barracksPoint = BWAPI::Position(3040, 563);
			bunkerPoint = BWAPI::Position(3169, 589);
			chokePoint1 = BWAPI::Position(3081, 447);

			//chokePoint1 = BWAPI::Position(3139, 273);
			chokePoint2 = BWAPI::Position(3112, 580);
			chokePoint3 = BWAPI::Position(3733, 1964);
			frontLine1 = BWAPI::Position(3112, 818);

			frontLine2 = BWAPI::Position(frontLine1.x + 1, frontLine1.y);
			frontLine3 = BWAPI::Position(frontLine1.x, frontLine1.y + 1);;

			if (Bases::Instance().enemyStart())
			{
				BWAPI::Position enemyBasePosition = Bases::Instance().enemyStart()->getPosition();
				if (enemyBasePosition.x < 1000)
				{
					frontLine2 = BWAPI::Position(2039, 1449);
					frontLine3 = BWAPI::Position(957, 1778);
				}
				else
				{
					frontLine2 = BWAPI::Position(2630, 1823);
					frontLine3 = BWAPI::Position(2814, 3287);
				}
				hasInitialized = true;
			}
		}
		//左三
		else //if (myStaringBase->getDistance(BWAPI::Position(3814, 3246)) < 1000)
		{/*
			supplyPoint = BWAPI::Position(3424, 3889);
			barracksPoint = BWAPI::Position(3337, 3768);
			bunkerPoint = BWAPI::Position(3458, 3826);
			*/
			supplyPoint = BWAPI::Position(2915, 3505);
			barracksPoint = BWAPI::Position(3009, 3476);
			bunkerPoint = BWAPI::Position(3141, 3532);
			chokePoint1 = BWAPI::Position(3020, 3630);


			//chokePoint1 = BWAPI::Position(3340, 3870);
			chokePoint2 = BWAPI::Position(3125, 3570);
			chokePoint3 = BWAPI::Position(1191, 3414);
			frontLine1 = BWAPI::Position(2812, 3300);

			frontLine2 = BWAPI::Position(frontLine1.x + 1, frontLine1.y);
			frontLine3 = BWAPI::Position(frontLine1.x, frontLine1.y + 1);;

			if (Bases::Instance().enemyStart())
			{
				BWAPI::Position enemyBasePosition = Bases::Instance().enemyStart()->getPosition();
				if (enemyBasePosition.x < 1000)
				{
					frontLine2 = BWAPI::Position(1990, 2412);
					frontLine3 = BWAPI::Position(856, 1779);
				}
				else
				{
					frontLine2 = BWAPI::Position(2570, 2340);
					frontLine3 = BWAPI::Position(3078, 852);
				}
				hasInitialized = true;
			}
		}
		return;
	}
	else if (BWAPI::Broodwar->mapFileName() == "(3)TauCross.scx")
	{
		//上一基地
		if (myStaringBase->getDistance(BWAPI::Position(3800, 329)) < 1000)
		{
			supplyPoint = BWAPI::Position(3777, 1006);
			barracksPoint = BWAPI::Position(3778, 1080);
			bunkerPoint = BWAPI::Position(3841, 1167);

			chokePoint1 = BWAPI::Position(3907, 1117);
			chokePoint2 = BWAPI::Position(3457, 1440);
			frontLine1 = BWAPI::Position(3604, 1618);

			frontLine2 = BWAPI::Position(frontLine1.x + 1, frontLine1.y);
			frontLine3 = BWAPI::Position(frontLine1.x, frontLine1.y + 1);;
			chokePoint3 = frontLine1;

			//假如敌方的start基地已知，设置3条阵线
			if (Bases::Instance().enemyStart())
			{
				BWAPI::Position enemyBasePosition = Bases::Instance().enemyStart()->getPosition();
				if (enemyBasePosition.x < 1000)
				{
					chokePoint3 = BWAPI::Position(1649, 3323);
					frontLine2 = BWAPI::Position(2363, 1618);
					frontLine3 = BWAPI::Position(1229, 731);
				}
				else
				{
					chokePoint3 = BWAPI::Position(1040, 631);
					frontLine2 = BWAPI::Position(2612, 2196);
					frontLine3 = BWAPI::Position(1611, 3140);
				}
				hasInitialized = true;
			}
		}
		//上二
		else if (myStaringBase->getDistance(BWAPI::Position(307, 1453)) < 1000)
		{
			supplyPoint = BWAPI::Position(354, 975);
			barracksPoint = BWAPI::Position(261, 887);
			bunkerPoint = BWAPI::Position(257, 815);

			chokePoint1 = BWAPI::Position(247, 977);
			chokePoint2 = BWAPI::Position(951, 638);
			frontLine1 = BWAPI::Position(1170, 742);

			frontLine2 = BWAPI::Position(frontLine1.x + 1, frontLine1.y);
			frontLine3 = BWAPI::Position(frontLine1.x, frontLine1.y + 1);;
			chokePoint3 = frontLine1;

			if (Bases::Instance().enemyStart())
			{
				BWAPI::Position enemyBasePosition = Bases::Instance().enemyStart()->getPosition();
				if (enemyBasePosition.y < 1000)
				{
					chokePoint3 = BWAPI::Position(1631, 3344);
					frontLine2 = BWAPI::Position(2257, 1687);
					frontLine3 = BWAPI::Position(3596, 1704);
				}
				else
				{
					chokePoint3 = BWAPI::Position(3569, 1478);
					frontLine2 = BWAPI::Position(1535, 2221);
					frontLine3 = BWAPI::Position(1616, 3125);
				}
				hasInitialized = true;
			}
		}
		//上三
		else //if (myStaringBase->getDistance(BWAPI::Position(3015, 3811)) < 1000)
		{
			supplyPoint = BWAPI::Position(2245, 3539);
			barracksPoint = BWAPI::Position(2177, 3607);
			bunkerPoint = BWAPI::Position(2245, 3696);

			chokePoint1 = BWAPI::Position(2292, 3623);
			chokePoint2 = BWAPI::Position(1633, 3397);
			frontLine1 = BWAPI::Position(1573, 3112);

			frontLine2 = BWAPI::Position(frontLine1.x + 1, frontLine1.y);
			frontLine3 = BWAPI::Position(frontLine1.x, frontLine1.y + 1);;
			chokePoint3 = frontLine1;

			if (Bases::Instance().enemyStart())
			{
				BWAPI::Position enemyBasePosition = Bases::Instance().enemyStart()->getPosition();
				if (enemyBasePosition.y < 1000)
				{
					chokePoint3 = BWAPI::Position(1065, 662);
					frontLine2 = BWAPI::Position(2217, 2479);
					frontLine3 = BWAPI::Position(3540, 1798);
				}
				else
				{
					chokePoint3 = BWAPI::Position(3513, 1170);
					frontLine2 = BWAPI::Position(1825, 2481);
					frontLine3 = BWAPI::Position(1257, 913);
				}
				hasInitialized = true;
			}
		}
		return;
	}
	else if (BWAPI::Broodwar->mapFileName() == "(4)Andromeda.scx")
	{
		//左上基地
		if (myStaringBase->getDistance(BWAPI::Position(292, 228)) < 1000)
		{
			supplyPoint = BWAPI::Position(483, 1041);
			barracksPoint = BWAPI::Position(354, 1016);
			bunkerPoint = BWAPI::Position(289, 943);

			chokePoint1 = BWAPI::Position(205, 1112);
			chokePoint2 = BWAPI::Position(870, 919);
			chokePoint3 = BWAPI::Position(2056, 2059);
			frontLine1 = BWAPI::Position(1480, 1328);
			chokePoint4 = BWAPI::Position(708, 1147);

			frontLine2 = BWAPI::Position(frontLine1.x + 1, frontLine1.y);
			frontLine3 = BWAPI::Position(frontLine1.x, frontLine1.y + 1);;

			//假如敌方的start基地已知，设置3条阵线
			if (Bases::Instance().enemyStart())
			{
				BWAPI::Position enemyBasePosition = Bases::Instance().enemyStart()->getPosition();
				if (enemyBasePosition.x < 1000 )//左下
				{
					frontLine2 = BWAPI::Position(1000, 2041);
					frontLine3 = BWAPI::Position(1212, 2981);
				}
				else if(enemyBasePosition.y < 1000)//右上
				{
					frontLine2 = BWAPI::Position(2012, 1222);
					frontLine3 = BWAPI::Position(2794, 1180);
				}
				else //右下
				{
					frontLine2 = BWAPI::Position(2338, 2302);
					frontLine3 = BWAPI::Position(2923, 2925);
				}
				hasInitialized = true;
			}
		}
		//左下
		else if (myStaringBase->getDistance(BWAPI::Position(270, 3810)) < 1000)
		{
			supplyPoint = BWAPI::Position(515, 2994);
			barracksPoint = BWAPI::Position(387, 3029);
			bunkerPoint = BWAPI::Position(291, 3117);

			chokePoint1 = BWAPI::Position(290, 3057);
			chokePoint2 = BWAPI::Position(923, 3143);
			chokePoint3 = BWAPI::Position(2056, 2059);
			frontLine1 = BWAPI::Position(1388, 2688);
			chokePoint4 = BWAPI::Position(684, 2936);

			frontLine2 = BWAPI::Position(frontLine1.x + 1, frontLine1.y);
			frontLine3 = BWAPI::Position(frontLine1.x, frontLine1.y + 1);;

			if (Bases::Instance().enemyStart())
			{
				BWAPI::Position enemyBasePosition = Bases::Instance().enemyStart()->getPosition();
				if (enemyBasePosition.x < 1000 && enemyBasePosition.y < 1000)//左上
				{
					frontLine2 = BWAPI::Position(984, 2034);
					frontLine3 = BWAPI::Position(1239, 1164);
				}
				else if (enemyBasePosition.y < 1000)//右上
				{
					frontLine2 = BWAPI::Position(2423, 1778);
					frontLine3 = BWAPI::Position(2882, 1173);
				}
				else//右下
				{
					frontLine2 = BWAPI::Position(2031, 2892);
					frontLine3 = BWAPI::Position(2948, 2984);
				}
				hasInitialized = true;
			}
		}
		//右上
		else if (myStaringBase->getDistance(BWAPI::Position(3800, 260)) < 1000)
		{
			supplyPoint = BWAPI::Position(3523, 1042);
			barracksPoint = BWAPI::Position(3618, 1015);
			bunkerPoint = BWAPI::Position(3716, 944);

			chokePoint1 = BWAPI::Position(3734, 981);
			chokePoint2 = BWAPI::Position(3214, 939);
			chokePoint3 = BWAPI::Position(2056, 2059);
			frontLine1 = BWAPI::Position(2686, 1485);
			chokePoint4 = BWAPI::Position(3372, 1148);

			frontLine2 = BWAPI::Position(frontLine1.x + 1, frontLine1.y);
			frontLine3 = BWAPI::Position(frontLine1.x, frontLine1.y + 1);;

			if (Bases::Instance().enemyStart())
			{
				BWAPI::Position enemyBasePosition = Bases::Instance().enemyStart()->getPosition();
				if (enemyBasePosition.y < 1000 && enemyBasePosition.x < 1000)//左上
				{
					frontLine2 = BWAPI::Position(2061, 1201);
					frontLine3 = BWAPI::Position(1239, 1164);
				}
				else if (enemyBasePosition.x < 1000)//左下
				{
					frontLine2 = BWAPI::Position(1751, 2300);
					frontLine3 = BWAPI::Position(1153, 3006);
				}
				else//右下
				{
					frontLine2 = BWAPI::Position(2913, 2050);
					frontLine3 = BWAPI::Position(2948, 2984);
				}
				hasInitialized = true;
			}
		}
		//右下
		else //if (myStaringBase->getDistance(BWAPI::Position(3809, 3850)) < 1000)
		{
			supplyPoint = BWAPI::Position(3492, 2990);
			barracksPoint = BWAPI::Position(3586, 3031);
			bunkerPoint = BWAPI::Position(3714, 3089);

			chokePoint1 = BWAPI::Position(3418, 2982);
			chokePoint3 = BWAPI::Position(2056, 2059);
			chokePoint2 = BWAPI::Position(3204, 3153);
			frontLine1 = BWAPI::Position(2885, 2654);
			chokePoint4 = BWAPI::Position(3360, 2911);

			frontLine2 = BWAPI::Position(frontLine1.x + 1, frontLine1.y);
			frontLine3 = BWAPI::Position(frontLine1.x, frontLine1.y + 1);;

			if (Bases::Instance().enemyStart())
			{
				BWAPI::Position enemyBasePosition = Bases::Instance().enemyStart()->getPosition();
				if (enemyBasePosition.x < 1000 && enemyBasePosition.y < 1000)//左上
				{
					frontLine2 = BWAPI::Position(1756, 1801);
					frontLine3 = BWAPI::Position(1294, 1182);
				}
				else if (enemyBasePosition.x < 1000)//左下
				{
					frontLine2 = BWAPI::Position(2057, 2899);
					frontLine3 = BWAPI::Position(1284, 2932);
				}
				else//右上
				{
					frontLine2 = BWAPI::Position(2948, 2058);
					frontLine3 = BWAPI::Position(2844, 1253);
				}
				hasInitialized = true;
			}
		}
		return;
	}
	else if (BWAPI::Broodwar->mapFileName() == "(4)CircuitBreaker.scx")
	{
		//左上基地
		if (myStaringBase->getDistance(BWAPI::Position(292, 320)) < 1000)
		{
			supplyPoint = BWAPI::Position(260, 752);
			barracksPoint = BWAPI::Position(130, 754);
			bunkerPoint = BWAPI::Position(34, 810);

			chokePoint1 = BWAPI::Position(88, 769);
			chokePoint2 = BWAPI::Position(608, 1125);
			frontLine1 = BWAPI::Position(889, 1071);

			frontLine2 = BWAPI::Position(frontLine1.x + 1, frontLine1.y);
			frontLine3 = BWAPI::Position(frontLine1.x, frontLine1.y + 1);;
			chokePoint3 = frontLine1;

			//假如敌方的start基地已知，设置3条阵线
			if (Bases::Instance().enemyStart())
			{
				BWAPI::Position enemyBasePosition = Bases::Instance().enemyStart()->getPosition();
				if (enemyBasePosition.x < 1000)//左下
				{
					chokePoint3 = BWAPI::Position(983, 1911);
					frontLine2 = BWAPI::Position(1400, 2045);
					frontLine3 = BWAPI::Position(1411, 2601);
				}
				else if (enemyBasePosition.y < 1000)//右上
				{
					chokePoint3 = BWAPI::Position(2101, 419);

					frontLine2 = BWAPI::Position(889, 1071);
					frontLine3 = BWAPI::Position(2685, 1466);
				}
				else //右下
				{
					chokePoint3 = BWAPI::Position(983, 1911);
					frontLine2 = BWAPI::Position(2050, 2037);
					frontLine3 = BWAPI::Position(2687, 2603);
				}
				hasInitialized = true;
			}
		}
		//左下
		else if (myStaringBase->getDistance(BWAPI::Position(250, 3810)) < 1000)
		{
			supplyPoint = BWAPI::Position(4, 3279);
			barracksPoint = BWAPI::Position(99, 3251);
			bunkerPoint = BWAPI::Position(228, 3283);

			chokePoint1 = BWAPI::Position(344, 3281);
			chokePoint2 = BWAPI::Position(620, 2995);
			frontLine1 = BWAPI::Position(1388, 2688);

			frontLine2 = BWAPI::Position(frontLine1.x + 1, frontLine1.y);
			frontLine3 = BWAPI::Position(frontLine1.x, frontLine1.y + 1);;
			chokePoint3 = frontLine1;

			if (Bases::Instance().enemyStart())
			{
				BWAPI::Position enemyBasePosition = Bases::Instance().enemyStart()->getPosition();
				if (enemyBasePosition.x < 1000 && enemyBasePosition.y < 1000)//左上
				{
					chokePoint3 = BWAPI::Position(922, 1875);

					frontLine2 = BWAPI::Position(1326, 2056);
					frontLine3 = BWAPI::Position(1403, 1460);
				}
				else if (enemyBasePosition.y < 1000)//右上
				{
					chokePoint3 = BWAPI::Position(1239, 1287);

					frontLine2 = BWAPI::Position(2419, 1824);
					frontLine3 = BWAPI::Position(2702, 1456);
				}
				else//右下
				{
					chokePoint3 = BWAPI::Position(2295, 3756);

					frontLine2 = BWAPI::Position(1197, 3412);
					frontLine3 = BWAPI::Position(3076, 3103);
				}
				hasInitialized = true;
			}
		}
		//右上
		else if (myStaringBase->getDistance(BWAPI::Position(3800, 305)) < 1000)
		{
			supplyPoint = BWAPI::Position(4002, 783);
			barracksPoint = BWAPI::Position(3877, 753);
			bunkerPoint = BWAPI::Position(3777, 747);

			chokePoint1 = BWAPI::Position(3765, 771);
			chokePoint2 = BWAPI::Position(3504, 1117);
			frontLine1 = BWAPI::Position(3108, 1017);

			frontLine2 = BWAPI::Position(frontLine1.x + 1, frontLine1.y);
			frontLine3 = BWAPI::Position(frontLine1.x, frontLine1.y + 1);;
			chokePoint3 = frontLine1;

			if (Bases::Instance().enemyStart())
			{
				BWAPI::Position enemyBasePosition = Bases::Instance().enemyStart()->getPosition();
				if (enemyBasePosition.y < 1000 && enemyBasePosition.x < 1000)//左上
				{
					chokePoint3 = BWAPI::Position(2101, 419);

					frontLine2 = BWAPI::Position(3108, 1017);
					frontLine3 = BWAPI::Position(843, 1081);
				}
				else if (enemyBasePosition.x < 1000)//左下
				{
					chokePoint3 = BWAPI::Position(3011, 1983);

					frontLine2 = BWAPI::Position(2112, 2000);
					frontLine3 = BWAPI::Position(1400, 2619);
				}
				else//右下
				{
					chokePoint3 = BWAPI::Position(3011, 1983);

					frontLine2 = BWAPI::Position(2763, 2038);
					frontLine3 = BWAPI::Position(2626, 2623);
				}
				hasInitialized = true;
			}
		}
		//右下
		else //if (myStaringBase->getDistance(BWAPI::Position(3809, 3796)) < 1000)
		{
			supplyPoint = BWAPI::Position(4000, 3214);
			barracksPoint = BWAPI::Position(3873, 3250);
			bunkerPoint = BWAPI::Position(3782, 3278);

			chokePoint1 = BWAPI::Position(3743, 3290);
			chokePoint2 = BWAPI::Position(3527, 3009);
			frontLine1 = BWAPI::Position(3169, 3055);

			frontLine2 = BWAPI::Position(frontLine1.x + 1, frontLine1.y);
			frontLine3 = BWAPI::Position(frontLine1.x, frontLine1.y + 1);;
			chokePoint3 = frontLine1;

			if (Bases::Instance().enemyStart())
			{
				BWAPI::Position enemyBasePosition = Bases::Instance().enemyStart()->getPosition();
				if (enemyBasePosition.x < 1000 && enemyBasePosition.y < 1000)//左上
				{
					chokePoint3 = BWAPI::Position(2963, 2018);

					frontLine2 = BWAPI::Position(2089, 2078);
					frontLine3 = BWAPI::Position(1400, 1464);
				}
				else if (enemyBasePosition.x < 1000)//左下
				{
					chokePoint3 = BWAPI::Position(1700, 3786);

					frontLine2 = BWAPI::Position(2851, 3440);
					frontLine3 = BWAPI::Position(1045, 3160);
				}
				else//右上
				{
					chokePoint3 = BWAPI::Position(2963, 2018);

					frontLine2 = BWAPI::Position(2773, 2041);
					frontLine3 = BWAPI::Position(2675, 1443);
				}
				hasInitialized = true;
			}
		}
		return;
	}
	else if (BWAPI::Broodwar->mapFileName() == "(4)EmpireoftheSun.scm")
	{
		//左上基地
		if (myStaringBase->getDistance(BWAPI::Position(292, 320)) < 1000)
		{
			supplyPoint = BWAPI::Position(674, 178);
			barracksPoint = BWAPI::Position(673, 245);
			bunkerPoint = BWAPI::Position(676, 335);

			chokePoint1 = BWAPI::Position(673, 444);
			chokePoint2 = BWAPI::Position(1181, 574);
			frontLine1 = BWAPI::Position(1228, 894);
			chokePoint3 = BWAPI::Position(537, 1826);

			frontLine2 = BWAPI::Position(frontLine1.x + 1, frontLine1.y);
			frontLine3 = BWAPI::Position(frontLine1.x, frontLine1.y + 1);;

			//假如敌方的start基地已知，设置3条阵线
			if (Bases::Instance().enemyStart())
			{
				BWAPI::Position enemyBasePosition = Bases::Instance().enemyStart()->getPosition();
				if (enemyBasePosition.x < 1000)//左下
				{
					frontLine2 = BWAPI::Position(1369, 2095);
					frontLine3 = BWAPI::Position(1210, 3120);
				}
				else if (enemyBasePosition.y < 1000)//右上
				{
					frontLine2 = BWAPI::Position(2080, 1391);
					frontLine3 = BWAPI::Position(2887, 945);
				}
				else //右下
				{
					frontLine2 = BWAPI::Position(2138, 1997);
					frontLine3 = BWAPI::Position(2925, 3130);
				}
				hasInitialized = true;
			}
		}
		//左下
		else if (myStaringBase->getDistance(BWAPI::Position(285, 3879)) < 1000)
		{
			supplyPoint = BWAPI::Position(676, 3696);
			barracksPoint = BWAPI::Position(676, 3770);
			bunkerPoint = BWAPI::Position(675, 3855);

			chokePoint1 = BWAPI::Position(618, 3946);
			chokePoint2 = BWAPI::Position(1157, 3562);
			frontLine1 = BWAPI::Position(1269, 3139);
			chokePoint3 = BWAPI::Position(590, 2187);

			frontLine2 = BWAPI::Position(frontLine1.x + 1, frontLine1.y);
			frontLine3 = BWAPI::Position(frontLine1.x, frontLine1.y + 1);;

			if (Bases::Instance().enemyStart())
			{
				BWAPI::Position enemyBasePosition = Bases::Instance().enemyStart()->getPosition();
				if (enemyBasePosition.x < 1000 && enemyBasePosition.y < 1000)//左上
				{
					frontLine2 = BWAPI::Position(1339, 2029);
					frontLine3 = BWAPI::Position(1292, 894);
				}
				else if (enemyBasePosition.y < 1000)//右上
				{
					frontLine2 = BWAPI::Position(2041, 2133);
					frontLine3 = BWAPI::Position(2839, 905);
				}
				else//右下
				{
					frontLine2 = BWAPI::Position(2058, 2691);
					frontLine3 = BWAPI::Position(3009, 3190);
				}
				hasInitialized = true;
			}
		}
		//右上
		else if (myStaringBase->getDistance(BWAPI::Position(3800, 224)) < 1000)
		{
			supplyPoint = BWAPI::Position(3333, 176);
			barracksPoint = BWAPI::Position(3301, 253);
			bunkerPoint = BWAPI::Position(3333, 337);

			chokePoint1 = BWAPI::Position(3415, 272);
			chokePoint2 = BWAPI::Position(2968, 528);
			frontLine1 = BWAPI::Position(2843, 879);
			chokePoint3 = BWAPI::Position(3610, 1886);

			frontLine2 = BWAPI::Position(frontLine1.x + 1, frontLine1.y);
			frontLine3 = BWAPI::Position(frontLine1.x, frontLine1.y + 1);;

			if (Bases::Instance().enemyStart())
			{
				BWAPI::Position enemyBasePosition = Bases::Instance().enemyStart()->getPosition();
				if (enemyBasePosition.y < 1000 && enemyBasePosition.x < 1000)//左上
				{
					frontLine2 = BWAPI::Position(2036, 1321);
					frontLine3 = BWAPI::Position(1252, 933);
				}
				else if (enemyBasePosition.x < 1000)//左下
				{
					frontLine2 = BWAPI::Position(2041, 2030);
					frontLine3 = BWAPI::Position(1264, 3124);
				}
				else//右下
				{
					frontLine2 = BWAPI::Position(2831, 2051);
					frontLine3 = BWAPI::Position(3004, 2980);
				}
				hasInitialized = true;
			}
		}
		//右下
		else //if (myStaringBase->getDistance(BWAPI::Position(3809, 3796)) < 1000)
		{
			supplyPoint = BWAPI::Position(3329, 3699);
			barracksPoint = BWAPI::Position(3300, 3768);
			bunkerPoint = BWAPI::Position(3328, 3855);

			chokePoint1 = BWAPI::Position(3407, 3938);
			chokePoint2 = BWAPI::Position(2963, 3555);
			frontLine1 = BWAPI::Position(2838, 3193);
			chokePoint3 = BWAPI::Position(3594, 2186);

			frontLine2 = BWAPI::Position(frontLine1.x + 1, frontLine1.y);
			frontLine3 = BWAPI::Position(frontLine1.x, frontLine1.y + 1);;

			if (Bases::Instance().enemyStart())
			{
				BWAPI::Position enemyBasePosition = Bases::Instance().enemyStart()->getPosition();
				if (enemyBasePosition.x < 1000 && enemyBasePosition.y < 1000)//左上
				{
					frontLine2 = BWAPI::Position(2051, 1986);
					frontLine3 = BWAPI::Position(1158, 941);
				}
				else if (enemyBasePosition.x < 1000)//左下
				{
					frontLine2 = BWAPI::Position(2083, 2650);
					frontLine3 = BWAPI::Position(1058, 3173);
				}
				else//右上
				{
					frontLine2 = BWAPI::Position(2849, 1967);
					frontLine3 = BWAPI::Position(2872, 917);
				}
				hasInitialized = true;
			}
		}
		return;
	}
	else if (BWAPI::Broodwar->mapFileName() == "(4)Fortress.scx")
	{
		//左基地/
		if (myStaringBase->getDistance(BWAPI::Position(292, 2399)) < 1000)
		{
			supplyPoint = BWAPI::Position(259, 1935);
			barracksPoint = BWAPI::Position(355, 1910);
			bunkerPoint = BWAPI::Position(483, 1936);

			chokePoint1 = BWAPI::Position(531, 2024);
			chokePoint2 = BWAPI::Position(680, 1647);
			frontLine1 = BWAPI::Position(1009, 1647);
			chokePoint3 = BWAPI::Position(1336, 2283);

			frontLine2 = BWAPI::Position(frontLine1.x + 1, frontLine1.y);
			frontLine3 = BWAPI::Position(frontLine1.x, frontLine1.y + 1);;

			//假如敌方的start基地已知，设置3条阵线
			if (Bases::Instance().enemyStart())
			{
				BWAPI::Position enemyBasePosition = Bases::Instance().enemyStart()->getPosition();
				if (enemyBasePosition.y < 1000)//上
				{
					frontLine2 = BWAPI::Position(1919, 1351);
					frontLine3 = BWAPI::Position(2412, 1000);
				}
				else if (enemyBasePosition.x > 3000)//右
				{
					frontLine2 = BWAPI::Position(2082, 2059);
					frontLine3 = BWAPI::Position(3076, 2557);
				}
				else //下
				{
					frontLine2 = BWAPI::Position(1591, 2431);
					frontLine3 = BWAPI::Position(1734, 3239);
				}
				hasInitialized = true;
			}
		}
		//右基地
		else if (myStaringBase->getDistance(BWAPI::Position(3800, 1774)) < 1000)
		{
			supplyPoint = BWAPI::Position(3491, 2163);
			barracksPoint = BWAPI::Position(3588, 2166);
			bunkerPoint = BWAPI::Position(3715, 2130);

			chokePoint1 = BWAPI::Position(3849, 2143);
			chokePoint2 = BWAPI::Position(3437, 2481);
			frontLine1 = BWAPI::Position(3283, 2480);
			chokePoint3 = BWAPI::Position(2826, 1899);

			frontLine2 = BWAPI::Position(frontLine1.x + 1, frontLine1.y);
			frontLine3 = BWAPI::Position(frontLine1.x, frontLine1.y + 1);;

			if (Bases::Instance().enemyStart())
			{
				BWAPI::Position enemyBasePosition = Bases::Instance().enemyStart()->getPosition();
				if (enemyBasePosition.x < 1000)//左
				{
					frontLine2 = BWAPI::Position(1995, 2056);
					frontLine3 = BWAPI::Position(1067, 1632);
				}
				else if (enemyBasePosition.y < 1000)//上
				{
					frontLine2 = BWAPI::Position(2532, 1600);
					frontLine3 = BWAPI::Position(2363, 987);
				}
				else//下
				{
					frontLine2 = BWAPI::Position(2132, 2869);
					frontLine3 = BWAPI::Position(1743, 3119);
				}
				hasInitialized = true;
			}
		}
		//上基地
		else if (myStaringBase->getDistance(BWAPI::Position(1635, 260)) < 1000)
		{
			supplyPoint = BWAPI::Position(2081, 147);
			barracksPoint = BWAPI::Position(2084, 214);
			bunkerPoint = BWAPI::Position(2145, 307);

			chokePoint1 = BWAPI::Position(2131, 404);
			chokePoint2 = BWAPI::Position(2566, 509);
			frontLine1 = BWAPI::Position(2391, 711);
			chokePoint3 = BWAPI::Position(1623, 1253);

			frontLine2 = BWAPI::Position(frontLine1.x + 1, frontLine1.y);
			frontLine3 = BWAPI::Position(frontLine1.x, frontLine1.y + 1);;

			if (Bases::Instance().enemyStart())
			{
				BWAPI::Position enemyBasePosition = Bases::Instance().enemyStart()->getPosition();
				if (enemyBasePosition.x < 1000)//左
				{
					frontLine2 = BWAPI::Position(2013, 1375);
					frontLine3 = BWAPI::Position(1105, 1673);
				}
				else if (enemyBasePosition.x > 3000)//右
				{
					frontLine2 = BWAPI::Position(2659, 1862);
					frontLine3 = BWAPI::Position(3022, 2399);
				}
				else//下
				{
					frontLine2 = BWAPI::Position(2090, 2019);
					frontLine3 = BWAPI::Position(1800, 3310);
				}
				hasInitialized = true;
			}
		}
		//下基地/
		else //if (myStaringBase->getDistance(BWAPI::Position(2532, 3877)) < 1000)
		{
			supplyPoint = BWAPI::Position(1923, 3953);
			barracksPoint = BWAPI::Position(1831, 3862);
			bunkerPoint = BWAPI::Position(1826, 3793);

			chokePoint1 = BWAPI::Position(2093, 3983);
			chokePoint2 = BWAPI::Position(1739, 3515);
			frontLine1 = BWAPI::Position(1792, 3330);
			chokePoint3 = BWAPI::Position(2253, 2984);

			frontLine2 = BWAPI::Position(frontLine1.x + 1, frontLine1.y);
			frontLine3 = BWAPI::Position(frontLine1.x, frontLine1.y + 1);;

			if (Bases::Instance().enemyStart())
			{
				BWAPI::Position enemyBasePosition = Bases::Instance().enemyStart()->getPosition();
				if (enemyBasePosition.y < 1000)//上
				{
					frontLine2 = BWAPI::Position(2065, 2060);
					frontLine3 = BWAPI::Position(2447, 900);
				}
				else if (enemyBasePosition.x < 1000)//左
				{
					frontLine2 = BWAPI::Position(1517, 2266);
					frontLine3 = BWAPI::Position(1073, 1666);
				}
				else//右
				{
					frontLine2 = BWAPI::Position(2239, 2731);
					frontLine3 = BWAPI::Position(3032, 2482);
				}
				hasInitialized = true;
			}
		}
		return;
	}
	else if (BWAPI::Broodwar->mapFileName() == "(4)Python.scx")
	{
		//左基地//
		if (myStaringBase->getDistance(BWAPI::Position(279, 2791)) < 1000)
		{
			supplyPoint = BWAPI::Position(164, 2259);
			barracksPoint = BWAPI::Position(256, 2296);
			bunkerPoint = BWAPI::Position(97, 2191);

			chokePoint1 = BWAPI::Position(191, 2328);
			chokePoint2 = BWAPI::Position(700, 2105);
			frontLine1 = BWAPI::Position(1281, 2071);
			chokePoint3 = BWAPI::Position(586, 709);

			frontLine2 = BWAPI::Position(frontLine1.x + 1, frontLine1.y);
			frontLine3 = BWAPI::Position(frontLine1.x, frontLine1.y + 1);;

			//假如敌方的start基地已知，设置3条阵线
			if (Bases::Instance().enemyStart())
			{
				BWAPI::Position enemyBasePosition = Bases::Instance().enemyStart()->getPosition();
				if (enemyBasePosition.y < 1000)//上
				{
					frontLine2 = BWAPI::Position(1591, 1389);
					frontLine3 = BWAPI::Position(1840, 814);
				}
				else if (enemyBasePosition.x > 3000)//右
				{
					frontLine2 = BWAPI::Position(2171, 1997);
					frontLine3 = BWAPI::Position(3206, 2057);
				}
				else //下
				{
					frontLine2 = BWAPI::Position(1664, 2554);
					frontLine3 = BWAPI::Position(2178, 3278);
				}
				hasInitialized = true;
			}
		}
		//右基地
		else if (myStaringBase->getDistance(BWAPI::Position(3800, 1335)) < 1000)
		{
			supplyPoint = BWAPI::Position(3875, 1775);
			//barracksPoint = BWAPI::Position(3906, 1847);
			barracksPoint = BWAPI::Position(3745, 1743);
			bunkerPoint = BWAPI::Position(3906, 1872);

			//bunkerPoint = BWAPI::Position(3778, 1778);

			chokePoint1 = BWAPI::Position(3641, 1787);
			chokePoint2 = BWAPI::Position(3403, 2077);
			frontLine1 = BWAPI::Position(2820, 1957);
			chokePoint3 = BWAPI::Position(2772, 1251);

			frontLine2 = BWAPI::Position(frontLine1.x + 1, frontLine1.y);
			frontLine3 = BWAPI::Position(frontLine1.x, frontLine1.y + 1);;

			if (Bases::Instance().enemyStart())
			{
				BWAPI::Position enemyBasePosition = Bases::Instance().enemyStart()->getPosition();
				if (enemyBasePosition.x < 1000)//左
				{
					frontLine2 = BWAPI::Position(2030, 2036);
					frontLine3 = BWAPI::Position(1092, 2063);
				}
				else if (enemyBasePosition.y < 1000)//上
				{
					frontLine2 = BWAPI::Position(2344, 1398);
					frontLine3 = BWAPI::Position(1775, 967);
				}
				else//下
				{
					frontLine2 = BWAPI::Position(2741, 2597);
					frontLine3 = BWAPI::Position(2238, 3110);
				}
				hasInitialized = true;
			}
		}
		//上基地
		else if (myStaringBase->getDistance(BWAPI::Position(2701, 306)) < 1000)
		{
			supplyPoint = BWAPI::Position(2017, 84);
			barracksPoint = BWAPI::Position(2050, 149);
			bunkerPoint = BWAPI::Position(1922, 82);

			chokePoint1 = BWAPI::Position(2243, 401);
			chokePoint2 = BWAPI::Position(1856, 619);
			frontLine1 = BWAPI::Position(1798, 1221);
			chokePoint3 = BWAPI::Position(642, 618);

			frontLine2 = BWAPI::Position(frontLine1.x + 1, frontLine1.y);
			frontLine3 = BWAPI::Position(frontLine1.x, frontLine1.y + 1);;

			if (Bases::Instance().enemyStart())
			{
				BWAPI::Position enemyBasePosition = Bases::Instance().enemyStart()->getPosition();
				if (enemyBasePosition.x < 1000)//左
				{
					frontLine2 = BWAPI::Position(1478, 1741);
					frontLine3 = BWAPI::Position(993, 2045);
				}
				else if (enemyBasePosition.x > 3000)//右
				{
					frontLine2 = BWAPI::Position(2324, 1572);
					frontLine3 = BWAPI::Position(3159, 2069);
				}
				else//下
				{
					frontLine2 = BWAPI::Position(2040 ,2041);
					frontLine3 = BWAPI::Position(2180, 3187);
				}
				hasInitialized = true;
			}
		}
		//下基地//
		else //if (myStaringBase->getDistance(BWAPI::Position(1402, 3850)) < 1000)
		{
			supplyPoint = BWAPI::Position(1986, 3922);
			barracksPoint = BWAPI::Position(1856, 3858);
			bunkerPoint = BWAPI::Position(2080, 3952);

			chokePoint1 = BWAPI::Position(1852, 3869);
			chokePoint2 = BWAPI::Position(2184, 3443);
			frontLine1 = BWAPI::Position(2159, 2975);
			chokePoint3 = BWAPI::Position(3356, 3457);
			
			frontLine2 = BWAPI::Position(frontLine1.x + 1, frontLine1.y);
			frontLine3 = BWAPI::Position(frontLine1.x, frontLine1.y + 1);;

			if (Bases::Instance().enemyStart())
			{
				BWAPI::Position enemyBasePosition = Bases::Instance().enemyStart()->getPosition();
				if (enemyBasePosition.y < 1000)//上
				{
					frontLine2 = BWAPI::Position(1906, 1723);
					frontLine3 = BWAPI::Position(1880, 809);
				}
				else if (enemyBasePosition.x < 1000)//左
				{
					frontLine2 = BWAPI::Position(1662, 2583);
					frontLine3 = BWAPI::Position(1155, 2105);
				}
				else//右
				{
					frontLine2 = BWAPI::Position(2549, 2512);
					frontLine3 = BWAPI::Position(3143, 2011);
				}
				hasInitialized = true;
			}
		}
		return;
	}
}

BWAPI::Position   InformationManager::getPosition(std::string positionName)
{
	if (positionName == "supplyPoint")
	{
		return supplyPoint;
	}
	else if (positionName == "barracksPoint")
	{
		return barracksPoint;
	}
	else if (positionName == "bunkerPoint")
	{
		return bunkerPoint;
	}
	else if (positionName == "chokePoint1")
	{
		return chokePoint1;
	}
	else if (positionName == "chokePoint2")
	{
		return chokePoint2;
	}
	else if (positionName == "chokePoint3")
	{
		return chokePoint3;
	}
	else if (positionName == "chokePoint4")
	{
		return chokePoint4;
	}
	else if (positionName == "frontLine1")
	{
		return frontLine1;
	}
	else if (positionName == "frontLine2")
	{
		return frontLine2;
	}
	else if (positionName == "frontLine3")
	{
		return frontLine3;
	}
	else
		return  BWAPI::Positions::None;

}

///////////////////////__

////@zhang 2019年9月3日18:44:13 for BWEM start
//LocutusUnit& InformationManager::getLocutusUnit(BWAPI::Unit unit)
//{
//	if (_myUnits.find(unit) == _myUnits.end())
//		_myUnits[unit] = LocutusUnit(unit);
//
//	return _myUnits[unit];
//}
////@zhang 2019年9月3日18:44:13 for BWEM end

InformationManager & InformationManager::Instance()
{
	static InformationManager instance;
	return instance;
}
