void LurkerManager::assignTargetsOld(const BWAPI::Unitset & targets) { const BWAPI::Unitset & LurkerUnits = getUnits(); // figure out targets BWAPI::Unitset LurkerUnitTargets; std::copy_if(targets.begin(), targets.end(), std::inserter(LurkerUnitTargets, LurkerUnitTargets.end()), [](BWAPI::Unit u){ return u->isVisible() && !u->isFlying(); }); for (auto & LurkerUnit : LurkerUnits) { /* We don't care what the order is, we just want to attack */ // if the order is to attack or defend //if (order.getType() == SquadOrderTypes::Attack || order.getType() == SquadOrderTypes::Defend) //{ // if there are targets //if (!LurkerUnitTargets.empty()) //{ // find the best target for this lurker BWAPI::Unit target = getTarget(LurkerUnit, LurkerUnitTargets); if (target && Config::Debug::DrawUnitTargetInfo) { BWAPI::Broodwar->drawLineMap(LurkerUnit->getPosition(), LurkerUnit->getTargetPosition(), BWAPI::Colors::Purple); } // burrow and attack it if (targetsInRange(LurkerUnit, targets) > 0) { LurkerUnit->burrow(); Micro::SmartAttackUnit(LurkerUnit, target); } else if (targetsInRange(LurkerUnit,targets) == 0){ LurkerUnit->unburrow(); Micro::SmartMove(LurkerUnit, order.getPosition()); } } // if there are no targets //else //{ // LurkerUnit->unburrow(); // if we're not near the order position //Micro::SmartMove(LurkerUnit, order.getPosition()); //} //} //} }
// still has bug in it somewhere, use Old version void RangedManager::assignTargetsNew(const BWAPI::Unitset & targets) { const BWAPI::Unitset & rangedUnits = getUnits(); // figure out targets BWAPI::Unitset rangedUnitTargets; std::copy_if(targets.begin(), targets.end(), std::inserter(rangedUnitTargets, rangedUnitTargets.end()), [](BWAPI::Unit u){ return u->isVisible(); }); BWAPI::Unitset rangedUnitsToAssign(rangedUnits); std::map<BWAPI::Unit, int> attackersAssigned; for (auto & unit : rangedUnitTargets) { attackersAssigned[unit] = 0; } // keep assigning targets while we have attackers and targets remaining while (!rangedUnitsToAssign.empty() && !rangedUnitTargets.empty()) { auto attackerAssignment = findClosestUnitPair(rangedUnitsToAssign, rangedUnitTargets); BWAPI::Unit & attacker = attackerAssignment.first; BWAPI::Unit & target = attackerAssignment.second; UAB_ASSERT_WARNING(attacker, "We should have chosen an attacker!"); if (!attacker) { break; } if (!target) { Micro::SmartAttackMove(attacker, order.getPosition()); continue; } if (Config::Micro::KiteWithRangedUnits) { if (attacker->getType() == BWAPI::UnitTypes::Zerg_Mutalisk || attacker->getType() == BWAPI::UnitTypes::Terran_Vulture) { Micro::SmartAttackUnit(attacker, target); } else { //Micro::MutaDanceTarget(attacker, target); } } else { Micro::SmartAttackUnit(attacker, target); } // update the number of units assigned to attack the target we found int & assigned = attackersAssigned[attackerAssignment.second]; assigned++; // if it's a small / fast unit and there's more than 2 things attacking it already, don't assign more if ((target->getType().isWorker() || target->getType() == BWAPI::UnitTypes::Zerg_Zergling) && (assigned > 2)) { rangedUnitTargets.erase(target); } // if it's a building and there's more than 10 things assigned to it already, don't assign more else if (target->getType().isBuilding() && (assigned > 10)) { rangedUnitTargets.erase(target); } rangedUnitsToAssign.erase(attacker); } // if there's no targets left, attack move to the order destination if (rangedUnitTargets.empty()) { for (auto & unit : rangedUnitsToAssign) { if (unit->getDistance(order.getPosition()) > 100) { // move to it Micro::SmartAttackMove(unit, order.getPosition()); } } } }
std::unordered_map<BWAPI::Unit, BWAPI::Unit> RangedManager::assignEnemy(const BWAPI::Unitset &meleeUnits, BWAPI::Unitset & meleeUnitTargets) { std::unordered_map<BWAPI::Unit, BWAPI::Unit> attacker2target; std::vector<PairEdge> edges(meleeUnits.size()*meleeUnitTargets.size()); int top = 0; for (auto &attacker : meleeUnits) { for (auto &target : meleeUnitTargets) { if (!target) continue; edges[top].attacker = attacker; edges[top].target = target; int groundWeaponRange = attacker->getType().groundWeapon().maxRange(); edges[top++].distance = -getRealPriority(attacker, target); } } sort(edges.begin(), edges.end()); sort(edges.begin(), edges.end(), [](PairEdge a, PairEdge b) { return a.target->getID() <b.target->getID(); }); PairEdge dummy; dummy.target = nullptr; edges.push_back(dummy); BWAPI::Unit p = nullptr; int sum = 0; for (auto idx = edges.begin(); idx!=edges.end(); idx++) { if (!idx->target) continue; double Health = (((double)idx->target->getHitPoints() + idx->target->getShields())); if (idx->target->getType().size() == BWAPI::UnitSizeTypes::Small) Health *= 2; if (idx->target->getType().size() == BWAPI::UnitSizeTypes::Medium) Health *= 1.5; if (p != idx->target) { sum = 0; p = idx->target; } else { sum++; //assign at most 7 units attack //BWAPI::Broodwar <<( idx->target->getHitPoints()+idx->target->getShields()) / idx->attacker->getType().groundWeapon().damageAmount() << std::endl; if (sum>std::min(8, 1+(int)(Health / idx->attacker->getType().groundWeapon().damageAmount()))) { idx->attacker = nullptr; if (meleeUnitTargets.find(idx->target) != meleeUnitTargets.end()) meleeUnitTargets.erase(idx->target); } } } int t = 0; for (bool halt=false; halt == false; halt = true) { halt= true; auto tmpRangeStart = edges.begin(); auto maxRangeStart = tmpRangeStart, maxRangeEnd = tmpRangeStart; double tmpsum = 0, tmpres = INT_MIN; for (auto idx = edges.begin(); idx->target != nullptr; idx++) { if (attacker2target.find(idx->attacker) != attacker2target.end()) continue; if (idx->target != (idx + 1)->target) { if (tmpsum > tmpres) { tmpres = tmpsum; maxRangeStart = tmpRangeStart; maxRangeEnd = idx + 1; } tmpsum = 0; tmpRangeStart = idx + 1; } else tmpsum += getRealPriority(idx->attacker, idx->target); } for (auto kdx = maxRangeStart; kdx < maxRangeEnd; kdx++) { if (attacker2target.find(kdx->attacker) != attacker2target.end()) continue; attacker2target[kdx->attacker] = kdx->target; halt = false; } t++; } return attacker2target; }
void CombatCommander::updateDefenseSquads() { if (_combatUnits.empty() || BWAPI::Broodwar->self()->allUnitCount(BWAPI::UnitTypes::Terran_Science_Vessel) == 1) { return; } BWTA::BaseLocation * enemyBaseLocation = InformationManager::Instance().getMainBaseLocation(BWAPI::Broodwar->enemy()); BWTA::Region * enemyRegion = nullptr; if (enemyBaseLocation) { enemyRegion = BWTA::getRegion(enemyBaseLocation->getPosition()); } // for each of our occupied regions for (BWTA::Region * myRegion : InformationManager::Instance().getOccupiedRegions(BWAPI::Broodwar->self())) { // don't defend inside the enemy region, this will end badly when we are stealing gas if (myRegion == enemyRegion) { continue; } BWAPI::Position regionCenter = myRegion->getCenter(); if (!regionCenter.isValid()) { continue; } // start off assuming all enemy units in region are just workers int numDefendersPerEnemyUnit = 2; // all of the enemy units in this region BWAPI::Unitset enemyUnitsInRegion; for (auto & unit : BWAPI::Broodwar->enemy()->getUnits()) { // if it's an overlord, don't worry about it for defense, we don't care what they see if (unit->getType() == BWAPI::UnitTypes::Zerg_Overlord) { continue; } if (BWTA::getRegion(BWAPI::TilePosition(unit->getPosition())) == myRegion) { enemyUnitsInRegion.insert(unit); } } // we can ignore the first enemy worker in our region since we assume it is a scout for (auto & unit : enemyUnitsInRegion) { if (unit->getType().isWorker()) { enemyUnitsInRegion.erase(unit); break; } } int numEnemyFlyingInRegion = std::count_if(enemyUnitsInRegion.begin(), enemyUnitsInRegion.end(), [](BWAPI::Unit u) { return u->isFlying(); }); int numEnemyGroundInRegion = std::count_if(enemyUnitsInRegion.begin(), enemyUnitsInRegion.end(), [](BWAPI::Unit u) { return !u->isFlying(); }); std::stringstream squadName; squadName << "Base Defense " << regionCenter.x << " " << regionCenter.y; // if there's nothing in this region to worry about if (enemyUnitsInRegion.empty()) { // if a defense squad for this region exists, remove it if (_squadData.squadExists(squadName.str())) { _squadData.getSquad(squadName.str()).clear(); } // and return, nothing to defend here continue; } else { // if we don't have a squad assigned to this region already, create one if (!_squadData.squadExists(squadName.str())) { SquadOrder defendRegion(SquadOrderTypes::Defend, regionCenter, 32 * 25, "Defend Region!"); _squadData.addSquad(squadName.str(), Squad(squadName.str(), defendRegion, BaseDefensePriority)); } } // assign units to the squad if (_squadData.squadExists(squadName.str())) { Squad & defenseSquad = _squadData.getSquad(squadName.str()); // figure out how many units we need on defense int flyingDefendersNeeded = numDefendersPerEnemyUnit * numEnemyFlyingInRegion; int groundDefensersNeeded = numDefendersPerEnemyUnit * numEnemyGroundInRegion; updateDefenseSquadUnits(defenseSquad, flyingDefendersNeeded, groundDefensersNeeded); } else { UAB_ASSERT_WARNING(false, "Squad should have existed: %s", squadName.str().c_str()); } } // for each of our defense squads, if there aren't any enemy units near the position, remove the squad std::set<std::string> uselessDefenseSquads; for (const auto & kv : _squadData.getSquads()) { const Squad & squad = kv.second; const SquadOrder & order = squad.getSquadOrder(); if (order.getType() != SquadOrderTypes::Defend) { continue; } bool enemyUnitInRange = false; for (auto & unit : BWAPI::Broodwar->enemy()->getUnits()) { if (unit->getPosition().getDistance(order.getPosition()) < order.getRadius()) { enemyUnitInRange = true; break; } } if (!enemyUnitInRange) { _squadData.getSquad(squad.getName()).clear(); } } }
void TankManager::executeMicro(const BWAPI::Unitset & targets) { const BWAPI::Unitset & tanks = getUnits(); // figure out targets BWAPI::Unitset tankTargets; std::copy_if(targets.begin(), targets.end(), std::inserter(tankTargets, tankTargets.end()), [](BWAPI::Unit u){ return u->isVisible() && !u->isFlying(); }); int siegeTankRange = BWAPI::UnitTypes::Terran_Siege_Tank_Siege_Mode.groundWeapon().maxRange() - 32; bool haveSiege = BWAPI::Broodwar->self()->hasResearched(BWAPI::TechTypes::Tank_Siege_Mode); // for each zealot for (auto & tank : tanks) { // train sub units such as scarabs or interceptors //trainSubUnits(rangedUnit); bool tankNearChokepoint = false; for (auto & choke : BWTA::getChokepoints()) { if (choke->getCenter().getDistance(tank->getPosition()) < 64) { tankNearChokepoint = true; break; } } // if the order is to attack or defend if (order.getType() == SquadOrderTypes::Attack || order.getType() == SquadOrderTypes::Defend) { // if there are targets if (!tankTargets.empty()) { // find the best target for this zealot BWAPI::Unit target = getTarget(tank, tankTargets); if (target && Config::Debug::DrawUnitTargetInfo) { BWAPI::Broodwar->drawLineMap(tank->getPosition(), tank->getTargetPosition(), BWAPI::Colors::Purple); } // if we are within siege range, siege up if (tank->getDistance(target) < siegeTankRange && tank->canSiege() && !tankNearChokepoint) { tank->siege(); } // otherwise unsiege and move in else if ((!target || tank->getDistance(target) > siegeTankRange) && tank->canUnsiege()) { tank->unsiege(); } // if we're in siege mode just attack the target if (tank->isSieged()) { Micro::SmartAttackUnit(tank, target); } // if we're not in siege mode kite the target else { Micro::SmartKiteTarget(tank, target); } } // if there are no targets else { // if we're not near the order position if (tank->getDistance(order.getPosition()) > 100) { if (tank->canUnsiege()) { tank->unsiege(); } else { // move to it Micro::SmartAttackMove(tank, order.getPosition()); } } } } } }