예제 #1
0
        /// <summary>Merge 'routes' into 'TradeRoutes' in order from most to least profitable</summary>
        private void MergeTradeRoutes(Location origin, IList <TradeRoute> routes)
        {
            // Remove any routes that don't start at 'origin_station'
            TradeRoutes.RemoveIf(x => x.Origin.Station.ID != origin.Station.ID);

            // Merge 'routes' into 'TradeRoutes' in order
            foreach (var route in routes)
            {
                // Remove duplicates
                TradeRoutes.RemoveIf(x =>
                                     x.Destination.System.ID == route.Destination.System.ID &&
                                     x.Destination.Station.ID == route.Destination.Station.ID &&
                                     x.CommodityID == route.CommodityID);

                // Merge routes
                var idx = TradeRoutes.BinarySearch(r => route.Profit.CompareTo(r.Profit), find_insert_position: true);
                if (idx < Settings.Instance.RouteCount)
                {
                    TradeRoutes.Insert(idx, route);
                }
                if (TradeRoutes.Count > Settings.Instance.RouteCount)
                {
                    TradeRoutes.RemoveToEnd(Settings.Instance.RouteCount);
                }
            }

            // Notify trade routes updated
            TradeRoutesChanged?.Invoke(this, EventArgs.Empty);
        }
예제 #2
0
        /// <summary>Search for trades</summary>
        private async Task FindTradeRoutes(Settings settings, int issue)         // worker thread context
        {
            if (!CanFindTradeRoutes(settings))
            {
                // Settings not valid, ignore until they are.
                RunOnMainThread(() =>
                {
                    if (issue != m_trade_routes_issue)
                    {
                        return;
                    }
                    m_trade_routes_issue_current = issue;
                });
                return;
            }
            else
            {
                // Settings are valid, reset the trade routes before starting
                RunOnMainThread(() =>
                {
                    if (issue != m_trade_routes_issue || TradeRoutes.Count == 0)
                    {
                        return;
                    }

                    TradeRoutes.Clear();
                    TradeRoutesChanged?.Invoke(this, EventArgs.Empty);
                });
            }

            // Get the start point
            var origin_system = await Src.GetStarSystem(settings.Origin.StarSystemID.Value);

            var origin_station = await Src.GetStation(settings.Origin.StationID.Value);

            var origin = new Location(origin_system, origin_station);

            // If a specific destination is given, find trades between the origin and that destination
            if (!settings.AnyDestination)
            {
                var destination_system = await Src.GetStarSystem(settings.Destination.StarSystemID.Value);

                var destination_station = settings.Destination.StationID != null ? await Src.GetStation(settings.Destination.StationID.Value) : null;

                Log.Write(ELogLevel.Info, $"Find trade routes {origin_system.Name}/{origin_station.Name} → {destination_system.Name}/{destination_station?.Name ?? "Any"}");

                var stations = destination_station != null
                                        ? new[] { destination_station }
                                        : Src.EnumStations(
                    system_id: destination_system.ID,
                    max_station_distance: settings.MaxStationDistance,
                    required_pad_size: settings.RequiredPadSize,
                    facilities_incl: EFacilities.Market | EFacilities.Docking,
                    ignore_planetary: settings.IgnorePlanetBases);

                // Look for trade routes between the given stations
                foreach (var station in stations)
                {
                    // Abort if the issue number changes
                    if (m_trade_routes_issue != issue)
                    {
                        return;
                    }

                    var routes = await FindTradeRoutes(settings, origin, new Location(destination_system, station), issue);

                    if (routes.Count == 0)
                    {
                        continue;
                    }

                    RunOnMainThread(() =>
                    {
                        if (issue != m_trade_routes_issue)
                        {
                            return;
                        }
                        MergeTradeRoutes(origin, routes);
                    });
                }
            }
            else
            {
                Log.Write(ELogLevel.Info, $"Find trade routes {origin_system.Name}/{origin_station.Name} within {settings.MaxTradeRouteDistance} LY");

                int considered_systems = 0, last_considered_systems = 0;
                var considered = new HashSet <StarSystemRef>();

                // A queue of systems to consider
                var queue = new Queue <StarSystem>();
                using (var msg = StatusStack.NewStatusMessage("Finding Trade Routes..."))
                {
                    var candidates = Src.Search(origin_system.Position, settings.MaxTradeRouteDistance.Value).ToList();
                    KDTree_.Build(candidates, 3);

                    // Find all systems within the maximum trade route distance.
                    for (queue.Enqueue(origin_system); queue.Count != 0 && !Shutdown.IsCancellationRequested;)
                    {
                        // Abort if the issue number changes
                        if (m_trade_routes_issue != issue)
                        {
                            return;
                        }

                        // Get the next system to consider
                        var hop = queue.Dequeue();

                        // Find the systems within the maximum jump range that have not been considered already
                        var system_refs = KDTree_.Search(candidates, 3, (double[])hop.Position, settings.MaxJumpRange).Where(x => !considered.Contains(x)).ToList();
                        if (system_refs.Count == 0)
                        {
                            continue;
                        }

                        // When the considered number gets large enough, remove them from the map and regenerate it
                        const int RebuildTreeThreshold = 256;
                        considered.AddRange(system_refs);
                        if (considered.Count > RebuildTreeThreshold)
                        {
                            candidates.RemoveSet(considered);
                            KDTree_.Build(candidates, 3);
                            considered.Clear();
                        }

                        // Check the stations in each system
                        foreach (var system_ref in system_refs)
                        {
                            // Abort if the issue number changes
                            if (m_trade_routes_issue != issue)
                            {
                                return;
                            }

                            // Get the system
                            var destination_system = await Src.GetStarSystem(system_ref.ID);

                            // Update status
                            if (++considered_systems - last_considered_systems > 100)
                            {
                                var distance = (destination_system.Position - origin_system.Position).Length;
                                msg.Message             = $"Finding Trade Routes... (checked:{considered_systems} queued:{queue.Count} distance:{distance})";
                                last_considered_systems = considered_systems;
                            }

                            // Needs a permit?
                            if (destination_system.NeedPermit && settings.IgnorePermitSystems)
                            {
                                continue;
                            }

                            // Check the suitable stations
                            var stations = Src.EnumStations(
                                system_id: destination_system.ID,
                                max_station_distance: settings.MaxStationDistance,
                                required_pad_size: settings.RequiredPadSize,
                                facilities_incl: EFacilities.Market | EFacilities.Docking,
                                ignore_planetary: settings.IgnorePlanetBases);
                            foreach (var station in stations)
                            {
                                // Abort if the issue number changes
                                if (m_trade_routes_issue != issue)
                                {
                                    return;
                                }

                                var routes = await FindTradeRoutes(settings, origin, new Location(destination_system, station), issue);

                                if (routes.Count == 0)
                                {
                                    continue;
                                }

                                RunOnMainThread(() =>
                                {
                                    if (issue != m_trade_routes_issue)
                                    {
                                        return;
                                    }
                                    MergeTradeRoutes(origin, routes);
                                });
                            }

                            // Add this system to be considered for the next hop
                            queue.Enqueue(destination_system);
                        }
                    }
                }
            }
            m_trade_routes_issue_current = issue;
        }