-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathTechBot.cpp
186 lines (165 loc) · 6.89 KB
/
TechBot.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
#include "TechBot.h"
#include "sc2api/sc2_action.h"
#include "sc2api/sc2_interfaces.h"
#include "UnitTypes.h"
#include "MapTopology.h"
#include "Placement.h"
#include <iostream>
#include <fstream>
bool isRelevant(const sc2::UnitTypeData & unitdesc, const std::unordered_map<int, int> & abilityToUnit) {
return unitdesc.available && unitdesc.race == sc2::Race::Protoss
&& !(unitdesc.name.find("Weapon") != std::string::npos
|| unitdesc.name.find("MP") != std::string::npos
|| unitdesc.name.find("SkinPreview") != std::string::npos
|| unitdesc.name.find("Interceptors") != std::string::npos)
&& (abilityToUnit.empty() || sc2util::IsBuilding(unitdesc.unit_type_id) || (abilityToUnit.find((int)unitdesc.ability_id) != abilityToUnit.end() || unitdesc.name == "Mothership"));
}
void suboo::TechBot::OnGameStart()
{
auto & types = Observation()->GetUnitTypeData();
auto & abilities = Observation()->GetAbilityData();
MapTopology map;
map.init(Observation(), Query(), Debug());
BuildingPlacer placer;
placer.init(Observation(), Query(), &map, Debug());
auto & info = Observation()->GetGameInfo();
// inspect and create an initial state
std::vector<UnitInstance> state;
for (auto u : Observation()->GetUnits(sc2::Unit::Alliance::Self)) {
state.emplace_back(UnitInstance(u->unit_type));
}
initial = GameState(state,Observation()->GetMinerals(), Observation()->GetVespene());
// time to create some units
Debug()->DebugGiveAllResources();
Debug()->DebugGiveAllTech();
Debug()->DebugGiveAllUpgrades();
initmin = Observation()->GetMinerals();
initvesp = Observation()->GetVespene();
auto point = map.getPosition(map.ally,map.main);
for (const sc2::UnitTypeData & unitdesc : types) {
if (isRelevant(unitdesc, {})) {
point = point + sc2::Point3D(3, 0, 0);
while (! placer.PlacementB(info, point,3)) {
point = point + sc2::Point3D(3, 0, 0);
if (point.x >= info.width) {
point = sc2::Point3D(0, point.y + 3, 0);
}
if (point.y >= info.height) {
return;
}
}
Debug()->DebugCreateUnit(unitdesc.unit_type_id, point,info.player_info[0].player_id);
// for power, or we don't get build/tech abilities
Debug()->DebugCreateUnit(sc2::UNIT_TYPEID::PROTOSS_PYLON, point + sc2::Point3D(0,-3,0), info.player_info[0].player_id);
}
}
Debug()->SendDebug();
}
void suboo::TechBot::OnStep()
{
if (Observation()->GetGameLoop() == 5) {
auto & types = Observation()->GetUnitTypeData();
auto & abilities = Observation()->GetAbilityData();
std::unordered_map<int, int> abilityToUnit;
for (auto u : Observation()->GetUnits(sc2::Unit::Alliance::Self)) {
auto & abilities = Query()->GetAbilitiesForUnit(u,true);
for (auto & ab : abilities.abilities) {
abilityToUnit[(int)ab.ability_id] = (int) u->unit_type;
}
}
std::ofstream out("TechTree" + version + ".cpp");
out << "// This file was generated by TechBot, do not edit. Run TechBot again to regenerate.\n";
out << "#include \"BuildOrder.h\"\n";
out << "namespace suboo {\n";
out << "TechTree::TechTree() :\n";
out << " initial({";
for (auto & u : initial.getFreeUnits()) {
if (sc2util::IsWorkerType(u.type)) {
out << " UnitInstance( (UnitId)" << (int)u.type << ", UnitInstance::MINING_MINERALS, 0),\n";
}
else {
// CC, larva
out << " UnitInstance( (UnitId)" << (int)u.type << "),\n";
}
}
out << " }) {\n";
out << " initial.getMinerals() = " << initmin << ";\n";
out << " initial.getVespene() = " << initvesp << ";\n";
out << " units = {\n";
// reindex units
int index = 0;
// to compute max
int maxunitID = 0;
// associations as pairs
std::vector<std::pair<int, int> > ind;
for (const sc2::UnitTypeData & unitdesc : types) {
if (isRelevant(unitdesc,abilityToUnit)) {
if ((int)unitdesc.unit_type_id > maxunitID) {
maxunitID = (int)unitdesc.unit_type_id;
}
ind.push_back({ (int)unitdesc.unit_type_id , index});
if (sc2util::IsBuilding(unitdesc.unit_type_id))
{ // protoss buildings are all produced by a probe walking there
int traveltime = 4; // default estimate is 4 seconds to reach build site
if (sc2util::IsCommandStructure(unitdesc.unit_type_id)) {
traveltime = 10; // CC require to move to an expansion, that takes about 10 secs
}
auto builderid = abilityToUnit[(int)unitdesc.ability_id];
if (builderid != 0) {
auto techreq = unitdesc.tech_requirement;
if (unitdesc.unit_type_id == UnitId::PROTOSS_GATEWAY) {
techreq = UnitId::PROTOSS_PYLON;
}
out << "{"
" " << index++ << ", // index" << std::endl <<
" (UnitId)" << unitdesc.unit_type_id << ", // ID" << std::endl <<
" \"" << unitdesc.name << "\", // name" << std::endl <<
" " << unitdesc.mineral_cost << ", // gold" << std::endl <<
" " << unitdesc.vespene_cost << ", // gas" << std::endl <<
" " << unitdesc.food_provided - unitdesc.food_required << ", // food" << std::endl <<
" (UnitId)" << (int)builderid << ", // builder unit " << std::endl <<
" (UnitId)" << (int)techreq << ", // tech requirement " << std::endl <<
" " << (int) ( (float) unitdesc.build_time / 22.4) << ", // build time" << std::endl << // 22.4 frames per game second
" " << traveltime << ", // travel time" << std::endl <<
" Unit::TRAVEL // probe behavior" << std::endl <<
"}," << std::endl;
}
}
else
{
// it's a moving unit, produced from a production building
auto builderid = abilityToUnit[(int)unitdesc.ability_id];
// no mothership (only one at atime on map = no ability avail on nexus),
if (unitdesc.name == "Mothership") {
builderid = (int) sc2::UNIT_TYPEID::PROTOSS_NEXUS;
}
// TODO no archons : need two templar to have the ability
if (builderid != 0) {
out << "{"
" " << index++ << ", // index" << std::endl <<
" (UnitId)" << unitdesc.unit_type_id << ", // ID" << std::endl <<
" \"" << unitdesc.name << "\", // name" << std::endl <<
" " << unitdesc.mineral_cost << ", // gold" << std::endl <<
" " << unitdesc.vespene_cost << ", // gas" << std::endl <<
" " << unitdesc.food_provided - unitdesc.food_required << ", // food" << std::endl <<
" (UnitId)" << (int)builderid << ", // builder unit " << std::endl <<
" (UnitId)" << (int)unitdesc.tech_requirement << ", // tech requirement " << std::endl <<
" " << (int)((float)unitdesc.build_time / 22.4) << ", // build time" << std::endl << // 22.4 frames per game second
" " << 0 << ", // travel time" << std::endl <<
" Unit::BUSY // producer behavior" << std::endl <<
"}," << std::endl;
}
}
}
};
out << " }; // end units\n";
// build index from unitID to index
out << " indexes=std::vector<int>("<< (maxunitID+1) <<",0); \n";
for (auto & p : ind) {
out << " indexes[" << p.first << "] = " << p.second << ";\n";
}
out << "} //end ctor \n";
out << "} //end ns \n";
out.close();
}
}