Ejemplo n.º 1
0
        private TradeMapSystemCollection GetSystemsInJumpRange(TradeMap map, TradeMapSystem startSystem, TradeMapSystemCollection systemCollection, int jumpRange)
        {
            // Traverse outwards from the start system using links.
            // Build a collection of systems within the specified jump radius from the start system

            TradeMapSystemCollection seenSystems = new TradeMapSystemCollection();

            if (!systemCollection.Contains(startSystem))
            {
                systemCollection.Add(startSystem);
            }
            Stack <TradeMapSystem> systemStack = new Stack <TradeMapSystem>();

            systemStack.Push(startSystem);
            Stack <TradeMapSystem> nextSystemStack;

            int jumpCount = 1;

            while (jumpCount <= jumpRange && systemStack.Count > 0)
            {
                // Start the next stack
                nextSystemStack = new Stack <TradeMapSystem>();

                // Add all of the linked systems
                while (systemStack.Count > 0)
                {
                    var thisSystem = systemStack.Pop();
                    if (seenSystems.Contains(thisSystem))
                    {
                        continue;
                    }

                    foreach (var link in thisSystem.Links)
                    {
                        if (link.System == null)
                        {
                            continue;
                        }
                        if (link.System == startSystem)
                        {
                            continue;                             // Ignore it if it's start system
                        }
                        // Good link
                        nextSystemStack.Push(link.System);
                        if (!systemCollection.Contains(link.System))
                        {
                            systemCollection.Add(link.System);
                        }
                        seenSystems.Add(thisSystem);
                    }
                }

                // Done with stack, ready the next stack
                systemStack = nextSystemStack;

                jumpCount++;
            }

            return(systemCollection);
        }
Ejemplo n.º 2
0
        private void ScanForRuns(TradeMapSystem startSystem, TradeMapSystem destinationSystem, int jumpsAway, RouteScannerRunCollection runCollection, RouteScannerOptions options)
        {
            // Go through each comodity sold here, and compare against all
            //_log.Debug($"Scanning for profitable runs between '{startSystem.Name}' and '{destinationSystem.Name}'");
            foreach (var startComodity in startSystem.Comodities)
            {
                foreach (var destComodity in destinationSystem.Comodities)
                {
                    _ct.ThrowIfCancellationRequested();
                    if (startComodity.Name == destComodity.Name)
                    {
                        // Comodity matches
                        // Compare prices
                        var profit = destComodity.Price - startComodity.Price;
                        if (profit >= options.MinProfitPerUnit)
                        {
                            // Profit is over threshold
                            var newRun = new RouteScannerRun()
                            {
                                Comodity        = startComodity.Name,
                                StartSystem     = startSystem,
                                StartSystemName = startSystem.Name,
                                EndSystem       = destinationSystem,
                                EndSystemName   = destinationSystem.Name,
                                Profit          = profit,
                                Jumps           = jumpsAway
                            };

                            _log.Debug($"{newRun}");

                            // Add runs to the all runs collection
                            runCollection.Add(newRun);

                            // Add run to that system
                            startSystem.Runs.Add(newRun);
                        }
                    }
                }
            }
        }
