1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045 |
- #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 "json.hpp"
- #include "logging.h"
- using json = nlohmann::json;
- // c++ default exceptions list
- // https://en.cppreference.com/w/cpp/error/exception
- 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;
- }
- /**
- * Is port unknown?
- *
- * As in we haven't visited it, we don't know what it has?
- * We were checking percent to 0, but we've seen valid ports with 0 percent.
- * We now check amount. If this becomes an issue, we'll change to an unknown
- * flag.
- *
- * @return true
- * @return false
- */
- 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);
- /*
- for (int x = 0; x < MAX_WARPS; ++x) {
- if (warps[x] == new_sector) return;
- if (warps[x] == 0) {
- warps[x] = new_sector;
- return;
- }
- }
- std::string message = str(boost::format("More then MAX %1% sectors for %2%") %
- MAX_WARPS % (int)sector);
- throw std::out_of_range(message);
- */
- }
- 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 ]"
- // #define GTEST_DEBUG
- // TODO: fix this. I want some trace output, but I don't want
- // my logs flooded ...
- struct port parse_portcim(const std::string line) {
- struct port p;
- p.sector = std::stoi(line);
- // 20 - 1708 97% - 710 56% 287 15%
- // [15954 - 1990 100% 20910 100% 32880 100% ]
- // SL: [ 4591 - 395 47% -15822 84% 19830 100% ]
- static std::regex portrx(
- "[ ]*([0-9]+) (.)[ ]*([0-9]+)[ ]+([0-9]+%) (.)[ "
- "]*([0-9]+)[ ]+([0-9]+%) (.)[ ]*([0-9]+)[ ]+([0-9]+%)[ ]*",
- std::regex_constants::ECMAScript);
- // does it not understand {3} ??
- // NO, it does not, from regex101.com:
- // A repeated capturing group will only capture the last iteration. Put a
- // capturing group around the repeated group to capture all iterations or use
- // a non-capturing group instead if you're not interested in the data
- //
- // static std::regex portrx("[ ]*([0-9]+)( (.)[ ]+([0-9]+)[ ]+([0-9]+%)){3}[
- // ]*",
- // std::regex_constants::ECMAScript);
- // sector + amount pct + amount pct + amount pct
- // 1 2 3 4 5 6 7 8 9 10
- #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;
- }
- // GTEST_COUT << "matches: " << matches.size() << std::endl;
- p.sector = stoi(matches[1]);
- // GTEST_COUT << "sector: " << matches[1] << std::endl;
- // for (int x = 1; x < 11; ++x) {
- // GTEST_COUT << x << " : " << matches[x] << std::endl;
- // }
- 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 = json();
- config = json();
- ports.clear();
- warps.clear();
- }
- void Galaxy::add_warp(sector_warps sw) {
- auto pos = warps.find(sw.sector);
- if (pos == warps.end()) {
- // not found
- // sw.sort();
- warps[sw.sector] = sw;
- // BUGZ_LOG(info) << "add_warp NEW " << sw.sector;
- } else {
- // found!
- if (pos->second.warps == sw.warps) {
- // BUGZ_LOG(trace) << "add_warp: Yup, I already know about " << sw.sector;
- } 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()) {
- // no such port.
- port p;
- p.sector = sector;
- p.type = port_type;
- for (int x = 0; x < 3; x++) {
- p.amount[x] = 0;
- p.percent[x] = 0;
- }
- // BUGZ_LOG(trace) << "add_port: " << sector << ", " << port_type << " : "
- // << p;
- ports[sector] = p;
- } else {
- // port was found, so:
- if (pos->second.type == port_type) {
- // BUGZ_LOG(trace) << "add_port: Yup, port " << sector << " is class " <<
- // 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()) {
- // BUGZ_LOG(trace) << "add_port: NEW " << p;
- 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) {
- // BUGZ_LOG(info) << "add_port: UPDATE " << p.sector;
- pos->second = p;
- } else {
- // BUGZ_LOG(info) << "add_port: Yup " << p.sector;
- }
- }
- }
- }
- void Galaxy::load(void) {
- std::string basename = "galaxy";
- if (CONFIG.contains("basename")) {
- basename = json_str(CONFIG["basename"]);
- }
- std::string filename =
- str(boost::format("%1%-%2%-%3%.json") % basename % game % username);
- // reset ?
- meta = json();
- config = json();
- ports.clear();
- warps.clear();
- if (file_exists(filename)) {
- BUGZ_LOG(fatal) << "Galaxy::load( " << filename << " )";
- json data;
- {
- std::ifstream fin(filename);
- data = json::parse(fin);
- }
- if (data.contains("meta")) {
- meta = data["meta"];
- } else {
- BUGZ_LOG(fatal) << "Missing meta data.";
- }
- meta["load_from"] = filename;
- meta["load_time"] = time_t_now(); // time_t
- if (data.contains("config")) {
- config = data["config"];
- } else {
- BUGZ_LOG(fatal) << "Missing config section.";
- }
- if (data.contains("ports")) {
- // const json &ports = data["ports"];
- for (auto const &port_iter : data["ports"].items()) {
- port p;
- p.sector = sstoi(port_iter.key()); // first.as<int>();
- p.type = port_iter.value()["class"].get<int>();
- int x;
- if (p.type == 0) {
- // nothing to load for type = 0, set defaults.
- for (x = 0; x < 3; ++x) {
- p.amount[x] = 0;
- p.percent[x] = 0;
- }
- } else {
- x = 0;
- for (auto const &amount : port_iter.value()["amount"].items()) {
- p.amount[x] = amount.value().get<int>();
- ++x;
- }
- x = 0;
- for (auto const &pct : port_iter.value()["pct"].items()) {
- p.percent[x] = pct.value().get<int>();
- ++x;
- }
- }
- add_port(p);
- }
- } else {
- BUGZ_LOG(fatal) << "Missing ports section.";
- }
- if (data.contains("warps")) {
- // const json &warps = data["warps"];
- // if (warps.IsMap()) {
- for (auto const &warp_iter : data["warps"].items()) {
- sector_warps sw;
- sw.sector = sstoi(warp_iter.key());
- for (auto const §or_iter : warp_iter.value().items()) {
- sw.add(sector_iter.value().get<int>());
- }
- // BUGZ_LOG(trace) << "YAML warp: " << sw;
- add_warp(sw);
- }
- // }
- } else {
- BUGZ_LOG(fatal) << "Missing warps section.";
- }
- BUGZ_LOG(trace) << "JSON: meta keys: " << meta.size();
- BUGZ_LOG(trace) << "JSON: config keys: " << config.size();
- BUGZ_LOG(trace) << "JSON: warp keys: " << warps.size();
- BUGZ_LOG(trace) << "JSON: port keys: " << ports.size();
- } else {
- BUGZ_LOG(fatal) << "Missing: " << filename;
- }
- }
- void Galaxy::save(void) {
- std::string basename = "galaxy";
- if (CONFIG.contains("basename")) {
- basename = CONFIG["basename"];
- }
- std::string filename =
- str(boost::format("%1%-%2%-%3%.json") % basename % game % username);
- std::ofstream fout(filename);
- BUGZ_LOG(fatal) << "save: " << filename;
- // int depth = 0;
- // std::string depth_spacer;
- meta["save_to"] = filename;
- meta["save_time"] = time_t_now(); // time_t
- // For now, we'll delete this manually.
- // FUTURE: delete all keys starting with _.
- if (meta.contains("density")) {
- meta.erase("density");
- }
- // clean meta data
- {
- // build vector of things to delete, don't invalidate your iterator. (UB)
- std::vector<std::string> to_delete;
- for (auto m : meta.items()) {
- if (m.key()[0] == '_') {
- to_delete.push_back(m.key());
- }
- }
- for (auto const &key : to_delete) {
- BUGZ_LOG(fatal) << "erasing meta key: [" << key << "]";
- meta.erase(key);
- }
- }
- /* // testing sequence code
- meta["sequence"]["part"].push_back(1);
- meta["sequence"]["part"].push_back(2);
- meta["sequence"]["part"].push_back(3);
- meta["sequence"]["smeg"].push_back(0);
- */
- json output;
- output["meta"] = meta;
- output["config"] = config;
- BUGZ_LOG(trace) << "JSON: meta: " << meta.size();
- // yaml_out(fout, depth, meta);
- BUGZ_LOG(trace) << "JSON: config: " << config.size();
- BUGZ_LOG(trace) << "JSON: warps: " << warps.size();
- // in config, I usually switch to doing flow instead. I'll keep this like
- // this for now.
- // yaml_out(fout, depth, config);
- for (auto const &warp : warps) {
- // fout << depth_spacer << warp.first << ": [";
- // bool first = true;
- std::string warp_text = std::to_string(warp.first);
- // output["warps"][warp.first] = json::array();
- for (auto const §or : warp.second.warps) {
- output["warps"][warp_text].push_back(sector);
- /*
- if (!first) {
- fout << ", ";
- } else
- first = false;
- fout << sector;
- */
- }
- // fout << "]" << std::endl;
- }
- BUGZ_LOG(trace) << "JSON: ports: " << ports.size();
- // fout << "ports:" << std::endl;
- for (auto const &port : ports) {
- std::string port_text = std::to_string(port.first);
- output["ports"][port_text]["class"] = (int)port.second.type;
- if (port.second.type != 0) {
- // write out the rest of the information
- // output["ports"][port.first]["amount"] =
- // json::array{port.second.amount[0], port.second.amount[1],
- // port.second.aount[2]};
- for (int x = 0; x < 3; x++) {
- // output["ports"][port.first]["amount"][x] = port.second.amount[x];
- output["ports"][port_text]["amount"].push_back(port.second.amount[x]);
- }
- // output["ports"][port.first]["pct"] =
- // json::array{port.second.percent[0], port.second.percent[1],
- // port.second.percent[2]};
- for (int x = 0; x < 3; x++) {
- // output["ports"][port.first]["pct"][x] = port.second.percent[x];
- output["ports"][port_text]["pct"].push_back(port.second.percent[x]);
- }
- }
- }
- fout << output;
- }
- std::vector<port_pair_type> Galaxy::find_trades(sector_type sector,
- bool highest) {
- std::vector<port_pair_type> pptv;
- // Does this sector have a port?
- auto port = ports.find(sector);
- if (port == ports.end()) return pptv;
- auto port_warps = warps.find(sector);
- // warps not found for port sector?
- if (port_warps == warps.end()) return pptv;
- for (auto const &s : port_warps->second.warps) {
- // only count the ports > our sector number -- so we don't have dups
- if (highest && (s < sector)) continue;
- // verify we have a way back
- {
- auto warpback = warps.find(s);
- // can we find that warp?
- if (warpback == warps.end()) continue;
- // does it link back to the port's sector?
- if (warpback->second.warps.find(sector) == warpback->second.warps.end())
- continue;
- }
- // Does this sector have a port?
- auto possible_port = ports.find(s);
- if (possible_port == ports.end()) continue;
- if (possible_port->second.type == 0) continue;
- // calculate trade type
- // int t = trade_type(port->second.type, possible_port->second.type);
- 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); // port->second.type, possible_port->second.type);
- 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 = json_int(config["burnt_percent"]);
- 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;
- }
- /**
- * Find_closest trade
- *
- * This works by getting all of the ports we know of.
- * Then, we find the nearest.
- *
- * @param sector
- * @return port_pair_type
- */
- port_pair_type Galaxy::find_closest(int sector) {
- auto trades = find_best_trades();
- // int type, sector_type s1, s2;
- 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) {
- // is current list in any of the trades ?
- for (auto const &t : trades) {
- if (t.type > 2) continue;
- if (current.find(t.s1) != current.end()) {
- // found one!
- 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) {
- // update the seen
- 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) {
- // have we already seen this sector?
- if (seen.find(w) != seen.end()) continue;
- // does it have a warp back to the original sector?
- auto warp_back = warps.find(w);
- if (warp_back != warps.end()) {
- if (warp_back->second.warps.find(li) !=
- warp_back->second.warps.end()) {
- // Ok, this links back to the original sector...
- 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;
- }
- /**
- * Find closest and best trade
- *
- * @param sector
- * @param lowest_trade_type
- * @return port_pair_type
- */
- port_pair_type Galaxy::find_closest_trade(int sector, int lowest_trade_type,
- int burnt_percent) {
- // int type, sector_type s1, s2;
- BUGZ_LOG(fatal) << "find_closest_trade(" << sector << ")";
- std::vector<port_pair_type> vppt;
- 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) {
- ++depth;
- BUGZ_LOG(info) << "depth: " << depth << " current:" << current.size()
- << " seen: " << seen.size();
- // search current for trades
- for (auto const &c : current) {
- auto port = ports.find(c);
- if (port == ports.end()) continue;
- if (port->second.type == 0) continue;
- auto port_warps = warps.find(c);
- if (port_warps == warps.end()) continue;
- for (auto const &s : port_warps->second.warps) {
- // verify we have a way back
- {
- auto warpback = warps.find(s);
- if (warpback == warps.end()) continue;
- if (warpback->second.warps.find(c) == warpback->second.warps.end())
- continue;
- }
- auto possible_port = ports.find(s);
- if (possible_port == ports.end()) continue;
- if (possible_port->second.type == 0) continue;
- trade_type_result ttr = trade_type_info(c, s, burnt_percent);
- if ((ttr.type == NONE) || (ttr.type > lowest_trade_type)) continue;
- // Ok! we found a trade that fits the criteria!
- vppt.push_back(port_pair_type{ttr.type, ttr.trades, c, s});
- found = true;
- }
- }
- added_new = false;
- if (found) {
- // ok, we've found some trades, sort and return the best
- sort_port_pair_type(vppt);
- return port_pair_type{vppt[0]};
- } else {
- // update the seen
- 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) {
- // have we already seen this sector?
- if (seen.find(w) != seen.end()) continue;
- // does it have a warp back to the original sector?
- auto warp_back = warps.find(w);
- if (warp_back != warps.end()) {
- if (warp_back->second.warps.find(li) !=
- warp_back->second.warps.end()) {
- // Ok, this links back to the original sector...
- 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;
- }
- sector_type Galaxy::find_nearest_unexplored(sector_type sector) {
- // search the galaxy for unexplored
- 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) {
- ++depth;
- BUGZ_LOG(info) << "depth: " << depth << " current:" << current.size()
- << " seen: " << seen.size();
- // search for warps
- for (auto const &c : current) {
- auto port_warps = warps.find(c);
- if (port_warps == warps.end()) return c;
- }
- // update the seen
- 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()) return li;
- for (auto const &w : wi->second.warps) {
- // have we already seen this sector?
- if (seen.find(w) != seen.end()) continue;
- current.insert(w);
- added_new = true;
- }
- }
- if (!added_new) {
- BUGZ_LOG(warning) << "No new sectors added. We're done!";
- found = false;
- }
- }
- return 0;
- }
- trade_type_result Galaxy::trade_type_info(sector_type port1, sector_type port2,
- int burnt_percent) {
- BUGZ_LOG(fatal) << "Trade_type_info(" << port1 << "," << port2 << ")";
- // This only gives us one trade_type per pair. There actually
- // should be multiple values returned here!
- // Like in case of BBB/SSS: return 3, 4 and 5.
- // NONE = 0
- // GOOD = 1 = OE PAIR
- // OK = 2 = ?? Pair
- // FAIR = 3 = B/S E
- // 4 = B/S O
- // 5 = B/S F
- 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; // or pos.size();
- std::vector<int> pos;
- // If we don't know how many holds the ship has, default to 300.
- int max_holds = 300;
- if (meta["ship"]["holds"].contains("total")) {
- max_holds = json_int(meta["ship"]["holds"]["total"]);
- }
- // find which FOE are flipped. Save index pos.
- for (int x = 0; x < 3; ++x) {
- inv2.foe[x] = (bsp1.foe[x] == inv2.foe[x]);
- // Ok, these are possible trades (B->S or S->B)
- // If known, check for burnt
- if (!p1->second.unknown()) {
- if (p1->second.percent[x] < burnt_percent) {
- BUGZ_LOG(fatal) << "Marking Port 1: " << x << " (burnt)";
- inv2.foe[x] = false;
- }
- if (p1->second.amount[x] < max_holds) {
- BUGZ_LOG(fatal) << "Marking Port 1: " << x << " (burnt/amount)";
- 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;
- }
- if (p2->second.amount[x] < max_holds) {
- BUGZ_LOG(fatal) << "Marking Port 2: " << x << " (burnt/amount)";
- 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) {
- // Check for BEST
- // O != E for both ports, and O != O, and ORG/EQU in inv2 list
- 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])) {
- // verify that fuel isn't set.
- inv2.foe[FUEL] = false;
- BUGZ_LOG(fatal) << "result: " << BEST << " " << inv2;
- return trade_type_result{BEST, inv2};
- }
- if (matches == 3) {
- // This could be SBB / BSS (it's a pair, but not BEST)
- // Is it FO or FE ?
- if (bsp1.foe[FUEL] != bsp2.foe[EQU]) {
- // OK, FE
- inv2.foe[ORG] = false;
- BUGZ_LOG(fatal) << "result: " << OK << " " << inv2;
- return trade_type_result{OK, inv2};
- }
- if (bsp1.foe[FUEL] != bsp2.foe[ORG]) {
- // OK, FO
- inv2.foe[EQU] = false;
- BUGZ_LOG(fatal) << "result: " << OK << " " << inv2;
- return trade_type_result{OK, inv2};
- }
- // Ok, take the highest (EQU)
- inv2.foe[FUEL] = false;
- inv2.foe[ORG] = false;
- BUGZ_LOG(fatal) << "result: " << FAIR_E << " " << inv2;
- return trade_type_result{FAIR_E, inv2};
- }
- // 2 matches. but are they trade pairs?
- if (bsp1.foe[pos[matches - 1]] != bsp1.foe[pos[matches - 2]]) {
- // yes!
- BUGZ_LOG(fatal) << "result: " << OK << " " << inv2;
- return trade_type_result{OK, inv2};
- } else {
- // they are NOT. Use highest one. clear the lower flag
- 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;
- }
- }
- // no matches.
- BUGZ_LOG(fatal) << "result: " << NONE << " " << inv2;
- return trade_type_result{NONE, inv2};
- }
- sector_type Galaxy::find_nearest_selling(int sector, int product, int selling) {
- BUGZ_LOG(fatal) << "find_nearest_selling(" << sector << ") " << product;
- std::set<sector_type> seen;
- std::set<sector_type> current;
- current.insert(sector);
- bool found = false;
- bool added_new = false;
- int depth = 0;
- // check current sector
- auto port = ports.find(sector);
- if (port != ports.end()) {
- // ok, port exists in starting sector
- // are they selling?
- int t = port->second.type;
- if (t != 0) {
- buysell bs = get_buysell(t);
- if (bs.foe[product] == false) {
- if (port->second.amount[product] >= selling) {
- BUGZ_LOG(fatal) << "Found port: " << port->first;
- return port->first;
- }
- }
- }
- }
- while (!found) {
- ++depth;
- BUGZ_LOG(info) << "depth: " << depth << " current:" << current.size()
- << " seen: " << seen.size();
- // search current for trades
- for (auto const &c : current) {
- auto port_warps = warps.find(c);
- if (port_warps == warps.end()) continue;
- for (auto const &s : port_warps->second.warps) {
- // I don't care if there's a way back the way we came
- auto possible_port = ports.find(s);
- if (possible_port == ports.end()) continue;
- if (possible_port->second.type == 0) continue;
- // are they selling?
- int t = possible_port->second.type;
- buysell bs = get_buysell(t);
- if (bs.foe[product] == true) continue;
- // check this port out
- if (possible_port->second.amount[product] >= selling) {
- BUGZ_LOG(fatal) << "Found port: " << possible_port->first;
- return possible_port->first;
- }
- }
- }
- added_new = false;
- // update the seen
- 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) {
- // have we already seen this sector?
- if (seen.find(w) != seen.end()) continue;
- // I don't care if it has a warp back or not.
- current.insert(w);
- added_new = true;
- }
- }
- if (!added_new) {
- BUGZ_LOG(warning) << "No new sectors added. We're done!";
- return 0;
- }
- }
- return 0;
- };
- std::vector<sector_type> Galaxy::find_safe(void) {
- std::vector<sector_type> vst;
- for (auto const &warp : warps) {
- if (warp.second.warps.size() == 1) {
- vst.push_back(warp.first);
- }
- }
- return vst;
- }
|