Skip to content

Commit ace7482

Browse files
Lawtrohuxtsunyoku
andauthored
Add a consistency factor to osu!taiko diffcalc (#33233)
* add consistency attribute * write attributes to json for serialisation * comment change * fix json, add mechanical difficulty * write new attributes to database --------- Co-authored-by: James Wilson <[email protected]>
1 parent ee055ba commit ace7482

File tree

3 files changed

+57
-9
lines changed

3 files changed

+57
-9
lines changed

osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,23 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
1010
{
1111
public class TaikoDifficultyAttributes : DifficultyAttributes
1212
{
13+
/// <summary>
14+
/// The difficulty corresponding to the mechanical skills in osu!taiko.
15+
/// This includes colour and stamina combined.
16+
/// </summary>
17+
[JsonProperty("mechanical_difficulty")]
18+
public double MechanicalDifficulty { get; set; }
19+
1320
/// <summary>
1421
/// The difficulty corresponding to the rhythm skill.
1522
/// </summary>
23+
[JsonProperty("rhythm_difficulty")]
1624
public double RhythmDifficulty { get; set; }
1725

1826
/// <summary>
1927
/// The difficulty corresponding to the reading skill.
2028
/// </summary>
29+
[JsonProperty("reading_difficulty")]
2130
public double ReadingDifficulty { get; set; }
2231

2332
/// <summary>
@@ -36,9 +45,11 @@ public class TaikoDifficultyAttributes : DifficultyAttributes
3645
[JsonProperty("mono_stamina_factor")]
3746
public double MonoStaminaFactor { get; set; }
3847

39-
public double RhythmTopStrains { get; set; }
40-
41-
public double ColourTopStrains { get; set; }
48+
/// <summary>
49+
/// The factor corresponding to the consistency of a map.
50+
/// </summary>
51+
[JsonProperty("consistency_factor")]
52+
public double ConsistencyFactor { get; set; }
4253

4354
public double StaminaTopStrains { get; set; }
4455

@@ -48,15 +59,23 @@ public class TaikoDifficultyAttributes : DifficultyAttributes
4859
yield return v;
4960

5061
yield return (ATTRIB_ID_DIFFICULTY, StarRating);
62+
yield return (ATTRIB_ID_MECHANICAL_DIFFICULTY, MechanicalDifficulty);
63+
yield return (ATTRIB_ID_RHYTHM_DIFFICULTY, RhythmDifficulty);
64+
yield return (ATTRIB_ID_READING_DIFFICULTY, ReadingDifficulty);
5165
yield return (ATTRIB_ID_MONO_STAMINA_FACTOR, MonoStaminaFactor);
66+
yield return (ATTRIB_ID_CONSISTENCY_FACTOR, ConsistencyFactor);
5267
}
5368

5469
public override void FromDatabaseAttributes(IReadOnlyDictionary<int, double> values, IBeatmapOnlineInfo onlineInfo)
5570
{
5671
base.FromDatabaseAttributes(values, onlineInfo);
5772

5873
StarRating = values[ATTRIB_ID_DIFFICULTY];
74+
MechanicalDifficulty = values[ATTRIB_ID_MECHANICAL_DIFFICULTY];
75+
RhythmDifficulty = values[ATTRIB_ID_RHYTHM_DIFFICULTY];
76+
ReadingDifficulty = values[ATTRIB_ID_READING_DIFFICULTY];
5977
MonoStaminaFactor = values[ATTRIB_ID_MONO_STAMINA_FACTOR];
78+
ConsistencyFactor = values[ATTRIB_ID_CONSISTENCY_FACTOR];
6079
}
6180
}
6281
}

osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,6 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat
115115
double monoStaminaSkill = singleColourStamina.DifficultyValue() * stamina_skill_multiplier;
116116
double monoStaminaFactor = staminaSkill == 0 ? 1 : Math.Pow(monoStaminaSkill / staminaSkill, 5);
117117

118-
double colourDifficultStrains = colour.CountTopWeightedStrains();
119-
double rhythmDifficultStrains = rhythm.CountTopWeightedStrains();
120118
double staminaDifficultStrains = stamina.CountTopWeightedStrains();
121119

122120
// As we don't have pattern integration in osu!taiko, we apply the other two skills relative to rhythm.
@@ -126,7 +124,7 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat
126124
+ Math.Min(Math.Max((staminaDifficultStrains - 1000) / 3700, 0), 0.15)
127125
+ Math.Min(Math.Max((staminaSkill - 7.0) / 1.0, 0), 0.05);
128126

