in rts/game_MC/state_feature.cc [55:167]
void MCExtractor::extract(const RTSState &s, PlayerId player_id, bool respect_fow, float *state) {
assert(player_id != INVALID);
const GameEnv &env = s.env();
const Extractor *ext_ut = info_.get("UnitType");
const Extractor *ext_feature = info_.get("Feature");
const Extractor *ext_resource = info_.get("Resource");
// The following features are optional and might be nullptr.
const Extractor *ext_hist_bin = info_.get("HistBin");
const Extractor *ext_ut_prev_seen = info_.get("UnitTypePrevSeen");
const Extractor *ext_hist_bin_prev_seen = info_.get("HistBinPrevSeen");
const int kAffiliation = ext_feature->Get(MCExtractorInfo::AFFILIATION);
const int kChHpRatio = ext_feature->Get(MCExtractorInfo::HP_RATIO);
const int kChBuildSinceDecay = ext_feature->Get(MCExtractorInfo::HISTORY_DECAY);
const auto &m = env.GetMap();
std::map<int, std::pair<int, float> > idx2record;
PlayerId visibility_check = respect_fow ? player_id : INVALID;
Tick tick = s.GetTick();
GameEnvAspect aspect(env, visibility_check);
UnitIterator unit_iter(aspect, UnitIterator::ALL);
const Player &player = env.GetPlayer(player_id);
float total_hp_ratio = 0.0;
int myworker = 0;
int mytroop = 0;
int mybarrack = 0;
float base_hp_level = 0.0;
while (! unit_iter.end()) {
const Unit &u = *unit_iter;
int x = int(u.GetPointF().x);
int y = int(u.GetPointF().y);
float hp_level = u.GetProperty()._hp / (u.GetProperty()._max_hp + 1e-6);
float build_since = 50.0 / (tick - u.GetBuiltSince() + 1);
UnitType t = u.GetUnitType();
bool self_unit = (u.GetPlayerId() == player_id);
accu_value(_OFFSET(ext_ut->Get(t), x, y, m), 1.0, idx2record);
// Self unit or enemy unit.
// For historical reason, the flag of enemy unit = 2
accu_value(_OFFSET(kAffiliation, x, y, m), (self_unit ? 1 : 2), idx2record);
accu_value(_OFFSET(kChHpRatio, x, y, m), hp_level, idx2record);
if (usage_.type >= BUILD_HISTORY) {
accu_value(_OFFSET(kChBuildSinceDecay, x, y, m), build_since, idx2record);
if (ext_hist_bin != nullptr) {
int h_idx = ext_hist_bin->Get(tick - u.GetBuiltSince());
accu_value(_OFFSET(h_idx, x, y, m), 1, idx2record);
}
}
total_hp_ratio += hp_level;
if (self_unit) {
if (t == WORKER) myworker += 1;
else if (t == MELEE_ATTACKER || t == RANGE_ATTACKER) mytroop += 1;
else if (t == BARRACKS) mybarrack += 1;
else if (t == BASE) base_hp_level = hp_level;
}
++ unit_iter;
}
// Add seen objects.
if (ext_ut_prev_seen != nullptr && ext_hist_bin_prev_seen != nullptr && usage_.type >= PREV_SEEN) {
for (int x = 0; x < m.GetXSize(); ++x) {
for (int y = 0; y < m.GetYSize(); ++y) {
Loc loc = m.GetLoc(x, y);
const Fog &f = player.GetFog(loc);
if (usage_.type == ONLY_PREV_SEEN && f.CanSeeTerrain()) continue;
for (const auto &u : f.seen_units()) {
UnitType t = u.GetUnitType();
int t_idx = ext_ut_prev_seen->Get(t);
accu_value(_OFFSET(t_idx, x, y, m), 1.0, idx2record);
int h_idx = ext_hist_bin_prev_seen->Get(tick - u.GetBuiltSince());
accu_value(_OFFSET(h_idx, x, y, m), 1, idx2record);
}
}
}
}
for (const auto &p : idx2record) {
state[p.first] = p.second.second / p.second.first;
}
myworker = min(myworker, 3);
mytroop = min(mytroop, 5);
mybarrack = min(mybarrack, 1);
// Add resource layer for the current player.
const int c_idx = ext_resource->Get(player.GetResource());
const int c = _OFFSET(c_idx, 0, 0, m);
std::fill(state + c, state + c + m.GetXSize() * m.GetYSize(), 1.0);
if (usage_.type >= BUILD_HISTORY) {
const int kChBaseHpRatio = ext_feature->Get(MCExtractorInfo::BASE_HP_RATIO);
const int c = _OFFSET(kChBaseHpRatio, 0, 0, m);
std::fill(state + c, state + c + m.GetXSize() * m.GetYSize(), base_hp_level);
}
}