Пример #1
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());
        }
Пример #2
0
        private double Score(QueueOrderSelectionInboundMatches config, bool queueAssignment)
        {
            // Init
            int    podCount  = _inboundPodsByDistance[_currentStation].Count;
            int    podNumber = 0;
            double score     = 0;
            // Get demands given by the current order
            List <IGrouping <ItemDescription, ExtractRequest> > demands = Instance.ResourceManager.GetExtractRequestsOfOrder(_currentOrder).GroupBy(r => r.Item).ToList();

            foreach (var itemRequests in demands)
            {
                _orderItemDemand[itemRequests.Key] = itemRequests.Count();
            }
            // Check all inbound pods
            foreach (var pod in _inboundPodsByDistance[_currentStation])
            {
                // Get distance to pod
                double distance;
                if (pod.Bot != null && pod.Bot.CurrentWaypoint != null)
                {
                    // Use the path distance (this should always be possible)
                    distance = Distances.CalculateShortestPathPodSafe(pod.Bot.CurrentWaypoint, _currentStation.Waypoint, Instance);
                }
                else
                {
                    // Use manhattan distance as a fallback
                    distance = Distances.CalculateManhattan(pod, _currentStation, Instance.WrongTierPenaltyDistance);
                }
                // Check all demands for the order for availability in the pod
                foreach (var item in demands.Select(d => d.Key))
                {
                    // If there is no demand left, skip this item
                    if (_orderItemDemand[item] <= 0)
                    {
                        continue;
                    }
                    // Get available count
                    int availableCount = Math.Min(_orderItemDemand[item], pod.CountAvailable(item));
                    // Update demand for item with available count
                    _orderItemDemand[item] -= availableCount;
                    // Update score by taking distance to pod into account
                    score += availableCount * distance > config.DistanceForWeighting ?
                             // Pod is too far away, do not weight it's resulting score
                             1 :
                             // Pod is sufficiently near, weight it's score by it's position in queue
                             (podCount - podNumber);
                }
                // Track pod number
                podNumber++;
            }
            // Return the score
            return(score);
        }
Пример #3
0
        /// <summary>
        /// Decides the waypoint to use when storing a pod. This call is measured by the timing done.
        /// </summary>
        /// <param name="pod">The pod to store.</param>
        /// <returns>The waypoint to use.</returns>
        protected override Waypoint GetStorageLocationForPod(Pod pod)
        {
            double minDistance = double.PositiveInfinity; Waypoint bestStorageLocation = null;

            foreach (var storageLocation in Instance.ResourceManager.UnusedPodStorageLocations)
            {
                // Calculate the distance
                double distance;
                switch (_config.PodDisposeRule)
                {
                case StationBasedPodStorageLocationDisposeRule.Euclid:
                    distance = (_config.OutputStationMode ? Instance.OutputStations.Cast <Circle>() : Instance.InputStations.Cast <Circle>())
                               .Min(station => Distances.CalculateEuclid(station, storageLocation, Instance.WrongTierPenaltyDistance));
                    break;

                case StationBasedPodStorageLocationDisposeRule.Manhattan:
                    distance = (_config.OutputStationMode ? Instance.OutputStations.Cast <Circle>() : Instance.InputStations.Cast <Circle>())
                               .Min(station => Distances.CalculateManhattan(station, storageLocation, Instance.WrongTierPenaltyDistance));
                    break;

                case StationBasedPodStorageLocationDisposeRule.ShortestPath:
                    distance = (_config.OutputStationMode ? Instance.OutputStations.Select(s => s.Waypoint) : Instance.InputStations.Select(s => s.Waypoint))
                               .Min(station => Distances.CalculateShortestPathPodSafe(storageLocation, station, Instance));
                    break;

                case StationBasedPodStorageLocationDisposeRule.ShortestTime:
                    distance = (_config.OutputStationMode ? Instance.OutputStations.Select(s => s.Waypoint) : Instance.InputStations.Select(s => s.Waypoint))
                               .Min(station => Distances.CalculateShortestTimePathPodSafe(storageLocation, station, Instance));
                    break;

                default: throw new ArgumentException("Unknown pod dispose rule: " + _config.PodDisposeRule);
                }
                // Update minimum
                if (distance < minDistance)
                {
                    minDistance         = distance;
                    bestStorageLocation = storageLocation;
                }
            }
            // Check success
            if (bestStorageLocation == null)
            {
                throw new InvalidOperationException("There was no suitable storage location for the pod: " + pod.ToString());
            }
            // Return it
            return(bestStorageLocation);
        }
