/// <summary>Unplaces the restricted spot.</summary> /// <param name="smoothPass">The smooth pass.</param> /// <param name="smoothSpot">The smooth spot.</param> /// <param name="smoothBreak">The smooth break.</param> /// <param name="spotActionMessage">The spot action message.</param> /// <param name="spotIdsUsed">The spot ids used.</param> private void UnplaceRestrictedSpot( SmoothPass smoothPass, SmoothSpot smoothSpot, SmoothBreak smoothBreak, string spotActionMessage, ISet <Guid> spotIdsUsed) { RaiseInfo( $"Unplacing booked spot {smoothSpot.Spot.ExternalSpotRef} " + $"from break {smoothBreak.TheBreak.ExternalBreakRef}: {spotActionMessage}" ); SpotPlacementService.RemoveSpotFromBreak( smoothBreak, smoothSpot.Spot, spotIdsUsed, _sponsorshipRestrictionService ); smoothSpot.IsCurrent = true; _smoothDiagnostics.LogSpotAction( smoothPass, 0, smoothSpot.Spot, smoothBreak, SmoothSpot.SmoothSpotActions.RemoveSpotFromBreak, spotActionMessage); }
public void LogBestBreakFactorMessage( SmoothPass smoothPass, SmoothPassDefaultIteration smoothPassIteration, BestBreakFactorGroup bestBreakFactorGroup, Break theBreak, IReadOnlyCollection <Spot> spots, decimal?bestBreakScore, string message) { if (!_isloggingEnabled || !_logBestBreakFactor) { return; } string file = _logFilenameFactory.FilenameFor(LogFilenameFactory.LogFileType.BestBreak); bool addHeaders = !File.Exists(file); int attempts = 0; do { attempts++; try { using var writer = new StreamWriter(file, true); if (addHeaders) { writer.WriteLine(string.Format("{1}{0}{2}{0}{3}{0}{4}{0}{5}{0}{6}{0}{7}{0}{8}{0}{9}{0}{10}", Delimiter, "ProcessorDateTime", "PassSeq", "PassIterationSeq", "PlaceSpotsSeq", "GroupName", "GroupSeq", "ExternalBreakRef", "Spots", "BestBreakScore", "Message")); } writer.WriteLine(string.Format("{1}{0}{2}{0}{3}{0}{4}{0}{5}{0}{6}{0}{7}{0}{8}{0}{9}{0}{10}", Delimiter, _processorDateTimeToString, smoothPass == null ? "" : smoothPass.Sequence.ToString(), smoothPassIteration == null ? "" : smoothPassIteration.Sequence.ToString(), 0, bestBreakFactorGroup == null ? "" : bestBreakFactorGroup.Name, bestBreakFactorGroup == null ? "" : bestBreakFactorGroup.Sequence.ToString(), theBreak == null ? "" : theBreak.ExternalBreakRef, spots == null || spots.Count == 0 ? "" : SpotUtilities.GetListOfSpotExternalReferences(",", spots), bestBreakScore == null ? "" : bestBreakScore.Value.ToString("0.000000000000000000000000000000"), message)); writer.Flush(); writer.Close(); return; } catch (Exception exception) when(IsExceptionForFileInUse(exception) && attempts < 10) { Thread.Sleep(100); } } while (attempts != -1); }
/// <summary> /// Executes action to move spot(s) to unplaced list /// </summary> private void ExecuteMoveToUnplacedAction( SmoothPass smoothPass, int smoothPassIteration, SmoothActionMoveSpotToUnplaced smoothAction, IReadOnlyCollection <SmoothBreak> progSmoothBreaks, ICollection <Guid> spotIdsUsed, bool logSpotAction) { foreach (var externalSpotRef in smoothAction.ExternalSpotRefs) { MoveSpotToUnplacedList( smoothPass, smoothPassIteration, externalSpotRef, progSmoothBreaks, spotIdsUsed, logSpotAction); } }
/// <summary> /// Moves the spot to the unplaced spots list /// </summary> private void MoveSpotToUnplacedList( SmoothPass smoothPass, int smoothPassIteration, string externalSpotRef, IReadOnlyCollection <SmoothBreak> progSmoothBreaks, ICollection <Guid> spotIdsUsed, bool logSpotAction) { // Find the break that spot is placed in var smoothBreak = progSmoothBreaks.FirstOrDefault(sb => sb.SmoothSpots.Any(s => s.Spot.ExternalSpotRef == externalSpotRef) ); if (smoothBreak is null) { return; } // Spot was placed in break var smoothSpot = smoothBreak.SmoothSpots.FirstOrDefault(s => s.Spot.ExternalSpotRef == externalSpotRef); SpotPlacementService.RemoveSpotFromBreak( smoothBreak, smoothSpot.Spot, spotIdsUsed, _sponsorshipRestrictionService ); if (logSpotAction) { _smoothDiagnostics.LogSpotAction( smoothPass, smoothPassIteration, smoothSpot.Spot, smoothBreak, SmoothSpot.SmoothSpotActions.RemoveSpotFromBreak, "Scenario"); } }
private void LogBestBreakFactorScore( SmoothPass smoothPass, SmoothPassDefaultIteration smoothPassIteration, SmoothBreak smoothBreak, IReadOnlyCollection <Spot> spots, decimal breakScore, BestBreakFactorGroup bestBreakFactorGroup, string scoreDebug, string type) { var spotsDuration = Duration.Zero; foreach (var spot in spots) { spotsDuration = spotsDuration.Plus(spot.SpotLength); } string spotList = SpotUtilities.GetSpotDetailsListString(spots); var message = new StringBuilder(128); _ = message .AppendFormat("Break={0}; ", smoothBreak.TheBreak.ExternalBreakRef) .AppendFormat("BreakDur={0} sec(s);", ((int)smoothBreak.TheBreak.Duration.ToTimeSpan().TotalSeconds).ToString()) .AppendFormat("Avail={0}s;", ((int)smoothBreak.RemainingAvailability.ToTimeSpan().TotalSeconds).ToString()) .AppendFormat("SpotsDetails={0}; ", spotList) .AppendFormat("SpotsLength={0}s; ", ((int)spotsDuration.ToTimeSpan().TotalSeconds).ToString()) .AppendFormat("ScoreDebug={0}; ", scoreDebug) .AppendFormat("Type={0}", type) ; _smoothDiagnostics.LogBestBreakFactorMessage( smoothPass, smoothPassIteration, bestBreakFactorGroup, smoothBreak.TheBreak, spots, breakScore, message.ToString()); }
/// <summary> /// Execute the action to move a spot /// </summary> private void ExecuteMoveSpotToBreakAction( SmoothPass smoothPass, int smoothPassIteration, SmoothActionMoveSpotToBreak smoothAction, IReadOnlyCollection <SmoothBreak> progSmoothBreaks, ICollection <Guid> spotIdsUsed, bool logSpotAction) { var externalSpotRefs = smoothAction.ExternalSpotRefs.ToList(); var externalBreakRefs = smoothAction.ExternalBreakRefs.ToList(); for (int index = 0; index < externalSpotRefs.Count; index++) { MoveSpotToBreak( smoothPass, smoothPassIteration, externalSpotRefs[index], externalBreakRefs[index], progSmoothBreaks, spotIdsUsed, logSpotAction); } }
/// <summary> /// Executes the scenario /// </summary> public void Execute( SmoothPass smoothPass, int smoothPassIteration, SmoothScenario smoothScenario, IReadOnlyCollection <SmoothBreak> progSmoothBreaks, ICollection <Guid> spotIdsUsed, bool logSpotAction) { foreach (var action in smoothScenario.Actions.OrderBy(a => a.Sequence)) { switch (action) { case SmoothActionMoveSpotToUnplaced unplaceAction: ExecuteMoveToUnplacedAction( smoothPass, smoothPassIteration, unplaceAction, progSmoothBreaks, spotIdsUsed, logSpotAction); break; case SmoothActionMoveSpotToBreak moveToBreakAction: ExecuteMoveSpotToBreakAction( smoothPass, smoothPassIteration, moveToBreakAction, progSmoothBreaks, spotIdsUsed, logSpotAction); break; } } }
/// <summary> /// Moves the spot to the break /// </summary> private void MoveSpotToBreak( SmoothPass smoothPass, int smoothPassIteration, string externalSpotRef, string externalBreakRef, IReadOnlyCollection <SmoothBreak> progSmoothBreaks, ICollection <Guid> spotIdsUsed, bool logSpotAction) { // Find the break that spot is placed in var srcSmoothBreak = progSmoothBreaks.FirstOrDefault(sb => sb.SmoothSpots.Any(s => s.Spot.ExternalSpotRef == externalSpotRef) ); if (srcSmoothBreak is null) { return; } SmoothSpot smoothSpot = srcSmoothBreak.SmoothSpots .First(s => s.Spot.ExternalSpotRef == externalSpotRef); SpotPlacementService.RemoveSpotFromBreak( srcSmoothBreak, smoothSpot.Spot, spotIdsUsed, _sponsorshipRestrictionService ); if (logSpotAction) { _smoothDiagnostics.LogSpotAction( smoothPass, smoothPassIteration, smoothSpot.Spot, srcSmoothBreak, SmoothSpot.SmoothSpotActions.RemoveSpotFromBreak, "Scenario"); } // Find the break that spot should be placed in. var dstSmoothBreak = progSmoothBreaks.FirstOrDefault(sb => sb.TheBreak.ExternalBreakRef == externalBreakRef); if (dstSmoothBreak is null) { return; } _ = SpotPlacementService.AddSpotsToBreak( dstSmoothBreak, smoothSpot.SmoothPassSequence, smoothPassIterationSequence: 0, new List <Spot>() { smoothSpot.Spot }, SpotPositionRules.Exact, canMoveSpotToOtherBreak: true, spotIdsUsed, bestBreakFactorGroupName: null, _spotInfos, _sponsorshipRestrictionService); if (logSpotAction) { _smoothDiagnostics.LogSpotAction( smoothPass, smoothPassIteration, smoothSpot.Spot, dstSmoothBreak, SmoothSpot.SmoothSpotActions.PlaceSpotInBreak, "Scenario"); } }
/// <summary> /// Returns best break to add spot(s) to. /// </summary> public BestBreakResult GetBestBreak( SmoothPass smoothPass, SmoothPassDefaultIteration smoothPassIteration, IReadOnlyCollection <BestBreakFactorGroup> bestBreakFactorGroups, IReadOnlyCollection <SmoothBreak> validSmoothBreaks, IReadOnlyCollection <Spot> spotsToPlace, IReadOnlyDictionary <Guid, SpotInfo> spotInfos, IReadOnlyDictionary <string, Clash> clashesByExternalRef, IReadOnlyDictionary <string, Product> productsByExternalRef, IReadOnlyCollection <SmoothBreak> progSmoothBreaks, out BestBreakFactorGroup usedBestBreakFactorGroup) { var bestBreakResult = new BestBreakResult(); usedBestBreakFactorGroup = null; string breakDetailsListString = BreakUtilities.GetListOfBreakExternalReferences( "; ", validSmoothBreaks.Select(sb => sb.TheBreak).ToList()); // Get spot details list as string string spotDetailsListString = SpotUtilities.GetSpotDetailsListString(spotsToPlace); // Check each group in priority order foreach (var bestBreakFactorGroup in bestBreakFactorGroups.OrderBy(g => g.Sequence)) { _smoothDiagnostics.LogBestBreakFactorMessage( smoothPass, smoothPassIteration, bestBreakFactorGroup, null, spotsToPlace, null, $"Checking best break factor group (Breaks={breakDetailsListString}; Spots={spotDetailsListString})" ); // Set all breaks to check var smoothBreaksRemaining = new List <SmoothBreak>(); smoothBreaksRemaining.AddRange(validSmoothBreaks); // Generate unique random score for each break so that we can // pick a random break if necessary. IReadOnlyCollection <double> randomScoreByBreak = GetRandomScoreByBreak( progSmoothBreaks, uniqueScore: true); // Calculate scores for each break, determine best score var scoreByBreak = new Dictionary <SmoothBreak, decimal>(); decimal bestBreakScore = -1; foreach (var smoothBreak in smoothBreaksRemaining) { var(breakScore, scoreDebug) = _bestBreakFactorForGroupService .GetBestBreakFactorScoreForGroup( smoothBreak, spotsToPlace, spotInfos, clashesByExternalRef, productsByExternalRef, progSmoothBreaks, randomScoreByBreak, bestBreakFactorGroup, _smoothResources ); LogBestBreakFactorScore( smoothPass, smoothPassIteration, smoothBreak, spotsToPlace, breakScore, bestBreakFactorGroup, "Main", scoreDebug ); scoreByBreak.Add(smoothBreak, breakScore); if (breakScore > bestBreakScore || bestBreakScore == -1) { bestBreakScore = breakScore; } } if (bestBreakScore > 0) // At least one break has a non-zero score { // Remove all breaks with score less than the best score var smoothBreaksToRemove = new List <SmoothBreak>(); foreach (var smoothBreak in smoothBreaksRemaining) { if (scoreByBreak[smoothBreak] < bestBreakScore) { smoothBreaksToRemove.Add(smoothBreak); } } while (smoothBreaksToRemove.Count > 0) { _ = smoothBreaksRemaining.Remove(smoothBreaksToRemove[0]); smoothBreaksToRemove.RemoveAt(0); } // Single break with best score, return it if (smoothBreaksRemaining.Count == 1) { _smoothDiagnostics.LogBestBreakFactorMessage( smoothPass, smoothPassIteration, bestBreakFactorGroup, smoothBreaksRemaining[0].TheBreak, spotsToPlace, bestBreakScore, $"Using single break which has best score (Spots={spotDetailsListString})" ); usedBestBreakFactorGroup = bestBreakFactorGroup; bestBreakResult.Score = bestBreakScore; bestBreakResult.SmoothBreak = smoothBreaksRemaining[0]; return(bestBreakResult); } // Multiple breaks with best score, determine what we do if (smoothBreaksRemaining.Count > 1) { switch (bestBreakFactorGroup.SameBreakGroupScoreAction) { // Check next group, our default and so no action // required here case SameBreakGroupScoreActions.CheckNextGroup: _smoothDiagnostics.LogBestBreakFactorMessage( smoothPass, smoothPassIteration, bestBreakFactorGroup, null, spotsToPlace, null, "CheckNextGroup: Need to check next group" ); break; // Check single factor to identify single break case SameBreakGroupScoreActions.UseSingleBreakFactorIfBestScoreIsNonZero: // Calculate score for each remaining break _smoothDiagnostics.LogBestBreakFactorMessage( smoothPass, smoothPassIteration, bestBreakFactorGroup, null, spotsToPlace, null, $"UseSingleBreakFactorIfBestScoreIsNonZero: Finding break for single break factor score for group (BreaksRemaining={smoothBreaksRemaining.Count.ToString()})" ); var scoreByBreak2 = new Dictionary <SmoothBreak, decimal>(); decimal bestBreakScore2 = -1; foreach (var smoothBreak in smoothBreaksRemaining) { decimal breakScore2 = _bestBreakFactorService .GetBestBreakFactorScoreForFactor( smoothBreak, spotsToPlace, spotInfos, clashesByExternalRef, productsByExternalRef, progSmoothBreaks, randomScoreByBreak, bestBreakFactorGroup.SameBreakGroupScoreFactor, _smoothResources ); var scoreDebug = $"UseSingleBreakFactorIfBestScoreIsNonZero: {bestBreakFactorGroup.SameBreakGroupScoreFactor.Factor.ToString()}={breakScore2.ToString("0.000000000000000000000000000000")}"; LogBestBreakFactorScore( smoothPass, smoothPassIteration, smoothBreak, spotsToPlace, breakScore2, bestBreakFactorGroup, "", scoreDebug ); scoreByBreak2.Add(smoothBreak, breakScore2); if (breakScore2 > bestBreakScore2 || bestBreakScore2 == -1) { bestBreakScore2 = breakScore2; } } // Remove all but the break with the best score var smoothBreaksToRemove2 = new List <SmoothBreak>(); foreach (var smoothBreak in smoothBreaksRemaining) { if (scoreByBreak2[smoothBreak] < bestBreakScore2) { smoothBreaksToRemove2.Add(smoothBreak); } } while (smoothBreaksToRemove2.Count > 0) { _ = smoothBreaksRemaining.Remove(smoothBreaksToRemove2[0]); smoothBreaksToRemove2.RemoveAt(0); } // Return first break Sanity check, if no break // then check next group if (smoothBreaksRemaining.Count > 0) { _smoothDiagnostics.LogBestBreakFactorMessage( smoothPass, smoothPassIteration, bestBreakFactorGroup, smoothBreaksRemaining[0].TheBreak, spotsToPlace, null, string.Format("UseSingleBreakFactorIfBestScoreIsNonZero: Found break for single break factor score for group (Spots={0}; BreaksRemaining={1})", spotDetailsListString, smoothBreaksRemaining.Count) ); usedBestBreakFactorGroup = bestBreakFactorGroup; bestBreakResult.Score = bestBreakScore2; bestBreakResult.SmoothBreak = smoothBreaksRemaining[0]; return(bestBreakResult); } else { _smoothDiagnostics.LogBestBreakFactorMessage( smoothPass, smoothPassIteration, bestBreakFactorGroup, null, spotsToPlace, null, string.Format("UseSingleBreakFactorIfBestScoreIsNonZero: WARNING: Not found break for single break factor score for group (Spots={0}; BreaksRemaining={1})", spotDetailsListString, smoothBreaksRemaining.Count) ); } break; } } } else // No break has a non-zero score, check next group { _smoothDiagnostics.LogBestBreakFactorMessage( smoothPass, smoothPassIteration, bestBreakFactorGroup, null, spotsToPlace, null, "No breaks with highest score, checking next group" ); } } _smoothDiagnostics.LogBestBreakFactorMessage( smoothPass, smoothPassIteration, null, null, spotsToPlace, null, "No best break for spots" ); // All groups checked, no best break, shouldn't really happen, // possibly bad configuration return(bestBreakResult); }