示例#1
0
 /// <summary>
 /// Creates a new instance of this manager.
 /// </summary>
 /// <param name="instance">The instance this manager belongs to.</param>
 public QueueOrderManager(Instance instance) : base(instance)
 {
     _config                = instance.ControllerConfig.OrderBatchingConfig as QueueOrderBatchingConfiguration;
     _stationQueues         = new VolatileIDDictionary <OutputStation, HashSet <Order> >(instance.OutputStations.Select(s => new VolatileKeyValuePair <OutputStation, HashSet <Order> >(s, new HashSet <Order>())).ToList());
     _inboundPodsByDistance = new VolatileIDDictionary <OutputStation, List <Pod> >(instance.OutputStations.Select(s => new VolatileKeyValuePair <OutputStation, List <Pod> >(s, new List <Pod>())).ToList());
     _nearestInboundPod     = new VolatileIDDictionary <OutputStation, Pod>(instance.OutputStations.Select(s => new VolatileKeyValuePair <OutputStation, Pod>(s, null)).ToList());
 }
        /// <summary>
        /// Initializes this controller.
        /// </summary>
        private void Initialize()
        {
            // Set some values for statistics
            _statPodMatchingScoreIndex = _config.LateBeforeMatch ? 1 : 0;
            // --> Setup normal scorers
            List <Func <double> > normalScorers = new List <Func <double> >();

            // Select late orders first
            if (_config.LateBeforeMatch)
            {
                normalScorers.Add(() =>
                {
                    return(_currentOrder.DueTime > Instance.Controller.CurrentTime ? 1 : 0);
                });
            }
            // Select best by match with inbound pods
            normalScorers.Add(() =>
            {
                return(_currentOrder.Positions.Sum(line => Math.Min(_currentStation.InboundPods.Sum(pod => pod.CountAvailable(line.Key)), line.Value)));
            });
            // If we run into ties use the oldest order
            normalScorers.Add(() =>
            {
                switch (_config.TieBreaker)
                {
                case Shared.OrderSelectionTieBreaker.Random: return(Instance.Randomizer.NextDouble());

                case Shared.OrderSelectionTieBreaker.EarliestDueTime: return(-_currentOrder.DueTime);

                case Shared.OrderSelectionTieBreaker.FCFS: return(-_currentOrder.TimeStamp);

                default: throw new ArgumentException("Unknown tie breaker: " + _config.FastLaneTieBreaker);
                }
            });
            // --> Setup fast lane scorers
            List <Func <double> > fastLaneScorers = new List <Func <double> >();

            // If we run into ties use the oldest order
            fastLaneScorers.Add(() =>
            {
                switch (_config.FastLaneTieBreaker)
                {
                case Shared.FastLaneTieBreaker.Random: return(Instance.Randomizer.NextDouble());

                case Shared.FastLaneTieBreaker.EarliestDueTime: return(-_currentOrder.DueTime);

                case Shared.FastLaneTieBreaker.FCFS: return(-_currentOrder.TimeStamp);

                default: throw new ArgumentException("Unknown tie breaker: " + _config.FastLaneTieBreaker);
                }
            });
            // Init selectors
            _bestCandidateSelectNormal   = new BestCandidateSelector(true, normalScorers.ToArray());
            _bestCandidateSelectFastLane = new BestCandidateSelector(true, fastLaneScorers.ToArray());
            if (_config.FastLane)
            {
                _nearestInboundPod = new VolatileIDDictionary <OutputStation, Pod>(Instance.OutputStations.Select(s => new VolatileKeyValuePair <OutputStation, Pod>(s, null)).ToList());
            }
        }
示例#3
0
        /// <summary>
        /// Initializes this manager.
        /// </summary>
        private void Init()
        {
            // --> Init shared component or ensure consistency
            Instance.SharedControlElements.StoragePartitioner.CreateOrEnsureZones(_config.ZoningConfiguration);
            // --> Store information about the station to which a cache storage location belongs
            _cacheStations = new VolatileIDDictionary <Waypoint, OutputStation>(
                Instance.SharedControlElements.StoragePartitioner.CachePartitions.SelectMany(kvp => kvp.Value.Select(wp => new VolatileKeyValuePair <Waypoint, OutputStation>(wp, kvp.Key))).ToList());
            // --> Init scoring
            List <Func <double> > scorers = new List <Func <double> >();

            // First select cache or not depending on decision
            scorers.Add(() =>
            {
                // Check whether the current location belongs to the current station's cache and the pod does make the cut according to the cache score
                if (_currentCacheable && _currentStorageLocation.InfoTagCache == ZoneType.Cache && _cacheStations[_currentStorageLocation] == _currentStation)
                {
                    // It fits, reward it
                    return(-1);
                }
                // Check whether the pod shouldn't be cached and the storage location does not belong to a cache
                else if (!_currentCacheable && _currentStorageLocation.InfoTagCache != ZoneType.Cache)
                {
                    // It fits, reward it
                    return(-1);
                }
                // Check whether the storage location belongs to a foreign station's cache
                else if (_currentStorageLocation.InfoTagCache == ZoneType.Cache)
                {
                    // Heavily penalize using foreign cache storage locations
                    return(1);
                }
                else
                {
                    // It does not fit, penalize it
                    return(0);
                }
            });
            // Then select the nearest one
            scorers.Add(() =>
            {
                switch (_config.PodDisposeRule)
                {
                case CacheStorageLocationSelectionRule.Euclid: return(Distances.CalculateEuclid(_currentPodLocation, _currentStorageLocation, Instance.WrongTierPenaltyDistance));

                case CacheStorageLocationSelectionRule.Manhattan: return(Distances.CalculateManhattan(_currentPodLocation, _currentStorageLocation, Instance.WrongTierPenaltyDistance));

                case CacheStorageLocationSelectionRule.ShortestPath: return(Distances.CalculateShortestPathPodSafe(_currentPodLocation, _currentStorageLocation, Instance));

                case CacheStorageLocationSelectionRule.ShortestTime: return(Distances.CalculateShortestTimePathPodSafe(_currentPodLocation, _currentStorageLocation, Instance));

                default: throw new ArgumentException("Unknown pod dispose rule: " + _config.PodDisposeRule);
                }
            });
            // Instantiate best candidate assessment
            _bestCandidateSelector = new BestCandidateSelector(false, scorers.ToArray());
        }
