Skip to content

Commit

Permalink
Merge branch 'master' into devel
Browse files Browse the repository at this point in the history
  • Loading branch information
bgol committed Oct 26, 2014
2 parents 04ab156 + a9b4dcb commit 77dcbe1
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 85 deletions.
6 changes: 6 additions & 0 deletions README.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ files from other commanders to fill out your database.
== CHANGE LOG
==============================================================================

v4.6.2 Oct 25/2014
. (kfsone) Added support for self-correcting star/station name changes,
. (kfsone) Added name corrections for maddavo's current TradeDangerous.prices,
. (kfsone) Assorted minor API changes,
. (kfsone) Minor startup optimization pass

v4.6.1 Oct 25/2014
. (kfsone) Added "--supply" (-S) which shows supply (demand and stock) fields when editing,
. (kfsone) Added "--timestamps" (-T) which shows timestamp field when editing,
Expand Down
11 changes: 7 additions & 4 deletions buildcache.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
from pathlib import Path
from collections import namedtuple
from tradeexcept import TradeException
from data import corrections

# Find the non-comment part of a string
noCommentRe = re.compile(r'^\s*(?P<text>(?:[^\\#]|\\.)*)\s*(#|$)')
Expand Down Expand Up @@ -196,9 +197,10 @@ def genSQLFromPriceLines(priceFile, db, defaultZero, debug=0):
matches = systemStationRe.match(text)
if matches:
# Change which station we're at
stationName = "%s/%s" % (matches.group(1).upper(), matches.group(2))
stationID, categoryID, uiOrder = systemByName[stationName], None, 0
if debug > 1: print("NEW STATION: {}".format(stationName))
systemName, stationName = (corrections.correct(matches.group(1)), corrections.correct(matches.group(2)))
facility = systemName.upper() + '/' + stationName
stationID, categoryID, uiOrder = systemByName[facility], None, 0
if debug > 1: print("NEW STATION: {}".format(facility))
continue
if not stationID:
print("Expecting: '@ SYSTEM / Station'.")
Expand Down Expand Up @@ -369,6 +371,7 @@ def commandLineBuildCache():
dbFilename = TradeDB.defaultDB
sqlFilename = TradeDB.defaultSQL
pricesFilename = TradeDB.defaultPrices
importTables = TradeDB.defaultTables

# Check command line for -w/--debug inputs.
import argparse
Expand Down Expand Up @@ -396,7 +399,7 @@ def commandLineBuildCache():
if not pricesPath.exists():
print("Prices file '{}' does not exist.".format(args.prices))

buildCache(dbPath, sqlPath, pricesPath, args.debug)
buildCache(dbPath, sqlPath, pricesPath, importTables, debug=args.debug)


if __name__ == '__main__':
Expand Down
14 changes: 14 additions & 0 deletions data/corrections.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Provides an interface for correcting star/station names that
# have changed in recent versions.

corrections = {
'LOUIS DE LACAILLE PROSPECT': 'Lacaille Prospect',
'HOPKINS HANGAR': 'Hopkins Hanger',
}

def correct(oldName):
try:
return corrections[oldName.upper()]
except KeyError:
return oldName

78 changes: 42 additions & 36 deletions trade.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,6 @@
from tradedb import TradeDB, AmbiguityError
from tradecalc import Route, TradeCalc, localedNo

tdb = None

######################################################################
# Helpers

Expand Down Expand Up @@ -272,7 +270,7 @@ def run(self, route, credits):
######################################################################
# "run" command functionality.

def parseAvoids(args):
def parseAvoids(tdb, args):
"""
Process a list of avoidances.
"""
Expand Down Expand Up @@ -330,7 +328,7 @@ def parseAvoids(args):
))