129-
double combinedRating = combinedDifficultyValue(rhythm, reading, colour, stamina, isRelax, isConvert);
127+
double combinedRating = combinedDifficultyValue(rhythm, reading, colour, stamina, isRelax, isConvert, out double consistencyFactor);
130128
double starRating = rescale(combinedRating * 1.4);
131129

132130
// Calculate proportional contribution of each skill to the combinedRating.
@@ -136,19 +134,20 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat
136134
double readingDifficulty = readingSkill * skillRating;
137135
double colourDifficulty = colourSkill * skillRating;
138136
double staminaDifficulty = staminaSkill * skillRating;
137+
double mechanicalDifficulty = colourDifficulty + staminaDifficulty; // Mechanical difficulty is the sum of colour and stamina difficulties.
139138

140139
TaikoDifficultyAttributes attributes = new TaikoDifficultyAttributes
141140
{
142141
StarRating = starRating,
143142
Mods = mods,
143+
MechanicalDifficulty = mechanicalDifficulty,
144144
RhythmDifficulty = rhythmDifficulty,
145145
ReadingDifficulty = readingDifficulty,
146146
ColourDifficulty = colourDifficulty,
147147
StaminaDifficulty = staminaDifficulty,
148148
MonoStaminaFactor = monoStaminaFactor,
149-
RhythmTopStrains = rhythmDifficultStrains,
150-
ColourTopStrains = colourDifficultStrains,
151149
StaminaTopStrains = staminaDifficultStrains,
150+
ConsistencyFactor = consistencyFactor,
152151
MaxCombo = beatmap.GetMaxCombo(),
153152
};
154153

@@ -162,7 +161,7 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat
162161
/// For each section, the peak strains of all separate skills are combined into a single peak strain for the section.
163162
/// The resulting partial rating of the beatmap is a weighted sum of the combined peaks (higher peaks are weighted more).
164163
/// </remarks>
165-
private double combinedDifficultyValue(Rhythm rhythm, Reading reading, Colour colour, Stamina stamina, bool isRelax, bool isConvert)
164+
private double combinedDifficultyValue(Rhythm rhythm, Reading reading, Colour colour, Stamina stamina, bool isRelax, bool isConvert, out double consistencyFactor)
166165
{
167166
List<double> peaks = new List<double>();
168167

@@ -196,9 +195,35 @@ private double combinedDifficultyValue(Rhythm rhythm, Reading reading, Colour co
196195
weight *= 0.9;
197196
}
198197

198+
consistencyFactor = calculateConsistencyFactor(peaks);
199+
199200
return difficulty;
200201
}
201202

203+
/// <summary>
204+
/// Calculates a consistency factor based on how 'spiked' the strain peaks are.
205+
/// Higher values indicate more consistent difficulty, lower values indicate diff-spike heavy maps.
206+
/// </summary>
207+
private double calculateConsistencyFactor(List<double> peaks)
208+
{
209+
// If there are too few sections in a map, assume it is consistent.
210+
if (peaks.Count < 3)
211+
return 1.0;
212+
213+
List<double> sorted = peaks.OrderDescending().ToList();
214+
215+
double topPeak = sorted[0];
216+
double secondTopPeak = sorted.Count > 1 ? sorted[1] : topPeak;
217+
218+
// Compute the average of the middle 50% of strain values.
219+
double midAvg = sorted.Skip(sorted.Count / 4).Take(sorted.Count / 2).Average();
220+
221+
// A higher ratio means the top sections are much harder than the average, indicating inconsistency.
222+
double spikeSeverity = (topPeak + secondTopPeak) / 2.0 / midAvg;
223+
224+
return 1.0 / spikeSeverity;
225+
}
226+
202227
/// <summary>
203228
/// Applies a final re-scaling of the star rating.
204229
/// </summary>

osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ public class DifficultyAttributes
3131
protected const int ATTRIB_ID_NESTED_SCORE_PER_OBJECT = 37;
3232
protected const int ATTRIB_ID_LEGACY_SCORE_BASE_MULTIPLIER = 39;
3333
protected const int ATTRIB_ID_MAXIMUM_LEGACY_COMBO_SCORE = 41;
34+
protected const int ATTRIB_ID_MECHANICAL_DIFFICULTY = 43;
35+
protected const int ATTRIB_ID_RHYTHM_DIFFICULTY = 45;
36+
protected const int ATTRIB_ID_READING_DIFFICULTY = 47;
37+
protected const int ATTRIB_ID_CONSISTENCY_FACTOR = 49;
3438

3539
/// <summary>
3640
/// The mods which were applied to the beatmap.

0 commit comments

Comments
 (0)