示例#4
0
        /// <summary>
        /// Initializes this controller.
        /// </summary>
        private void Initialize()
        {
            // Set some values for statistics
            _statLinesInCommonScoreIndex = 0;
            // Setup scorers
            _bestCandidateSelectNormal = new BestCandidateSelector(true,
                                                                   // First select order with most lines in common
                                                                   () => { return(_currentOrder.Positions.Sum(line => _currentStation.AssignedOrders.Sum(o => o.GetDemandCount(line.Key) > 0 ? 1 : 0))); },
                                                                   // If we run into ties use the oldest order
                                                                   () =>
            {
                switch (_config.TieBreaker)
                {
                case Shared.OrderSelectionTieBreaker.Random: return(Instance.Randomizer.NextDouble());

                case Shared.OrderSelectionTieBreaker.EarliestDueTime: return(-_currentOrder.DueTime);

                case Shared.OrderSelectionTieBreaker.FCFS: return(-_currentOrder.TimeStamp);

                default: throw new ArgumentException("Unknown tie breaker: " + _config.FastLaneTieBreaker);
                }
            });
            _bestCandidateSelectFastLane = new BestCandidateSelector(true,
                                                                     // If we run into ties, break them
                                                                     () =>
            {
                switch (_config.FastLaneTieBreaker)
                {
                case Shared.FastLaneTieBreaker.Random: return(Instance.Randomizer.NextDouble());

                case Shared.FastLaneTieBreaker.EarliestDueTime: return(-_currentOrder.DueTime);

                case Shared.FastLaneTieBreaker.FCFS: return(-_currentOrder.TimeStamp);

                default: throw new ArgumentException("Unknown tie breaker: " + _config.FastLaneTieBreaker);
                }
            });
            if (_config.FastLane)
            {
                _nearestInboundPod = new VolatileIDDictionary <OutputStation, Pod>(Instance.OutputStations.Select(s => new VolatileKeyValuePair <OutputStation, Pod>(s, null)).ToList());
            }
        }
示例#5
0
 /// <summary>
 /// Prepares another assessment run.
 /// </summary>
 private void PrepareAssessment()
 {
     if (_orderItemDemand == null)
     {
         _orderItemDemand = new VolatileIDDictionary <ItemDescription, int>(Instance.ItemDescriptions.Select(i => new VolatileKeyValuePair <ItemDescription, int>(i, 0)).ToList());
     }
     Instance.OutputStations.ForEach(station => _inboundPodsByDistance[station] = station.InboundPods.OrderBy(p =>
     {
         if (p.Bot != null && p.Bot.CurrentWaypoint != null)
         {
             // Use the path distance (this should always be possible)
             return(Distances.CalculateShortestPathPodSafe(p.Bot.CurrentWaypoint, station.Waypoint, Instance));
         }
         else
         {
             // Use manhattan distance as a fallback
             return(Distances.CalculateManhattan(p, station, Instance.WrongTierPenaltyDistance));
         }
     }).ToList());
     Instance.OutputStations.ForEach(station => _nearestInboundPod[station] = _inboundPodsByDistance[station].FirstOrDefault());;
 }
示例#6
0
 /// <summary>
 /// Initializes this manager.
 /// </summary>
 public void InitOrEnsureInit(PodUtilityConfiguration config)
 {
     // Check whether this has already been done
     if (_config != null)
     {
         // --> Ensure compatibility
         if (!_config.Match(config))
         {
             throw new ArgumentException("Incompatible pod utility configurations: " + _config.ToString() + " vs. " + config.ToString());
         }
     }
     else
     {
         // Store config
         _config = config;
         // Calculate some additional info
         _storageLocationsToUse = (int)(_instance.ElementMetaInfoTracker.StorageLocationsOrdered.Count * _config.BufferStorageLocations) + _instance.Pods.Count;
         // Init temp score storage
         _temporaryPodScores       = new VolatileIDDictionary <Pod, double>(_instance.Pods.Select(p => new VolatileKeyValuePair <Pod, double>(p, 0)).ToList());
         _temporaryPodScoreIndeces = new VolatileIDDictionary <Pod, int>(_instance.Pods.Select(p => new VolatileKeyValuePair <Pod, int>(p, 0)).ToList());
     }
 }