def parseVias(args):
def parseVias(tdb, args):
"""
Process a list of station names and build them into a
list of waypoints for the route.
Expand All @@ -346,7 +344,7 @@ def parseVias(args):
viaStations.add(station)


def processRunArguments(args):
def processRunArguments(tdb, args):
"""
Process arguments to the 'run' option.
"""
Expand Down Expand Up @@ -384,9 +382,9 @@ def processRunArguments(args):
raise CommandLineError("More than one hop required to use same from/to destination")

if args.avoid:
parseAvoids(args)
parseAvoids(tdb, args)
if args.via:
parseVias(args)
parseVias(tdb, args)

unspecifiedHops = args.hops + (0 if originStation else 1) - (1 if finalStation else 0)
if len(viaStations) > unspecifiedHops:
Expand Down Expand Up @@ -423,10 +421,12 @@ def processRunArguments(args):
raise CommandLineError("Requested unique trip with more hops than there are stations...")
if args.unique:
if ((originStation and originStation == finalStation) or
(originStation and originStation in viaStations) or
(originStation and originStation in viaStations) or
(finalStation and finalStation in viaStations)):
raise CommandLineError("from/to/via repeat conflicts with --unique")

tdb.loadTrades()

if originStation and originStation.itemCount == 0:
raise NoDataError("Start station {} doesn't have any price data.".format(originStation.name()))
if finalStation and finalStation.itemCount == 0:
Expand All @@ -443,17 +443,15 @@ def processRunArguments(args):
args.mfd = None


def runCommand(args):
def runCommand(tdb, args):
""" Calculate trade runs. """

global tdb

if args.debug: print("# 'run' mode")

if tdb.tradingCount == 0:
raise NoDataError("Database does not contain any profitable trades.")

processRunArguments(args)
processRunArguments(tdb, args)

startCr = args.credits - args.insurance
routes = [
Expand Down Expand Up @@ -511,7 +509,7 @@ def runCommand(args):
routes = [ route for route in routes if viaStations & set(route.route[viaStartPos:]) ]

if not routes:
print("No routes matched your critera, or price data for that route is missing.")
print("No profitable trades matched your critera, or price data along the route is missing.")
return

routes.sort()
Expand Down Expand Up @@ -562,7 +560,7 @@ def getEditorPaths(args, editorName, envVar, windowsFolders, winExe, nixExe):
raise CommandLineError("ERROR: Unable to locate {} editor.\nEither specify the path to your editor with --editor or set the {} environment variable to point to it.".format(editorName, envVar))


def editUpdate(args, stationID):
def editUpdate(tdb, args, stationID):
"""
Dump the price data for a specific station to a file and
launch the user's text editor to let them make changes
Expand Down Expand Up @@ -671,7 +669,7 @@ def editUpdate(args, stationID):
if absoluteFilename: tmpPath.unlink()


def updateCommand(args):
def updateCommand(tdb, args):
"""
Allow the user to update the prices database.
"""
Expand All @@ -684,7 +682,7 @@ def updateCommand(args):

if args._editing:
# User specified one of the options to use an editor.
return editUpdate(args, stationID)
return editUpdate(tdb, args, stationID)

if args.debug: print('# guided "update" mode station:{}'.format(args.station))

Expand All @@ -694,7 +692,7 @@ def updateCommand(args):
######################################################################
#

def lookupSystem(name, intent):
def lookupSystemByNameOrStation(tdb, name, intent):
"""
Look up a name using either a system or station name.
"""
Expand All @@ -708,7 +706,7 @@ def lookupSystem(name, intent):
raise CommandLineError("Unknown {} system/station, '{}'".format(intent, name))


def distanceAlongPill(sc, percent):
def distanceAlongPill(tdb, sc, percent):
"""
Estimate a distance along the Pill using 2 reference systems
"""
Expand All @@ -725,72 +723,82 @@ def distanceAlongPill(sc, percent):

return dotProduct / length

def localCommand(args):

def localCommand(tdb, args):
"""
Local systems
"""

srcSystem = lookupSystem(args.system, 'system')
srcSystem = lookupSystemByNameOrStation(tdb, args.system, 'system')

if args.ship:
ship = tdb.lookupShip(args.ship)
args.ship = ship
if args.ly is None: args.ly = (ship.maxLyFull if args.full else ship.maxLyEmpty)
ly = args.ly or tdb.maxSystemLinkLy
lySq = ly ** 2

