#include "galaxy.h" #include // sort #include #include #include #include #include #include #include "logging.h" #include "yaml-cpp/yaml.h" // c++ default exceptions list // https://en.cppreference.com/w/cpp/error/exception bool buysell::operator==(const buysell &rhs) const { return ((foe[0] == rhs.foe[0]) && (foe[1] == rhs.foe[1]) && (foe[2] == rhs.foe[2])); } std::ostream &operator<<(std::ostream &os, const buysell &bs) { os << bs.foe[0] << bs.foe[1] << bs.foe[2]; return os; } bool buysell_text::operator==(const buysell_text &rhs) const { return ((txt[0] == rhs.txt[0]) && (txt[1] == rhs.txt[1]) && (txt[2] == rhs.txt[2])); } std::ostream &operator<<(std::ostream &os, const buysell_text &bst) { os << '"' << bst.txt[0] << bst.txt[1] << bst.txt[2] << '"'; return os; } 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; } sector_warps::sector_warps() { sector = 0; for (int x = 0; x < MAX_WARPS; ++x) warps[x] = 0; } void sector_warps::add(sector_type 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 << " "; for (int x = 0; x < MAX_WARPS; ++x) { if (warps.warps[x] != 0) { if (x != 0) os << ","; os << warps.warps[x]; } } return os; } bool sector_sort(sector_type st1, sector_type st2) { /* Sort sectors, put 0's at the end. */ if (st1 == 0) return false; if (st2 == 0) return false; return (st1 < st2); } void sector_warps::sort(void) { std::sort(&warps[0], &warps[MAX_WARPS], sector_sort); } bool sector_warps::operator==(const sector_warps &rhs) const { /* Comapre if the sector_warps are the same. They do not need to be in the same order. */ std::set contains; if (sector == rhs.sector) { int x; for (x = 0; x < MAX_WARPS; ++x) { if (warps[x] == 0) break; contains.insert(warps[x]); } for (x = 0; x < MAX_WARPS; ++x) { if (warps[0] == 0) break; auto pos = contains.find(rhs.warps[x]); if (pos == contains.end()) return false; contains.erase(pos); } return contains.empty(); } // sector number doesn't match! return false; } #define GTEST_COUT std::cerr << "[ ] [ INFO ]" // #define GTEST_DEBUG struct port parse_portcim(const std::string line) { struct port p; p.sector = std::stoi(line); // 20 - 1708 97% - 710 56% 287 15% 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() {} Galaxy::~Galaxy() { BUGZ_LOG(fatal) << "Galaxy::~Galaxy()"; } 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 == sw) { 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_class) {} void Galaxy::add_port(port p) {} namespace YAML { template <> struct convert { static Node encode(const Galaxy &rhs) { Node node; for (auto const &config_iter : rhs.config) { node["config"][config_iter.first] = config_iter.second; } for (auto const &warp : rhs.warps) { for (int x = 0; x < MAX_WARPS; ++x) { if (warp.second.warps[x] == 0) break; node["warps"][warp.first].push_back(warp.second.warps[x]); } } /* node.push_back(rhs.x); node.push_back(rhs.y); node.push_back(rhs.z); return node; */ return node; } static bool decode(const Node &node, Galaxy &rhs) { if (!node.IsMap()) return false; if (node["config"]) { } else { BUGZ_LOG(fatal) << "YAML missing config section."; } if (node["ports"]) { } else { BUGZ_LOG(fatal) << "YAML missing ports section."; } if (node["warps"]) { const Node &warps = node["warps"]; if (warps.IsMap()) { for (auto const warp_iter : warps) { sector_warps sw; sw.sector = warp_iter.first.as(); for (auto const sector_iter : warp_iter.second) { sw.add(sector_iter.as()); } BUGZ_LOG(fatal) << "YAML warp: " << sw; rhs.add_warp(sw); } } } else { BUGZ_LOG(fatal) << "YAML missing warps section."; } /* if(!node.IsSequence() || node.size() != 3) { return false; } rhs.x = node[0].as(); rhs.y = node[1].as(); rhs.z = node[2].as(); */ return true; } }; } // namespace YAML void Galaxy::load(void) { std::string filename = str(boost::format("galaxy-%1%-%2%.json") % game % username); // reset ? config.clear(); ports.clear(); warps.clear(); if (file_exists(filename)) { YAML::Node data = YAML::LoadFile(filename); Galaxy g = data["galaxy"].as(); BUGZ_LOG(fatal) << "YAML: config keys: " << g.config.size(); BUGZ_LOG(fatal) << "YAML: warp keys: " << g.warps.size(); BUGZ_LOG(fatal) << "YAML: port keys: " << g.ports.size(); // *this = data.as(); } else { BUGZ_LOG(fatal) << "Missing YAML: " << filename; } } void Galaxy::save(void) { std::string filename = str(boost::format("galaxy-%1%-%2%.json") % game % username); YAML::Node data; data["galaxy"] = *this; std::ofstream fout(filename); fout << data << std::endl; BUGZ_LOG(fatal) << "YAML: " << filename; }