示例#7
0
        private void Init()
        {
            // --> Init shared component or ensure consistency
            Instance.SharedControlElements.StoragePartitioner.CreateOrEnsureZones(_config.ZoningConfiguration);
            // --> Init meta info
            _cacheTargetCounts = new VolatileIDDictionary <OutputStation, int>(
                Instance.OutputStations.Select(s => new VolatileKeyValuePair <OutputStation, int>(s,
                                                                                                  (int)(_config.TargetFillCache * Instance.SharedControlElements.StoragePartitioner.CachePartitions[s].Count))).ToList());
            _cachePodCounts = new VolatileIDDictionary <OutputStation, int>(
                Instance.OutputStations.Select(s => new VolatileKeyValuePair <OutputStation, int>(s, 0)).ToList());
            _storageLocationStations = new VolatileIDDictionary <Waypoint, OutputStation>(
                Instance.Waypoints.Select(w => new VolatileKeyValuePair <Waypoint, OutputStation>(w, null)).ToList());
            foreach (var station in Instance.OutputStations)
            {
                foreach (var wp in Instance.SharedControlElements.StoragePartitioner.CachePartitions[station])
                {
                    _storageLocationStations[wp] = station;
                }
            }
            _cacheableInfoPerStation = new VolatileIDDictionary <OutputStation, bool>(
                Instance.OutputStations.Select(s => new VolatileKeyValuePair <OutputStation, bool>(s, false)).ToList());
            // --> Init move scoring
            List <Func <double> > scorers = new List <Func <double> >();

            // First try to keep the move on the same tier, if desired (this heavily influences the possible moves)
            if (_config.PreferSameTierMoves)
            {
                scorers.Add(() => { return(_currentPod.Tier == _currentBot.Tier && _currentStorageLocation.Tier == _currentBot.Tier ? 1 : 0); });
            }
            // Then decide about move type
            scorers.Add(() =>
            {
                if (_currentPod.Waypoint.InfoTagCache == ZoneType.Dropoff && _currentStorageLocation.InfoTagCache == ZoneType.None)
                {
                    // Drop-off -> Normal
                    return(2);
                }
                else if (_currentPod.Waypoint.InfoTagCache == ZoneType.Dropoff && _currentStorageLocation.InfoTagCache == ZoneType.Cache)
                {
                    // Drop-off -> Cache
                    return(2);
                }
                else if (_currentPod.Waypoint.InfoTagCache == ZoneType.Cache && _currentStorageLocation.InfoTagCache == ZoneType.None)
                {
                    // Cache -> Normal
                    return(1);
                }
                else if (_currentPod.Waypoint.InfoTagCache == ZoneType.None && _currentStorageLocation.InfoTagCache == ZoneType.Cache)
                {
                    // Normal -> Cache
                    return(1);
                }
                else
                {
                    throw new InvalidOperationException("Forbidden move: " + _currentPod.Waypoint.InfoTagCache + " -> " + _currentStorageLocation.InfoTagCache);
                }
            });
            // Then prefer moves keeping cache at targeted level
            scorers.Add(() =>
            {
                // Move types should now be separated, i.e. if there is a drop-off clearing move there is no 'normal' move, respectively, if there is no drop-off clearing move there are only 'normal' moves
                if (_currentPod.Waypoint.InfoTagCache == ZoneType.Cache && _currentStorageLocation.InfoTagCache == ZoneType.None)
                {
                    // Cache -> Normal
                    return
                    // Current cache level minus
                    ((double)_cachePodCounts[_storageLocationStations[_currentPod.Waypoint]] / Instance.SharedControlElements.StoragePartitioner.CachePartitions[_storageLocationStations[_currentPod.Waypoint]].Count -
                     // targeted cache level
                     _config.TargetFillCache);
                }
                else if (_currentPod.Waypoint.InfoTagCache == ZoneType.None && _currentStorageLocation.InfoTagCache == ZoneType.Cache)
                {
                    // Normal -> Cache
                    return
                    // Targeted cache level minus
                    (_config.TargetFillCache -
                     // current cache level
                     (double)_cachePodCounts[_storageLocationStations[_currentStorageLocation]] / Instance.SharedControlElements.StoragePartitioner.CachePartitions[_storageLocationStations[_currentStorageLocation]].Count);
                }
                else if (_currentPod.Waypoint.InfoTagCache == ZoneType.Dropoff && _currentStorageLocation.InfoTagCache == ZoneType.None)
                {
                    // Drop-off -> Normal
                    return
                    (_cacheableAtAll ? 0 : 1);
                }
                else if (_currentPod.Waypoint.InfoTagCache == ZoneType.Dropoff && _currentStorageLocation.InfoTagCache == ZoneType.Cache)
                {
                    // Drop-off -> Cache
                    return
                    (_cacheableInfoPerStation[_storageLocationStations[_currentStorageLocation]] ? 1 : 0);
                }
                else
                {
                    throw new InvalidOperationException("Forbidden move: " + _currentPod.Waypoint.InfoTagCache + " -> " + _currentStorageLocation.InfoTagCache);
                }
            });
            // Then prefer moves that make the greatest contribution in keeping the cache hot (depending on settings)
            scorers.Add(() =>
            {
                if (_currentPod.Waypoint.InfoTagCache == ZoneType.Cache) // Cache clearing move
                {
                    return(1 - Instance.ElementMetaInfoTracker.GetPodCombinedScore(_currentPod, _config.WeightSpeed, _config.WeightUtility));
                }
                else if (_currentStorageLocation.InfoTagCache == ZoneType.Cache) // Cache filling move
                {
                    return(Instance.ElementMetaInfoTracker.GetPodCombinedScore(_currentPod, _config.WeightSpeed, _config.WeightUtility));
                }
                else
                {
                    return(0); // Drop-off clearing -> highest priority
                }
            });
            // Then prefer the shortest moves
            scorers.Add(() =>
            {
                switch (_config.PodDisposeRule)
                {
                case CacheStorageLocationSelectionRule.Euclid: return(-Distances.CalculateEuclid(_currentPod.Waypoint, _currentStorageLocation, Instance.WrongTierPenaltyDistance));

                case CacheStorageLocationSelectionRule.Manhattan: return(-Distances.CalculateManhattan(_currentPod.Waypoint, _currentStorageLocation, Instance.WrongTierPenaltyDistance));

                case CacheStorageLocationSelectionRule.ShortestPath: return(-Distances.CalculateShortestPathPodSafe(_currentPod.Waypoint, _currentStorageLocation, Instance));

                case CacheStorageLocationSelectionRule.ShortestTime: return(-Distances.CalculateShortestTimePathPodSafe(_currentPod.Waypoint, _currentStorageLocation, Instance));

                default: throw new ArgumentException("Unknown pod dispose rule: " + _config.PodDisposeRule);
                }
            });
            // Then use randomness
            scorers.Add(() =>
            {
                return(Instance.Randomizer.NextDouble());
            });
            // Instantiate best candidate assessment
            _bestCandidateSelector = new BestCandidateSelector(true, scorers.ToArray());
        }
