store fixes and probe role

This commit is contained in:
Richard 2024-01-13 21:42:49 +01:00
parent 188ef320cc
commit 7d92a45d12
12 changed files with 65 additions and 42 deletions

View File

@ -153,8 +153,7 @@ class Analyzer:
def prices(self, system):
prices = {}
for m in self.store.all_members(system, Marketplace):
for p in m.prices.values():
r = p['symbol']
for r, p in m.prices.items():
if not r in prices:
prices[r] = []
prices[r].append({
@ -168,7 +167,7 @@ class Analyzer:
prices = self.prices(system)
occupied_resources = set()
for s in self.store.all('Ship'):
if s.mission != 'haul':
if s.mission != 'trade':
continue
occupied_resources.add(s.mission_state['resource'])
best = None

View File

@ -1,7 +1,7 @@
from nullptr.store import Store
from nullptr.models.ship import Ship
from nullptr.missions import create_mission, get_mission_class
from random import choice
from random import choice, randrange
from time import sleep
from threading import Thread
from nullptr.atlas_builder import AtlasBuilder
@ -106,10 +106,23 @@ class CentralCommand:
def assign_mission(self, s):
if s.role == 'hauler':
self.assign_haul(s)
if s.role == 'trader':
self.assign_trade(s)
elif s.role == 'probe':
self.assign_probe(s)
def assign_haul(self, s):
def assign_probe(self, s):
system = s.location.system
m = [m.waypoint for m in self.store.all_members(system, 'Marketplace')]
m = self.analyzer.solve_tsp(m)
hops = [w.symbol for w in m]
start_hop = randrange(0, len(hops))
print(f'Assigning {s} to probe {len(hops)} starting at {hops[start_hop]}')
self.init_mission(s, 'probe')
self.smipa(s, 'hops', hops)
self.smipa(s, 'next-hop', start_hop)
def assign_trade(self, s):
t = self.analyzer.find_trade(s.location.system)
if t is None:
print(f"No trade for {s} found. Idling")
@ -117,7 +130,7 @@ class CentralCommand:
self.smipa(s, 'seconds', 600)
return
print(f'assigning {s} to deliver {t.resource} from {t.source} to {t.dest} at a margin of {t.margin}')
self.init_mission(s, 'haul')
self.init_mission(s, 'trade')
self.smipa(s, 'resource', t.resource)
self.smipa(s, 'site', t.source)
self.smipa(s, 'dest', t.dest)

View File

@ -20,6 +20,7 @@ class Commander(CommandLine):
def __init__(self, data_dir='data'):
store_file = os.path.join(data_dir, 'store.npt')
hist_file = os.path.join(data_dir, 'cmd.hst')
self.cred_file = os.path.join(data_dir, 'creds.txt')
self.hist_file = hist_file
if os.path.isfile(hist_file):
readline.read_history_file(hist_file)
@ -107,7 +108,7 @@ class Commander(CommandLine):
if len(faction) > 50:
self.agent.token = faction
else:
api.register(faction.upper().strip())
self.do_register(faction)
print('=== agent:')
print(agent)
print('=== ships')
@ -126,6 +127,10 @@ class Commander(CommandLine):
def do_register(self, faction):
self.api.register(faction.upper())
with open(self.cred_file, 'w') as f:
f.write(self.api.agent.symbol)
f.write('\n')
f.write(self.api.agent.token)
pprint(self.api.agent)
######## Fleet #########
@ -306,7 +311,7 @@ class Commander(CommandLine):
pprint(self.ship.mission_state)
def do_role(self, role):
roles = [None, 'hauler']
roles = [None, 'trader', 'probe']
if not self.has_ship(): return
if role == 'none':
role = None
@ -407,7 +412,7 @@ class Commander(CommandLine):
return
_, m, _, _ = m[0]
site = self.store.get(Waypoint, m.symbol)
self.centcom.init_mission(self.ship, 'haul')
self.centcom.init_mission(self.ship, 'trade')
self.centcom.set_mission_param(self.ship, 'site', site)
self.centcom.set_mission_param(self.ship, 'resource', resource)
self.centcom.set_mission_param(self.ship, 'dest', destination)
@ -432,18 +437,6 @@ class Commander(CommandLine):
self.centcom.set_mission_param(self.ship, 'hops', markets)
self.print_mission()
def do_sprobe(self):
if not self.has_ship(): return
system = self.ship.location.system
m = [m.waypoint for m in self.store.all_members(system, 'Marketplace')]
print("pre", path_dist(m))
m = self.analyzer.solve_tsp(m)
print("post", path_dist(m))
hops = [w.symbol for w in m]
self.centcom.init_mission(self.ship, 'probe')
self.centcom.set_mission_param(self.ship, 'hops', hops)
self.print_mission()
######## Travel #########
def do_travel(self, dest):
dest = self.resolve('Waypoint', dest)

View File

@ -1,6 +1,6 @@
from nullptr.missions.survey import SurveyMission
from nullptr.missions.mine import MiningMission
from nullptr.missions.haul import HaulMission
from nullptr.missions.trade import TradeMission
from nullptr.missions.travel import TravelMission
from nullptr.missions.probe import ProbeMission
from nullptr.missions.idle import IdleMission
@ -10,7 +10,7 @@ def get_mission_class( mtype):
types = {
'survey': SurveyMission,
'mine': MiningMission,
'haul': HaulMission,
'trade': TradeMission,
'travel': TravelMission,
'probe': ProbeMission,
'idle': IdleMission

View File

@ -49,7 +49,7 @@ class MiningMission(BaseMission):
site = self.rst(Waypoint,'site')
# todo optimize
for s in self.store.all(Survey):
if resource in s.deposits and site.symbol == s.waypoint():
if resource in s.deposits and site.symbol == s.waypoint:
return s
return None

View File

@ -2,7 +2,7 @@ from nullptr.missions.base import BaseMission, MissionParam
from nullptr.models.waypoint import Waypoint
from nullptr.models.survey import Survey
from nullptr.models.contract import Contract
class HaulMission(BaseMission):
class TradeMission(BaseMission):
def start_state(self):
return 'travel-to'

View File

@ -14,6 +14,9 @@ class Reference:
def resolve(self):
return self.store.get(self.typ, self.symbol)
def f(self, detail):
return f'{self.symbol}.{self.typ.ext()}'
def __repr__(self):
return f'*REF*{self.symbol}.{self.typ.ext()}'
@ -46,6 +49,9 @@ class Base:
def define(self):
pass
def created(self):
pass
def __hash__(self):
return hash((str(type(self)), self.symbol))
@ -84,12 +90,16 @@ class Base:
def __setattr__(self, name, value):
if not name.startswith('_') and not self._disable_dirty:
self.store.dirty(self)
self.dirty()
if issubclass(type(value), Base):
value = Reference.create(value)
super().__setattr__(name, value)
def __getattribute__(self, nm):
if nm == 'system':
return self.get_system()
if nm == 'waypoint':
return self.get_waypoint()
val = super().__getattribute__(nm)
if type(val) == Reference:
val = val.resolve()

View File

@ -5,7 +5,6 @@ from dataclasses import field
class Jumpgate(Base):
def define(self):
self.connections: list = []
self.system = self.get_system()
def update(self, d):
getter = self.store.getter(Waypoint, create=True)

View File

@ -1,5 +1,5 @@
from .base import Base
from .base import Base, Reference
from time import time
from nullptr.util import *
from dataclasses import field, dataclass
@ -32,12 +32,9 @@ class Marketplace(Base):
self.exchange:list = []
self.prices:dict = {}
self.last_prices:int = 0
self.set_waypoint()
self.system = self.get_system()
def set_waypoint(self):
waypoint = self.store.get(Waypoint, self.symbol, create=True)
self.waypoint = waypoint
def get_waypoint(self):
return self.store.get('Waypoint', self.symbol, create=True)
def is_fuel(self):
return self.imports + self.exports + self.exchange == ['FUEL']
@ -51,7 +48,7 @@ class Marketplace(Base):
e = self.prices[symbol] = MarketEntry()
buy = mg(g, 'purchasePrice')
sell = mg(g, 'sellPrice')
volume = mg(g, 'tradeVolumes')
volume = mg(g, 'tradeVolume')
supply = SUPPLY.index(mg(g, 'supply'))
activity = ACTIVITY.index(sg(g, 'activity','STRONG'))
e.add(buy, sell, volume, supply, activity)
@ -68,12 +65,12 @@ class Marketplace(Base):
def buy_price(self, resource):
if resource not in self.prices:
return None
return self.prices[resource]['buy']
return self.prices[resource].buy
def volume(self, resource):
if resource not in self.prices:
return None
return self.prices[resource]['volume']
return self.prices[resource].volume
def sellable_items(self, resources):
return [r for r in resources if r in self.prices]

View File

@ -28,7 +28,7 @@ class Survey(Base):
def api_dict(self):
return {
'signature': self.symbol,
'symbol': self.waypoint(),
'symbol': self.waypoint,
'deposits': [{'symbol': d} for d in self.deposits],
'expiration': self.expires_str,
'size': size_names[self.size]

View File

@ -12,7 +12,6 @@ class Waypoint(Base):
self.traits:list = []
self.faction:str = ''
self.is_under_construction:bool = False
self.system = self.get_system()
self.uncharted = True
@ -24,6 +23,9 @@ class Waypoint(Base):
self.seta('is_under_construction', d, 'isUnderConstruction')
self.setlst('traits', d, 'traits', 'symbol')
self.uncharted = 'UNCHARTED' in self.traits
def created(self):
self.get_system()
def distance(self, other):
return int(sqrt((self.x - other.x) ** 2 + (self.y - other.y) ** 2))

View File

@ -72,6 +72,7 @@ class ChunkHeader:
class Store:
def __init__(self, data_file, verbose=False):
self.init_models()
self.data_file = data_file
self.data_dir = os.path.dirname(data_file)
self.fil = open_file(data_file)
self.data = {m: {} for m in self.models}
@ -90,6 +91,9 @@ class Store:
return
print(m)
def f(self, detail):
return f'Store {self.data_file}'
def close(self):
self.flush()
self.fil.close()
@ -112,6 +116,9 @@ class Store:
buf = BytesIO(data)
p = StoreUnpickler(buf, self)
obj = p.load()
x = self.get(type(obj), obj.symbol)
if x is not None and x in self.dirty_objects:
self.dirty_objects.remove(obj)
obj._file_offset = offset
self.hold(obj)
@ -138,6 +145,8 @@ class Store:
offset = self.fil.tell()
dur = time() - start_time
# just in case any temp objects were created
self.dirty_objects = set()
self.p(f'Loaded {cnt} objects in {dur:.2f} seconds')
self.p(f'Fragmented space: {free} / {total} bytes')
@ -210,14 +219,15 @@ class Store:
symbol = obj.symbol
obj.store = self
self.data[typ][symbol] = obj
if hasattr(obj, 'system'):
system_str = obj.get_system().symbol
if type(obj).__name__ in ['Waypoint','Marketplace', 'Jumpgate', 'Survey']:
system_str = obj.system.symbol
if system_str not in self.system_members:
self.system_members[system_str] = set()
self.system_members[system_str].add(obj)
def create(self, typ, symbol):
obj = typ(symbol, self)
obj.created()
self.hold(obj)
self.dirty(obj)
return obj