Пример #4
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());;
 }
Пример #5
0
        /// <summary>
        /// Returns a suitable storage location for the given pod.
        /// </summary>
        /// <param name="pod">The pod to fetch a storage location for.</param>
        /// <returns>The storage location to use.</returns>
        protected override Waypoint GetStorageLocationForPod(Pod pod)
        {
            double   minDistance = double.PositiveInfinity; Waypoint bestStorageLocation = null;
            Waypoint podLocation = // Get current waypoint of pod, if we want to estimate a path
                                   _config.PodDisposeRule == NearestPodStorageLocationDisposeRule.ShortestPath || _config.PodDisposeRule == NearestPodStorageLocationDisposeRule.ShortestTime ?
                                   Instance.WaypointGraph.GetClosestWaypoint(pod.Tier, pod.X, pod.Y) :
                                   null;

            foreach (var storageLocation in Instance.ResourceManager.UnusedPodStorageLocations)
            {
                // Calculate the distance
                double distance;
                switch (_config.PodDisposeRule)
                {
                case NearestPodStorageLocationDisposeRule.Euclid: distance = Distances.CalculateEuclid(pod, storageLocation, Instance.WrongTierPenaltyDistance); break;

                case NearestPodStorageLocationDisposeRule.Manhattan: distance = Distances.CalculateManhattan(pod, storageLocation, Instance.WrongTierPenaltyDistance); break;

                case NearestPodStorageLocationDisposeRule.ShortestPath: distance = Distances.CalculateShortestPathPodSafe(podLocation, storageLocation, Instance); break;

                case NearestPodStorageLocationDisposeRule.ShortestTime: distance = Distances.CalculateShortestTimePathPodSafe(podLocation, storageLocation, Instance); break;

                default: throw new ArgumentException("Unknown pod dispose rule: " + _config.PodDisposeRule);
                }
                // Update minimum
                if (distance < minDistance)
                {
                    minDistance         = distance;
                    bestStorageLocation = storageLocation;
                }
            }
            // Check success
            if (bestStorageLocation == null)
            {
                throw new InvalidOperationException("There was no suitable storage location for the pod: " + pod.ToString());
            }
            // Return it
            return(bestStorageLocation);
        }
Пример #6
0
 /// <summary>
 /// Prepares some meta information.
 /// </summary>
 private void PrepareAssessment()
 {
     if (_config.FastLane)
     {
         foreach (var station in Instance.OutputStations.Where(s => IsAssignable(s)))
         {
             _nearestInboundPod[station] = station.InboundPods.ArgMin(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));
                 }
             });
         }
     }
 }
Пример #7
0
        /// <summary>
        /// This is called to decide about potentially pending orders.
        /// This method is being timed for statistical purposes and is also ONLY called when <code>SituationInvestigated</code> is <code>false</code>.
        /// Hence, set the field accordingly to react on events not tracked by this outer skeleton.
        /// </summary>
        protected override void DecideAboutPendingOrders()
        {
            foreach (var order in _pendingOrders.Where(o => o.Positions.All(p => Instance.StockInfo.GetActualStock(p.Key) >= p.Value)).ToArray())
            {
                // Check all pods for the maximum number of picks that can be done with them
                List <Pod> bestPods     = new List <Pod>();
                int        bestPodPicks = -1;
                foreach (var pod in Instance.Pods.Where(p => !p.InUse))
                {
                    // Calculate picks that can potentially be done with the pod
                    int picks = order.Positions.Sum(pos => Math.Min(pod.CountAvailable(pos.Key), pos.Value));
                    // Check whether we found even more possible picks with this pod
                    if (bestPodPicks < picks)
                    {
                        bestPods.Clear();
                        bestPods.Add(pod);
                        bestPodPicks = picks;
                    }
                    else
                    {
                        // Check whether the current pod belongs into the winner group
                        if (bestPodPicks == picks)
                        {
                            bestPods.Add(pod);
                        }
                    }
                }
                // Choose station nearest to one of the best pods
                OutputStation chosenStation    = null;
                double        shortestDistance = double.PositiveInfinity;
                foreach (var station in Instance.OutputStations.Where(s => s.Active && s.FitsForReservation(order)))
                {
                    foreach (var pod in bestPods)
                    {
                        double distance;
                        switch (_config.DistanceRule)
                        {
                        case NearBestPodOrderBatchingDistanceRule.Euclid: distance = Distances.CalculateEuclid(pod, station, Instance.WrongTierPenaltyDistance); break;

                        case NearBestPodOrderBatchingDistanceRule.Manhattan: distance = Distances.CalculateManhattan(pod, station, Instance.WrongTierPenaltyDistance); break;

                        case NearBestPodOrderBatchingDistanceRule.ShortestPath: distance = Distances.CalculateShortestPathPodSafe(pod.Waypoint, station.Waypoint, Instance); break;

                        default: throw new ArgumentException("Unknown distance rule: " + _config.DistanceRule);
                        }
                        if (distance < shortestDistance)
                        {
                            shortestDistance = distance;
                            chosenStation    = station;
                        }
                    }
                }
                // If we found a station, assign the bundle to it
                if (chosenStation != null)
                {
                    AllocateOrder(order, chosenStation);
                }
            }
        }