示例#8
0
 /// <summary>
 /// Inits demand tracking, if not already done.
 /// </summary>
 private void InitDemandTracking()
 {
     _backlogDemandStore  = new VolatileIDDictionary <ItemDescription, int>(_instance.ItemDescriptions.Select(i => new VolatileKeyValuePair <ItemDescription, int>(i, 0)).ToList());
     _queuedDemandStore   = new VolatileIDDictionary <ItemDescription, int>(_instance.ItemDescriptions.Select(i => new VolatileKeyValuePair <ItemDescription, int>(i, 0)).ToList());
     _assignedDemandStore = new VolatileIDDictionary <ItemDescription, int>(_instance.ItemDescriptions.Select(i => new VolatileKeyValuePair <ItemDescription, int>(i, 0)).ToList());
 }
示例#9
0
 /// <summary>
 /// Inits this controller.
 /// </summary>
 private void InitTimeouts()
 {
     _botTimeouts = new VolatileIDDictionary <Bot, double>(Instance.Bots.Select(b => new VolatileKeyValuePair <Bot, double>(b, double.MinValue)).ToList());
 }
示例#10
0
        /// <summary>
        /// Creates all zones or ensures their consistency between different managers using those.
        /// </summary>
        /// <param name="config">The configuration to use for creating the zones.</param>
        internal void CreateOrEnsureZones(CacheConfiguration config)
        {
            // Check whether this was already done
            if (_config != null)
            {
                // --> Ensure compatibility
                if (!_config.Match(config))
                {
                    throw new ArgumentException("Incompatible cache configurations: " + _config.ToString() + " vs. " + config.ToString());
                }
            }
            else
            {
                // Init
                _config = config;
                List <ZoneType> zoneTypes = new List <ZoneType>()
                {
                    ZoneType.Cache, ZoneType.Dropoff
                };
                UnzonedStorageLocations = Instance.Waypoints.Where(w => w.PodStorageLocation).ToHashSet();
                CachePartitions         = new VolatileIDDictionary <OutputStation, HashSet <Waypoint> >(Instance.OutputStations.Select(s =>
                                                                                                                                       new VolatileKeyValuePair <OutputStation, HashSet <Waypoint> >(s, new HashSet <Waypoint>())).ToList());
                int cacheWPCountPerStation = (int)Math.Ceiling(UnzonedStorageLocations.Count * _config.CacheFraction / Instance.OutputStations.Count);
                DropoffPartitions = new VolatileIDDictionary <OutputStation, HashSet <Waypoint> >(Instance.OutputStations.Select(s =>
                                                                                                                                 new VolatileKeyValuePair <OutputStation, HashSet <Waypoint> >(s, new HashSet <Waypoint>())).ToList());
                int dropoffWPCountPerStation = _config.DropoffCount;
                // Init selector
                BestCandidateSelector scorer = new BestCandidateSelector(false,
                                                                         // First adhere to preference between zone types
                                                                         () =>
                {
                    switch (_config.ZonePriority)
                    {
                    case ZonePriority.CacheFirst: return(_currentZoneType == ZoneType.Cache ? 0 : 1);

                    case ZonePriority.DropoffFirst: return(_currentZoneType == ZoneType.Dropoff ? 0 : 1);

                    case ZonePriority.CacheDropoffEqual: return(0);

                    default: throw new ArgumentException("Unknown priority: " + _config.ZonePriority);
                    }
                },
                                                                         // Then assess the main distance metric
                                                                         () =>
                {
                    switch (_currentZoneType)
                    {
                    case ZoneType.Cache: return(Distances.CalculateShortestTimePathPodSafe(_currentStorageLocation, _currentStation.Waypoint, Instance));

                    case ZoneType.Dropoff: return(Distances.CalculateShortestTimePathPodSafe(_currentStation.Waypoint, _currentStorageLocation, Instance));

                    default: throw new ArgumentException("Unknown zone type for partitioning: " + _currentZoneType.ToString());
                    }
                },
                                                                         // Break ties based on the value for the other zone
                                                                         () =>
                {
                    switch (_currentZoneType)
                    {
                    case ZoneType.Cache: return(-Distances.CalculateShortestTimePathPodSafe(_currentStation.Waypoint, _currentStorageLocation, Instance));

                    case ZoneType.Dropoff: return(-Distances.CalculateShortestTimePathPodSafe(_currentStorageLocation, _currentStation.Waypoint, Instance));

                    default: throw new ArgumentException("Unknown zone type for partitioning: " + _currentZoneType.ToString());
                    }
                });

                // --> Create partitions
                // Assign storage locations to different zones
                while ( // Check for any remaining assignments
                    CachePartitions.Values.Any(p => p.Count < cacheWPCountPerStation) ||
                    DropoffPartitions.Values.Any(p => p.Count < dropoffWPCountPerStation))
                {
                    // Search for next assignment
                    scorer.Recycle();
                    OutputStation bestStation         = null;
                    Waypoint      bestStorageLocation = null;
                    ZoneType      bestZoneType        = ZoneType.None;
                    // Check all unzoned storage locations
                    foreach (var storageLocation in UnzonedStorageLocations)
                    {
                        _currentStorageLocation = storageLocation;
                        // Check all stations
                        foreach (var station in Instance.OutputStations)
                        {
                            _currentStation = station;
                            // Check all types
                            foreach (var zoneType in zoneTypes)
                            {
                                _currentZoneType = zoneType;
                                // Skip invalid assignments
                                if (zoneType == ZoneType.Cache && CachePartitions[station].Count >= cacheWPCountPerStation)
                                {
                                    continue;
                                }
                                if (zoneType == ZoneType.Dropoff && DropoffPartitions[station].Count >= dropoffWPCountPerStation)
                                {
                                    continue;
                                }
                                // Determine score and update assignment
                                if (scorer.Reassess())
                                {
                                    bestStation         = _currentStation;
                                    bestStorageLocation = _currentStorageLocation;
                                    bestZoneType        = _currentZoneType;
                                }
                            }
                        }
                    }
                    // Sanity check
                    if (bestStation == null)
                    {
                        throw new InvalidOperationException("Ran out of available assignments while partitioning the caches - partitions so far: " +
                                                            "Cache: " + string.Join(",", CachePartitions.Select(p => p.Key.ToString() + "(" + p.Value.Count + ")")) +
                                                            "Dropoff: " + string.Join(",", DropoffPartitions.Select(p => p.Key.ToString() + "(" + p.Value.Count + ")")));
                    }
                    // Set assignment
                    switch (bestZoneType)
                    {
                    case ZoneType.Cache:
                        CachePartitions[bestStation].Add(bestStorageLocation);
                        bestStorageLocation.InfoTagCache = ZoneType.Cache;
                        break;

                    case ZoneType.Dropoff:
                        DropoffPartitions[bestStation].Add(bestStorageLocation);
                        bestStorageLocation.InfoTagCache = ZoneType.Dropoff;
                        break;

                    default: throw new InvalidOperationException("Invalid zone determined: " + bestZoneType);
                    }
                    UnzonedStorageLocations.Remove(bestStorageLocation);
                }
            }
        }
