// Get a sunken position depending on whether or not we have an expansion. BWAPI::TilePosition BuildingManager::getSunkenPosition() { BWAPI::UnitType sunk = BWAPI::UnitTypes::Zerg_Creep_Colony; // Always make sunkens at natural expansion if you can. if (createdHatcheriesSet.size() >= 1) { BWAPI::TilePosition hatchPosition = createdHatcheriesVector[0]; BWAPI::Unit pExpansion = BWAPI::Broodwar->getClosestUnit(BWAPI::Position(hatchPosition), BWAPI::Filter::IsResourceDepot); BWAPI::Unitset myUnits = pExpansion->getUnitsInRadius(200); BWAPI::UnitType larva = BWAPI::UnitTypes::Zerg_Larva; BWAPI::UnitType egg = BWAPI::UnitTypes::Zerg_Egg; std::set<BWAPI::TilePosition> stuffBlocking; for (BWAPI::Unit p : myUnits) { if (p->getType() == larva || p->getType() == egg) { stuffBlocking.insert(p->getTilePosition()); } } while (buildableSunkenTilePositions.size() >= 1) { std::set<BWAPI::TilePosition>::iterator it = buildableSunkenTilePositions.begin(); BWAPI::TilePosition mySunkPosition = *it; Building z(sunk, mySunkPosition); if (!isCreepStarted()) { if (BWAPI::Broodwar->hasCreep(mySunkPosition) && createdBuilding.find(mySunkPosition) == createdBuilding.end() && stuffBlocking.find(mySunkPosition) == stuffBlocking.end()) { return *it; } else { buildableSunkenTilePositions.erase(*it); } } else { if (BWAPI::Broodwar->hasCreep(mySunkPosition) && BuildingPlacer::Instance().canBuildHere(mySunkPosition, z) && createdBuilding.find(mySunkPosition) == createdBuilding.end() && stuffBlocking.find(mySunkPosition) == stuffBlocking.end()) { return *it; } else { buildableSunkenTilePositions.erase(*it); } } } //BWAPI::Position hatchPositionBWP = BWAPI::Position(hatchPosition); BWAPI::TilePosition sunkPosition; const std::set<BWTA::BaseLocation*, std::less<BWTA::BaseLocation*>> locations = BWTA::getBaseLocations(); BWTA::BaseLocation *myLocation; for (BWTA::BaseLocation *p : locations) { BWAPI::TilePosition z = p->getTilePosition(); if (z == hatchPosition){ // This is the BWTA::Location of the first hatchery. myLocation = p; } } // Get the set of mineral patches closest to BWTA::Location of the hatchery(it will return like 8 mineral patches usually in the set) const BWAPI::Unitset mineralSet = myLocation->getMinerals(); //const std::set<BWAPI::Unit*> mineralSet = myLocation->getMinerals(); int counter3 = 0; int theX = 0; int theY = 0; for (BWAPI::Unit p : mineralSet) { // Calculate the difference between LeftMostMineralPatch.x - ExpansionHatchery.x and store it in theX theX = p->getTilePosition().x - hatchPosition.x; // Calculate the difference between LeftMostMineralPatch.y - ExpansionHatchery.y and store it in theY theY = p->getTilePosition().y - hatchPosition.y; break; } int gasX = 0; int gasY = 0; int counter4 = 0; //Get all geysers near the expansion -- it should only return 1 for every map we play.. const BWAPI::Unitset gasSet = myLocation->getGeysers(); for (BWAPI::Unit p : gasSet) { // Calculate the difference between Geyser.x- ExpansionHatchery.x and store it in gasX gasX = p->getTilePosition().x - hatchPosition.x; // Calculate the difference between Geyser.y- ExpansionHatchery.y and store it in gasY gasY = p->getTilePosition().y - hatchPosition.y; break; } int newx, newy; int outercounter = 0; int counter = 0; newx = hatchPosition.x; newy = hatchPosition.y; int beginX = hatchPosition.x; int beginY = hatchPosition.y; //sunkPosition = BWAPI::TilePosition(newx, newy); //test4 = BuildingPlacer::Instance().canBuildHere(sunkPosition, b); // Form a new sunken position that starts at the hatchery positive. std::vector<bool> incrementDecrement(8); bool useGasX = false; bool useGasY = false; bool useMinX = false; bool useMinY = false; if (abs(gasX) > abs(gasY)) { useGasX = true; } else { useGasY = true; } if (abs(theX) > abs(theY)) { useMinX = true; } else { useMinY = true; } // Gas differences is probably more reliable than mineral differences. if (useGasX && useMinX) { useMinX = false; useMinY = true; } // Gas differences is probably more reliable than mineral differences. if (useGasY && useMinY) { useMinY = false; useMinX = true; } // This is where we decide which directions we can make sunkens in // It is based on X and Y differences in LeftMostMineral - Hatchery and Geyser - Hatchery // It is not very good right now because we only use two variables. We should use four variables for better dection : theX, theY, gasX, gasY // If the difference between LeftMostMineral.y - Hatchery.y is negative : It means the mierals are North of the hatchery // If the difference between Geyser.X - Hatchery.X is negative : It means that the geyser is Left of the Hatchery if (useMinY && useGasX) { if (theY < 0 && gasX < 0) { /* Allow the following directions for sunken to be built : Increase X & Keep Y the same (East) Increase X & Increase Y (Go South East) Decrease X & Increase Y (Go South West) Keep X Same, Increase Y (Go South) Go NORTHEAST **Test** */ incrementDecrement = { true, false, true, true, false, false, true, false }; } // If the difference between LeftMostMineral.y - Hatchery.y is positive : It means the mierals are South of the hatchery // If the difference between Geyser.X - Hatchery.X is negative : It means that the geyser is Left of the Hatchery else if (gasX < 0 && theY > 0) { /* Allow the following directions for sunken to be built : Increase X & Keep Y the same (East) Increase X & Decrease Y (Go North East) Decrease X & Decrease Y (Go North West) Keep X Same, Decrease Y (Go North) GO SOUTHEAST --> Test */ incrementDecrement = { false, true, true, false, true, false, false, true }; } // If the difference between LeftMostMineral.y - Hatchery.y is negative : It means the mierals are North of the hatchery // If the difference between Geyser.X - Hatchery.X is positive : It means that the geyser is Right or East of the Hatchery else if (gasX > 0 && theY < 0) { /* Allow the following directions for sunken to be built : Decrease X & Keep Y the same (West) Decrease X & Increase Y (Go South West) Increase X & Increase Y (Go South East) Keep X Same, Increase Y (Go South) Go Northwest */ incrementDecrement = { true, false, false, true, false, true, true, false }; } // If the difference between LeftMostMineral.y - Hatchery.y is positive : It means the mierals are South of the hatchery // If the difference between Geyser.X - Hatchery.X is positive : It means that the geyser is Right or East of the Hatchery else if (theY > 0 && gasX > 0) { /* Decrease X & Keep Y the same (West) Decrease X & Decrease Y (Go North West) Increase X & Decrease Y (Go North East) Don't change X Decrease y (Go North) Go Southwest */ incrementDecrement = { false, true, false, false, true, true, false, true }; } } else if (useMinX && useGasY) { // If the difference between LeftMostMineral.x - Hatchery.x is positive : It means the mierals are East of the hatchery // If the difference between Geyser.Y - Hatchery.Y is negative : It means that the geyser is North of the Hatchery if (gasY < 0 && theX > 0) { /* Decrease X(Go West) Increase Y(Go South) Decrease X, Increase Y(Go South West) Decrease X, Decrease Y(Go North West) I think can try SouthEast ? */ incrementDecrement = { false, false, false, true, true, true, true, false }; } // If the difference between LeftMostMineral.x - Hatchery.x is positive : It means the mierals are East of the hatchery // If the difference between Geyser.Y - Hatchery.Y is positive : It means that the geyser is South of the Hatchery else if (theX > 0 && gasY > 0) { /* Decrease X(Go West) Decrease Y(Go North) Decrease X, INcrease Y(Go SOuth West) Decrease X, Decrease Y(Go North West) I think can try NOrthEast? */ incrementDecrement = { false, false, false, true, true, true, false, true }; } // If the difference between LeftMostMineral.x - Hatchery.x is negative : It means the minerals are West of the hatchery // If the difference between Geyser.Y - Hatchery.Y is negative : It means that the geyser is North of the Hatchery else if (gasY < 0 && theX < 0) { /* Increase X(Go East) Increase Y(Go South) Increase X, Increase Y(Go South East) Increase X, Decrease Y(Go North East) I think maybe Southwest is okay?.. Even NW might be okay */ incrementDecrement = { true, true, true, false, false, false, true, false }; } // If the difference between LeftMostMineral.x - Hatchery.x is negative : It means the minerals are West of the hatchery // If the difference between Geyser.Y - Hatchery.Y is positive : It means that the geyser is South of the Hatchery else if (gasY > 0 && theX < 0) { incrementDecrement = { true, true, true, false, false, false, false, true }; /* Increase X(Go East) Decrease Y(Go North) Increase X, Increase Y(Go South East) Increase X, Decrease Y(Go North East) I think maybe Northwest is okay? */ } } beginX = hatchPosition.x; beginY = hatchPosition.y; std::vector<std::pair<int, int> > myVec; std::pair<int, int> p1; for (int i = 0; i < 8; i++) { if (incrementDecrement[i]) { if (i == 0) { p1.first = 1; p1.second = 1; } else if (i == 1) { p1.first = 1; p1.second = -1; } else if (i == 2) { p1.first = 1; p1.second = 0; } else if (i == 3) { p1.first = -1; p1.second = 1; } else if (i == 4) { p1.first = -1; p1.second = -1; } else if (i == 5) { p1.first = -1; p1.second = 0; } else if (i == 6) { p1.first = 0; p1.second = 1; } else if (i == 7) { p1.first = 0; p1.second = -1; } myVec.push_back(p1); } } for (int i = 0; i < 30; i++) for (int j = 0; j < 30; j++) for (int k = 0; k < 30; k++) for (int l = 0; l < 30; l++) { int xChange = beginX; int yChange = beginY; xChange += i * myVec[0].first; yChange += i * myVec[0].second; xChange += j * myVec[1].first; yChange += j * myVec[1].second; xChange += k * myVec[2].first; yChange += k * myVec[2].second; xChange += l * myVec[3].first; yChange += l * myVec[3].second; /* if (beginX + 1 == xChange) { if (yChange == beginY) { BWAPI::Broodwar->printf("%d", xChange); } } */ sunkPosition = BWAPI::TilePosition(xChange, yChange); Building b(sunk, sunkPosition); if (!isCreepStarted()) { if (BWAPI::Broodwar->hasCreep(sunkPosition) && stuffBlocking.find(sunkPosition) == stuffBlocking.end() && createdBuilding.find(sunkPosition) == createdBuilding.end()) { buildableSunkenTilePositions.insert(sunkPosition); } } else { if (BWAPI::Broodwar->hasCreep(sunkPosition) && BuildingPlacer::Instance().canBuildHere(sunkPosition, b) && stuffBlocking.find(sunkPosition) == stuffBlocking.end() && createdBuilding.find(sunkPosition) == createdBuilding.end()) { buildableSunkenTilePositions.insert(sunkPosition); } } } if (buildableSunkenTilePositions.size() != 0) { std::set<BWAPI::TilePosition>::iterator it = buildableSunkenTilePositions.begin(); return *it; } else { return BWAPI::TilePositions::None; } } }
void CombatManager::update() { // Get new agents into state addNewAgents(); // TODO : Merge squads // Attack? const int numTroops = numLivingAgents(); //const int threshold = 15; // Update squad leaders for (SquadVectorIter it = attackSquads.begin(); it != attackSquads.end(); it++) { Agent *leader = (*it)->getLeader(); BWAPI::Unit * leaderUnit = &(leader->getUnit()); // Attack with full squad force (adjust to lower) // Otherwise while we are filling up, look mean if ((*it)->getSize() == AttackSquadSize && leader != NULL && numTroops > 50) { leader->setState(AttackState); leader->setPositionTarget(enemyBase); } else if (leader != NULL){ leader->setState(AttackState); // keep position target at base chokepoint } // check for enemy unit targets in range of leader // TODO: set this up for closest weakest enemy //BWAPI::WeaponType wt = leader->getUnitWeaponType(); // TODO: add more weapon types //set<BWAPI::Unit *> unitsInRange = leaderUnit->getUnitsInWeaponRange(wt); // hopefully this covers the back of the squad better (furthest from leader) int killZoneRadius = leaderUnit->getType().seekRange() + (*it)->getRadius(); set<BWAPI::Unit *> unitsInRange = leaderUnit->getUnitsInRadius(killZoneRadius); if ((int)unitsInRange.size() > 0) { int hitPoints = 99999; BWAPI::Unit * enemyTargetInRange = NULL; // get weakest enemy or a medic target for (UnitSetIter unitIt = unitsInRange.begin(); unitIt != unitsInRange.end(); unitIt++) { // check for enemy if ((*unitIt)->getPlayer() != Broodwar->self() && ((*unitIt)->getType().canAttack() || (*unitIt)->getType() == BWAPI::UnitTypes::Terran_Medic || (*unitIt)->getType() == BWAPI::UnitTypes::Terran_Bunker)) { // also check shields int tempHitPoints = (*unitIt)->getHitPoints() + (*unitIt)->getShields(); if (tempHitPoints == 0) continue; if ((*unitIt)->getType() == BWAPI::UnitTypes::Terran_Medic) { enemyTargetInRange = *unitIt; break; } else if (tempHitPoints < hitPoints) { hitPoints = tempHitPoints; enemyTargetInRange = *unitIt; } } } // find a target? if (enemyTargetInRange != NULL) { leader->setState(AttackState); leader->setUnitTarget(enemyTargetInRange); } else { // reset if no targets in range leader->setUnitTarget(NULL); } } } // end squad leader update // Move marines from defense squad to bunker squad if one available if ((int)bunkerAgents.size() > 0 && (int)bunkerSquads.size() > 0 && (int)defendSquads.size() > 0) { while ( bunkerSquads.back()->getSize() < 4 && defendSquads.back()->getSize() > 0) { defendSquads.back()->moveAgent(*(defendSquads.back()->getAgents().begin()), bunkerSquads.back()); } } /* Update attack, defend, and bunker squads */ for (SquadVectorIter it = attackSquads.begin(); it != attackSquads.end(); it++) { (*it)->update(); } for (SquadVectorIter it = defendSquads.begin(); it != defendSquads.end(); it++) { (*it)->update(); } for (SquadVectorIter it = bunkerSquads.begin(); it != bunkerSquads.end(); it++) { (*it)->update(); } // Clean up squads where everyone is dead vector<SquadVectorIter> itersToErase; for(SquadVectorIter it = attackSquads.begin(); it != attackSquads.end(); ++it) { Squad *squad = *it; if( squad->numAlive() == 0 ) { delete squad; itersToErase.push_back(it); } } for(vector<SquadVectorIter>::iterator it = itersToErase.begin(); it != itersToErase.end(); ++it) { attackSquads.erase(*it); } itersToErase.clear(); for(SquadVectorIter it = defendSquads.begin(); it != defendSquads.end(); ++it) { Squad *squad = *it; if( squad->numAlive() == 0 ) { delete squad; itersToErase.push_back(it); } } for(vector<SquadVectorIter>::iterator it = itersToErase.begin(); it != itersToErase.end(); ++it) { defendSquads.erase(*it); } itersToErase.clear(); for(SquadVectorIter it = bunkerSquads.begin(); it != bunkerSquads.end(); ++it) { Squad *squad = *it; if( squad->numAlive() == 0 ) { delete squad; itersToErase.push_back(it); } } for(vector<SquadVectorIter>::iterator it = itersToErase.begin(); it != itersToErase.end(); ++it) { bunkerSquads.erase(*it); } itersToErase.clear(); /* Base class updates Agents */ Manager::update(); }