in featurizers/coarse_conv_featurizer.cpp [20:88]
Frame combine(const vector<Frame*> &frames, int32_t perspective, bool full) {
Frame combined;
for (const auto *next_frame : frames) {
// For units, accumulate presence and commands
for (const auto& player : next_frame->units) {
auto& player_id = player.first;
auto& player_units = player.second;
auto& combined_units = combined.units[player_id];
// Build dictionary of uid -> position in current frame unit vector
std::unordered_map<int32_t, int32_t> next_idx;
for (size_t i = 0; i < player_units.size(); i++)
next_idx[player_units[i].id] = i;
for (auto unit = combined_units.begin();
unit != combined_units.end(); ) {
// If unit isn't in next frame, it must have died, so we delete it.
// This doesn't delete units that went into the FOW, although it will
// delete garrisoned marines I think.
if (next_idx.count(unit->id) == 0)
unit = combined_units.erase(unit);
else unit++;
}
std::unordered_map<int32_t, int32_t> combined_idx;
for (size_t i = 0; i < combined_units.size(); i++)
combined_idx[combined_units[i].id] = i;
// Iterate over units in next frame
for (const auto& unit : player_units) {
auto visible = (unit.visible >> perspective) & 0x1;
if (!full && !visible) continue; // Don't featurize if we can't see unit
if (combined_idx.count(unit.id) == 0) {
// Unit wasn't in current frame, add it
combined_units.push_back(unit);
} else {
int32_t i = combined_idx[unit.id];
// Take unit state from next frame but accumulate orders
// so as to have a vector of all the orders taken
std::vector<Order> ords = std::move(combined_units[i].orders);
ords.reserve(ords.size() + unit.orders.size());
for (auto& ord : unit.orders) {
if (ords.empty() || !(ord == ords.back())) {
ords.push_back(ord);
}
}
combined_units[i] = unit;
combined_units[i].orders = std::move(ords);
}
}
// For resources: keep the ones of the next frame
if (next_frame->resources.find(player_id) != next_frame->resources.end()) {
auto next_res = next_frame->resources.at(player_id);
combined.resources[player_id].ore = next_res.ore;
combined.resources[player_id].gas = next_res.gas;
combined.resources[player_id].used_psi = next_res.used_psi;
combined.resources[player_id].total_psi = next_res.total_psi;
}
}
// For other stuff, simply keep that of next_frame
combined.actions = next_frame->actions;
combined.bullets = next_frame->bullets;
combined.reward = next_frame->reward;
combined.is_terminal = next_frame->is_terminal;
}
return combined;
}