示例#11
0
 /// <summary>
 /// Initializes the stock information.
 /// </summary>
 private void InitStockInfo()
 {
     _currentActualStock    = new VolatileIDDictionary <ItemDescription, int>(Instance.ItemDescriptions.Select(i => new VolatileKeyValuePair <ItemDescription, int>(i, 0)).ToList());
     _currentAvailableStock = new VolatileIDDictionary <ItemDescription, int>(Instance.ItemDescriptions.Select(i => new VolatileKeyValuePair <ItemDescription, int>(i, 0)).ToList());
     _currentOverallDemand  = new VolatileIDDictionary <ItemDescription, int>(Instance.ItemDescriptions.Select(i => new VolatileKeyValuePair <ItemDescription, int>(i, 0)).ToList());
 }
示例#12
0
 /// <summary>
 /// Initializes this tracker.
 /// </summary>
 private void EnsureInit()
 {
     if (_podsContainingItems == null)
     {
         // --> Init storage location info
         _storageLocationProminence = new VolatileIDDictionary <Waypoint, double>(_instance.Waypoints
                                                                                  .Where(w => w.PodStorageLocation)
                                                                                  // Determine pod prominence score
                                                                                  .Select(w => new VolatileKeyValuePair <Waypoint, double>(w, _instance.OutputStations.Min(s => { return(Distances.CalculateShortestTimePathPodSafe(w, s.Waypoint, _instance)); })))
                                                                                  .ToList());
         StorageLocationsOrdered = _storageLocationProminence
                                   // Order storage locations by their prominence
                                   .OrderBy(kvp => kvp.Value)
                                   // Break ties randomly
                                   .ThenBy(kvp => _instance.Randomizer.NextDouble())
                                   // Select the actual locations and build a list
                                   .Select(kvp => kvp.Key).ToList();
         // Store prominence index
         _storageLocationIndeces = new VolatileIDDictionary <Waypoint, int>(StorageLocationsOrdered.Select(w => new VolatileKeyValuePair <Waypoint, int>(w, 0)).ToList());
         for (int i = 0; i < StorageLocationsOrdered.Count; i++)
         {
             _storageLocationIndeces[StorageLocationsOrdered[i]] = i;
         }
         // Determine prominence ranks
         _storageLocationRanks = new VolatileIDDictionary <Waypoint, int>(StorageLocationsOrdered.Select(w => new VolatileKeyValuePair <Waypoint, int>(w, 0)).ToList());
         int currentRank = 1; double currentProminenceValue = _storageLocationProminence[StorageLocationsOrdered.First()];
         foreach (var storageLocation in StorageLocationsOrdered)
         {
             // Update rank, if required
             if (_storageLocationProminence[storageLocation] > currentProminenceValue)
             {
                 currentRank++;
                 currentProminenceValue = _storageLocationProminence[storageLocation];
             }
             // Set rank of storage location
             _storageLocationRanks[storageLocation] = currentRank;
         }
         _storageLocationsPerRank = _storageLocationRanks.GroupBy(kvp => kvp.Value).ToDictionary(k => k.Key, v => v.Select(kvp => kvp.Key).OrderBy(kvp => _instance.Randomizer.NextDouble()).ToList());
         StorageLocationRankMax   = _storageLocationRanks.Values.Max();
         // Store prominence ranks for statistics tracking
         foreach (var w in StorageLocationsOrdered)
         {
             w.InfoTagProminence = 1.0 - ((_storageLocationRanks[w] - 1.0) / (StorageLocationRankMax - 1.0));
         }
         // --> Init pod score values
         _podsContainingItems = new VolatileIDDictionary <ItemDescription, HashSet <Pod> >(
             _instance.ItemDescriptions.Select(i => new VolatileKeyValuePair <ItemDescription, HashSet <Pod> >(i, _instance.Pods.Where(p => p.IsContained(i)).ToHashSet())).ToList());
         _podsAvailableItems = new VolatileIDDictionary <ItemDescription, HashSet <Pod> >(
             _instance.ItemDescriptions.Select(i => new VolatileKeyValuePair <ItemDescription, HashSet <Pod> >(i, _instance.Pods.Where(p => p.IsAvailable(i)).ToHashSet())).ToList());
         // Determine initial pod utility
         _podUtility = new VolatileIDDictionary <Pod, double>(
             _instance.Pods.Select(p => new VolatileKeyValuePair <Pod, double>(p, p.ItemDescriptionsContained.Sum(i => Math.Min(p.CountContained(i), _instance.StockInfo.GetCurrentDemand(i)))))
             .ToList());
         VolatileKeyValuePair <Pod, double> bestUtility = _podUtility.ArgMax(pu => pu.Value);
         _podUtilityMaxPod = bestUtility.Key;
         PodUtilityMax     = bestUtility.Value;
         // Determine initial pod speed
         _podSpeed = new VolatileIDDictionary <Pod, double>(
             _instance.Pods.Select(p => new VolatileKeyValuePair <Pod, double>(p, p.ItemDescriptionsContained.Sum(i => p.CountContained(i) * _instance.FrequencyTracker.GetStaticFrequency(i))))
             .ToList());
         VolatileKeyValuePair <Pod, double> bestSpeed = _podSpeed.ArgMax(ps => ps.Value);
         _podSpeedMaxPod = bestSpeed.Key;
         PodSpeedMax     = bestSpeed.Value;
     }
 }