Ejemplo n.º 3
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
        }
        public void MapBuilder_SimpleRead()
        {
            var sampleDataRoot = new DefNode();

            var sampleDataSystem1 = new DefNode();

            sampleDataRoot.ChildNodes.Add(sampleDataSystem1);
            sampleDataSystem1.Tokens.Add("system").Add("Tarazed");
            sampleDataSystem1.ChildNodes.Add(new DefNode()
            {
                Tokens = new DefTokenCollection().Add("belt").Add("1169")
            });
            sampleDataSystem1.ChildNodes.Add(new DefNode()
            {
                Tokens = new DefTokenCollection().Add("link").Add("Enif")
            });
            sampleDataSystem1.ChildNodes.Add(new DefNode()
            {
                Tokens = new DefTokenCollection().Add("trade").Add("Clothing").Add("305")
            });
            sampleDataSystem1.ChildNodes.Add(new DefNode()
            {
                Tokens = new DefTokenCollection().Add("trade").Add("Electronics").Add("761")
            });
            sampleDataSystem1.ChildNodes.Add(new DefNode()
            {
                Tokens = new DefTokenCollection().Add("trade").Add("Equipment").Add("395")
            });
            sampleDataSystem1.ChildNodes.Add(new DefNode()
            {
                Tokens = new DefTokenCollection().Add("trade").Add("Food").Add("238")
            });

            var sampleDataSystem2 = new DefNode();

            sampleDataRoot.ChildNodes.Add(sampleDataSystem2);
            sampleDataSystem2.Tokens.Add("system").Add("Enif");
            sampleDataSystem2.ChildNodes.Add(new DefNode()
            {
                Tokens = new DefTokenCollection().Add("belt").Add("1169")
            });
            sampleDataSystem2.ChildNodes.Add(new DefNode()
            {
                Tokens = new DefTokenCollection().Add("link").Add("Tarazed")
            });
            sampleDataSystem2.ChildNodes.Add(new DefNode()
            {
                Tokens = new DefTokenCollection().Add("link").Add("Sadalmelik")
            });
            sampleDataSystem2.ChildNodes.Add(new DefNode()
            {
                Tokens = new DefTokenCollection().Add("trade").Add("Clothing").Add("361")
            });
            sampleDataSystem2.ChildNodes.Add(new DefNode()
            {
                Tokens = new DefTokenCollection().Add("trade").Add("Electronics").Add("800")
            });
            sampleDataSystem2.ChildNodes.Add(new DefNode()
            {
                Tokens = new DefTokenCollection().Add("trade").Add("Equipment").Add("485")
            });
            sampleDataSystem2.ChildNodes.Add(new DefNode()
            {
                Tokens = new DefTokenCollection().Add("trade").Add("Food").Add("335")
            });

            var sampleDataSystem3 = new DefNode();

            sampleDataRoot.ChildNodes.Add(sampleDataSystem3);
            sampleDataSystem3.Tokens.Add("system").Add("Sadalmelik");
            sampleDataSystem3.ChildNodes.Add(new DefNode()
            {
                Tokens = new DefTokenCollection().Add("belt").Add("1169")
            });
            sampleDataSystem3.ChildNodes.Add(new DefNode()
            {
                Tokens = new DefTokenCollection().Add("link").Add("Enif")
            });
            sampleDataSystem3.ChildNodes.Add(new DefNode()
            {
                Tokens = new DefTokenCollection().Add("trade").Add("Clothing").Add("361")
            });
            sampleDataSystem3.ChildNodes.Add(new DefNode()
            {
                Tokens = new DefTokenCollection().Add("trade").Add("Electronics").Add("800")
            });
            sampleDataSystem3.ChildNodes.Add(new DefNode()
            {
                Tokens = new DefTokenCollection().Add("trade").Add("Equipment").Add("485")
            });
            sampleDataSystem3.ChildNodes.Add(new DefNode()
            {
                Tokens = new DefTokenCollection().Add("trade").Add("Food").Add("335")
            });

            var resultMap = new TradeMapBuilder().Build(sampleDataRoot, CancellationToken.None);

            var expectedMap = new TradeMap();

            var tradeSystem1 = new TradeMapSystem();

            expectedMap.Systems.Add(tradeSystem1);
            tradeSystem1.Name = "Tarazed";
            tradeSystem1.Comodities.Add(new TradeMapComodity {
                Name = "Clothing", Price = 305
            });
            tradeSystem1.Comodities.Add(new TradeMapComodity {
                Name = "Electronics", Price = 761
            });
            tradeSystem1.Comodities.Add(new TradeMapComodity {
                Name = "Equipment", Price = 395
            });
            tradeSystem1.Comodities.Add(new TradeMapComodity {
                Name = "Food", Price = 238
            });

            var tradeSystem2 = new TradeMapSystem();

            expectedMap.Systems.Add(tradeSystem2);
            tradeSystem2.Name = "Enif";
            tradeSystem2.Comodities.Add(new TradeMapComodity {
                Name = "Clothing", Price = 361
            });
            tradeSystem2.Comodities.Add(new TradeMapComodity {
                Name = "Electronics", Price = 800
            });
            tradeSystem2.Comodities.Add(new TradeMapComodity {
                Name = "Equipment", Price = 485
            });
            tradeSystem2.Comodities.Add(new TradeMapComodity {
                Name = "Food", Price = 335
            });

            var tradeSystem3 = new TradeMapSystem();

            expectedMap.Systems.Add(tradeSystem3);
            tradeSystem3.Name = "Sadalmelik";
            tradeSystem3.Comodities.Add(new TradeMapComodity {
                Name = "Clothing", Price = 361
            });
            tradeSystem3.Comodities.Add(new TradeMapComodity {
                Name = "Electronics", Price = 800
            });
            tradeSystem3.Comodities.Add(new TradeMapComodity {
                Name = "Equipment", Price = 485
            });
            tradeSystem3.Comodities.Add(new TradeMapComodity {
                Name = "Food", Price = 335
            });

            tradeSystem1.Links.Add(new TradeMapSystemLink()
            {
                Name = "Enif", System = tradeSystem2
            });
            tradeSystem2.Links.Add(new TradeMapSystemLink()
            {
                Name = "Tarazed", System = tradeSystem1
            });
            tradeSystem2.Links.Add(new TradeMapSystemLink()
            {
                Name = "Sadalmelik", System = tradeSystem3
            });
            tradeSystem3.Links.Add(new TradeMapSystemLink()
            {
                Name = "Enif", System = tradeSystem2
            });

            // TODO assert
        }
        public TradeMap CreateMap(DefNode rootNode, CancellationToken ct)
        {
            var map = new TradeMap();

            //foreach (var topNode in rootNode.ChildNodes)
            for (int iNode = 0; iNode < rootNode.ChildNodes.Count; iNode++)
            {
                ProgressEvents.DoEvent(this, new ProgressEventArgs(iNode, rootNode.ChildNodes.Count, ProgressEventStatus.Working, $"Reading node {iNode}/{rootNode.ChildNodes.Count}"));
                var topNode = rootNode.ChildNodes[iNode];
                // Only care about "system" nodes
                if (topNode.Tokens.Count >= 2 && topNode.Tokens[0] == NODE_NAME_SYSTEM)
                {
                    // Is a system node
                    var newSystem = new TradeMapSystem();
                    newSystem.Name = topNode.Tokens[1].Trim();
                    // TODO handle blank system name

                    foreach (var subNode in topNode.ChildNodes)
                    {
                        if (subNode.Tokens.Count >= 2 && subNode.Tokens[0] == NODE_NAME_LINK)
                        {
                            // TODO handle blank system name in link
                            newSystem.Links.Add(new TradeMapSystemLink()
                            {
                                Name = subNode.Tokens[1].Trim()
                            });
                        }

                        if (subNode.Tokens.Count >= 3 && subNode.Tokens[0] == NODE_NAME_TRADE)
                        {
                            int tradePrice;
                            if (!int.TryParse(subNode.Tokens[2].Trim(), out tradePrice))
                            {
                                // TODO Handle bad number on trade price
                            }
                            else
                            {
                                // TODO handle empty comodity name
                                newSystem.Comodities.Add(new TradeMapComodity()
                                {
                                    Name = subNode.Tokens[1].Trim(), Price = tradePrice
                                });
                            }
                        }

                        if (subNode.Tokens.Count >= 2 && subNode.Tokens[0] == NODE_NAME_OBJECT)
                        {
                            newSystem.NamedObjects.Add(subNode.Tokens[1].Trim());
                        }
                    }

                    newSystem.Name = newSystem.Name.Trim();
                    map.Systems.Add(newSystem);
                }
                else if (topNode.Tokens.Count >= 2 && topNode.Tokens[0] == NODE_NAME_PLANET)
                {
                    // Is a planet
                    // I was really annoyed when I found out that a bunch of systems in the map
                    // have trade & comoddity information, but no planets to trade on.
                    // I had to change the way I did things, shat me to tears :(
                    var newPlanet = new TradeMapPlanet();
                    newPlanet.Name = topNode.Tokens[1].Trim();

                    foreach (var subNode in topNode.ChildNodes)
                    {
                        if (subNode.Tokens.Count >= 2 && subNode.Tokens[0] == NODE_NAME_SPACEPORT)
                        {
                            newPlanet.HasSpaceport = true;
                        }
                    }

                    // Only save planets that have spaceports
                    if (newPlanet.HasSpaceport)
                    {
                        map.Planets.Add(newPlanet);
                    }
                }
                else
                {
                    // skipping node I don't care about, like "galaxy"
                }
            }

            return(map);
        }