protected double CalculateDifficulty() { double ActualStrainStep = STRAIN_STEP * TimeRate; // Find the highest strain value within each strain step List <double> HighestStrains = new List <double>(); double IntervalEndTime = ActualStrainStep; double MaximumStrain = 0; // We need to keep track of the maximum strain in the current interval DifficultyHitObjectTaiko PreviousHitObject = null; foreach (DifficultyHitObjectTaiko hitObject in DifficultyHitObjects) { // While we are beyond the current interval push the currently available maximum to our strain list while (hitObject.BaseHitObject.StartTime > IntervalEndTime) { HighestStrains.Add(MaximumStrain); // The maximum strain of the next interval is not zero by default! We need to take the last hitObject we encountered, take its strain and apply the decay // until the beginning of the next interval. if (PreviousHitObject == null) { MaximumStrain = 0; } else { double Decay = Math.Pow(DifficultyHitObjectTaiko.DECAY_BASE, (double)(IntervalEndTime - PreviousHitObject.BaseHitObject.StartTime) / 1000); MaximumStrain = PreviousHitObject.Strain * Decay; } // Go to the next time interval IntervalEndTime += ActualStrainStep; } // Obtain maximum strain if (hitObject.Strain > MaximumStrain) { MaximumStrain = hitObject.Strain; } PreviousHitObject = hitObject; } // Build the weighted sum over the highest strains for each interval double Difficulty = 0; double Weight = 1; HighestStrains.Sort((a, b) => b.CompareTo(a)); // Sort from highest to lowest strain. foreach (double Strain in HighestStrains) { Difficulty += Weight * Strain; Weight *= DECAY_WEIGHT; } return(Difficulty); }
protected bool CalculateStrainValues() { // Traverse hitObjects in pairs to calculate the strain value of NextHitObject from the strain value of CurrentHitObject and environment. List <DifficultyHitObjectTaiko> .Enumerator HitObjectsEnumerator = DifficultyHitObjects.GetEnumerator(); if (HitObjectsEnumerator.MoveNext() == false) { return(false); } DifficultyHitObjectTaiko CurrentHitObject = HitObjectsEnumerator.Current; DifficultyHitObjectTaiko NextHitObject; // First hitObject starts at strain 1. 1 is the default for strain values, so we don't need to set it here. See DifficultyHitObject. while (HitObjectsEnumerator.MoveNext()) { NextHitObject = HitObjectsEnumerator.Current; NextHitObject.CalculateStrains(CurrentHitObject, TimeRate); CurrentHitObject = NextHitObject; } return(true); }