예제 #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
        /// <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);
        }
예제 #3
0
        /// <summary>
        /// Gets the storage location most suitable for the given pod.
        /// </summary>
        /// <param name="pod">The pod to get a storage location for.</param>
        /// <param name="tripStart">The current location of the pod / where the trip starts (to improve the distance traveled).</param>
        /// <returns>The storage location to use for the given pod.</returns>
        public Waypoint GetStorageLocation(Pod pod, Waypoint tripStart)
        {
            // Search for a storage location that is available around the best rank
            int storageLocationRank = DetermineRank(pod);
            int ranksAssessed = 0; Waypoint bestStorageLocation = null; double bestTripTime = double.PositiveInfinity; bool goBetter = false;
            int betterRank = storageLocationRank;
            int worseRank  = storageLocationRank;

            while (
                // keep searching as long as not enough ranks have been assessed and ...
                ranksAssessed < _config.RankCorridor ||
                // no storage location was found at all
                bestStorageLocation == null)
            {
                // Change search direction
                goBetter = !goBetter;
                // Get current rank
                int currentRank = goBetter ? betterRank : worseRank;
                // Update index for next iteration
                if (goBetter)
                {
                    betterRank--;
                }
                else
                {
                    worseRank++;
                }
                // Check all unused storage locations of the rank
                foreach (var storageLocation in _instance.ElementMetaInfoTracker.GetStorageLocationsOfRank(currentRank).Where(sl => !_instance.ResourceManager.IsStorageLocationClaimed(sl)))
                {
                    // Check whether storage location is a new best
                    double tripTime = Distances.CalculateShortestTimePathPodSafe(tripStart, storageLocation, _instance);
                    if (tripTime < bestTripTime)
                    {
                        bestTripTime        = tripTime;
                        bestStorageLocation = storageLocation;
                    }
                }
                // Keep track of assessed locations
                ranksAssessed++;
            }
            // Return it
            return(bestStorageLocation);
        }
예제 #4
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);
        }
예제 #5
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;
        }
예제 #6
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();
        }
예제 #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>
        /// 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);
                }
            }
        }
예제 #9
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;
     }
 }
예제 #10
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);
        }