示例#13
0
        /// <summary>
        /// Initializes this controller.
        /// </summary>
        private void Initialize()
        {
            // Setup scorers
            switch (_config.OrderSelectionRule)
            {
            case DefaultOrderSelection.Random:
                _bestCandidateSelectOrder = new BestCandidateSelector(false, () =>
                {
                    return(Instance.Randomizer.NextDouble());
                });
                break;

            case DefaultOrderSelection.FCFS:
                _bestCandidateSelectOrder = new BestCandidateSelector(false, () =>
                {
                    return(_currentOrder.TimeStamp);
                });
                break;

            case DefaultOrderSelection.DueTime:
                _bestCandidateSelectOrder = new BestCandidateSelector(false, () =>
                {
                    return(_currentOrder.DueTime);
                });
                break;

            case DefaultOrderSelection.FrequencyAge:
                _bestCandidateSelectOrder = new BestCandidateSelector(false, () =>
                {
                    double orderBirth = 1 - ((_currentOrder.TimeStamp - _oldestOrderTimestamp) / (_newestOrderTimestamp - _oldestOrderTimestamp));
                    double frequency  = _currentOrder.Positions.Average(p => Instance.FrequencyTracker.GetMeasuredFrequency(p.Key));
                    return(-(orderBirth * frequency));
                });
                break;

            default: throw new ArgumentException("Unknown selection rule: " + _config.OrderSelectionRule);
            }
            switch (_config.StationSelectionRule)
            {
            case DefaultOutputStationSelection.Random:
                _bestCandidateSelectStation = new BestCandidateSelector(false, () =>
                {
                    return(Instance.Randomizer.NextDouble());
                });
                break;

            case DefaultOutputStationSelection.LeastBusy:
                _bestCandidateSelectStation = new BestCandidateSelector(false, () =>
                {
                    return((_currentStation.CapacityInUse + _currentStation.CapacityReserved) / (double)_currentStation.Capacity);
                });
                break;

            case DefaultOutputStationSelection.MostBusy:
                _bestCandidateSelectStation = new BestCandidateSelector(false, () =>
                {
                    return(-((_currentStation.CapacityInUse + _currentStation.CapacityReserved) / (double)_currentStation.Capacity));
                });
                break;

            default: throw new ArgumentException("Unknown selection rule: " + _config.OrderSelectionRule);
            }
            // Setup fast lane helpers
            _bestCandidateSelectFastLane = new BestCandidateSelector(true,
                                                                     // If we run into ties use the oldest order
                                                                     () =>
            {
                switch (_config.FastLaneTieBreaker)
                {
                case Shared.FastLaneTieBreaker.Random: return(Instance.Randomizer.NextDouble());

                case Shared.FastLaneTieBreaker.EarliestDueTime: return(-_currentOrder.DueTime);

                case Shared.FastLaneTieBreaker.FCFS: return(-_currentOrder.TimeStamp);

                default: throw new ArgumentException("Unknown tie breaker: " + _config.FastLaneTieBreaker);
                }
            });
            if (_config.FastLane)
            {
                _nearestInboundPod = new VolatileIDDictionary <OutputStation, Pod>(Instance.OutputStations.Select(s => new VolatileKeyValuePair <OutputStation, Pod>(s, null)).ToList());
            }
        }