Пример #8
0
        /// <summary>
        /// Reallocates the pods to different classes.
        /// </summary>
        private void ReallocatePods()
        {
            // Sort pods by their current average frequency
            _podsOrdered = Instance.Pods
                           .OrderBy(p => p.ItemDescriptionsContained.Any() ? p.ItemDescriptionsContained.Average(item => item.OrderCount) : 0)
                           .ThenBy(p => Instance.OutputStations.Min(o =>
            {
                double value = 0;
                switch (_storageLocationClassRule)
                {
                case TurnoverPodStorageLocationClassRule.OutputStationDistanceEuclidean:
                    value = Distances.CalculateEuclid(p, o, Instance.WrongTierPenaltyDistance); break;

                case TurnoverPodStorageLocationClassRule.OutputStationDistanceManhattan:
                    value = Distances.CalculateManhattan(p, o, Instance.WrongTierPenaltyDistance); break;

                case TurnoverPodStorageLocationClassRule.OutputStationDistanceShortestPath:
                    value = Distances.CalculateShortestPathPodSafe(Instance.WaypointGraph.GetClosestWaypoint(p.Tier, p.X, p.Y), o.Waypoint, Instance); break;

                case TurnoverPodStorageLocationClassRule.OutputStationDistanceShortestTime:
                    value = Distances.CalculateShortestTimePathPodSafe(Instance.WaypointGraph.GetClosestWaypoint(p.Tier, p.X, p.Y), o.Waypoint, Instance); break;

                default: throw new ArgumentException("Unknown storage location rule: " + _storageLocationClassRule);
                }
                return(value);
            }))
                           .ToList();

            // Determine the shares of the capacity of the storage location classes
            double overallCapacity = _classStorageLocations.Sum(l => l.Count);
            Dictionary <int, double> classStorageCapacityShares = new Dictionary <int, double>();

            for (int i = 0; i < _classCount; i++)
            {
                classStorageCapacityShares[i] = _classStorageLocations[i].Count / overallCapacity;
            }

            // Group pods to classes
            _podClasses       = new Dictionary <Pod, int>();
            _classStoragePods = Enumerable.Range(0, _classCount).Select(i => new List <Pod>()).ToArray();
            int currentClass = 0; int podCount = 0; double aggregatedRelativeCapacity = classStorageCapacityShares[0];

            foreach (var pod in _podsOrdered)
            {
                podCount++;
                // See whether the pod still fits in the current storage location area
                if ((double)podCount / _podsOrdered.Count > aggregatedRelativeCapacity)
                {
                    // Update virtual capacity
                    currentClass++;
                    if (currentClass < _classCount)
                    {
                        aggregatedRelativeCapacity += classStorageCapacityShares[currentClass];
                    }
                }
                // Assign the pod to the class
                _podClasses[pod] = currentClass;
                _classStoragePods[currentClass].Add(pod);
                // Mark the pods
                pod.InfoTagPodStorageType = (_classCount - currentClass - 1.0) / (_classCount - 1.0);
                pod.InfoTagPodStorageInfo = "Class" + currentClass;
            }

            // Log this reallocation
            Instance.LogInfo("Reallocated pods - classes: " + string.Join(";", Enumerable.Range(0, _classCount).Select(c => c + ":" + _classStoragePods[c].Count)));

            // Mark this re-allocation
            _lastReallocation = Instance.Controller.CurrentTime;
        }
