Exemple #1
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)
        {
            // Ensure init
            if (_bestCandidateSelector == null)
            {
                Init();
            }
            // Get output station this pod is coming from (it has to be the nearest one)
            _currentStation = Instance.OutputStations.ArgMin(s => Distances.CalculateEuclid(s, pod, Instance.WrongTierPenaltyDistance));
            // Get current pod location (pod has to be at station's position right now)
            _currentPodLocation = _currentStation.Waypoint;
            // Determine whether the pod should be put in the cache
            double cacheUtilityValue =
                Instance.SharedControlElements.StoragePartitioner.GetCacheValue(pod, _currentStation, _config.WeightSpeed, _config.WeightUtility);
            double cacheFill =
                (double)Instance.SharedControlElements.StoragePartitioner.CachePartitions[_currentStation].Count(c => c.Pod != null) /
                Instance.SharedControlElements.StoragePartitioner.CachePartitions[_currentStation].Count;

            _currentCacheable = ((1 - cacheFill) * _config.WeightCacheFill + cacheUtilityValue * _config.WeightCacheUtility) / 2.0 > _config.PodCacheableThreshold;
            // Get best storage location
            _bestCandidateSelector.Recycle();
            Waypoint bestStorageLocation = null;

            foreach (var storageLocation in Instance.ResourceManager.UnusedPodStorageLocations)
            {
                // Update current candidate
                _currentStorageLocation = storageLocation;
                // Assess new candidate
                if (_bestCandidateSelector.Reassess())
                {
                    bestStorageLocation = _currentStorageLocation;
                }
            }
            // Return it
            return(bestStorageLocation);
        }
Exemple #2
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)
        {
            // Ensure init
            if (_bestCandidateSelector == null)
            {
                Init();
            }
            // Prepare some meta info
            PrepareAssessment();
            // Init
            Pod      bestPod             = null;
            Waypoint bestStorageLocation = null;

            // Clear potential old results
            _bestCandidateSelector.Recycle();
            // Search for best move
            foreach (var pod in Instance.ResourceManager.UnusedPods)
            {
                // Update current candidate to assess
                _currentPod = pod;

                // If the pod is stored at a drop-off location, we need information about its cache potential
                if (pod.Waypoint.InfoTagCache == ZoneType.Dropoff)
                {
                    // Update cacheable info
                    foreach (var station in Instance.OutputStations)
                    {
                        _cacheableInfoPerStation[station] =
                            // Determine cacheable
                            Instance.SharedControlElements.StoragePartitioner.GetCacheValue(pod, station, _config.WeightSpeed, _config.WeightUtility) > _config.PodCacheableThreshold;
                    }
                    _cacheableAtAll = _cacheableInfoPerStation.Any();
                }

                // Assess all valid pod destination combinations
                foreach (var storageLocation in Instance.ResourceManager.UnusedPodStorageLocations.Where(sl => IsValidMove(pod, sl)))
                {
                    // Update current candidate to assess
                    _currentStorageLocation = storageLocation;
                    // Check whether the current combination is better
                    if (_bestCandidateSelector.Reassess())
                    {
                        // Update best candidate
                        bestPod             = _currentPod;
                        bestStorageLocation = _currentStorageLocation;
                    }
                }
            }

            // Check for unavailable or useless move
            if (bestPod != null)
            {
                // Return the move
                return(new RepositioningMove()
                {
                    Pod = bestPod, StorageLocation = bestStorageLocation
                });
            }
            else
            {
                // No suitable move ... penalize with a timeout
                GlobalTimeout = Instance.Controller.CurrentTime + _config.GlobalTimeout;
                return(null);
            }
        }
