1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-14 07:42:57 +08:00

Fix post-merge errors

This commit is contained in:
smoogipoo 2018-06-21 12:26:15 +09:00
parent c9581a2d56
commit 5d0c847835
4 changed files with 82 additions and 50 deletions

View File

@ -0,0 +1,20 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Difficulty;
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Catch.Difficulty
{
public class CatchDifficultyAttributes : DifficultyAttributes
{
public double AimRating;
public double ApproachRate;
public int MaxCombo;
public CatchDifficultyAttributes(Mod[] mods, double starRating)
: base(mods, starRating)
{
}
}
}

View File

@ -2,6 +2,8 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System; using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore.Internal;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Difficulty;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
@ -13,31 +15,39 @@ namespace osu.Game.Rulesets.Catch.Difficulty
{ {
public class CatchDifficultyCalculator : DifficultyCalculator public class CatchDifficultyCalculator : DifficultyCalculator
{ {
/// <summary>
/// In milliseconds. For difficulty calculation we will only look at the highest strain value in each time interval of size STRAIN_STEP.
/// This is to eliminate higher influence of stream over aim by simply having more HitObjects with high strain.
/// The higher this value, the less strains there will be, indirectly giving long beatmaps an advantage.
/// </summary>
private const double strain_step = 750;
/// <summary>
/// The weighting of each strain value decays to this number * it's previous value
/// </summary>
private const double decay_weight = 0.94;
private const double star_scaling_factor = 0.145; private const double star_scaling_factor = 0.145;
private const float playfield_width = CatchPlayfield.BASE_WIDTH;
private readonly List<CatchDifficultyHitObject> difficultyHitObjects = new List<CatchDifficultyHitObject>(); public CatchDifficultyCalculator(Ruleset ruleset, WorkingBeatmap beatmap)
: base(ruleset, beatmap)
public CatchDifficultyCalculator(IBeatmap beatmap)
: base(beatmap)
{ {
} }
public CatchDifficultyCalculator(IBeatmap beatmap, Mod[] mods) protected override DifficultyAttributes Calculate(IBeatmap beatmap, Mod[] mods, double timeRate)
: base(beatmap, mods)
{ {
} if (!beatmap.HitObjects.Any())
return new CatchDifficultyAttributes(mods, 0);
public override double Calculate(Dictionary<string, double> categoryDifficulty = null) float circleSize = beatmap.BeatmapInfo.BaseDifficulty.CircleSize;
{
difficultyHitObjects.Clear();
float circleSize = Beatmap.BeatmapInfo.BaseDifficulty.CircleSize;
float catcherWidth = (1.0f - 0.7f * (circleSize - 5) / 5) * 0.62064f * CatcherArea.CATCHER_SIZE; float catcherWidth = (1.0f - 0.7f * (circleSize - 5) / 5) * 0.62064f * CatcherArea.CATCHER_SIZE;
float catcherWidthHalf = catcherWidth / 2; float catcherWidthHalf = catcherWidth / 2;
catcherWidthHalf *= 0.8f; catcherWidthHalf *= 0.8f;
foreach (var hitObject in Beatmap.HitObjects) var difficultyHitObjects = new List<CatchDifficultyHitObject>();
foreach (var hitObject in beatmap.HitObjects)
{ {
// We want to only consider fruits that contribute to the combo. Droplets are addressed as accuracy and spinners are not relevant for "skill" calculations. // We want to only consider fruits that contribute to the combo. Droplets are addressed as accuracy and spinners are not relevant for "skill" calculations.
if (hitObject is Fruit) if (hitObject is Fruit)
@ -60,28 +70,26 @@ namespace osu.Game.Rulesets.Catch.Difficulty
difficultyHitObjects.Sort((a, b) => a.BaseHitObject.StartTime.CompareTo(b.BaseHitObject.StartTime)); difficultyHitObjects.Sort((a, b) => a.BaseHitObject.StartTime.CompareTo(b.BaseHitObject.StartTime));
if (!CalculateStrainValues()) return 0; if (!calculateStrainValues(difficultyHitObjects, timeRate))
return new CatchDifficultyAttributes(mods, 0);
double starRating = Math.Sqrt(CalculateDifficulty()) * star_scaling_factor; double ar = beatmap.BeatmapInfo.BaseDifficulty.ApproachRate;
double preEmpt = BeatmapDifficulty.DifficultyRange(ar, 1800, 1200, 450) / timeRate;
if (categoryDifficulty != null) double starRating = Math.Sqrt(calculateDifficulty(difficultyHitObjects, timeRate)) * star_scaling_factor;
return new CatchDifficultyAttributes(mods, starRating)
{ {
categoryDifficulty["Aim"] = starRating; AimRating = starRating,
ApproachRate = preEmpt > 1200.0 ? -(preEmpt - 1800.0) / 120.0 : -(preEmpt - 1200.0) / 150.0 + 5.0,
double ar = Beatmap.BeatmapInfo.BaseDifficulty.ApproachRate; MaxCombo = difficultyHitObjects.Count
double preEmpt = BeatmapDifficulty.DifficultyRange(ar, 1800, 1200, 450) / TimeRate; };
categoryDifficulty["AR"] = preEmpt > 1200.0 ? -(preEmpt - 1800.0) / 120.0 : -(preEmpt - 1200.0) / 150.0 + 5.0;
categoryDifficulty["Max combo"] = difficultyHitObjects.Count;
}
return starRating;
} }
protected bool CalculateStrainValues() private bool calculateStrainValues(List<CatchDifficultyHitObject> objects, double timeRate)
{ {
// Traverse hitObjects in pairs to calculate the strain value of NextHitObject from the strain value of CurrentHitObject and environment. // Traverse hitObjects in pairs to calculate the strain value of NextHitObject from the strain value of CurrentHitObject and environment.
using (List<CatchDifficultyHitObject>.Enumerator hitObjectsEnumerator = difficultyHitObjects.GetEnumerator()) using (var hitObjectsEnumerator = objects.GetEnumerator())
{ {
if (!hitObjectsEnumerator.MoveNext()) return false; if (!hitObjectsEnumerator.MoveNext()) return false;
@ -91,7 +99,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty
while (hitObjectsEnumerator.MoveNext()) while (hitObjectsEnumerator.MoveNext())
{ {
CatchDifficultyHitObject nextHitObject = hitObjectsEnumerator.Current; CatchDifficultyHitObject nextHitObject = hitObjectsEnumerator.Current;
nextHitObject?.CalculateStrains(currentHitObject, TimeRate); nextHitObject?.CalculateStrains(currentHitObject, timeRate);
currentHitObject = nextHitObject; currentHitObject = nextHitObject;
} }
@ -99,22 +107,10 @@ namespace osu.Game.Rulesets.Catch.Difficulty
} }
} }
/// <summary> private double calculateDifficulty(List<CatchDifficultyHitObject> objects, double timeRate)
/// In milliseconds. For difficulty calculation we will only look at the highest strain value in each time interval of size STRAIN_STEP.
/// This is to eliminate higher influence of stream over aim by simply having more HitObjects with high strain.
/// The higher this value, the less strains there will be, indirectly giving long beatmaps an advantage.
/// </summary>
private const double strain_step = 750;
/// <summary>
/// The weighting of each strain value decays to this number * it's previous value
/// </summary>
private const double decay_weight = 0.94;
protected double CalculateDifficulty()
{ {
// The strain step needs to be adjusted for the algorithm to be considered equal with speed changing mods // The strain step needs to be adjusted for the algorithm to be considered equal with speed changing mods
double actualStrainStep = strain_step * TimeRate; double actualStrainStep = strain_step * timeRate;
// Find the highest strain value within each strain step // Find the highest strain value within each strain step
List<double> highestStrains = new List<double>(); List<double> highestStrains = new List<double>();
@ -122,7 +118,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty
double maximumStrain = 0; // We need to keep track of the maximum strain in the current interval double maximumStrain = 0; // We need to keep track of the maximum strain in the current interval
CatchDifficultyHitObject previousHitObject = null; CatchDifficultyHitObject previousHitObject = null;
foreach (CatchDifficultyHitObject hitObject in difficultyHitObjects) foreach (CatchDifficultyHitObject hitObject in objects)
{ {
// While we are beyond the current interval push the currently available maximum to our strain list // While we are beyond the current interval push the currently available maximum to our strain list
while (hitObject.BaseHitObject.StartTime > intervalEndTime) while (hitObject.BaseHitObject.StartTime > intervalEndTime)
@ -151,8 +147,16 @@ namespace osu.Game.Rulesets.Catch.Difficulty
previousHitObject = hitObject; previousHitObject = hitObject;
} }
// calculate maximun strain difficulty // Build the weighted sum over the highest strains for each interval
double difficulty = StrainCalculator(highestStrains, decay_weight); 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; return difficulty;
} }

View File

@ -8,7 +8,7 @@ using OpenTK;
namespace osu.Game.Rulesets.Catch.Difficulty namespace osu.Game.Rulesets.Catch.Difficulty
{ {
internal class CatchDifficultyHitObject public class CatchDifficultyHitObject
{ {
internal static readonly double DECAY_BASE = 0.20; internal static readonly double DECAY_BASE = 0.20;
private const float normalized_hitobject_radius = 41.0f; private const float normalized_hitobject_radius = 41.0f;

View File

@ -110,8 +110,16 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
previousHitObject = hitObject; previousHitObject = hitObject;
} }
// calculate maximun strain difficulty // Build the weighted sum over the highest strains for each interval
double difficulty = StrainCalculator(highestStrains, decay_weight); 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; return difficulty;
} }