from nullptr.models.marketplace import Marketplace from nullptr.models.jumpgate import Jumpgate from nullptr.models.system import System from dataclasses import dataclass @dataclass class SearchNode: system: System parent: 'SearchNode' def __hash__(self): return hash(self.system.symbol) def path(self): result = [] n = self while n is not None: result.append(n.system) n = n.parent result.reverse() return result def __repr__(self): return self.system.symbol class Analyzer: def __init__(self, store): self.store = store def find_markets(self, resource, sellbuy): for m in self.store.all(Marketplace): resources = m.imports if sellbuy == 'sell' else m.exports if resource in resources: yield m def find_closest_market(self, resource, sellbuy, location): if type(location) == str: location = self.store.get(System, location) market = None distance = None for m in self.find_markets(resource, sellbuy): system = self.store.get(System, m.system()) p = self.find_path(location, system) if p is None: continue if distance is None or len(p) < distance: market = m distance = len(p) return market def get_jumpgate(self, system): gates = self.store.all_members(system, Jumpgate) return next(gates, None) def find_path(self, orig, to, depth=100, seen=None): if depth < 1: return None if seen is None: seen = set() if type(orig) == System: orig = set([SearchNode(orig,None)]) result = [n for n in orig if n.system==to] if len(result) > 0: return result[0].path() dest = set() for o in orig: jg = self.get_jumpgate(o.system) if jg is None: continue for s in jg.systems: if s in seen: continue seen.add(s) system = self.store.get(System, s) if system is None: continue dest.add(SearchNode(system, o)) if len(dest) == 0: return None return self.find_path(dest, to, depth-1, seen)