Exemple #3
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()
        {
            // If not initialized, do it now
            if (_bestCandidateSelectNormal == null)
            {
                Initialize();
            }
            // Define filter functions
            Func <OutputStation, bool> validStationNormalAssignment   = _config.FastLane ? (Func <OutputStation, bool>)IsAssignableKeepFastLaneSlot : IsAssignable;
            Func <OutputStation, bool> validStationFastLaneAssignment = IsAssignable;

            // Get some meta info
            PrepareAssessment();
            // Assign fast lane orders while possible
            bool furtherOptions = true;

            while (furtherOptions && _config.FastLane)
            {
                // Prepare helpers
                OutputStation chosenStation = null;
                Order         chosenOrder   = null;
                _bestCandidateSelectFastLane.Recycle();
                // Look for next station to assign orders to
                foreach (var station in Instance.OutputStations
                         // Station has to be valid
                         .Where(s => validStationFastLaneAssignment(s)))
                {
                    // Set station
                    _currentStation = station;
                    // Check whether there is a suitable pod
                    if (_nearestInboundPod[station] != null && _nearestInboundPod[station].GetDistance(station) < Instance.SettingConfig.Tolerance)
                    {
                        // Search for best order for the station in all fulfillable orders
                        foreach (var order in _pendingOrders.Where(o =>
                                                                   // Order needs to be immediately fulfillable
                                                                   o.Positions.All(p => _nearestInboundPod[station].CountAvailable(p.Key) >= p.Value)))
                        {
                            // Set order
                            _currentOrder = order;
                            // --> Assess combination
                            if (_bestCandidateSelectFastLane.Reassess())
                            {
                                chosenStation = _currentStation;
                                chosenOrder   = _currentOrder;
                            }
                        }
                    }
                }
                // Assign best order if available
                if (chosenOrder != null)
                {
                    // Assign the order
                    AllocateOrder(chosenOrder, chosenStation);
                    // Log fast lane assignment
                    Instance.StatCustomControllerInfo.CustomLogOB1++;
                }
                else
                {
                    // No more options to assign orders to stations
                    furtherOptions = false;
                }
            }
            // Assign orders while possible
            furtherOptions = true;
            while (furtherOptions)
            {
                // Prepare helpers
                OutputStation chosenStation = null;
                Order         chosenOrder   = null;
                _bestCandidateSelectNormal.Recycle();
                // Look for next station to assign orders to
                foreach (var station in Instance.OutputStations
                         // Station has to be valid
                         .Where(s => validStationNormalAssignment(s)))
                {
                    // Set station
                    _currentStation = station;
                    // Search for best order for the station in all fulfillable orders
                    foreach (var order in _pendingOrders.Where(o => o.Positions.All(p => Instance.StockInfo.GetActualStock(p.Key) >= p.Value)))
                    {
                        // Set order
                        _currentOrder = order;
                        // --> Assess combination
                        if (_bestCandidateSelectNormal.Reassess())
                        {
                            chosenStation = _currentStation;
                            chosenOrder   = _currentOrder;
                        }
                    }
                }
                // Assign best order if available
                if (chosenOrder != null)
                {
                    // Assign the order
                    AllocateOrder(chosenOrder, chosenStation);
                    // Log score statistics
                    if (_statScorerValues == null)
                    {
                        _statScorerValues = _bestCandidateSelectNormal.BestScores.ToArray();
                    }
                    else
                    {
                        for (int i = 0; i < _bestCandidateSelectNormal.BestScores.Length; i++)
                        {
                            _statScorerValues[i] += _bestCandidateSelectNormal.BestScores[i];
                        }
                    }
                    _statAssignments++;
                    Instance.StatCustomControllerInfo.CustomLogOB2 = _statScorerValues[_statLinesInCommonScoreIndex] / _statAssignments;
                }
                else
                {
                    // No more options to assign orders to stations
                    furtherOptions = false;
                }
            }
        }
        /// <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()
        {
            // --> Define filter functions
            // Define station filter for order to station assignment
            Func <OutputStation, bool> validStation = _config.FastLane ? (Func <OutputStation, bool>)ValidStationKeepFastLane : ValidStationIgnoreFastLane;
            // Only assign as many orders to the queue as specified
            Func <HashSet <Order>, bool> validQueue = (HashSet <Order> q) => { return(q.Count < _config.QueueLength); };

            // --> Initiate
            Init();
            // Keep track of assignment success
            bool success = false;

            // --> Prepare meta information (if any valid assignment opportunity)
            if (Instance.OutputStations.Any(s => (_config.FastLane && ValidStationIgnoreFastLane(s)) || validStation(s)) || _stationQueues.Values.Any(q => validQueue(q)))
            {
                PrepareAssessment();
            }

            // --> ASSIGN ORDERS TO QUEUES
            do
            {
                // Reset indicator
                success = false;
                // Reset
                _bestCandidateSelectorQueue.Recycle();
                Order         bestOrder   = null;
                OutputStation bestStation = null;

                // Try all assignable orders
                foreach (var order in _pendingOrders.Where(o => o.Positions.All(p => Instance.StockInfo.GetActualStock(p.Key) >= p.Value)))
                {
                    // Update current order
                    _currentOrder = order;

                    // Try all station queues
                    foreach (var stationQueueKVP in _stationQueues.Where(q => validQueue(q.Value)))
                    {
                        // Update current station
                        _currentStation = stationQueueKVP.Key;

                        // Assess
                        if (_bestCandidateSelectorQueue.Reassess())
                        {
                            bestOrder   = _currentOrder;
                            bestStation = _currentStation;
                        }
                    }
                }

                // Commit best assignment
                if (bestOrder != null && bestStation != null)
                {
                    success = true;
                    _pendingOrders.Remove(bestOrder);
                    _stationQueues[bestStation].Add(bestOrder);
                    // Announce queue decision
                    Instance.Controller.Allocator.Queue(bestOrder, bestStation);
                }
            }while (success);

            // --> ASSIGN ORDERS TO FAST-LANE OF THE STATIONS
            if (_config.FastLane)
            {
                do
                {
                    // Reset indicator
                    success = false;
                    // Assign orders from queue for all valid stations
                    foreach (var station in Instance.OutputStations.Where(s => ValidStationIgnoreFastLane(s)))
                    {
                        // Only consider, if pod is in front of station
                        if (_nearestInboundPod[station] == null || _nearestInboundPod[station].GetDistance(station) > Instance.SettingConfig.Tolerance)
                        {
                            continue;
                        }
                        // Reset
                        _bestCandidateSelectorFastLane.Recycle();
                        Order bestOrder = null;
                        _currentStation = station;
                        // Check all queued orders
                        foreach (var order in _stationQueues[station])
                        {
                            // Update current order
                            _currentOrder = order;
                            // Only consider valid assignment
                            if (!ValidFastLaneAssignment(_currentStation, _currentOrder))
                            {
                                continue;
                            }
                            // Assess
                            if (_bestCandidateSelectorFastLane.Reassess())
                            {
                                bestOrder = _currentOrder;
                            }
                        }
                        // Commit best assignment
                        if (bestOrder != null)
                        {
                            success = true;
                            _stationQueues[station].Remove(bestOrder);
                            AllocateOrder(bestOrder, station);
                        }
                        else
                        {
                            // Reset
                            _bestCandidateSelectorFastLane.Recycle();
                            bestOrder       = null;
                            _currentStation = station;
                            // Check all pending orders
                            foreach (var order in _pendingOrders)
                            {
                                // Update current order
                                _currentOrder = order;
                                // Only consider valid assignment
                                if (!ValidFastLaneAssignment(_currentStation, _currentOrder))
                                {
                                    continue;
                                }
                                // Assess
                                if (_bestCandidateSelectorFastLane.Reassess())
                                {
                                    bestOrder = _currentOrder;
                                }
                            }
                            // Commit best assignment
                            if (bestOrder != null)
                            {
                                success = true;
                                _pendingOrders.Remove(bestOrder);
                                AllocateOrder(bestOrder, station);
                            }
                        }
                    }
                }while (success);
            }

            // --> ASSIGN ORDERS FROM QUEUES TO STATIONS
            do
            {
                // Reset indicator
                success = false;
                // Assign orders from queue for all valid stations
                foreach (var station in Instance.OutputStations.Where(s => validStation(s)))
                {
                    // Reset
                    _bestCandidateSelectorStation.Recycle();
                    Order bestOrder = null;
                    _currentStation = station;
                    // Check all queued orders
                    foreach (var order in _stationQueues[station].Where(o => o.Positions.All(p => Instance.StockInfo.GetActualStock(p.Key) >= p.Value)))
                    {
                        // Update current order
                        _currentOrder = order;
                        // Assess
                        if (_bestCandidateSelectorStation.Reassess())
                        {
                            bestOrder = _currentOrder;
                        }
                    }
                    // Commit best assignment
                    if (bestOrder != null)
                    {
                        success = true;
                        _stationQueues[station].Remove(bestOrder);
                        AllocateOrder(bestOrder, station);
                    }
                }
            }while (success);
        }
