trade routes instead of resources
This commit is contained in:
parent
7d92a45d12
commit
560ac056ff
@ -27,6 +27,7 @@ class TradeOption:
|
|||||||
resource: str
|
resource: str
|
||||||
source: Waypoint
|
source: Waypoint
|
||||||
dest: Waypoint
|
dest: Waypoint
|
||||||
|
buy: int
|
||||||
margin: int
|
margin: int
|
||||||
dist: int
|
dist: int
|
||||||
score: float
|
score: float
|
||||||
@ -159,31 +160,49 @@ class Analyzer:
|
|||||||
prices[r].append({
|
prices[r].append({
|
||||||
'wp': m.waypoint,
|
'wp': m.waypoint,
|
||||||
'buy': p.buy,
|
'buy': p.buy,
|
||||||
'sell': p.sell
|
'sell': p.sell,
|
||||||
|
'volume': p.volume
|
||||||
})
|
})
|
||||||
return prices
|
return prices
|
||||||
|
|
||||||
def find_trade(self, system):
|
def find_trade(self, system):
|
||||||
prices = self.prices(system)
|
prices = self.prices(system)
|
||||||
occupied_resources = set()
|
occupied_routes = set()
|
||||||
for s in self.store.all('Ship'):
|
for s in self.store.all('Ship'):
|
||||||
if s.mission != 'trade':
|
if s.mission != 'trade':
|
||||||
continue
|
continue
|
||||||
occupied_resources.add(s.mission_state['resource'])
|
occupied_routes.add((s.mission_state['site'], s.mission_state['dest']))
|
||||||
best = None
|
best = None
|
||||||
for resource, markets in prices.items():
|
for resource, markets in prices.items():
|
||||||
if resource in occupied_resources:
|
|
||||||
continue
|
|
||||||
source = sorted(markets, key=lambda x: x['buy'])[0]
|
source = sorted(markets, key=lambda x: x['buy'])[0]
|
||||||
dest = sorted(markets, key=lambda x: x['sell'])[-1]
|
dest = sorted(markets, key=lambda x: x['sell'])[-1]
|
||||||
|
swp = source['wp']
|
||||||
|
dwp = dest['wp']
|
||||||
margin = dest['sell'] -source['buy']
|
margin = dest['sell'] -source['buy']
|
||||||
|
if (swp.symbol,dwp.symbol) in occupied_routes:
|
||||||
dist = source['wp'].distance(dest['wp'])
|
continue
|
||||||
|
dist = swp.distance(dwp)
|
||||||
dist = max(dist, 0.0001)
|
dist = max(dist, 0.0001)
|
||||||
score = margin / dist
|
score = margin / dist
|
||||||
if margin < 0:
|
if margin < 0:
|
||||||
continue
|
continue
|
||||||
o = TradeOption(resource, source['wp'], dest['wp'], margin, dist, score)
|
o = TradeOption(resource, swp, dwp, source['buy'], margin, dist, score)
|
||||||
if best is None or best.score < o.score:
|
if best is None or best.score < o.score:
|
||||||
best = o
|
best = o
|
||||||
return best
|
return best
|
||||||
|
|
||||||
|
def find_deal(self, smkt, dmkt):
|
||||||
|
best_margin = 0
|
||||||
|
best_resource = None
|
||||||
|
print(f'finding deal from {smkt} to {dmkt}')
|
||||||
|
for r, sp in smkt.prices.items():
|
||||||
|
if not r in dmkt.prices:
|
||||||
|
print(r, 'not in dmkt')
|
||||||
|
continue
|
||||||
|
dp = dmkt.prices[r]
|
||||||
|
margin = dp.sell - sp.buy
|
||||||
|
print(r, margin)
|
||||||
|
if margin > best_margin:
|
||||||
|
best_margin = margin
|
||||||
|
best_resource = r
|
||||||
|
return best_resource
|
||||||
|
@ -131,10 +131,8 @@ class CentralCommand:
|
|||||||
return
|
return
|
||||||
print(f'assigning {s} to deliver {t.resource} from {t.source} to {t.dest} at a margin of {t.margin}')
|
print(f'assigning {s} to deliver {t.resource} from {t.source} to {t.dest} at a margin of {t.margin}')
|
||||||
self.init_mission(s, 'trade')
|
self.init_mission(s, 'trade')
|
||||||
self.smipa(s, 'resource', t.resource)
|
|
||||||
self.smipa(s, 'site', t.source)
|
self.smipa(s, 'site', t.source)
|
||||||
self.smipa(s, 'dest', t.dest)
|
self.smipa(s, 'dest', t.dest)
|
||||||
self.smipa(s, 'delivery', 'sell')
|
|
||||||
|
|
||||||
def init_mission(self, s, mtyp):
|
def init_mission(self, s, mtyp):
|
||||||
if mtyp == 'none':
|
if mtyp == 'none':
|
||||||
|
@ -85,7 +85,7 @@ class Commander(CommandLine):
|
|||||||
elif len(matches) > 1:
|
elif len(matches) > 1:
|
||||||
raise CommandError('multiple matches')
|
raise CommandError('multiple matches')
|
||||||
else:
|
else:
|
||||||
raise CommandError('not found')
|
raise CommandError(f'{arg} not found')
|
||||||
|
|
||||||
def resolve_system(self, system_str):
|
def resolve_system(self, system_str):
|
||||||
if type(system_str) == System:
|
if type(system_str) == System:
|
||||||
@ -97,6 +97,20 @@ class Commander(CommandLine):
|
|||||||
system = self.store.get(System, system_str)
|
system = self.store.get(System, system_str)
|
||||||
return system
|
return system
|
||||||
|
|
||||||
|
def resolve_waypoint(self, w):
|
||||||
|
if type(w) == Waypoint:
|
||||||
|
return w
|
||||||
|
if w == '':
|
||||||
|
if not self.has_ship(): return
|
||||||
|
return self.ship.location
|
||||||
|
p = w.split('-')
|
||||||
|
if len(p) == 1:
|
||||||
|
if not self.has_ship(): return
|
||||||
|
s = self.ship.location.system
|
||||||
|
w = f'{s}-{w}'
|
||||||
|
return self.store.get(Waypoint, w)
|
||||||
|
|
||||||
|
|
||||||
######## First run #########
|
######## First run #########
|
||||||
def agent_setup(self):
|
def agent_setup(self):
|
||||||
symbol = input('agent name: ')
|
symbol = input('agent name: ')
|
||||||
@ -232,12 +246,17 @@ class Commander(CommandLine):
|
|||||||
r = self.api.jumps(waypoint)
|
r = self.api.jumps(waypoint)
|
||||||
pprint(r)
|
pprint(r)
|
||||||
|
|
||||||
def do_shipyard(self):
|
def do_shipyard(self, w=''):
|
||||||
if not self.has_ship(): return
|
location = self.resolve_waypoint(w)
|
||||||
location = self.ship.location
|
if location is None:
|
||||||
|
raise CommandError(f'waypoint {w} not found')
|
||||||
data = self.api.shipyard(location)
|
data = self.api.shipyard(location)
|
||||||
|
if 'ships' in data:
|
||||||
for s in must_get(data, 'ships'):
|
for s in must_get(data, 'ships'):
|
||||||
print(s['type'], s['purchasePrice'])
|
print(s['type'], s['purchasePrice'])
|
||||||
|
else:
|
||||||
|
for s in must_get(data, 'shipTypes'):
|
||||||
|
print(s['type'])
|
||||||
|
|
||||||
######## Commerce #########
|
######## Commerce #########
|
||||||
def do_refuel(self, source='market'):
|
def do_refuel(self, source='market'):
|
||||||
@ -532,9 +551,12 @@ class Commander(CommandLine):
|
|||||||
system = self.ship.location.system
|
system = self.ship.location.system
|
||||||
prices = self.analyzer.prices(system)
|
prices = self.analyzer.prices(system)
|
||||||
if resource is not None:
|
if resource is not None:
|
||||||
pprint(prices[resource.upper()])
|
prices = {resource: prices[resource.upper()]}
|
||||||
else:
|
|
||||||
pprint(prices)
|
for res, p in prices.items():
|
||||||
|
print('==' + res)
|
||||||
|
for m in p:
|
||||||
|
print(f"{m['wp'].symbol:12s} {m['volume']:5d} {m['buy']:5d} {m['sell']:5d}")
|
||||||
|
|
||||||
def do_path(self, waypoint_str):
|
def do_path(self, waypoint_str):
|
||||||
if not self.has_ship(): return
|
if not self.has_ship(): return
|
||||||
|
@ -61,6 +61,8 @@ class Mission:
|
|||||||
|
|
||||||
def rst(self, typ, nm):
|
def rst(self, typ, nm):
|
||||||
symbol = self.st(nm)
|
symbol = self.st(nm)
|
||||||
|
if symbol is None:
|
||||||
|
return None
|
||||||
return self.store.get(typ, symbol)
|
return self.store.get(typ, symbol)
|
||||||
|
|
||||||
def st(self, nm):
|
def st(self, nm):
|
||||||
@ -186,21 +188,6 @@ class BaseMission(Mission):
|
|||||||
else:
|
else:
|
||||||
return 'more'
|
return 'more'
|
||||||
|
|
||||||
def step_load(self):
|
|
||||||
credits = self.api.agent.credits
|
|
||||||
cargo_space = self.ship.cargo_capacity - self.ship.cargo_units
|
|
||||||
resource = self.st('resource')
|
|
||||||
loc = self.ship.location
|
|
||||||
market = self.store.get('Marketplace', loc.symbol)
|
|
||||||
price = market.buy_price(resource)
|
|
||||||
volume = market.volume(resource)
|
|
||||||
affordable = credits // price
|
|
||||||
amount = min(cargo_space, affordable)
|
|
||||||
while amount > 0:
|
|
||||||
amt = min(amount, volume)
|
|
||||||
self.api.buy(self.ship, resource, amt)
|
|
||||||
amount -= amt
|
|
||||||
|
|
||||||
def step_travel(self):
|
def step_travel(self):
|
||||||
traject = self.st('traject')
|
traject = self.st('traject')
|
||||||
if traject is None or traject == []:
|
if traject is None or traject == []:
|
||||||
|
@ -6,14 +6,29 @@ class TradeMission(BaseMission):
|
|||||||
def start_state(self):
|
def start_state(self):
|
||||||
return 'travel-to'
|
return 'travel-to'
|
||||||
|
|
||||||
|
def step_load(self):
|
||||||
|
credits = self.api.agent.credits
|
||||||
|
cargo_space = self.ship.cargo_capacity - self.ship.cargo_units
|
||||||
|
smkt = self.store.get('Marketplace', self.st('site'))
|
||||||
|
dmkt = self.store.get('Marketplace', self.st('dest'))
|
||||||
|
resource = self.analyzer.find_deal(smkt, dmkt)
|
||||||
|
if resource is None:
|
||||||
|
return 'done'
|
||||||
|
price = smkt.buy_price(resource)
|
||||||
|
volume = smkt.volume(resource)
|
||||||
|
affordable = credits // price
|
||||||
|
print(cargo_space, affordable, volume)
|
||||||
|
amount = min(cargo_space, affordable, volume)
|
||||||
|
if amount == 0:
|
||||||
|
return 'done'
|
||||||
|
self.api.buy(self.ship, resource, amount)
|
||||||
|
return 'done' if amount == cargo_space else 'more'
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def params(cls):
|
def params(cls):
|
||||||
return {
|
return {
|
||||||
'site': MissionParam(Waypoint, True),
|
'site': MissionParam(Waypoint, True),
|
||||||
'resource': MissionParam(str, True),
|
|
||||||
'dest': MissionParam(Waypoint, True),
|
'dest': MissionParam(Waypoint, True),
|
||||||
'delivery': MissionParam(str, True, 'deliver'),
|
|
||||||
'contract': MissionParam(Contract, False)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def steps(self):
|
def steps(self):
|
||||||
@ -21,7 +36,10 @@ class TradeMission(BaseMission):
|
|||||||
**self.travel_steps('to', 'site', 'dock'),
|
**self.travel_steps('to', 'site', 'dock'),
|
||||||
'dock': (self.step_dock, 'market-pre'),
|
'dock': (self.step_dock, 'market-pre'),
|
||||||
'market-pre': (self.step_market, 'load'),
|
'market-pre': (self.step_market, 'load'),
|
||||||
'load': (self.step_load, 'market-post'),
|
'load': (self.step_load, {
|
||||||
|
'more': 'market-pre',
|
||||||
|
'done': 'market-post'
|
||||||
|
}),
|
||||||
'market-post': (self.step_market, 'travel-back'),
|
'market-post': (self.step_market, 'travel-back'),
|
||||||
**self.travel_steps('back', 'dest', 'dock-dest'),
|
**self.travel_steps('back', 'dest', 'dock-dest'),
|
||||||
'dock-dest': (self.step_dock, 'unload'),
|
'dock-dest': (self.step_dock, 'unload'),
|
||||||
|
@ -100,7 +100,7 @@ class Marketplace(Base):
|
|||||||
r += 'X: ' + ', '.join(self.exchange) + '\n'
|
r += 'X: ' + ', '.join(self.exchange) + '\n'
|
||||||
|
|
||||||
r += '\n'
|
r += '\n'
|
||||||
for p in self.prices.values():
|
for res, p in self.prices.items():
|
||||||
t = self.rtype(p['symbol'])
|
t = self.rtype(res)
|
||||||
r += f'{t} {p["symbol"]:25s} {p["sell"]:5d} {p["buy"]:5d}\n'
|
r += f'{t} {res:25s} {p.sell:5d} {p.buy:5d}\n'
|
||||||
return r
|
return r
|
||||||
|
@ -99,6 +99,8 @@ class Ship(Base):
|
|||||||
|
|
||||||
def deliverable_cargo(self, contract):
|
def deliverable_cargo(self, contract):
|
||||||
result = []
|
result = []
|
||||||
|
if contract is None:
|
||||||
|
return result
|
||||||
for d in contract.deliveries:
|
for d in contract.deliveries:
|
||||||
if self.get_cargo(d['trade_symbol']) > 0:
|
if self.get_cargo(d['trade_symbol']) > 0:
|
||||||
result.append(d['trade_symbol'])
|
result.append(d['trade_symbol'])
|
||||||
@ -126,6 +128,8 @@ class Ship(Base):
|
|||||||
mstatus = self.mission_status
|
mstatus = self.mission_status
|
||||||
if mstatus == 'error':
|
if mstatus == 'error':
|
||||||
mstatus = mstatus.upper()
|
mstatus = mstatus.upper()
|
||||||
|
if mstatus is None:
|
||||||
|
mstatus = 'none'
|
||||||
status = self.status.lower()
|
status = self.status.lower()
|
||||||
if status.startswith('in_'):
|
if status.startswith('in_'):
|
||||||
status = status[3:]
|
status = status[3:]
|
||||||
|
Loading…
Reference in New Issue
Block a user