Пример #9
0
        /// <summary>
        /// Initializes this manager.
        /// </summary>
        private void Init()
        {
            // Remember initialization
            _initialized = true;
            // Fetch additional settings
            if (Instance.Controller.PodStorageManager is TurnoverPodStorageManager)
            {
                _storageLocationClassRule = (Instance.ControllerConfig.PodStorageConfig as TurnoverPodStorageConfiguration).StorageLocationClassRule;
            }
            // Initialize ordered storage location list
            _storageLocationsOrdered = Instance.Waypoints
                                       .Where(wp => wp.PodStorageLocation)
                                       .OrderBy(wp => Instance.OutputStations.Min(o =>
            {
                double value = 0;
                switch (_storageLocationClassRule)
                {
                case TurnoverPodStorageLocationClassRule.OutputStationDistanceEuclidean: value = Distances.CalculateEuclid(wp, o, Instance.WrongTierPenaltyDistance); break;

                case TurnoverPodStorageLocationClassRule.OutputStationDistanceManhattan: value = Distances.CalculateManhattan(wp, o, Instance.WrongTierPenaltyDistance); break;

                case TurnoverPodStorageLocationClassRule.OutputStationDistanceShortestPath: value = Distances.CalculateShortestPathPodSafe(wp, o.Waypoint, Instance); break;

                case TurnoverPodStorageLocationClassRule.OutputStationDistanceShortestTime: value = Distances.CalculateShortestTimePathPodSafe(wp, o.Waypoint, Instance); break;

                default: throw new ArgumentException("Unknown storage location rule: " + _storageLocationClassRule);
                }
                return(value);
            }))
                                       .ToList();

            // Allocate storage locations to classes
            _classStorageLocations = new List <Waypoint> [_classCount];
            List <Waypoint> tempPodsOrdered = _storageLocationsOrdered.ToList();

            for (int i = 0; i < _classCount; i++)
            {
                if (i < _classCount - 1)
                {
                    _classStorageLocations[i] = tempPodsOrdered.Take((int)(_classBorders[i] * _storageLocationsOrdered.Count)).ToList();
                    tempPodsOrdered.RemoveRange(0, _classStorageLocations[i].Count);
                }
                else
                {
                    _classStorageLocations[i] = tempPodsOrdered;
                }
            }

            // Log this reallocation
            Instance.LogInfo("Allocated storage locations - classes: " + string.Join(";", Enumerable.Range(0, _classCount).Select(c => c + ":" + _classStorageLocations[c].Count)));

            // Reallocate items and pods for the first time
            ReallocatePods();

            // Reallocate items and pods for the first time
            ReallocateItems();
        }
Пример #10
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());
        }
Пример #11
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);
            }
        }