tdb.buildLinks()

printHeading("Local systems to {} within {} ly.".format(srcSystem.name(), ly))

distances = { }

for (destSys, destDist) in srcSystem.links.items():
for (destSys, destDistSq) in srcSystem.links.items():
if args.debug:
print("Checking {} dist={:5.2f}".format(destSys.str(), destDist))
if destDist > ly:
if destDist > lySq:
continue
distances[destSys] = destDist
distances[destSys] = math.sqrt(destDistSq)

for (system, dist) in sorted(distances.items(), key=lambda x: x[1]):
pillLength = ""
if args.pill or args.percent:
pillLengthFormat = " [{:4.0f}%]" if args.percent else " [{:5.1f}]"
pillLength = pillLengthFormat.format(distanceAlongPill(system, args.percent))
pillLength = pillLengthFormat.format(distanceAlongPill(tdb, system, args.percent))
print("{:5.2f}{} {}".format(dist, pillLength, system.str()))
if args.detail:
for (station) in system.stations:
stationDistance = " {} ls".format(station.lsFromStar) if station.lsFromStar > 0 else ""
print("\t<{}>{}".format(station.str(), stationDistance))

def navCommand(args):

def navCommand(tdb, args):
"""
Give player directions A->B
"""

srcSystem = lookupSystem(args.start, 'start')
dstSystem = lookupSystem(args.end, 'end')
srcSystem = lookupSystemByNameOrStation(tdb, args.start, 'start')
dstSystem = lookupSystemByNameOrStation(tdb, args.end, 'end')

avoiding = []
if args.ship:
ship = tdb.lookupShip(args.ship)
args.ship = ship
if args.maxLyPer is None: args.maxLyPer = (ship.maxLyFull if args.full else ship.maxLyEmpty)
maxLyPer = args.maxLyPer or tdb.maxSystemLinkLy
maxLyPerSq = maxLyPer ** 2

if args.debug:
print("# Route from {} to {} with max {} ly per jump.".format(srcSystem.name(), dstSystem.name(), maxLyPer))

openList = { srcSystem: 0.0 }
distances = { srcSystem: [ 0.0, None ] }

tdb.buildLinks()

# As long as the open list is not empty, keep iterating.
while openList and not dstSystem in distances:
# Expand the search domain by one jump; grab the list of
# nodes that are this many hops out and then clear the list.
openNodes, openList = openList, {}

for (node, startDist) in openNodes.items():
for (destSys, destDist) in node.links.items():
if destDist > maxLyPer:
for (node, startDistSq) in openNodes.items():
startDist = math.sqrt(startDistSq)
for (destSys, destDistSq) in node.links.items():
if destDistSq > maxLyPerSq:
continue
destDist = math.sqrt(destDistSq)
dist = startDist + destDist
# If we already have a shorter path, do nothing
try:
Expand Down Expand Up @@ -851,13 +859,11 @@ def present(action, system):
######################################################################
# functionality for the "cleanup" command

def cleanupCommand(args):
def cleanupCommand(tdb, args):
"""
Perform maintenance on the database.
"""

global tdb

if args.minutes <= 0:
raise CommandLineError("Invalid --minutes specification.")

Expand Down Expand Up @@ -921,7 +927,7 @@ def cleanupCommand(args):


def main():
global args, tdb
global args

parser = argparse.ArgumentParser(description='Trade run calculator', add_help=False, epilog='For help on a specific command, use the command followed by -h.')
parser.set_defaults(_editing=False)
Expand Down Expand Up @@ -1045,11 +1051,11 @@ def main():
os.chdir(str(exePath))

# load the database
tdb = TradeDB(debug=args.debug, dbFilename=args.db)
tdb = TradeDB(debug=args.debug, dbFilename=args.db, buildLinks=False, includeTrades=False)

# run the commands
commandFunction = args.proc
return commandFunction(args)
return commandFunction(tdb, args)


######################################################################
Expand Down
Loading

0 comments on commit 77dcbe1

Please sign in to comment.