コード例 #1
0
        private RouteScannerRoute UpdateRouteHash(RouteScannerRoute route)
        {
            // Generate a hash of the runs in the route.
            // A route that has the same runs but in a different order should result in the same hash.

            // Create the string
            var runs = new List <string>();

            foreach (var run in route.Runs)
            {
                runs.Add($"{run.StartSystemName},{run.EndSystemName},{run.Comodity}");
            }
            runs.Sort();

            // MD5 it
            using (var md5 = System.Security.Cryptography.MD5.Create())
            {
                byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(string.Join("|", runs));
                byte[] hashBytes  = md5.ComputeHash(inputBytes);

                var sb = new StringBuilder();
                for (int i = 0; i < hashBytes.Length; i++)
                {
                    sb.Append(hashBytes[i].ToString("X2"));
                }

                route.Hash = sb.ToString();
            }

            return(route);
        }
コード例 #2
0
        private RouteScannerRoute UpdateRoute(RouteScannerRoute route)
        {
            UpdateRouteHash(route);

            int   totalProfit = 0;
            int   totalJumps  = 0;
            float pps         = 0.0f;
            float ppj         = 0.0f;

            foreach (var run in route.Runs)
            {
                totalProfit += run.Profit;
                totalJumps  += run.Jumps;
            }

            pps = totalProfit / route.Runs.Count;
            ppj = totalProfit / totalJumps;

            route.TotalProfit   = totalProfit;
            route.TotalJumps    = totalJumps;
            route.ProfitPerRun  = pps;
            route.ProfitPerJump = ppj;

            UpdateRouteScore(route);


            return(route);
        }
コード例 #3
0
        private RouteScannerRoute UpdateRouteScore(RouteScannerRoute route)
        {
            route.ScoreTrail.Clear();

            // Start the score with the profit per run
            float score = route.ProfitPerRun;

            route.ScoreTrail.Add($"Base score: {score}");

            // Apply weight per run
            // Use an exponential type equasion. A little more is a little weight, a lot more is a LOT of weight.
            int runCountWeight = (route.Runs.Count * _options.ScoreWeightPerRun) * route.Runs.Count;

            score += runCountWeight;
            route.ScoreTrail.Add($"Route length score: {runCountWeight}");

            // Apply weight per duplicate trades
            int duplicateTradeCount = 0;
            var seenTrades          = new List <string>();

            foreach (var run in route.Runs)
            {
                var buyTrade  = $"b;{run.StartSystemName};{run.Comodity}";
                var sellTrade = $"s;{run.EndSystemName};{run.Comodity}";

                if (seenTrades.Contains(buyTrade))
                {
                    duplicateTradeCount++;
                }
                else
                {
                    seenTrades.Add(buyTrade);
                }

                if (seenTrades.Contains(sellTrade))
                {
                    duplicateTradeCount++;
                }
                else
                {
                    seenTrades.Add(sellTrade);
                }
            }
            int duplicateTradeWeight = duplicateTradeCount * _options.ScoreWeightPerDuplicateTrade;

            score += duplicateTradeWeight;
            route.ScoreTrail.Add($"Repeat trade score: {duplicateTradeWeight}");

            route.Score = score;

            return(route);
        }
