BWAPI::TilePosition BuildingPlacer::getBuildLocationNear(const Building & b, int buildDist, bool horizontalOnly) const
{
    SparCraft::Timer t;
    t.start();

    // get the precomputed vector of tile positions which are sorted closes to this location
    const std::vector<BWAPI::TilePosition> & closestToBuilding = MapTools::Instance().getClosestTilesTo(BWAPI::Position(b.desiredPosition));

    double ms1 = t.getElapsedTimeInMilliSec();

    // special easy case of having no pylons
    int numPylons = BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Protoss_Pylon);
    if (b.type.requiresPsi() && numPylons == 0)
    {
        return BWAPI::TilePositions::None;
    }

    // iterate through the list until we've found a suitable location
    for (size_t i(0); i < closestToBuilding.size(); ++i)
    {
        if (canBuildHereWithSpace(closestToBuilding[i], b, buildDist, horizontalOnly))
        {
            double ms = t.getElapsedTimeInMilliSec();
            //BWAPI::Broodwar->printf("Building Placer Took %d iterations, lasting %lf ms @ %lf iterations/ms, %lf setup ms", i, ms, (i / ms), ms1);

            return closestToBuilding[i];
        }
    }

    double ms = t.getElapsedTimeInMilliSec();
    //BWAPI::Broodwar->printf("Building Placer Took %lf ms", ms);

	return  BWAPI::TilePositions::None;
}
BWAPI::TilePosition BuildingPlacer::getBuildLocationNear(const Building & b, int buildDist, bool horizontalOnly) const
{
    SparCraft::Timer t;
	t.start();

	BWTA::BaseLocation *home = findHome();
	BWAPI::TilePosition chokeTile = findChoke(home);

	int homex = home->getTilePosition().x;
	int homey = home->getTilePosition().y;
	int midx = (chokeTile.x + homex) / 2;
	int midy = (chokeTile.y + homey) / 2;
	static int px = midx;
	static int py = midy;

	// 1 if choke farther right, -1 if farther left
	int ix = chokeTile.x > midx ? 1 : -1;
	// 1 if choke farther south, -1 if farther north
	int iy = chokeTile.y < midy ? -1 : 1;

    // get the precomputed vector of tile positions which are sorted closes to this location
    const std::vector<BWAPI::TilePosition> & closestToBuilding = MapTools::Instance().getClosestTilesTo(BWAPI::Position(b.desiredPosition));

    double ms1 = t.getElapsedTimeInMilliSec();

    // special easy case of having no pylons
    int numPylons = BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Protoss_Pylon);
	int numGate = BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Protoss_Gateway);
	int numCan = BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Protoss_Photon_Cannon);

    if (b.type.requiresPsi() && numPylons == 0)
    {
        return BWAPI::TilePositions::None;
    }

	if (BWAPI::Broodwar->mapName().compare(1,9,"Andromeda")) {
		if (b.type == BWAPI::UnitTypes::Protoss_Pylon && numPylons == 0) {
			BWAPI::TilePosition pos = drawPylon(midx, midy, ix, iy, b);
			if (pos != BWAPI::TilePositions::None) {
				px = pos.x;
				py = pos.y;
				return pos;
			}

		}

		else if (b.type == BWAPI::UnitTypes::Protoss_Forge) {
			BWAPI::TilePosition pos = drawForge(midx, midy, ix, iy, b);
			if (pos != BWAPI::TilePositions::None) {
				return pos;
			}
		}

		else if (b.type == BWAPI::UnitTypes::Protoss_Photon_Cannon) {
			BWAPI::TilePosition pos = drawProtonCannon(homex, homey, ix, iy, b);
			if (pos != BWAPI::TilePositions::None) {
				return pos;
			}
		}

		//else if (b.type == BWAPI::UnitTypes::Protoss_Gateway && numGate == 0) {
		//	return drawGateway(homex, homey, ix, iy, b);
		//}

	}

	// iterate through the list until we've found a suitable location
	for (size_t i(0); i < closestToBuilding.size(); ++i)
	{
		if (b.type == BWAPI::UnitTypes::Protoss_Gateway && numGate == 0) {
			buildDist = 0;
		}
		if (canBuildHereWithSpace(closestToBuilding[i], b, buildDist, horizontalOnly))
		{
			double ms = t.getElapsedTimeInMilliSec();
			//BWAPI::Broodwar->printf("Building Placer Took %d iterations, lasting %lf ms @ %lf iterations/ms, %lf setup ms", i, ms, (i / ms), ms1);

			return closestToBuilding[i];
		}
	}

	double ms = t.getElapsedTimeInMilliSec();
	//BWAPI::Broodwar->printf("Building Placer Took %lf ms", ms);
	

	return  BWAPI::TilePositions::None;
}
BWAPI::TilePosition BuildingPlacer::getBuildLocationNear(const Building & b, int buildDist, bool inRegionPriority, bool horizontalOnly) const
{
	//returns a valid build location near the specified tile position.
	//searches outward in a spiral.
	int x      = b.desiredPosition.x;
	int y      = b.desiredPosition.y;
	int length = 1;
	int j      = 0;
	bool first = true;
	int dx     = 0;
	int dy     = 1;

    SparCraft::Timer t;
    t.start();
    int iter = 0;
    int buildingPlacerTimeLimit = 2000;

	while (length < BWAPI::Broodwar->mapWidth()) //We'll ride the spiral to the end
	{
        if (t.getElapsedTimeInMilliSec() > buildingPlacerTimeLimit)
        {
            if (Options::Debug::DRAW_UALBERTABOT_DEBUG)
            {
                BWAPI::Broodwar->printf("Building Placer Timed Out %d ms", buildingPlacerTimeLimit);
            }

            return BWAPI::TilePositions::None;
        }

		//if we can build here, return this tile position
		if (x >= 0 && x < BWAPI::Broodwar->mapWidth() && y >= 0 && y < BWAPI::Broodwar->mapHeight())
		{
            iter++;
            
			// can we build this building at this location
			bool canBuild					= this->canBuildHereWithSpace(BWAPI::TilePosition(x, y), b, buildDist, horizontalOnly);

			// my starting region
			BWTA::Region * myRegion			= BWTA::getRegion(BWTA::getStartLocation(BWAPI::Broodwar->self())->getTilePosition()); 

			// the region the build tile is in
			BWTA::Region * tileRegion		= BWTA::getRegion(BWAPI::TilePosition(x,y));

			// is the proposed tile in our region?
			bool tileInRegion				= (tileRegion == myRegion);

			// if this location has priority to be built within our own region
			if (inRegionPriority)
			{
				// if the tile is in region and we can build it there
				if (tileInRegion && canBuild)
				{
                    if (Options::Debug::DRAW_UALBERTABOT_DEBUG)
                    {
                        //BWAPI::Broodwar->printf("Building Placer Took %lf ms", t.getElapsedTimeInMilliSec());
                    }

					// return that position
					return BWAPI::TilePosition(x, y);
				}
			}
			// otherwise priority is not set for this building
			else
			{
				if (canBuild)
				{
                    if (Options::Debug::DRAW_UALBERTABOT_DEBUG)
                    {
                        //BWAPI::Broodwar->printf("Building Placer Took %lf ms", t.getElapsedTimeInMilliSec());
                    }

			        return BWAPI::TilePosition(x, y);
				}
			}
		}

		//otherwise, move to another position
		x = x + dx;
		y = y + dy;

		//count how many steps we take in this direction
		j++;
		if (j == length) //if we've reached the end, its time to turn
		{
			//reset step counter
			j = 0;

			//Spiral out. Keep going.
			if (!first)
				length++; //increment step counter if needed

			//first=true for every other turn so we spiral out at the right rate
			first =! first;

			//turn counter clockwise 90 degrees:
			if (dx == 0)
			{
				dx = dy;
				dy = 0;
			}
			else
			{
				dy = -dx;
				dx = 0;
			}
		}
		//Spiral out. Keep going.
	}

	return  BWAPI::TilePositions::None;
}
//ctx add
BWAPI::TilePosition BuildingPlacer::getBuildLocationFarFromChokePoint(const Building & b, int buildDist, bool horizontalOnly, bool flag) const
{
	SparCraft::Timer t;
	t.start();

	BWAPI::TilePosition startTitlePos = BWAPI::Broodwar->self()->getStartLocation();
	BWTA::Chokepoint *chokePoint = BWTA::getNearestChokepoint(startTitlePos);
	BWAPI::Position chokeCenterPosition = chokePoint->getCenter();
	BWTA::Region *baseRegion = BWTA::getRegion(BWAPI::Broodwar->self()->getStartLocation());
	BWTA::Polygon basePolygon = baseRegion->getPolygon();
	BWAPI::Position farPosition =  BWAPI::Position(0, 0);
	BWAPI::TilePosition resultPosition = BWAPI::TilePosition(0, 0);
	double dis = 0.0;

	

	for (int i = 0; i < (int)basePolygon.size(); i++) {
		BWAPI::Position point = basePolygon[i];
		double ms1 = t.getElapsedTimeInMilliSec();
		if (point.getDistance(chokeCenterPosition) > dis) {
			dis = point.getDistance(chokeCenterPosition);
			farPosition = point;
		}
	}

	const std::vector<BWAPI::TilePosition> & closestToBuilding = MapTools::Instance().getClosestTilesTo(BWAPI::Position(b.desiredPosition));

	//get best solution
	dis = farPosition.getDistance(BWAPI::Position(startTitlePos));
	
	if (flag == true) {
		for (size_t i = 0; i < closestToBuilding.size(); ++i)
		{
			double ms1 = t.getElapsedTimeInMilliSec();
			if (canBuildHereWithSpace(closestToBuilding[i], b, buildDist, horizontalOnly) && dis > farPosition.getDistance(BWAPI::Position(closestToBuilding[i])))
			{
				resultPosition = closestToBuilding[i];
				break;
				//return closestToBuilding[i];
			}
		}
	}
	else {
		for (size_t i = 0; i < closestToBuilding.size(); ++i)
		{
			double ms1 = t.getElapsedTimeInMilliSec();
			if (canBuildHereWithSpace(closestToBuilding[i], b, buildDist, horizontalOnly) && dis < farPosition.getDistance(BWAPI::Position(closestToBuilding[i])))
			{
				resultPosition = closestToBuilding[i];
				break;
				//return closestToBuilding[i];
			}
		}
	}
	
	if (!basePolygon.isInside(BWAPI::Position(resultPosition))) {
		resultPosition = getBuildLocationNear(b, buildDist, horizontalOnly);
	}

	return resultPosition;
}
BWAPI::TilePosition BuildingPlacer::getBuildLocationNear(const Building & b, int buildDist, int timeLimitMS, bool inRegionPriority, bool horizontalOnly) const
{
	struct SearchState{
		int _length;
		int _j;
		bool _first;
		int _dx;
		int _dy;
		int _x;
		int _y;
		bool _timeOut;
		BWAPI::TilePosition _candidatePos;
		SearchState(int length, int j, bool first, int dx, int dy, int x, int y, bool timeOut = false, BWAPI::TilePosition candidatePos = BWAPI::TilePositions::None) :
			_length(length), _j(j), _first(first), _dx(dx), _dy(dy), _x(x), _y(y), _timeOut(timeOut), _candidatePos(candidatePos)
		{}
		SearchState() :_timeOut(false), _candidatePos(BWAPI::TilePositions::None)
		{}
	};
	struct SearchParams{
		Building _b;
		int _buildDist;
		bool _inRegionPriority;
		bool _horizontalOnly;
		SearchParams(const Building & b, int buildDist, bool inRegionPriority, bool horizontalOnly):
			_b(b), _buildDist(buildDist), _inRegionPriority(inRegionPriority), _horizontalOnly(horizontalOnly)
		{}
		SearchParams()
		{}
		bool operator==(const SearchParams& other)
		{
			return _b.type == other._b.type &&
				_b.desiredPosition == other._b.desiredPosition&&
				_b.builderUnit == other._b.builderUnit&&
				_buildDist == other._buildDist&&
				_inRegionPriority == other._inRegionPriority&&
				_horizontalOnly == other._horizontalOnly;
		}
	};
	if (timeLimitMS <= 0)
	{
		throw std::runtime_error("Building Placer not given any time: "+timeLimitMS);
	}
	static SearchState lastState;
	static SearchParams lastParams;
	SearchState state(1, 0, true, 0, 1, b.desiredPosition.x, b.desiredPosition.y);
	SearchParams params(b, buildDist, inRegionPriority, horizontalOnly);
	if (lastState._timeOut && lastParams == params)
	{
		state = lastState;

		//BWAPI::Broodwar->printf("Building Placer for building %s resuming... %d",b.type.getName().c_str(),state._length);
		//Logger::LogAppendToFile(UAB_LOGFILE, "Building Placer for building %s resuming... %d\n", b.type.getName().c_str(), state._length);
	}

    SparCraft::Timer t;
    t.start();
	// my starting region
	//BWTA::Region * myRegion = BWTA::getRegion(BWTA::getStartLocation(BWAPI::Broodwar->self())->getTilePosition());
	BWTA::Region * myRegion = BWTA::getRegion(b.desiredPosition);
	
	//get max spiral size
	int maxDist = 0;
	for (auto point : myRegion->getPolygon())
	{
		int radius = std::ceil((BWAPI::TilePosition(point) - b.desiredPosition).getLength());
		if (radius > maxDist)
		{
			maxDist = radius;
		}
	}
	while (state._length < maxDist || (state._length <BWAPI::Broodwar->mapWidth() && state._candidatePos == BWAPI::TilePositions::None)) //We'll ride the spiral to the end
	{
		if (t.getElapsedTimeInMilliSec() > timeLimitMS)
        {
            if (Options::Debug::DRAW_UALBERTABOT_DEBUG && !state._timeOut)
            {
				//BWAPI::Broodwar->printf("Building Placer Timed Out at %d ms on building %s", timeLimitMS, b.type.getName().c_str());
				//Logger::LogAppendToFile(UAB_LOGFILE, "Building Placer Timed Out at %d ms on building %s\n", timeLimitMS, b.type.getName().c_str());
            }
			lastState = state;
			lastState._timeOut = true; 
			lastParams = params;
			throw std::runtime_error("Building Placer Timed Out. State saved for resuming later.");
        }

		//if we can build here, return this tile position
		if (state._x >= 0 && state._x < BWAPI::Broodwar->mapWidth() && state._y >= 0 && state._y < BWAPI::Broodwar->mapHeight())
		{
            
			// can we build this building at this location
			bool canBuild = this->canBuildHereWithSpace(BWAPI::TilePosition(state._x, state._y), b, buildDist, horizontalOnly);

			if (canBuild)
			{
				// if this location has priority to be built within our own region
				if (inRegionPriority)
				{
					// the region the build tile is in
					BWTA::Region * tileRegion = BWTA::getRegion(BWAPI::TilePosition(state._x, state._y));

					// is the proposed tile in our region?
					bool tileInRegion = (tileRegion == myRegion);

					// if the tile is in region and we can build it there
					if (tileInRegion)
					{
						if (Options::Debug::DRAW_UALBERTABOT_DEBUG)
						{
							//BWAPI::Broodwar->printf("Building Placer Took %lf ms", t.getElapsedTimeInMilliSec());
							//BWAPI::Broodwar->printf("Building position found in region");
							//Logger::LogAppendToFile(UAB_LOGFILE, "Building position found in region\n");
						}

						// return that position
						lastState._timeOut = false;

						return BWAPI::TilePosition(state._x, state._y);
					}
					else if (state._candidatePos==BWAPI::TilePositions::None)//save an out of region position as candidate
					{
						if (Options::Debug::DRAW_UALBERTABOT_DEBUG)
						{
							//BWAPI::Broodwar->printf("Saving position found not in region");
							//Logger::LogAppendToFile(UAB_LOGFILE, "Saving position found not in region\n");
						}
						state._candidatePos = BWAPI::TilePosition(state._x, state._y);
					}
				}
				// otherwise priority is not set for this building
				else
				{
					if (Options::Debug::DRAW_UALBERTABOT_DEBUG)
					{
						//BWAPI::Broodwar->printf("Building Placer Took %lf ms", t.getElapsedTimeInMilliSec());
						//BWAPI::Broodwar->printf("Building position found not in region");
						//Logger::LogAppendToFile(UAB_LOGFILE, "Building position found not in region\n");
					}
					lastState._timeOut = false;
					return BWAPI::TilePosition(state._x, state._y);
				}
			}
		}

		//otherwise, move to another position
		state._x = state._x + state._dx;
		state._y = state._y + state._dy;

		//count how many steps we take in this direction
		state._j++;
		if (state._j == state._length) //if we've reached the end, its time to turn
		{
			//reset step counter
			state._j = 0;

			//Spiral out. Keep going.
			if (!state._first)
			{
				state._length++; //increment step counter if needed
			}

			//first=true for every other turn so we spiral out at the right rate
			state._first = !state._first;

			//turn counter clockwise 90 degrees:
			if (state._dx == 0)
			{
				state._dx = state._dy;
				state._dy = 0;
			}
			else
			{
				state._dy = -state._dx;
				state._dx = 0;
			}
		}
		//Spiral out. Keep going.
	}
	lastState._timeOut = false;
	if (Options::Debug::DRAW_UALBERTABOT_DEBUG)
	{
		//BWAPI::Broodwar->printf("Rode spiral out. Building %s position: %d %d", b.type.getName().c_str(), state._candidatePos.x, state._candidatePos.y);
		//Logger::LogAppendToFile(UAB_LOGFILE, "Rode spiral out. Building %s position: %d %d\n", b.type.getName().c_str(),  state._candidatePos.x, state._candidatePos.y);
	}
	return  state._candidatePos;
}
void ProductionManager::manageBuildOrderQueue(int timeLimitMS)
{
	// if there is nothing in the queue, oh well
	if (queue.isEmpty()) 
	{
		return;
	}
	SparCraft::Timer t;
	t.start();
	// the current item to be used
	BuildOrderItem & currentItem = queue.getHighestPriorityItem();

	// while there is still something left in the queue
	while (!queue.isEmpty()) 
	{
		// this is the unit which can produce the currentItem
        BWAPI::UnitInterface* producer = getProducer(currentItem.metaType);

		// check to see if we can make it right now
		bool canMake = canMakeNow(producer, currentItem.metaType);

		// if we try to build too many refineries manually remove it
		if (currentItem.metaType.isRefinery() && (BWAPI::Broodwar->self()->allUnitCount(BWAPI::Broodwar->self()->getRace().getRefinery() >= 3)))
		{
			queue.removeCurrentHighestPriorityItem();
			break;
		}

		// if the next item in the list is a building and we can't yet make it
        if (currentItem.metaType.isBuilding() && !(producer && canMake) && !currentItem.metaType.unitType.isAddon())
		{
			// construct a temporary building object
			Building b(currentItem.metaType.unitType, BWAPI::Broodwar->self()->getStartLocation());

			// set the producer as the closest worker, but do not set its job yet
			producer = WorkerManager::Instance().getBuilder(b, false);

			// predict the worker movement to that building location
			predictWorkerMovement(b, timeLimitMS - t.getElapsedTimeInMilliSec());
		}

		// if we can make the current item
		if (producer && canMake) 
		{
			// create it
			createMetaType(producer, currentItem.metaType);
			assignedWorkerForThisBuilding = false;
			haveLocationForThisBuilding = false;

			// and remove it from the queue
			queue.removeCurrentHighestPriorityItem();

			// don't actually loop around in here
			break;
		}
		// otherwise, if we can skip the current item
		else if (queue.canSkipItem())
		{
			// skip it
			queue.skipItem();

			// and get the next one
			currentItem = queue.getNextHighestPriorityItem();				
		}
		else 
		{
			// so break out
			break;
		}
	}
}