// dump_designs // // Runs every save design through the rules and writes, per design, the // findings as (rule, level, slot, bank), applied_techs per slot and the // derived stats -- the input of oracle/compare.py. #include #include #include #include #include "game/data/catalog.h" #include "game/design/rules.h" #include "game/design/stats.h" #include "json_min.h" #include "stock_designs.h" using namespace game::data; using namespace game::design; using json_min::quote; namespace { std::string num(double v) { char buf[64]; std::snprintf(buf, sizeof buf, "%.17g", v); return buf; } std::string str_list(const std::vector& v) { std::string s = "["; for (std::size_t i = 0; i < v.size(); ++i) s += (i ? "," : "") + quote(v[i]); return s + "]"; } std::string opt_num(const std::optional& v) { return v ? num(*v) : "null"; } std::string opt_int(const std::optional& v) { return v ? std::to_string(*v) : "null"; } } // namespace int main(int argc, char** argv) { if (argc != 4) { std::fprintf(stderr, "usage: dump_designs \n"); return 2; } Catalog cat = load_catalog(argv[1]); std::vector designs; std::string err; if (!load_stock_designs(argv[2], designs, err)) { std::fprintf(stderr, "%s\n", err.c_str()); return 1; } Ruleset rules(cat); std::ofstream out(argv[3], std::ios::binary); if (!out) { std::fprintf(stderr, "cannot write %s\n", argv[3]); return 1; } out << "[\n"; bool first = true; for (StockDesign& sd : designs) { Design& d = sd.design; rules.strip_applied_techs(d); std::vector v = rules.validate(d); DesignStats st = derive_stats(rules, d); out << (first ? "" : ",\n") << "{\"player_index\":" << sd.player_index << ",\"design_index\":" << sd.design_index << ",\"save\":" << quote(sd.save) << ",\"player\":" << quote(sd.player) << ",\"name\":" << quote(d.name) << ",\"race\":" << quote(std::string(species_name(d.effective_race()))) << ",\"hidden\":" << (d.hidden ? "true" : "false"); out << ",\"violations\":["; for (std::size_t i = 0; i < v.size(); ++i) { const Violation& x = v[i]; out << (i ? "," : "") << "{\"rule\":" << quote(x.rule) << ",\"level\":" << quote(std::string(level_name(x.level))) << ",\"slot\":" << (x.slot ? quote(std::string(slot_name(*x.slot))) : "null") << ",\"bank\":" << (x.bank ? std::to_string(*x.bank) : "null") << ",\"message\":" << quote(x.message) << "}"; } out << "],\"applied_techs\":{"; bool fa = true; for (const SectionStats& s : st.sections) { out << (fa ? "" : ",") << quote(std::string(slot_name(s.slot))) << ":" << str_list(s.applied_techs); fa = false; } out << "},\"options\":{"; fa = true; for (Slot s : kUsedSlots) { if (d.slot(s).empty()) continue; out << (fa ? "" : ",") << quote(std::string(slot_name(s))) << ":" << str_list(d.slot(s).options); fa = false; } out << "},\"stats\":{" << "\"hull_class\":" << quote(st.hull_class) << ",\"mass\":" << num(st.mass) << ",\"section_cost\":" << num(st.section_cost) << ",\"section_cost_with_options\":" << num(st.section_cost_with_options) << ",\"weapon_cost_per_bank\":" << num(st.weapon_cost_per_bank) << ",\"weapon_cost_per_mount\":" << num(st.weapon_cost_per_mount) << ",\"total_cost_estimate\":" << num(st.total_cost_estimate) << ",\"health_total\":" << num(st.health_total) << ",\"crew\":" << st.crew << ",\"cpoints\":" << st.cpoints << ",\"banks\":" << st.banks << ",\"turrets\":" << st.turrets << ",\"command_cost\":" << st.command_cost << ",\"maintenance_cost\":" << st.maintenance_cost << ",\"command_quota\":" << opt_int(st.command_quota) << ",\"ftlspeed\":" << opt_num(st.ftlspeed) << ",\"nodespeed\":" << opt_num(st.nodespeed) << ",\"engine_techera\":" << quote(st.engine_techera) << ",\"capacities\":{"; for (std::size_t i = 0; i < st.capacities.size(); ++i) out << (i ? "," : "") << quote(st.capacities[i].first) << ":" << quote(st.capacities[i].second); out << "},\"sections\":{"; fa = true; for (const SectionStats& s : st.sections) { out << (fa ? "" : ",") << quote(std::string(slot_name(s.slot))) << ":{\"section\":" << quote(s.section->stem) << ",\"mass\":" << num(s.mass) << ",\"cost\":" << num(s.cost) << ",\"option_cost_multiplier\":" << num(s.option_cost_multiplier) << ",\"health\":" << num(s.health) << ",\"crew\":" << s.crew << ",\"cpoints\":" << s.cpoints << ",\"banks\":["; for (std::size_t i = 0; i < s.banks.size(); ++i) { const BankStats& b = s.banks[i]; out << (i ? "," : "") << "{\"size\":" << quote(fold(b.size)) << ",\"class\":" << quote(fold(b.turret_class)) << ",\"mounts\":" << b.mounts << ",\"weapon\":" << (b.weapon ? quote(b.weapon->stem) : "null") << ",\"weapon_cost\":" << num(b.weapon_cost) << ",\"turret_model\":" << (b.turret ? quote(b.turret->model) : "null") << ",\"turret_health\":" << (b.turret ? opt_num(b.turret->health) : "null") << "}"; } out << "]}"; fa = false; } out << "}}}"; first = false; } out << "\n]\n"; std::printf("wrote %zu designs to %s\n", designs.size(), argv[3]); return 0; }