private void BundleStored(InputStation iStation, Bot bot, Pod pod, ItemBundle bundle) { // Skip callback, if inactive if (!_instance.SettingConfig.MonitorWellSortedness) { return; } // Return if not in use yet if (_podsContainingItems == null) { return; } // --> Add pod to the list of pods containing / offering the respective item _podsAvailableItems[bundle.ItemDescription].Add(pod); _podsContainingItems[bundle.ItemDescription].Add(pod); // --> Update pod utility int itemDemand = _instance.StockInfo.GetCurrentDemand(bundle.ItemDescription); int beforeCount = pod.CountContained(bundle.ItemDescription) - bundle.ItemCount; // Add either rest of demand that now can be supplied by the pod or simply the content of the bundle if (beforeCount < itemDemand) { _podUtility[pod] += Math.Min(itemDemand - beforeCount, bundle.ItemCount); // Update max value if (_podUtility[pod] > PodUtilityMax) { PodUtilityMax = _podUtility[pod]; _podUtilityMaxPod = pod; } } // --> Update pod speed _podSpeed[pod] += bundle.ItemCount * _instance.FrequencyTracker.GetStaticFrequency(bundle.ItemDescription); if (_podSpeed[pod] > PodSpeedMax) { PodSpeedMax = _podSpeed[pod]; _podSpeedMaxPod = pod; } }
private void ItemExtracted(Pod pod, ItemDescription item) { // Skip callback, if inactive if (!_instance.SettingConfig.MonitorWellSortedness) { return; } // Return if not in use yet if (_podsContainingItems == null) { return; } // --> Update pod utility int itemDemand = _instance.StockInfo.GetCurrentDemand(item); bool updateUtilityMax = false; // Update demand by new content of pod (pod lost one of these items) if (itemDemand >= pod.CountContained(item)) { // The demand for this item is still high, but we can now supply one item less (because the content is low in comparison to the demand) _podUtility[pod]--; // Check whether utility max has to be updated if (pod == _podUtilityMaxPod) { updateUtilityMax = true; } } // Update to new demand (demand for the given item sunk by one) foreach (var itemPod in _podsContainingItems[item]) { // If the demand for the item is less then the pod content, we need to update to the new demand by decreasing the utility by one if (itemDemand < itemPod.CountContained(item)) { _podUtility[itemPod]--; // Check whether utility max has to be updated if (itemPod == _podUtilityMaxPod) { updateUtilityMax = true; } } } // Refresh new max if (updateUtilityMax) { VolatileKeyValuePair <Pod, double> bestUtility = _podUtility.ArgMax(pu => pu.Value); _podUtilityMaxPod = bestUtility.Key; PodUtilityMax = bestUtility.Value; } // --> Remove pod from list of pods containing / offering the item, if it was the last one if (!pod.IsAvailable(item)) { _podsAvailableItems[item].Remove(pod); } if (!pod.IsContained(item)) { _podsContainingItems[item].Remove(pod); } // --> Update pod speed _podSpeed[pod] -= _instance.FrequencyTracker.GetStaticFrequency(item); if (pod == _podSpeedMaxPod) { // Refresh max value VolatileKeyValuePair <Pod, double> bestSpeed = _podSpeed.ArgMax(ps => ps.Value); _podSpeedMaxPod = bestSpeed.Key; PodSpeedMax = bestSpeed.Value; } }
/// <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); } }