コード例 #4
0
        // Walk through runs to try and find profitable circular routes that start and end in the same system
        private void ScanForRoutes(TradeMapSystem startSystem, ICollection <RouteScannerRoute> routeCollection, RouteScannerOptions options)
        {
            _ct.ThrowIfCancellationRequested();
            _log.Info($"Scanning for profitable routes starting from '{startSystem.Name}'");
            var foundRoutes = new List <RouteScannerRoute>(); // Build a list of routes found
            Stack <RouteScannerRun>          tradeRunStack      = new Stack <RouteScannerRun>();
            Stack <Stack <RouteScannerRun> > tradeRunQueueStack = new Stack <Stack <RouteScannerRun> >();

            // Start off the run queue
            _log.Debug("Enqueuing start system's runs");
            var newQueueStack = new Stack <RouteScannerRun>();

            foreach (var run in startSystem.Runs)
            {
                _log.Debug($"Enqueuing run: {run}");
                newQueueStack.Push(run);
            }
            tradeRunQueueStack.Push(newQueueStack);

            // Work the queues, while there are queues to work
            while (tradeRunQueueStack.Count > 0)
            {
                _ct.ThrowIfCancellationRequested();
                _log.Debug($"tradeRunQueueStack: {tradeRunQueueStack.Count}");
                // Get the queue at the top of the stack
                var tradeRunQueue = tradeRunQueueStack.Peek();
                _log.Debug($"tradeRunQueue: {tradeRunQueue.Count}");

                // If the queue is empty, pop it, and go back down a level
                if (tradeRunQueue.Count <= 0)
                {
                    _log.Debug("tradeRunQueue empty for this step, going back a level");
                    tradeRunQueueStack.Pop();

                    if (tradeRunStack.Count > 0)
                    {
                        tradeRunStack.Pop();
                        continue;
                    }
                    else
                    {
                        // Hit the end, finished processing this start system
                        return;
                    }
                }
                else
                {
                    // Have a queue to work on
                    // Take it from the queue
                    var thisRun = tradeRunQueue.Pop();

                    _log.Debug($"Checking run: {thisRun}");

                    // Don't double-back on runs.
                    // If this run is already in the stack, don't scan it again.
                    if (tradeRunStack.Contains(thisRun))
                    {
                        _log.Debug("Already checked this run, skipping to avoid looped routes");
                        continue;
                    }

                    tradeRunStack.Push(thisRun);

                    // If this trade run ends at the start system, it's good.
                    // Save it as a route
                    if (thisRun.EndSystem.Name == startSystem.Name)
                    {
                        _log.Debug("Route ends back at start, this is a complete route");

                        var newTradeRoute = new RouteScannerRoute();
                        foreach (var run in tradeRunStack.ToArray().Reverse())
                        {
                            newTradeRoute.StartSystem = startSystem;
                            newTradeRoute.Runs.Add(run);
                        }
                        UpdateRoute(newTradeRoute);

                        if (newTradeRoute.Score < options.MinRouteScore)
                        {
                            _log.Debug($"Ignoring route, score {newTradeRoute.Score} min {options.MinRouteScore}");
                        }
                        else if (routeCollection.FirstOrDefault(r => r.Hash == newTradeRoute.Hash) != null)
                        {
                            _log.Debug($"Ignoring route, similar route already found");
                        }
                        else if (options.SingleRoutePerStartSystem)
                        {
                            // Check that a route doesn't already exist for this system
                            var currentRouteForStartSystem = routeCollection.FirstOrDefault(r => r.StartSystem == startSystem);
                            if (currentRouteForStartSystem != null)
                            {
                                if (currentRouteForStartSystem.Score >= newTradeRoute.Score)
                                {
                                    _log.Debug("Ignoring route, single route mode active and new route scored less than existing route");
                                }
                                else
                                {
                                    _log.Debug("New route more profitable than existing route");
                                    routeCollection.Remove(currentRouteForStartSystem);
                                    routeCollection.Add(newTradeRoute);
                                }
                            }
                            else
                            {
                                routeCollection.Add(newTradeRoute);
                            }
                        }
                        else
                        {
                            _log.Debug("Saving route");
                            routeCollection.Add(newTradeRoute);
                        }

                        // Don't try to walk further than this.
                        //tradeRunQueueStack.Pop();
                        tradeRunStack.Pop();
                        continue;
                    }

                    // If we haven't hit the run limit, see if there's any runs to walk through from this system
                    if (tradeRunStack.Count < options.RouteMaxStops)
                    {
                        _log.Debug($"{tradeRunStack.Count} is under the stop limit {options.RouteMaxStops}, enqueuing this stop's trade runs");
                        // Add a new trade run queue to the queue stack
                        newQueueStack = new Stack <RouteScannerRun>();
                        foreach (var nextRun in thisRun.EndSystem.Runs)
                        {
                            if (!options.AllowSameStopBuySell && nextRun.Comodity == thisRun.Comodity)
                            {
                                // Don't buy the comodity that you just sold
                                _log.Debug("Skipping this run, don't buy what was just sold");
                                continue;
                            }

                            _log.Debug($"Enqueuing run: {nextRun}");
                            newQueueStack.Push(nextRun);
                        }

                        if (newQueueStack.Count > 0)
                        {
                            tradeRunQueueStack.Push(newQueueStack);
                        }
                        else
                        {
                            _log.Debug("No more runs from this system");
                            tradeRunStack.Pop();
                            continue;
                        }
                    }
                    else
                    {
                        _log.Debug($"Stop limit {options.RouteMaxStops} has been met, not looking any deeper");
                        tradeRunStack.Pop();
                    }
                }
            } // End of worker loop
        }