Пример #12
0
        /// <summary>
        /// Chooses the storage location to use for the given pod.
        /// </summary>
        /// <param name="pod">The pod to store.</param>
        /// <returns>The storage location to use for the pod.</returns>
        private Waypoint ChooseStorageLocation(Pod pod)
        {
            // Get the storage class the pod should end up in
            int desiredStorageClass = _classManager.DetermineStorageClass(pod);
            // Try to allocate the pod to its storage class - if not possible try neighboring classes
            int      currentClassTriedLow = desiredStorageClass; int currentClassTriedHigh = desiredStorageClass;
            Waypoint chosenStorageLocation = null;

            while (true)
            {
                // Try the less frequent class first
                if (currentClassTriedLow < _classManager.ClassCount)
                {
                    chosenStorageLocation = _classManager.GetClassStorageLocations(currentClassTriedLow)
                                            .Where(wp => !Instance.ResourceManager.IsStorageLocationClaimed(wp)) // Only use not occupied ones
                                            .OrderBy(wp =>
                    {
                        switch (_config.PodDisposeRule)
                        {
                        case TurnoverPodStorageLocationDisposeRule.NearestEuclid:
                            return(Distances.CalculateEuclid(wp, pod, Instance.WrongTierPenaltyDistance));

                        case TurnoverPodStorageLocationDisposeRule.NearestManhattan:
                            return(Distances.CalculateManhattan(wp, pod, Instance.WrongTierPenaltyDistance));

                        case TurnoverPodStorageLocationDisposeRule.NearestShortestPath:
                            return(Distances.CalculateShortestPathPodSafe(Instance.WaypointGraph.GetClosestWaypoint(pod.Tier, pod.X, pod.Y), wp, Instance));

                        case TurnoverPodStorageLocationDisposeRule.NearestShortestTime:
                            return(Distances.CalculateShortestTimePathPodSafe(Instance.WaypointGraph.GetClosestWaypoint(pod.Tier, pod.X, pod.Y), wp, Instance));

                        case TurnoverPodStorageLocationDisposeRule.OStationNearestEuclid:
                            return(Instance.OutputStations.Min(s => Distances.CalculateEuclid(wp, s, Instance.WrongTierPenaltyDistance)));

                        case TurnoverPodStorageLocationDisposeRule.OStationNearestManhattan:
                            return(Instance.OutputStations.Min(s => Distances.CalculateManhattan(wp, s, Instance.WrongTierPenaltyDistance)));

                        case TurnoverPodStorageLocationDisposeRule.OStationNearestShortestPath:
                            return(Instance.OutputStations.Min(s => Distances.CalculateShortestPathPodSafe(wp, s.Waypoint, Instance)));

                        case TurnoverPodStorageLocationDisposeRule.OStationNearestShortestTime:
                            return(Instance.OutputStations.Min(s => Distances.CalculateShortestTimePathPodSafe(wp, s.Waypoint, Instance)));

                        case TurnoverPodStorageLocationDisposeRule.Random:
                            return(wp.Instance.Randomizer.NextDouble());

                        default: throw new ArgumentException("Unknown pod dispose rule: " + _config.PodDisposeRule);
                        }
                    })                                         // Order the remaining ones by the given rule
                                            .FirstOrDefault(); // Use the first one
                }
                // Check whether we found a suitable pod of this class
                if (chosenStorageLocation != null)
                {
                    break;
                }
                // Try the higher frequent class next
                if (currentClassTriedHigh >= 0 && currentClassTriedHigh != currentClassTriedLow)
                {
                    chosenStorageLocation = _classManager.GetClassStorageLocations(currentClassTriedHigh)
                                            .Where(wp => !Instance.ResourceManager.IsStorageLocationClaimed(wp)) // Only use not occupied ones
                                            .OrderBy(wp =>
                    {
                        switch (_config.PodDisposeRule)
                        {
                        case TurnoverPodStorageLocationDisposeRule.NearestEuclid:
                            return(Distances.CalculateEuclid(wp, pod, Instance.WrongTierPenaltyDistance));

                        case TurnoverPodStorageLocationDisposeRule.NearestManhattan:
                            return(Distances.CalculateManhattan(wp, pod, Instance.WrongTierPenaltyDistance));

                        case TurnoverPodStorageLocationDisposeRule.NearestShortestPath:
                            return(Distances.CalculateShortestPathPodSafe(Instance.WaypointGraph.GetClosestWaypoint(pod.Tier, pod.X, pod.Y), wp, Instance));

                        case TurnoverPodStorageLocationDisposeRule.NearestShortestTime:
                            return(Distances.CalculateShortestTimePathPodSafe(Instance.WaypointGraph.GetClosestWaypoint(pod.Tier, pod.X, pod.Y), wp, Instance));

                        case TurnoverPodStorageLocationDisposeRule.OStationNearestEuclid:
                            return(Instance.OutputStations.Min(s => Distances.CalculateEuclid(wp, s, Instance.WrongTierPenaltyDistance)));

                        case TurnoverPodStorageLocationDisposeRule.OStationNearestManhattan:
                            return(Instance.OutputStations.Min(s => Distances.CalculateManhattan(wp, s, Instance.WrongTierPenaltyDistance)));

                        case TurnoverPodStorageLocationDisposeRule.OStationNearestShortestPath:
                            return(Instance.OutputStations.Min(s => Distances.CalculateShortestPathPodSafe(wp, s.Waypoint, Instance)));

                        case TurnoverPodStorageLocationDisposeRule.OStationNearestShortestTime:
                            return(Instance.OutputStations.Min(s => Distances.CalculateShortestTimePathPodSafe(wp, s.Waypoint, Instance)));

                        case TurnoverPodStorageLocationDisposeRule.Random:
                            return(wp.Instance.Randomizer.NextDouble());

                        default: throw new ArgumentException("Unknown pod dispose rule: " + _config.PodDisposeRule);
                        }
                    })                                         // Order the remaining ones by the given rule
                                            .FirstOrDefault(); // Use the first one
                }
                // Check whether we found a suitable pod of this class
                if (chosenStorageLocation != null)
                {
                    break;
                }
                // Update the class indeces to check next
                currentClassTriedLow++; currentClassTriedHigh--;
                // Check index correctness
                if (currentClassTriedHigh < 0 && currentClassTriedLow >= _classManager.ClassCount)
                {
                    throw new InvalidOperationException("There was no storage location available!");
                }
            }
            // Return the chosen one
            return(chosenStorageLocation);
        }