Exemple #5
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);
                }
            }
        }
Exemple #6
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()
        {
            // If not initialized, do it now
            if (_bestCandidateSelectOrder == null)
            {
                Initialize();
            }
            // Define filter functions
            Func <OutputStation, bool> validStationNormalAssignment   = _config.FastLane ? (Func <OutputStation, bool>)IsAssignableKeepFastLaneSlot : IsAssignable;
            Func <OutputStation, bool> validStationFastLaneAssignment = IsAssignable;

            // Get some meta info
            PrepareAssessment();
            // Assign fast lane orders while possible
            bool furtherOptions = true;

            while (furtherOptions && _config.FastLane)
            {
                // Prepare helpers
                OutputStation chosenStation = null;
                Order         chosenOrder   = null;
                _bestCandidateSelectFastLane.Recycle();
                // Look for next station to assign orders to
                foreach (var station in Instance.OutputStations
                         // Station has to be valid
                         .Where(s => validStationFastLaneAssignment(s)))
                {
                    // Set station
                    _currentStation = station;
                    // Check whether there is a suitable pod
                    if (_nearestInboundPod[station] != null && _nearestInboundPod[station].GetDistance(station) < Instance.SettingConfig.Tolerance)
                    {
                        // Search for best order for the station in all fulfillable orders
                        foreach (var order in _pendingOrders.Where(o =>
                                                                   // Order needs to be immediately fulfillable
                                                                   o.Positions.All(p => _nearestInboundPod[station].CountAvailable(p.Key) >= p.Value)))
                        {
                            // Set order
                            _currentOrder = order;
                            // --> Assess combination
                            if (_bestCandidateSelectFastLane.Reassess())
                            {
                                chosenStation = _currentStation;
                                chosenOrder   = _currentOrder;
                            }
                        }
                    }
                }
                // Assign best order if available
                if (chosenOrder != null)
                {
                    // Assign the order
                    AllocateOrder(chosenOrder, chosenStation);
                    // Log fast lane assignment
                    Instance.StatCustomControllerInfo.CustomLogOB1++;
                }
                else
                {
                    // No more options to assign orders to stations
                    furtherOptions = false;
                }
            }
            // Repeat normal assignment until no further options
            furtherOptions = true;
            while (furtherOptions)
            {
                // Prepare some helper values
                if (_config.OrderSelectionRule == DefaultOrderSelection.FrequencyAge)
                {
                    _oldestOrderTimestamp = _pendingOrders.Where(o => o.Positions.All(p => Instance.StockInfo.GetActualStock(p.Key) >= p.Value)).MinOrDefault(o => o.TimeStamp, -1);
                    _newestOrderTimestamp = _pendingOrders.Where(o => o.Positions.All(p => Instance.StockInfo.GetActualStock(p.Key) >= p.Value)).MaxOrDefault(o => o.TimeStamp, -1);
                    // Avoid division by zero, if necessary
                    if (_oldestOrderTimestamp == _newestOrderTimestamp)
                    {
                        _newestOrderTimestamp += 1;
                    }
                }
                // Choose order
                _bestCandidateSelectOrder.Recycle();
                Order bestOrder = null;
                foreach (var order in _pendingOrders.Where(o => o.Positions.All(p => Instance.StockInfo.GetActualStock(p.Key) >= p.Value)))
                {
                    // Update candidate
                    _currentOrder = order;
                    // Assess next order
                    if (_bestCandidateSelectOrder.Reassess())
                    {
                        bestOrder = _currentOrder;
                    }
                }
                // Check success
                if (bestOrder != null)
                {
                    // Try to reuse the last station for this order
                    OutputStation bestStation = null;
                    bool          recycling   = false;
                    if (_config.Recycle && _lastChosenStation != null && _lastChosenStation.Active && _lastChosenStation.FitsForReservation(bestOrder))
                    {
                        // Last chosen station can be used for this order too
                        bestStation = _lastChosenStation;
                        recycling   = true;
                    }
                    else
                    {
                        // Choose new station
                        _bestCandidateSelectStation.Recycle();
                        foreach (var station in Instance.OutputStations.Where(s => validStationNormalAssignment(s)))
                        {
                            // Update candidate
                            _currentStation = station;
                            // Assess next order
                            if (_bestCandidateSelectStation.Reassess())
                            {
                                bestStation = _currentStation;
                            }
                        }
                        // Store decision
                        _lastChosenStation = bestStation;
                    }

                    // Check success
                    if (bestStation != null)
                    {
                        // Add the assignment to the ready list
                        AllocateOrder(bestOrder, bestStation);
                        // Log score statistics (order)
                        if (_statScorerValuesOrder == null)
                        {
                            _statScorerValuesOrder = _bestCandidateSelectOrder.BestScores.ToArray();
                        }
                        else
                        {
                            for (int i = 0; i < _bestCandidateSelectOrder.BestScores.Length; i++)
                            {
                                _statScorerValuesOrder[i] += _bestCandidateSelectOrder.BestScores[i];
                            }
                        }
                        _statOrderSelections++;
                        Instance.StatCustomControllerInfo.CustomLogOB1 = _statScorerValuesOrder[0] / _statOrderSelections;
                        // Log score statistics (station)
                        if (!recycling)
                        {
                            if (_statScorerValuesStation == null)
                            {
                                _statScorerValuesStation = _bestCandidateSelectStation.BestScores.ToArray();
                            }
                            else
                            {
                                for (int i = 0; i < _bestCandidateSelectStation.BestScores.Length; i++)
                                {
                                    _statScorerValuesStation[i] += _bestCandidateSelectStation.BestScores[i];
                                }
                            }
                            _statStationSelections++;
                            Instance.StatCustomControllerInfo.CustomLogOB2 = _statScorerValuesStation[0] / _statStationSelections;
                        }
                    }
                    else
                    {
                        // No further options
                        furtherOptions = false;
                    }
                }
                else
                {
                    // No further options
                    furtherOptions = false;
                }
            }
        }
Exemple #7
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);
            }
        }