Created
August 12, 2017 12:01
-
-
Save cotcotquedec/2afe2ca90eaecb01bb237d7d2f02bf2e to your computer and use it in GitHub Desktop.
My SC2 Bot
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "sc2api/sc2_api.h" | |
#include <iostream> | |
using namespace sc2; | |
class Bot : public Agent { | |
public: | |
const ObservationInterface* o; | |
Units unitsIdle = Units(); | |
bool food_capped = false; | |
int vespene = 0; | |
int minerals = 0; | |
virtual void OnGameStart() final { | |
std::cout << "Hello, World!" << std::endl; | |
} | |
virtual void OnStep() { | |
o = Observation(); | |
vespene = o->GetVespene(); | |
minerals = o->GetMinerals(); | |
TryBuildSupplyDepot(); | |
TryTrainScv(); | |
TryBuildRefinery(); | |
} | |
virtual void OnUnitIdle(const Unit& unit) final { | |
switch (unit.unit_type.ToType()) { | |
case UNIT_TYPEID::TERRAN_REFINERY: { | |
TryExploitRefinery(unit); | |
TryExploitRefinery(unit); | |
TryExploitRefinery(unit); | |
TryExploitRefinery(unit); | |
break; | |
} | |
case UNIT_TYPEID::TERRAN_SCV: { | |
uint64_t mineral_target; | |
if (FindNearestMineralPatch(unit.pos, mineral_target)) { | |
Actions()->UnitCommand(unit, ABILITY_ID::SMART, mineral_target); | |
} | |
break; | |
} | |
default: | |
unitsIdle.push_back(unit); | |
} | |
} | |
private: | |
void debug(char* value, int i = 0) { | |
std::cout << value << " : " << i << std::endl; | |
} | |
/* RENVOIE TRUE si la nourriture utilsé eest supererieur au max - 2*/ | |
bool IsFoodCapped() { | |
bool capped = o->GetFoodUsed() > o->GetFoodCap() - 2; | |
// si il y a une modifcation de la valeur, on le debug | |
if (capped != food_capped) { | |
food_capped = capped; | |
if (capped) { | |
debug("FOOD CAPPED", 1); | |
} | |
else { | |
debug("FOOD CAPPED", 0); | |
} | |
} | |
return food_capped; | |
} | |
/* Récuperation d'une unité libre */ | |
Unit GetUnitIdleByType(UNIT_TYPEID unit_type = UNIT_TYPEID::TERRAN_SCV) { | |
for (const auto& unit : unitsIdle) { | |
if (unit.unit_type == unit_type) { | |
return unit; | |
} | |
} | |
return Unit(); | |
} | |
/* TRY REMOVE UNIT OCCUPIED*/ | |
void RemoveUnitIdle(Unit u) { | |
Units idle = Units(); | |
for (const auto& unit : unitsIdle) { | |
if (unit.tag != u.tag) { | |
idle.push_back(unit); | |
} | |
} | |
unitsIdle = idle; | |
} | |
/*Renvoiele nombre d'unité que vous avez pour un type*/ | |
int GetUnitTypeCount(UNIT_TYPEID type) { | |
int count = 0; | |
Units units = o->GetUnits(Unit::Alliance::Self); | |
for (const auto& u : units) { | |
if (u.unit_type == type) { | |
count++; | |
} | |
} | |
return count; | |
} | |
bool TryExploitRefinery(Unit refinery) { | |
Unit scv = GetScv(); | |
float distance = std::numeric_limits<float>::max(); | |
for (const auto& order : scv.orders) { | |
if (order.target_unit_tag != refinery.tag) { | |
debug("EXPLOIT REFINERY", 1); | |
Actions()->UnitCommand(scv, ABILITY_ID::SMART, refinery.tag); | |
RemoveUnitIdle(scv); | |
} | |
} | |
return false; | |
} | |
bool TryBuildRefinery() { | |
uint64_t vespene_target; | |
if (GetUnitTypeCount(UNIT_TYPEID::TERRAN_REFINERY) >= 2) { | |
return false; | |
} | |
// ON verifie que l'mon abien la bonn e quantité de resource | |
if (minerals < 75) { | |
return false; | |
} | |
// Si on est capé, on ne fait rien | |
if (IsFoodCapped()) { | |
return false; | |
} | |
if (IsAbilityInProgress(ABILITY_ID::BUILD_REFINERY)) { | |
return false; | |
} | |
// GET SCV | |
Unit unit = GetScv(); | |
if (unit.unit_type == 0) { | |
return false; | |
} | |
if (FindNearestVespenePatch(unit.pos, vespene_target)) { | |
Actions()->UnitCommand(unit, ABILITY_ID::BUILD_REFINERY, vespene_target); | |
debug("BUILD_REFINERY", 1); | |
RemoveUnitIdle(unit); | |
} | |
return false; | |
} | |
/* TRAIN A SCV*/ | |
bool TryTrainScv() { | |
// ON verifie que l'mon abien la bonn e quantité de resource | |
if (minerals < 50) { | |
return false; | |
} | |
if (GetUnitTypeCount(UNIT_TYPEID::TERRAN_SCV) >= 20) { | |
return false; | |
} | |
// Si on est capé, on ne fait rien | |
if (IsFoodCapped()) { | |
return false; | |
} | |
// Recuperation d'un CC | |
Unit unit = GetUnitIdleByType(UNIT_TYPEID::TERRAN_COMMANDCENTER); | |
if (unit.unit_type == 0) { | |
return false; | |
} | |
// ON envoie la demande | |
debug("TRAIN SCV", 1); | |
Actions()->UnitCommand(unit, ABILITY_ID::TRAIN_SCV); | |
RemoveUnitIdle(unit); | |
return true; | |
} | |
/* Renvoie le SCV le moins occupé*/ | |
Unit GetScv(Tag exclude_tag = NULL) { | |
// ON cherche si un CSV est libre | |
Unit unit = GetUnitIdleByType(UNIT_TYPEID::TERRAN_SCV); | |
if (unit.unit_type == 0) { | |
Units units = o->GetUnits(Unit::Alliance::Self); | |
for (const auto& u : units) { | |
if (u.unit_type == UNIT_TYPEID::TERRAN_SCV) { | |
for (const auto& order : u.orders) { | |
if (order.ability_id == ABILITY_ID::HARVEST_GATHER) { | |
if (order.target_unit_tag != exclude_tag) { | |
unit = u; | |
} | |
} | |
} | |
} | |
} | |
} | |
return unit; | |
} | |
bool IsAbilityInProgress(ABILITY_ID ability) { | |
Units units = o->GetUnits(Unit::Alliance::Self); | |
for (const auto& unit : units) { | |
for (const auto& order : unit.orders) { | |
if (order.ability_id == ability) { | |
return true; | |
} | |
} | |
} | |
return false; | |
} | |
/*Tentative de constreuction d'un depot*/ | |
bool TryBuildSupplyDepot() { | |
if (minerals < 100) { | |
return false; | |
} | |
// If we are not supply capped, don't build a supply depot. | |
if (!IsFoodCapped()) | |
return false; | |
// ON check si un depot n'est pas encours de construction | |
if (IsAbilityInProgress(ABILITY_ID::BUILD_SUPPLYDEPOT)) | |
return false; | |
// Recuperation d'un SCV | |
Unit unit = GetScv(); | |
if (unit.unit_type == 0) { | |
return false; | |
} | |
float rx = GetRandomScalar(); | |
float ry = GetRandomScalar(); | |
// GIVE ORDER | |
Actions()->UnitCommand(unit, | |
ABILITY_ID::BUILD_SUPPLYDEPOT, | |
Point2D(unit.pos.x + rx * 15.0f, unit.pos.y + ry * 15.0f)); | |
RemoveUnitIdle(unit); | |
debug("BUILD_SUPPLYDEPOT", 1); | |
return true; | |
} | |
/* TORUVE DU MINERAI */ | |
bool FindNearestMineralPatch(const Point2D& start, uint64_t& target) { | |
Units units = Observation()->GetUnits(Unit::Alliance::Neutral); | |
float distance = std::numeric_limits<float>::max(); | |
for (const auto& u : units) { | |
if (u.unit_type == UNIT_TYPEID::NEUTRAL_MINERALFIELD) { | |
float d = DistanceSquared2D(u.pos, start); | |
if (d < distance) { | |
distance = d; | |
target = u.tag; | |
} | |
} | |
} | |
if (distance == std::numeric_limits<float>::max()) { | |
return false; | |
} | |
return true; | |
} | |
/* TROUVE UN GEYSER VESPENE */ | |
bool FindNearestVespenePatch(const Point2D& start, uint64_t& target) { | |
Units units = Observation()->GetUnits(Unit::Alliance::Neutral); | |
float distance = std::numeric_limits<float>::max(); | |
for (const auto& u : units) { | |
if (u.unit_type == UNIT_TYPEID::NEUTRAL_VESPENEGEYSER) { | |
float d = DistanceSquared2D(u.pos, start); | |
if (d < distance) { | |
distance = d; | |
target = u.tag; | |
} | |
} | |
} | |
if (distance == std::numeric_limits<float>::max()) { | |
return false; | |
} | |
return true; | |
} | |
}; | |
int main(int argc, char* argv[]) { | |
Coordinator coordinator; | |
coordinator.LoadSettings(argc, argv); | |
Bot bot; | |
coordinator.SetParticipants({ | |
CreateParticipant(Race::Terran, &bot), | |
CreateComputer(Race::Zerg) | |
}); | |
coordinator.LaunchStarcraft(); | |
coordinator.StartGame(sc2::kMapBelShirVestigeLE); | |
while (coordinator.Update()) { | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment