122 lines
5.7 KiB
C++
122 lines
5.7 KiB
C++
// dump_designs <data-root> <stock_designs.json> <out.json>
|
|
//
|
|
// 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 <cstdio>
|
|
#include <fstream>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#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<std::string>& 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<double>& v) { return v ? num(*v) : "null"; }
|
|
std::string opt_int(const std::optional<std::int64_t>& v) { return v ? std::to_string(*v) : "null"; }
|
|
|
|
} // namespace
|
|
|
|
int main(int argc, char** argv) {
|
|
if (argc != 4) {
|
|
std::fprintf(stderr, "usage: dump_designs <data-root> <stock_designs.json> <out.json>\n");
|
|
return 2;
|
|
}
|
|
Catalog cat = load_catalog(argv[1]);
|
|
std::vector<StockDesign> 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<Violation> 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;
|
|
}
|