Esempio n. 1
0
        private 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

            ManiaHitObjectDifficulty previousHitObject = null;

            foreach (var 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 individualDecay = Math.Pow(ManiaHitObjectDifficulty.INDIVIDUAL_DECAY_BASE, (intervalEndTime - previousHitObject.BaseHitObject.StartTime) / 1000);
                        double overallDecay    = Math.Pow(ManiaHitObjectDifficulty.OVERALL_DECAY_BASE, (intervalEndTime - previousHitObject.BaseHitObject.StartTime) / 1000);
                        maximumStrain = previousHitObject.IndividualStrain * individualDecay + previousHitObject.OverallStrain * overallDecay;
                    }

                    // Go to the next time interval
                    intervalEndTime += actualStrainStep;
                }

                // Obtain maximum strain
                double strain = hitObject.IndividualStrain + hitObject.OverallStrain;
                maximumStrain = Math.Max(strain, maximumStrain);

                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);
        }
Esempio n. 2
0
        private bool calculateStrainValues()
        {
            // Traverse hitObjects in pairs to calculate the strain value of NextHitObject from the strain value of CurrentHitObject and environment.
            using (List <ManiaHitObjectDifficulty> .Enumerator hitObjectsEnumerator = difficultyHitObjects.GetEnumerator())
            {
                if (!hitObjectsEnumerator.MoveNext())
                {
                    return(false);
                }

                ManiaHitObjectDifficulty current = hitObjectsEnumerator.Current;

                // 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())
                {
                    var next = hitObjectsEnumerator.Current;
                    next?.CalculateStrains(current, TimeRate);
                    current = next;
                }

                return(true);
            }
        }
Esempio n. 3
0
        private double calculateDifficulty(List <ManiaHitObjectDifficulty> objects, double timeRate)
        {
            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

            // Strain summation variables
            List <double> summedStrains = new List <double>();

            summedStrains.Add(0);
            double summedStrainsAvg = 0, summedStrainsMax = 0;

            ManiaHitObjectDifficulty previousHitObject = null;

            foreach (var hitObject in objects)
            {
                // While we are beyond the current interval push the currently available maximum to our strain list
                while (hitObject.BaseHitObject.StartTime > intervalEndTime)
                {
                    highestStrains.Add(maximumStrain);
                    summedStrains.Add(0);

                    // 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 individualDecay = Math.Pow(ManiaHitObjectDifficulty.INDIVIDUAL_DECAY_BASE, (intervalEndTime - previousHitObject.BaseHitObject.StartTime) / 1000);
                        double overallDecay    = Math.Pow(ManiaHitObjectDifficulty.OVERALL_DECAY_BASE, (intervalEndTime - previousHitObject.BaseHitObject.StartTime) / 1000);
                        maximumStrain = previousHitObject.IndividualStrain * individualDecay + previousHitObject.OverallStrain * overallDecay;
                    }

                    // Go to the next time interval
                    intervalEndTime += actualStrainStep;
                }

                // Obtain maximum strain
                double strain = hitObject.IndividualStrain + hitObject.OverallStrain;
                summedStrains[summedStrains.Count - 1] += strain;
                maximumStrain = Math.Max(strain, maximumStrain);

                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;
            }

            difficulty *= 0.8;
            difficulty *= star_scaling_factor;

            // Compute summed strains average and max
            foreach (double strain in summedStrains)
            {
                summedStrainsAvg += strain;
                if (strain > summedStrainsMax)
                {
                    summedStrainsMax = strain;
                }
            }
            summedStrainsAvg /= summedStrains.Count;

            // compute bonus or penalty
            double error = 0.0;

            foreach (double strain in summedStrains)
            {
                error += Math.Pow((summedStrainsMax - strain) / summedStrainsAvg, 2.25);
            }
            error /= summedStrains.Count;
            error /= 100.0;

            double rating_weight = Math.Min(difficulty / 2.5, 1.0);
            double star_rating   = (1 - (.025 * rating_weight)) * difficulty;

            if (error <= 0.13)
            {
                double bonus = 1 + ((Math.Pow((0.13 - error) / 0.13, 1.80) * 0.065) * rating_weight);
                star_rating *= bonus;
            }
            else
            {
                double penalty = 1 - ((0.11 - Math.Pow(Math.Max(0.15 - (error - 0.13), 0.0) / 0.15, 1.45) * 0.11) * rating_weight);
                star_rating *= penalty;
            }
            return(star_rating);
        }