void ScoutManager::calculateEnemyRegionVertices() { BWTA::BaseLocation * enemyBaseLocation = InformationManager::Instance().getMainBaseLocation(BWAPI::Broodwar->enemy()); //UAB_ASSERT_WARNING(enemyBaseLocation, "We should have an enemy base location if we are fleeing"); if (!enemyBaseLocation) { return; } BWTA::Region * enemyRegion = enemyBaseLocation->getRegion(); //UAB_ASSERT_WARNING(enemyRegion, "We should have an enemy region if we are fleeing"); if (!enemyRegion) { return; } const BWAPI::Position basePosition = BWAPI::Position(BWAPI::Broodwar->self()->getStartLocation()); const std::vector<BWAPI::TilePosition> & closestTobase = MapTools::Instance().getClosestTilesTo(basePosition); std::set<BWAPI::Position> unsortedVertices; // check each tile position for (size_t i(0); i < closestTobase.size(); ++i) { const BWAPI::TilePosition & tp = closestTobase[i]; if (BWTA::getRegion(tp) != enemyRegion) { continue; } // a tile is 'surrounded' if // 1) in all 4 directions there's a tile position in the current region // 2) in all 4 directions there's a buildable tile bool surrounded = true; if (BWTA::getRegion(BWAPI::TilePosition(tp.x+1, tp.y)) != enemyRegion || !BWAPI::Broodwar->isBuildable(BWAPI::TilePosition(tp.x+1, tp.y)) || BWTA::getRegion(BWAPI::TilePosition(tp.x, tp.y+1)) != enemyRegion || !BWAPI::Broodwar->isBuildable(BWAPI::TilePosition(tp.x, tp.y+1)) || BWTA::getRegion(BWAPI::TilePosition(tp.x-1, tp.y)) != enemyRegion || !BWAPI::Broodwar->isBuildable(BWAPI::TilePosition(tp.x-1, tp.y)) || BWTA::getRegion(BWAPI::TilePosition(tp.x, tp.y-1)) != enemyRegion || !BWAPI::Broodwar->isBuildable(BWAPI::TilePosition(tp.x, tp.y -1))) { surrounded = false; } // push the tiles that aren't surrounded if (!surrounded && BWAPI::Broodwar->isBuildable(tp)) { if (Config::Debug::DrawScoutInfo) { int x1 = tp.x * 32 + 2; int y1 = tp.y * 32 + 2; int x2 = (tp.x+1) * 32 - 2; int y2 = (tp.y+1) * 32 - 2; BWAPI::Broodwar->drawTextMap(x1+3, y1+2, "%d", MapTools::Instance().getGroundDistance(BWAPI::Position(tp), basePosition)); BWAPI::Broodwar->drawBoxMap(x1, y1, x2, y2, BWAPI::Colors::Green, false); } unsortedVertices.insert(BWAPI::Position(tp) + BWAPI::Position(16, 16)); } } std::vector<BWAPI::Position> sortedVertices; BWAPI::Position current = *unsortedVertices.begin(); _enemyRegionVertices.push_back(current); unsortedVertices.erase(current); // while we still have unsorted vertices left, find the closest one remaining to current while (!unsortedVertices.empty()) { double bestDist = 1000000; BWAPI::Position bestPos; for (const BWAPI::Position & pos : unsortedVertices) { double dist = pos.getDistance(current); if (dist < bestDist) { bestDist = dist; bestPos = pos; } } current = bestPos; sortedVertices.push_back(bestPos); unsortedVertices.erase(bestPos); } // let's close loops on a threshold, eliminating death grooves int distanceThreshold = 100; while (true) { // find the largest index difference whose distance is less than the threshold int maxFarthest = 0; int maxFarthestStart = 0; int maxFarthestEnd = 0; // for each starting vertex for (int i(0); i < (int)sortedVertices.size(); ++i) { int farthest = 0; int farthestIndex = 0; // only test half way around because we'll find the other one on the way back for (size_t j(1); j < sortedVertices.size()/2; ++j) { int jindex = (i + j) % sortedVertices.size(); if (sortedVertices[i].getDistance(sortedVertices[jindex]) < distanceThreshold) { farthest = j; farthestIndex = jindex; } } if (farthest > maxFarthest) { maxFarthest = farthest; maxFarthestStart = i; maxFarthestEnd = farthestIndex; } } // stop when we have no long chains within the threshold if (maxFarthest < 4) { break; } double dist = sortedVertices[maxFarthestStart].getDistance(sortedVertices[maxFarthestEnd]); std::vector<BWAPI::Position> temp; for (size_t s(maxFarthestEnd); s != maxFarthestStart; s = (s+1) % sortedVertices.size()) { temp.push_back(sortedVertices[s]); } sortedVertices = temp; } _enemyRegionVertices = sortedVertices; }
void ScoutManager::moveScouts() { if (!workerScout || !workerScout->exists() || !workerScout->getPosition().isValid() || !(workerScout->getHitPoints() > 0)) { return; } // get the enemy base location, if we have one BWTA::BaseLocation * enemyBaseLocation = InformationManager::Instance().getMainBaseLocation(BWAPI::Broodwar->enemy()); // determine the region that the enemy is in BWTA::Region * enemyRegion = enemyBaseLocation ? enemyBaseLocation->getRegion() : NULL; // determine the region the scout is in BWAPI::TilePosition scoutTile(workerScout->getPosition()); BWTA::Region * scoutRegion = scoutTile.isValid() ? BWTA::getRegion(scoutTile) : NULL; // we only care if the scout is under attack within the enemy region // this ignores if their scout worker attacks it on the way to their base if (workerScout->isUnderAttack() && (scoutRegion == enemyRegion)) { scoutUnderAttack = true; } if (!workerScout->isUnderAttack() && !enemyWorkerInRadius()) { scoutUnderAttack = false; } // if we know where the enemy region is and where our scout is if (enemyRegion && scoutRegion) { // if the scout is in the enemy region if (scoutRegion == enemyRegion) { std::vector<GroundThreat> groundThreats; fillGroundThreats(groundThreats, workerScout->getPosition()); // get the closest enemy worker BWAPI::UnitInterface* closestWorker = closestEnemyWorker(); // if the worker scout is not under attack if (!scoutUnderAttack) { // if there is a worker nearby, harass it if (closestWorker && (workerScout->getDistance(closestWorker) < 800)) { smartAttack(workerScout, closestWorker); } // otherwise keep moving to the enemy region else { // move to the enemy region smartMove(workerScout, enemyBaseLocation->getPosition()); BWAPI::Broodwar->drawLineMap(workerScout->getPosition().x, workerScout->getPosition().y, enemyBaseLocation->getPosition().x, enemyBaseLocation->getPosition().y, BWAPI::Colors::Yellow); } } // if the worker scout is under attack else { BWAPI::Position fleeTo = calcFleePosition(groundThreats, NULL); if (Options::Debug::DRAW_UALBERTABOT_DEBUG) BWAPI::Broodwar->drawCircleMap(fleeTo.x, fleeTo.y, 10, BWAPI::Colors::Red); for (BWAPI::UnitInterface* unit : BWAPI::Broodwar->getUnitsInRadius(fleeTo, 10)) { if (Options::Debug::DRAW_UALBERTABOT_DEBUG) BWAPI::Broodwar->drawCircleMap(unit->getPosition().x, unit->getPosition().y, 5, BWAPI::Colors::Cyan, true); } smartMove(workerScout, fleeTo); } } // if the scout is not in the enemy region else if (scoutUnderAttack) { smartMove(workerScout, BWAPI::Position(BWAPI::Broodwar->self()->getStartLocation())); } else { // move to the enemy region smartMove(workerScout, enemyBaseLocation->getPosition()); } } // for each start location in the level if (!enemyRegion) { for (BWTA::BaseLocation * startLocation : BWTA::getStartLocations()) { // if we haven't explored it yet if (!BWAPI::Broodwar->isExplored(startLocation->getTilePosition())) { // assign a zergling to go scout it smartMove(workerScout, BWAPI::Position(startLocation->getTilePosition())); return; } } } }