示例#14
0
        /// <summary>
        /// Decides the next repositioning move to do for the given robot.
        /// </summary>
        /// <param name="robot">The robot that is asking to conduct such a move.</param>
        /// <returns>A repositioning move or <code>null</code> if no such move was available.</returns>
        protected override RepositioningMove GetRepositioningMove(Bot robot)
        {
            // Prepare hot zones
            if (_chacheStorageLocations == null)
            {
                // Ensure valid zones
                Instance.SharedControlElements.StoragePartitioner.CreateOrEnsureZones(_config.ZoningConfiguration);
                // Store zones for fast access
                _chacheStorageLocations = Instance.SharedControlElements.StoragePartitioner.CachePartitions;
                foreach (var station in _chacheStorageLocations.Keys)
                {
                    foreach (var storageLocation in _chacheStorageLocations[station])
                    {
                        _stationsOfStorageLocations[storageLocation] = station;
                    }
                }
                _regularStorageLocations = Instance.Waypoints.Except(_chacheStorageLocations.SelectMany(c => c.Value)).ToHashSet();
            }
            // Init
            if (_bestCandidateSelectorClear == null)
            {
                _bestCandidateSelectorClear = new BestCandidateSelector(false,
                                                                        // First try to keep the move on the same tier as the robot
                                                                        () => { return(_currentPod.Tier == robot.Tier && _currentStorageLocation.Tier == robot.Tier ? 0 : 1); },
                                                                        // Then try to find a pod useless for the station
                                                                        () =>
                {
                    // Check the number of potential picks possible with the pod (given by station orders' demand)
                    int potentialPicks = Instance.ResourceManager.GetExtractRequestsOfStation(_currentStation)
                                         .Concat(Instance.ResourceManager.GetQueuedExtractRequestsOfStation(_currentStation))
                                         .GroupBy(r => r.Item).Sum(g => Math.Min(_currentPod.CountContained(g.Key), g.Count()));
                    // Use negative potential picks to mark useless pod
                    return(potentialPicks);
                },
                                                                        // Then try to find a pod useless overall
                                                                        () =>
                {
                    // Check the number of potential picks possible with the pod (given by all orders' demand)
                    int potentialPicks = _currentPod.ItemDescriptionsContained.Sum(i => Math.Min(_currentPod.CountContained(i),
                                                                                                 Instance.ResourceManager.GetDemandAssigned(i) +
                                                                                                 Instance.ResourceManager.GetDemandQueued(i) +
                                                                                                 (_config.UselessConsiderBacklog ? Instance.ResourceManager.GetDemandBacklog(i) : 0)));
                    // Use negative potential picks to mark useless pod
                    return(potentialPicks);
                },
                                                                        // Then try to use an empty pod
                                                                        () => { return(_currentPod.CapacityInUse); },
                                                                        // Then try to get a destination location most near to the input-stations (if pod is considered empty) or the shortest move distance (if pod still has sufficient content)
                                                                        () =>
                {
                    return((_currentPod.CapacityInUse / _currentPod.Capacity < _config.PodEmptyThreshold) ?
                           _currentStorageLocation.ShortestPodPathDistanceToNextInputStation :
                           Distances.CalculateShortestPathPodSafe(_currentPod.Waypoint, _currentStorageLocation, Instance));
                },
                                                                        // Then try to make a move with the pod most near to an output-station
                                                                        () => { return(_currentPod.Waypoint.ShortestPodPathDistanceToNextOutputStation); });
            }
            if (_bestCandidateSelectorFill == null)
            {
                _bestCandidateSelectorFill = new BestCandidateSelector(false,
                                                                       // First try to keep the move on the same tier as the robot
                                                                       () => { return(_currentPod.Tier == robot.Tier && _currentStorageLocation.Tier == robot.Tier ? 0 : 1); },
                                                                       // Then try to find a pod useful for the station
                                                                       () =>
                {
                    // Check the number of potential picks possible with the pod (given by station orders' demand)
                    int potentialPicks = Instance.ResourceManager.GetExtractRequestsOfStation(_currentStation)
                                         .Concat(Instance.ResourceManager.GetQueuedExtractRequestsOfStation(_currentStation))
                                         .GroupBy(r => r.Item).Sum(g => Math.Min(_currentPod.CountContained(g.Key), g.Count()));
                    // Use negative potential picks to mark useless pod
                    return(-potentialPicks);
                },
                                                                       // Then try to find a pod useful overall
                                                                       () =>
                {
                    // Check the number of potential picks possible with the pod (given by all orders' demand)
                    int potentialPicks = _currentPod.ItemDescriptionsContained.Sum(i => Math.Min(_currentPod.CountContained(i),
                                                                                                 Instance.ResourceManager.GetDemandAssigned(i) +
                                                                                                 Instance.ResourceManager.GetDemandQueued(i) +
                                                                                                 (_config.UselessConsiderBacklog ? Instance.ResourceManager.GetDemandBacklog(i) : 0)));
                    // Use negative potential picks to mark useless pod
                    return(-potentialPicks);
                },
                                                                       // Then try to use a full pod
                                                                       () => { return(-_currentPod.CapacityInUse); },
                                                                       // Then try to do a short move
                                                                       () => { return(Distances.CalculateShortestPathPodSafe(_currentPod.Waypoint, _currentStorageLocation, Instance)); });
            }

            // Init
            Pod      bestPod             = null;
            Waypoint bestStorageLocation = null;

            // Check whether any cache has too many pods
            if (Instance.OutputStations.Any(s => NeedsClearingRepositioning(s)))
            {
                // Clear potential old results
                _bestCandidateSelectorClear.Recycle();
                // Check all stations
                foreach (var station in Instance.OutputStations.Where(s => NeedsClearingRepositioning(s)))
                {
                    // Update current candidate to assess
                    _currentStation = station;
                    // Check occupied storage locations of cache of station
                    foreach (var from in _chacheStorageLocations[station].Where(w => w.Pod != null && !Instance.ResourceManager.IsPodClaimed(w.Pod)))
                    {
                        // Check unoccupied storage locations not in a cache
                        foreach (var to in Instance.ResourceManager.UnusedPodStorageLocations.Where(w => _regularStorageLocations.Contains(w)))
                        {
                            // Update current candidate to assess
                            _currentPod             = from.Pod;
                            _currentStorageLocation = to;
                            // Check whether the current combination is better
                            if (_bestCandidateSelectorClear.Reassess())
                            {
                                // Update best candidate
                                bestPod             = _currentPod;
                                bestStorageLocation = _currentStorageLocation;
                            }
                        }
                    }
                }
            }
            // Check whether any cache has too few pods
            if (Instance.OutputStations.Any(s => NeedsFillingRepositioning(s)))
            {
                // Clear potential old results
                _bestCandidateSelectorFill.Recycle();
                // Check all stations
                foreach (var station in Instance.OutputStations.Where(s => NeedsFillingRepositioning(s)))
                {
                    // Update current candidate to assess
                    _currentStation = station;
                    // Check unused pods
                    foreach (var pod in Instance.ResourceManager.UnusedPods.Where(p => _regularStorageLocations.Contains(p.Waypoint)))
                    {
                        // Check unoccupied storage locations of cache of station
                        foreach (var to in _chacheStorageLocations[station].Where(w => !Instance.ResourceManager.IsStorageLocationClaimed(w)))
                        {
                            // Update current candidate to assess
                            _currentPod             = pod;
                            _currentStorageLocation = to;
                            // Check whether the current combination is better
                            if (_bestCandidateSelectorFill.Reassess())
                            {
                                // Update best candidate
                                bestPod             = _currentPod;
                                bestStorageLocation = _currentStorageLocation;
                            }
                        }
                    }
                }
            }

            // Check whether a move was obtained
            if (bestPod != null)
            {
                // Return the move
                return(new RepositioningMove()
                {
                    Pod = bestPod, StorageLocation = bestStorageLocation
                });
            }
            else
            {
                // No move available - block calls for a while
                GlobalTimeout = Instance.Controller.CurrentTime + _config.GlobalTimeout;
                return(null);
            }
        }