add param filtering in materialize optimizer

This commit is contained in:
Martin Michelsen
2026-02-12 21:37:33 -08:00
parent 99630c999d
commit 8717f00106
+48 -13
View File
@@ -3182,13 +3182,14 @@ Action a_optimize_materialized_map(
Runs the Challenge Mode random enemy generation algorithm on the input map\n\
file, looking for the seed that results in the fewest extra events and the\n\
fewest enemies overall, optionally restricting to specific enemy types. A\n\
version option is required. The --minimize=TYPE option may be used\n\
(possibly multiple times) to specify enemies that are undesirable in the\n\
resulting map, and the optimizer will try to minimize occurrences of those\n\
enemies. TYPE should be specified as an integer (for example, 0x0040 for\n\
Hildebears; see Map.cc for a full listing). Event count always takes\n\
precedence; that is, a map with fewer events is always considered better\n\
than any map with more events, regardless of the enemy counts. The\n\
version option is required. The --minimize=TYPE[:PARAM:VALUE] option may\n\
be used (possibly multiple times) to specify enemies that are undesirable\n\
in the resulting map, and the optimizer will try to minimize occurrences\n\
of those enemies. TYPE should be specified as an integer (for example,\n\
0x0040 for Hildebears and Hildeblues, or 0x0044:6:2 for Gigobooma; see\n\
Map.cc for a full listing of types and parameters). Event count always\n\
takes precedence; that is, a map with fewer events is always considered\n\
better than any map with more events, regardless of the enemy counts. The\n\
--threads=NUM-THREADS option may be used to limit parallelism; by default,\n\
uses one thread per CPU core.\n",
+[](phosg::Arguments& args) {
@@ -3201,9 +3202,14 @@ Action a_optimize_materialized_map(
throw std::runtime_error("input map file does not have any random sections");
}
std::unordered_set<uint16_t> minimize_types;
std::unordered_map<uint16_t, std::pair<uint8_t, int32_t>> minimize_types;
for (const auto& arg : args.get_multi<std::string>("minimize")) {
minimize_types.emplace(std::stoul(arg, nullptr, 16));
auto tokens = phosg::split(arg, ':');
if (tokens.size() == 1) {
minimize_types.emplace(std::stoul(arg, nullptr, 16), std::make_pair(0xFF, 0));
} else if (tokens.size() == 3) {
minimize_types.emplace(std::stoul(tokens[0], nullptr, 16), std::make_pair(std::stoul(tokens[1], nullptr, 16), std::stoul(tokens[2], nullptr, 16)));
}
}
size_t num_threads = args.get<size_t>("threads", 0);
@@ -3212,6 +3218,35 @@ Action a_optimize_materialized_map(
auto thread_fn = [&](uint64_t seed, size_t) -> bool {
auto materialized = map_file->materialize_random_sections(seed);
auto is_minimize_target = [&](const MapFile::EnemySetEntry& ene) -> bool {
if (minimize_types.empty()) {
return true;
}
auto it = minimize_types.find(ene.base_type);
if (it == minimize_types.end()) {
return false;
}
const auto& [param, value] = it->second;
switch (param) {
case 1:
return ene.param1.load() == value;
case 2:
return ene.param2.load() == value;
case 3:
return ene.param3.load() == value;
case 4:
return ene.param4.load() == value;
case 5:
return ene.param5.load() == value;
case 6:
return ene.param6.load() == value;
case 7:
return ene.param7.load() == value;
default:
return true;
}
};
size_t extra_event_count = 0;
size_t total_event_count = 0;
size_t total_enemy_set_count = 0;
@@ -3232,9 +3267,9 @@ Action a_optimize_materialized_map(
total_enemy_set_count += fs.enemy_set_count;
for (size_t z = 0; z < fs.enemy_set_count; z++) {
uint16_t base_type = fs.enemy_sets[z].base_type;
enemy_set_counts.emplace(base_type, 0).first->second++;
if (minimize_types.empty() || minimize_types.count(base_type)) {
const auto& ene = fs.enemy_sets[z];
enemy_set_counts.emplace(ene.base_type, 0).first->second++;
if (is_minimize_target(ene)) {
minimized_enemy_set_count++;
}
}
@@ -3243,7 +3278,7 @@ Action a_optimize_materialized_map(
size_t this_count = (total_event_count << 16) | minimized_enemy_set_count;
{
lock_guard g(output_lock);
if (this_count < min_counts) {
if (this_count <= min_counts) {
min_counts = this_count;
string line = std::format("SEED {:08X}: event_count={} (extra={}) enemy_sets=[",
seed, total_event_count, extra_event_count);