/// <summary> /// This is called to decide about potentially pending orders. /// This method is being timed for statistical purposes and is also ONLY called when <code>SituationInvestigated</code> is <code>false</code>. /// Hence, set the field accordingly to react on events not tracked by this outer skeleton. /// </summary> protected override void DecideAboutPendingOrders() { foreach (var order in _pendingOrders.Where(o => o.Positions.All(p => Instance.StockInfo.GetActualStock(p.Key) >= p.Value)).ToArray()) { OutputStation chosenStation = null; // Try to reuse the last station for this order if (_config.Recycle && _lastChosenStation != null && _lastChosenStation.Active && _lastChosenStation.FitsForReservation(order)) { // Last chosen station can be used for this order too chosenStation = _lastChosenStation; } else { // Choose a random station chosenStation = Instance.OutputStations .Where(s => s.Active && s.FitsForReservation(order)) // There has to be sufficient capacity left at the station .OrderBy(s => Instance.Randomizer.NextDouble()) // Choose a random one .FirstOrDefault(); _lastChosenStation = chosenStation; } // If we found a station, assign the bundle to it if (chosenStation != null) { AllocateOrder(order, chosenStation); } } }
/// <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; } } }