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;
            }
        }
Exemple #3
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);
            }
        }