galaxy.cpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. #include "galaxy.h"
  2. #include <algorithm> // sort
  3. #include <boost/format.hpp>
  4. #include <exception>
  5. #include <ostream>
  6. #include <set>
  7. #include <string>
  8. #include <fstream>
  9. #include "logging.h"
  10. #include "yaml-cpp/yaml.h"
  11. // c++ default exceptions list
  12. // https://en.cppreference.com/w/cpp/error/exception
  13. bool buysell::operator==(const buysell &rhs) const {
  14. return ((foe[0] == rhs.foe[0]) && (foe[1] == rhs.foe[1]) &&
  15. (foe[2] == rhs.foe[2]));
  16. }
  17. std::ostream &operator<<(std::ostream &os, const buysell &bs) {
  18. os << bs.foe[0] << bs.foe[1] << bs.foe[2];
  19. return os;
  20. }
  21. bool buysell_text::operator==(const buysell_text &rhs) const {
  22. return ((txt[0] == rhs.txt[0]) && (txt[1] == rhs.txt[1]) &&
  23. (txt[2] == rhs.txt[2]));
  24. }
  25. std::ostream &operator<<(std::ostream &os, const buysell_text &bst) {
  26. os << '"' << bst.txt[0] << bst.txt[1] << bst.txt[2] << '"';
  27. return os;
  28. }
  29. std::ostream &operator<<(std::ostream &os, const port &p) {
  30. if (p.type == 0) {
  31. os << p.sector << ": " << (int)p.type;
  32. } else {
  33. os << p.sector << ": " << (int)p.type << " " << text_from_type(p.type)
  34. << " " << p.amount[0] << "," << p.amount[1] << "," << p.amount[2];
  35. }
  36. return os;
  37. }
  38. sector_warps::sector_warps() {
  39. sector = 0;
  40. for (int x = 0; x < MAX_WARPS; ++x) warps[x] = 0;
  41. }
  42. void sector_warps::add(sector_type new_sector) {
  43. for (int x = 0; x < MAX_WARPS; ++x) {
  44. if (warps[x] == new_sector) return;
  45. if (warps[x] == 0) {
  46. warps[x] = new_sector;
  47. return;
  48. }
  49. }
  50. std::string message = str(boost::format("More then MAX %1% sectors for %2%") %
  51. MAX_WARPS % (int)sector);
  52. throw std::out_of_range(message);
  53. }
  54. std::ostream &operator<<(std::ostream &os, const sector_warps &warps) {
  55. os << "Sector: " << warps.sector << " ";
  56. for (int x = 0; x < MAX_WARPS; ++x) {
  57. if (warps.warps[x] != 0) {
  58. if (x != 0) os << ",";
  59. os << warps.warps[x];
  60. }
  61. }
  62. return os;
  63. }
  64. bool sector_sort(sector_type st1, sector_type st2) {
  65. /* Sort sectors, put 0's at the end. */
  66. if (st1 == 0) return false;
  67. if (st2 == 0) return false;
  68. return (st1 < st2);
  69. }
  70. void sector_warps::sort(void) {
  71. std::sort(&warps[0], &warps[MAX_WARPS], sector_sort);
  72. }
  73. bool sector_warps::operator==(const sector_warps &rhs) const {
  74. /*
  75. Comapre if the sector_warps are the same.
  76. They do not need to be in the same order.
  77. */
  78. std::set<sector_type> contains;
  79. if (sector == rhs.sector) {
  80. int x;
  81. for (x = 0; x < MAX_WARPS; ++x) {
  82. if (warps[x] == 0) break;
  83. contains.insert(warps[x]);
  84. }
  85. for (x = 0; x < MAX_WARPS; ++x) {
  86. if (warps[0] == 0) break;
  87. auto pos = contains.find(rhs.warps[x]);
  88. if (pos == contains.end()) return false;
  89. contains.erase(pos);
  90. }
  91. return contains.empty();
  92. }
  93. // sector number doesn't match!
  94. return false;
  95. }
  96. #define GTEST_COUT std::cerr << "[ ] [ INFO ]"
  97. // #define GTEST_DEBUG
  98. struct port parse_portcim(const std::string line) {
  99. struct port p;
  100. p.sector = std::stoi(line);
  101. // 20 - 1708 97% - 710 56% 287 15%
  102. static std::regex portrx(
  103. "[ ]*([0-9]+) (.)[ ]+([0-9]+)[ ]+([0-9]+%) (.)[ "
  104. "]+([0-9]+)[ ]+([0-9]+%) (.)[ ]+([0-9]+)[ ]+([0-9]+%)[ ]*",
  105. std::regex_constants::ECMAScript);
  106. // does it not understand {3} ??
  107. // NO, it does not, from regex101.com:
  108. // A repeated capturing group will only capture the last iteration. Put a
  109. // capturing group around the repeated group to capture all iterations or use
  110. // a non-capturing group instead if you're not interested in the data
  111. //
  112. // static std::regex portrx("[ ]*([0-9]+)( (.)[ ]+([0-9]+)[ ]+([0-9]+%)){3}[
  113. // ]*",
  114. // std::regex_constants::ECMAScript);
  115. // sector + amount pct + amount pct + amount pct
  116. // 1 2 3 4 5 6 7 8 9 10
  117. #ifdef GTEST_DEBUG
  118. GTEST_COUT << "Sector: " << p.sector << std::endl;
  119. GTEST_COUT << "Line: [" << line << "]" << std::endl;
  120. #endif
  121. buysell port_buysell;
  122. std::smatch matches;
  123. if (std::regex_match(line, matches, portrx)) {
  124. #ifdef GTEST_DEBUG
  125. for (size_t x = 1; x < matches.size(); ++x) {
  126. GTEST_COUT << x << " : " << matches[x] << std::endl;
  127. }
  128. #endif
  129. if (matches.size() != 11) {
  130. #ifdef GTEST_DEBUG
  131. GTEST_COUT << "Now you have 101 problems." << std::endl;
  132. #endif
  133. p.sector = 0;
  134. p.type = 0;
  135. return p;
  136. }
  137. // GTEST_COUT << "matches: " << matches.size() << std::endl;
  138. p.sector = stoi(matches[1]);
  139. // GTEST_COUT << "sector: " << matches[1] << std::endl;
  140. // for (int x = 1; x < 11; ++x) {
  141. // GTEST_COUT << x << " : " << matches[x] << std::endl;
  142. // }
  143. for (int x = 0; x < 3; ++x) {
  144. int pos = x * 3;
  145. port_buysell.foe[x] = matches[pos + 2] == "-";
  146. p.amount[x] = stoi(matches[pos + 3]);
  147. p.percent[x] = stoi(matches[pos + 4]);
  148. }
  149. p.type = type_from_buysell(port_buysell);
  150. #ifdef GTEST_DEBUG
  151. GTEST_COUT << "port is type " << (int)p.type << std::endl;
  152. #endif
  153. return p;
  154. } else {
  155. #ifdef GTEST_DEBUG
  156. GTEST_COUT << "regex_match failed." << std::endl;
  157. #endif
  158. p.type = 0;
  159. p.sector = 0;
  160. return p;
  161. }
  162. }
  163. Galaxy::Galaxy() {}
  164. Galaxy::~Galaxy() { BUGZ_LOG(fatal) << "Galaxy::~Galaxy()"; }
  165. void Galaxy::add_warp(sector_warps sw) {
  166. auto pos = warps.find(sw.sector);
  167. if (pos == warps.end()) {
  168. // not found
  169. sw.sort();
  170. warps[sw.sector] = sw;
  171. BUGZ_LOG(info) << "add_warp NEW " << sw.sector;
  172. } else {
  173. // found!
  174. if (pos->second == sw) {
  175. BUGZ_LOG(trace) << "add_warp: Yup, I already know about " << sw.sector;
  176. } else {
  177. BUGZ_LOG(info) << "add_warp: Warps don't match! Updating...";
  178. BUGZ_LOG(warning) << "Have: " << pos->second;
  179. BUGZ_LOG(warning) << "Got : " << sw;
  180. warps[sw.sector] = sw;
  181. }
  182. }
  183. }
  184. void Galaxy::add_port(sector_type sector, int port_class) {}
  185. void Galaxy::add_port(port p) {}
  186. namespace YAML {
  187. template <>
  188. struct convert<Galaxy> {
  189. static Node encode(const Galaxy &rhs) {
  190. Node node;
  191. for (auto const &config_iter : rhs.config) {
  192. node["config"][config_iter.first] = config_iter.second;
  193. }
  194. for (auto const &warp : rhs.warps) {
  195. for (int x = 0; x < MAX_WARPS; ++x) {
  196. if (warp.second.warps[x] == 0) break;
  197. node["warps"][warp.first].push_back(warp.second.warps[x]);
  198. }
  199. }
  200. /*
  201. node.push_back(rhs.x);
  202. node.push_back(rhs.y);
  203. node.push_back(rhs.z);
  204. return node;
  205. */
  206. return node;
  207. }
  208. static bool decode(const Node &node, Galaxy &rhs) {
  209. if (!node.IsMap()) return false;
  210. if (node["config"]) {
  211. } else {
  212. BUGZ_LOG(fatal) << "YAML missing config section.";
  213. }
  214. if (node["ports"]) {
  215. } else {
  216. BUGZ_LOG(fatal) << "YAML missing ports section.";
  217. }
  218. if (node["warps"]) {
  219. const Node &warps = node["warps"];
  220. if (warps.IsMap()) {
  221. for (auto const warp_iter : warps) {
  222. sector_warps sw;
  223. sw.sector = warp_iter.first.as<int>();
  224. for (auto const sector_iter : warp_iter.second) {
  225. sw.add(sector_iter.as<int>());
  226. }
  227. BUGZ_LOG(fatal) << "YAML warp: " << sw;
  228. rhs.add_warp(sw);
  229. }
  230. }
  231. } else {
  232. BUGZ_LOG(fatal) << "YAML missing warps section.";
  233. }
  234. /*
  235. if(!node.IsSequence() || node.size() != 3) {
  236. return false;
  237. }
  238. rhs.x = node[0].as<double>();
  239. rhs.y = node[1].as<double>();
  240. rhs.z = node[2].as<double>();
  241. */
  242. return true;
  243. }
  244. };
  245. } // namespace YAML
  246. void Galaxy::load(void) {
  247. std::string filename =
  248. str(boost::format("galaxy-%1%-%2%.json") % game % username);
  249. // reset ?
  250. config.clear();
  251. ports.clear();
  252. warps.clear();
  253. if (file_exists(filename)) {
  254. YAML::Node data = YAML::LoadFile(filename);
  255. Galaxy g = data["galaxy"].as<Galaxy>();
  256. BUGZ_LOG(fatal) << "YAML: config keys: " << g.config.size();
  257. BUGZ_LOG(fatal) << "YAML: warp keys: " << g.warps.size();
  258. BUGZ_LOG(fatal) << "YAML: port keys: " << g.ports.size();
  259. // *this = data.as<Galaxy>();
  260. } else {
  261. BUGZ_LOG(fatal) << "Missing YAML: " << filename;
  262. }
  263. }
  264. void Galaxy::save(void) {
  265. std::string filename =
  266. str(boost::format("galaxy-%1%-%2%.json") % game % username);
  267. YAML::Node data;
  268. data["galaxy"] = *this;
  269. std::ofstream fout(filename);
  270. fout << data << std::endl;
  271. BUGZ_LOG(fatal) << "YAML: " << filename;
  272. }