123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800 |
- #include "galaxy.h"
- #include <algorithm> // sort
- #include <boost/format.hpp>
- #include <chrono>
- #include <exception>
- #include <fstream>
- #include <ostream>
- #include <set>
- #include <string>
- #include "config.h"
- #include "logging.h"
- #include "yaml-cpp/yaml.h"
- std::ostream &operator<<(std::ostream &os, const port &p) {
- if (p.type == 0) {
- os << p.sector << ": " << (int)p.type;
- } else {
- os << p.sector << ": " << (int)p.type << " " << text_from_type(p.type)
- << " " << p.amount[0] << "," << p.amount[1] << "," << p.amount[2];
- }
- return os;
- }
- bool port::unknown(void) {
- for (int x = 0; x < 3; ++x) {
- if (amount[x] != 0) return false;
- }
- return true;
- }
- density_scan::density_scan() { reset(0); }
- void density_scan::reset(sector_type s) {
- sector = s;
- pos = 0;
- for (int x = 0; x < (int)d.size(); ++x) {
- d[x].sector = 0;
- }
- }
- void density_scan::add_scan(density den) {
- if (pos > (int)d.size()) {
- std::string message("density_scan::add_scan() exceeded max size ");
- message.append(std::to_string(d.size()));
- throw std::out_of_range(message);
- }
- d[pos] = den;
- ++pos;
- }
- density density_scan::find(sector_type sector) {
- for (int x = 0; x < pos; ++x) {
- if (d[x].sector == sector) return d[x];
- }
- BUGZ_LOG(fatal) << "density_scan::find failed: " << sector << " we have "
- << pos << " scans.";
- density den;
- den.sector = 0;
- return den;
- }
- bool operator==(const density lhs, const density rhs) {
- return ((lhs.sector == rhs.sector) && (lhs.density == rhs.density) &&
- (lhs.navhaz == rhs.navhaz) && (lhs.anomaly == rhs.anomaly) &&
- (lhs.warps == rhs.warps) && (lhs.known == rhs.known));
- }
- sector_warps::sector_warps() { sector = 0; }
- sector_warps::sector_warps(sector_type s, std::set<sector_type> w) {
- sector = s;
- warps = w;
- }
- void sector_warps::add(sector_type new_sector) {
- warps.insert(new_sector);
-
- }
- std::ostream &operator<<(std::ostream &os, const sector_warps &warps) {
- os << "Sector: " << warps.sector << " ";
- bool comma = false;
- for (auto const &warp : warps.warps) {
- if (comma)
- os << ",";
- else
- comma = true;
- os << warp;
- }
- return os;
- }
- #define GTEST_COUT std::cerr << "[ ] [ INFO ]"
- struct port parse_portcim(const std::string line) {
- struct port p;
- p.sector = std::stoi(line);
-
- static std::regex portrx(
- "[ ]*([0-9]+) (.)[ ]+([0-9]+)[ ]+([0-9]+%) (.)[ "
- "]+([0-9]+)[ ]+([0-9]+%) (.)[ ]+([0-9]+)[ ]+([0-9]+%)[ ]*",
- std::regex_constants::ECMAScript);
-
-
-
-
-
-
-
-
-
-
-
- #ifdef GTEST_DEBUG
- GTEST_COUT << "Sector: " << p.sector << std::endl;
- GTEST_COUT << "Line: [" << line << "]" << std::endl;
- #endif
- buysell port_buysell;
- std::smatch matches;
- if (std::regex_match(line, matches, portrx)) {
- #ifdef GTEST_DEBUG
- for (size_t x = 1; x < matches.size(); ++x) {
- GTEST_COUT << x << " : " << matches[x] << std::endl;
- }
- #endif
- if (matches.size() != 11) {
- #ifdef GTEST_DEBUG
- GTEST_COUT << "Now you have 101 problems." << std::endl;
- #endif
- p.sector = 0;
- p.type = 0;
- return p;
- }
-
- p.sector = stoi(matches[1]);
-
-
-
-
- for (int x = 0; x < 3; ++x) {
- int pos = x * 3;
- port_buysell.foe[x] = matches[pos + 2] == "-";
- p.amount[x] = stoi(matches[pos + 3]);
- p.percent[x] = stoi(matches[pos + 4]);
- }
- p.type = type_from_buysell(port_buysell);
- #ifdef GTEST_DEBUG
- GTEST_COUT << "port is type " << (int)p.type << std::endl;
- #endif
- return p;
- } else {
- #ifdef GTEST_DEBUG
- GTEST_COUT << "regex_match failed." << std::endl;
- #endif
- p.type = 0;
- p.sector = 0;
- return p;
- }
- }
- Galaxy::Galaxy() { burnt_percent = 40; }
- Galaxy::~Galaxy() { BUGZ_LOG(fatal) << "Galaxy::~Galaxy()"; }
- void Galaxy::reset(void) {
- meta = YAML::Node();
- config = YAML::Node();
- ports.clear();
- warps.clear();
- }
- void Galaxy::add_warp(sector_warps sw) {
- auto pos = warps.find(sw.sector);
- if (pos == warps.end()) {
-
-
- warps[sw.sector] = sw;
-
- } else {
-
- if (pos->second.warps == sw.warps) {
-
- } else {
- BUGZ_LOG(info) << "add_warp: Warps don't match! Updating...";
- BUGZ_LOG(warning) << "Have: " << pos->second;
- BUGZ_LOG(warning) << "Got : " << sw;
- warps[sw.sector] = sw;
- }
- }
- }
- void Galaxy::add_port(sector_type sector, int port_type) {
- auto pos = ports.find(sector);
- if (pos == ports.end()) {
-
- port p;
- p.sector = sector;
- p.type = port_type;
- for (int x = 0; x < 3; x++) {
- p.amount[x] = 0;
- p.percent[x] = 0;
- }
-
-
- ports[sector] = p;
- } else {
-
- if (pos->second.type == port_type) {
-
-
- } else {
- BUGZ_LOG(fatal) << "add_port: " << sector << " shows " << pos->second.type
- << " >> set to " << port_type;
- pos->second.type = port_type;
- }
- }
- }
- void Galaxy::add_port(port p) {
- auto pos = ports.find(p.sector);
- if (pos == ports.end()) {
-
- ports[p.sector] = p;
- } else {
- if (pos->second.type != p.type) {
- if ((pos->second.type == 9) && (p.type == 8)) {
- BUGZ_LOG(trace) << "add_port: StarDock " << p.sector;
- p.type = 9;
- ports[p.sector] = p;
- } else {
- BUGZ_LOG(fatal) << "add_port: " << pos->second << " NEW : " << p;
- ports[p.sector] = p;
- }
- } else {
- if (pos->second.amount != p.amount) {
-
- pos->second = p;
- } else {
-
- }
- }
- }
- }
- void Galaxy::load(void) {
- std::string basename = "galaxy";
- if (CONFIG["basename"]) {
- basename = CONFIG["basename"].as<std::string>();
- }
- std::string filename =
- str(boost::format("%1%-%2%-%3%.yaml") % basename % game % username);
-
- meta = YAML::Node();
- config = YAML::Node();
- ports.clear();
- warps.clear();
- if (file_exists(filename)) {
- YAML::Node data = YAML::LoadFile(filename);
- if (config["meta"]) meta = config["meta"];
- meta["load_from"] = filename;
- std::chrono::_V2::system_clock::time_point now =
- std::chrono::system_clock::now();
- meta["load_time"] = std::chrono::system_clock::to_time_t(now);
- if (data["config"]) {
- config = data["config"];
- } else {
- BUGZ_LOG(fatal) << "YAML Missing config section.";
- }
- if (data["ports"]) {
- const YAML::Node ports = data["ports"];
- for (auto const &port_iter : ports) {
- port p;
- p.sector = port_iter.first.as<int>();
- p.type = port_iter.second["class"].as<int>();
- int x;
- if (p.type == 0) {
-
- for (x = 0; x < 3; ++x) {
- p.amount[x] = 0;
- p.percent[x] = 0;
- }
- } else {
- x = 0;
- for (auto const &amount : port_iter.second["amount"]) {
- p.amount[x] = amount.as<int>();
- ++x;
- }
- x = 0;
- for (auto const &pct : port_iter.second["pct"]) {
- p.percent[x] = pct.as<int>();
- ++x;
- }
- }
- add_port(p);
- }
- } else {
- BUGZ_LOG(fatal) << "YAML Missing ports section.";
- }
- if (data["warps"]) {
- const YAML::Node &warps = data["warps"];
-
- for (auto const warp_iter : warps) {
- sector_warps sw;
- sw.sector = warp_iter.first.as<int>();
- for (auto const sector_iter : warp_iter.second) {
- sw.add(sector_iter.as<int>());
- }
-
- add_warp(sw);
- }
-
- } else {
- BUGZ_LOG(fatal) << "YAML Missing warps section.";
- }
- BUGZ_LOG(fatal) << "YAML: config keys: " << config.size();
- BUGZ_LOG(fatal) << "YAML: warp keys: " << warps.size();
- BUGZ_LOG(fatal) << "YAML: port keys: " << ports.size();
- } else {
- BUGZ_LOG(fatal) << "Missing YAML: " << filename;
- }
- }
- void Galaxy::save(void) {
- std::string basename = "galaxy";
- if (CONFIG["basename"]) {
- basename = CONFIG["basename"].as<std::string>();
- }
- std::string filename =
- str(boost::format("%1%-%2%-%3%.yaml") % basename % game % username);
- std::ofstream fout(filename);
- fout << "%YAML 1.2" << std::endl << "---" << std::endl;
- BUGZ_LOG(fatal) << "YAML: " << filename;
- int depth = 0;
- std::string depth_spacer;
- meta["save_to"] = filename;
- std::chrono::_V2::system_clock::time_point now =
- std::chrono::system_clock::now();
- meta["save_time"] = std::chrono::system_clock::to_time_t(now);
-
- fout << "meta:" << std::endl;
- ++depth;
- depth_spacer.assign(depth * 2, ' ');
- std::function<void(std::ofstream & of, int depth, const YAML::Node &n)>
- yaml_out;
- yaml_out = [&yaml_out](std::ofstream &of, int yaml_depth,
- const YAML::Node &n) {
- std::string yaml_spacer;
- yaml_spacer.assign(yaml_depth * 2, ' ');
- for (auto const &data : n) {
- if (data.second.Type() == YAML::NodeType::Scalar) {
- of << yaml_spacer << data.first << ": " << data.second << std::endl;
- } else if (data.second.Type() == YAML::NodeType::Map) {
-
- of << yaml_spacer << data.first << ":" << std::endl;
- yaml_out(of, yaml_depth + 1, data.second);
- } else if (data.second.Type() == YAML::NodeType::Sequence) {
-
- BUGZ_LOG(fatal) << "Ignoring Sequence... " << data.first;
- } else {
- BUGZ_LOG(fatal) << "Unsupported NodeType: " << data.second.Type();
- }
- }
- };
- yaml_out(fout, depth, meta);
- BUGZ_LOG(fatal) << "YAML config: " << config.size();
- fout << "config:" << std::endl;
-
-
- yaml_out(fout, depth, config);
- BUGZ_LOG(fatal) << "YAML warps: " << warps.size();
- fout << "warps:" << std::endl;
- for (auto const &warp : warps) {
- fout << depth_spacer << warp.first << ": [";
- bool first = true;
- for (auto const §or : warp.second.warps) {
- if (!first) {
- fout << ", ";
- } else
- first = false;
- fout << sector;
- }
- fout << "]" << std::endl;
- }
- BUGZ_LOG(fatal) << "YAML ports: " << ports.size();
- fout << "ports:" << std::endl;
-
- for (auto const &port : ports) {
- fout << depth_spacer << port.second.sector
- << ": {class: " << (int)port.second.type;
- if (port.second.type == 0) {
- fout << "}" << std::endl;
- } else {
-
- fout << ", amount: [";
- for (int x = 0; x < 3; x++) {
- fout << port.second.amount[x];
- if (x != 2) fout << ", ";
- }
- fout << "], pct: [";
- for (int x = 0; x < 3; x++) {
- fout << (int)port.second.percent[x];
- if (x != 2) fout << ", ";
- }
- fout << "]}" << std::endl;
- }
- }
-
-
-
- }
- std::vector<port_pair_type> Galaxy::find_trades(sector_type sector,
- bool highest) {
- std::vector<port_pair_type> pptv;
-
- auto port = ports.find(sector);
- if (port == ports.end()) return pptv;
- auto port_warps = warps.find(sector);
-
- if (port_warps == warps.end()) return pptv;
- for (auto const &s : port_warps->second.warps) {
-
- if (highest && (s < sector)) continue;
-
- {
- auto warpback = warps.find(s);
-
- if (warpback == warps.end()) continue;
-
- if (warpback->second.warps.find(sector) == warpback->second.warps.end())
- continue;
- }
-
- auto possible_port = ports.find(s);
- if (possible_port == ports.end()) continue;
- if (possible_port->second.type == 0) continue;
-
-
- BUGZ_LOG(trace) << "find_trades: Port " << sector << ","
- << (int)port->second.type << " " << s
- << (int)possible_port->second.type;
- trade_type_result ttr = trade_type_info(
- sector, s);
- if ((ttr.type == NONE) || (ttr.type == FAIR_F)) continue;
- pptv.push_back(port_pair_type{ttr.type, ttr.trades, sector, s});
- BUGZ_LOG(trace) << "sector: " << sector << " and " << s
- << " tt:" << ttr.type;
- }
- return pptv;
- }
- bool compare_port_pair(const port_pair_type &ppt1, const port_pair_type &ppt2) {
- if (ppt1.type == ppt2.type) {
- return ppt1.s1 < ppt2.s1;
- } else {
- return (ppt1.type < ppt2.type);
- }
- }
- void Galaxy::sort_port_pair_type(std::vector<port_pair_type> &pptv) {
- sort(pptv.begin(), pptv.end(), compare_port_pair);
- }
- std::vector<port_pair_type> Galaxy::find_best_trades(void) {
- std::vector<port_pair_type> pptv;
- burnt_percent = config["burnt_percent"].as<int>();
- if (burnt_percent > 90) {
- burnt_percent = 90;
- config["burnt_percent"] = 90;
- }
- if (burnt_percent < 10) {
- burnt_percent = 10;
- config["burnt_percent"] = 10;
- }
- for (auto const &pi : ports) {
- if (pi.second.type == 0) continue;
- sector_type sector = pi.second.sector;
- auto port_warps = warps.find(sector);
- if (port_warps == warps.end()) continue;
- std::vector<port_pair_type> ppt_sector = find_trades(sector, true);
- if (ppt_sector.empty()) continue;
- pptv.insert(pptv.end(), ppt_sector.begin(), ppt_sector.end());
- }
- return pptv;
- }
- port_pair_type Galaxy::find_closest(int sector) {
- auto trades = find_best_trades();
-
- std::set<sector_type> seen;
- std::set<sector_type> current;
- current.insert(sector);
- bool found = false;
- bool added_new = false;
- int depth = 0;
- while (!found) {
-
- for (auto const &t : trades) {
- if (t.type > 2) continue;
- if (current.find(t.s1) != current.end()) {
-
- return t;
- }
- if (current.find(t.s2) != current.end()) {
- return t;
- }
- }
- ++depth;
- BUGZ_LOG(info) << "depth: " << depth << " current:" << current.size()
- << " seen: " << seen.size();
- added_new = false;
- if (!found) {
-
- seen.insert(current.begin(), current.end());
- auto look_in = current;
- current.clear();
- for (auto const &li : look_in) {
- auto wi = warps.find(li);
- if (wi == warps.end()) continue;
- for (auto const &w : wi->second.warps) {
-
- if (seen.find(w) != seen.end()) continue;
-
- auto warp_back = warps.find(w);
- if (warp_back != warps.end()) {
- if (warp_back->second.warps.find(li) !=
- warp_back->second.warps.end()) {
-
- current.insert(w);
- added_new = true;
- }
- }
- }
- }
- if (!added_new) {
- BUGZ_LOG(warning) << "No new sectors added. We're done!";
- port_pair_type ppt;
- ppt.type = 0;
- return ppt;
- }
- }
- }
- port_pair_type ppt;
- ppt.type = 0;
- return ppt;
- }
- trade_type_result Galaxy::trade_type_info(sector_type port1, sector_type port2,
- int burnt_percent) {
- BUGZ_LOG(fatal) << "Trade_type_info(" << port1 << "," << port2 << ")";
-
-
-
-
-
-
-
-
-
- buysell inv2;
- auto p1 = ports.find(port1);
- if (p1 == ports.end()) {
- BUGZ_LOG(fatal) << "Can't find port 1: " << (int)port1;
- return {NONE, inv2};
- }
- BUGZ_LOG(fatal) << "port 1: " << p1->first << " " << p1->second.sector << ", "
- << (int)p1->second.type;
- auto p2 = ports.find(port2);
- if (p2 == ports.end()) {
- BUGZ_LOG(fatal) << "Can't find port 2: " << (int)port2;
- return {NONE, inv2};
- }
- BUGZ_LOG(fatal) << "port 2: " << p2->first << " " << p2->second.sector << ", "
- << (int)p2->second.type;
- buysell bsp1 = get_buysell(p1->second.type);
- buysell bsp2 = get_buysell(p2->second.type);
- inv2 = invert_buysell(bsp2);
- int matches = 0;
- std::vector<int> pos;
-
- for (int x = 0; x < 3; ++x) {
- inv2.foe[x] = (bsp1.foe[x] == inv2.foe[x]);
-
-
- if (!p1->second.unknown()) {
- if (p1->second.percent[x] < burnt_percent) {
- BUGZ_LOG(fatal) << "Marking Port 1: " << x << " (burnt)";
- inv2.foe[x] = false;
- }
- } else {
- BUGZ_LOG(fatal) << "Port 1 : unknown / skip burnt checks";
- }
- if (!p2->second.unknown()) {
- if (p2->second.percent[x] < burnt_percent) {
- BUGZ_LOG(fatal) << "Marking Port 2: " << x << " (burnt)";
- inv2.foe[x] = false;
- }
- } else {
- BUGZ_LOG(fatal) << "Port 2 : unknown / skip burnt checks";
- }
- if (inv2.foe[x]) {
- matches++;
- pos.push_back(x);
- }
- }
- BUGZ_LOG(fatal) << "Matches: " << matches << " inv: " << inv2;
- if (matches > 1) {
-
-
- if (inv2.foe[ORG] && inv2.foe[EQU] && (bsp1.foe[ORG] != bsp1.foe[EQU]) &&
- (bsp2.foe[ORG] != bsp2.foe[EQU]) && (bsp1.foe[ORG] != bsp2.foe[ORG])) {
-
- inv2.foe[FUEL] = false;
- BUGZ_LOG(fatal) << "result: " << BEST << " " << inv2;
- return trade_type_result{BEST, inv2};
- }
- if (matches == 3) {
-
-
- if (bsp1.foe[FUEL] != bsp2.foe[EQU]) {
-
- inv2.foe[ORG] = false;
- BUGZ_LOG(fatal) << "result: " << OK << " " << inv2;
- return trade_type_result{OK, inv2};
- }
- if (bsp1.foe[FUEL] != bsp2.foe[ORG]) {
-
- inv2.foe[EQU] = false;
- BUGZ_LOG(fatal) << "result: " << OK << " " << inv2;
- return trade_type_result{OK, inv2};
- }
-
- inv2.foe[FUEL] = false;
- inv2.foe[ORG] = false;
- BUGZ_LOG(fatal) << "result: " << FAIR_E << " " << inv2;
- return trade_type_result{FAIR_E, inv2};
- }
-
- if (bsp1.foe[pos[matches - 1]] != bsp1.foe[pos[matches - 2]]) {
-
- BUGZ_LOG(fatal) << "result: " << OK << " " << inv2;
- return trade_type_result{OK, inv2};
- } else {
-
- inv2.foe[pos[0]] = false;
- switch (pos[1]) {
- case 0:
- BUGZ_LOG(fatal) << "result: " << FAIR_F << " " << inv2;
- return trade_type_result{FAIR_F, inv2};
- break;
- case 1:
- BUGZ_LOG(fatal) << "result: " << FAIR_O << " " << inv2;
- return trade_type_result{FAIR_O, inv2};
- break;
- case 2:
- BUGZ_LOG(fatal) << "result: " << FAIR_E << " " << inv2;
- return trade_type_result{FAIR_E, inv2};
- break;
- }
- }
- }
- if (matches == 1) {
- switch (pos[0]) {
- case 0:
- BUGZ_LOG(fatal) << "result: " << FAIR_F << " " << inv2;
- return trade_type_result{FAIR_F, inv2};
- break;
- case 1:
- BUGZ_LOG(fatal) << "result: " << FAIR_O << " " << inv2;
- return trade_type_result{FAIR_O, inv2};
- break;
- case 2:
- BUGZ_LOG(fatal) << "result: " << FAIR_E << " " << inv2;
- return trade_type_result{FAIR_E, inv2};
- break;
- }
- }
-
- BUGZ_LOG(fatal) << "result: " << NONE << " " << inv2;
- return trade_type_result{NONE, inv2};
- }
|