Frame combine()

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;
}