1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-06 09:58:21 +08:00

Reorder members for better readability

This commit is contained in:
Bartłomiej Dach 2020-08-22 17:51:35 +02:00
parent 7e2bef3b9f
commit 8ace7df0fd
6 changed files with 158 additions and 160 deletions

View File

@ -13,11 +13,15 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing
private const int roll_min_repetitions = 12;
private const int tl_min_repetitions = 16;
private List<TaikoDifficultyHitObject> hitObjects;
private readonly List<TaikoDifficultyHitObject> hitObjects;
public void FindCheese(List<TaikoDifficultyHitObject> difficultyHitObjects)
public StaminaCheeseDetector(List<TaikoDifficultyHitObject> hitObjects)
{
this.hitObjects = hitObjects;
}
public void FindCheese()
{
hitObjects = difficultyHitObjects;
findRolls(3);
findRolls(4);
findTlTap(0, HitType.Rim);

View File

@ -13,11 +13,10 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing
{
public readonly TaikoDifficultyHitObjectRhythm Rhythm;
public readonly HitType? HitType;
public readonly int ObjectIndex;
public bool StaminaCheese;
public readonly int ObjectIndex;
public TaikoDifficultyHitObject(HitObject hitObject, HitObject lastObject, HitObject lastLastObject, double clockRate, int objectIndex)
: base(hitObject, lastObject, clockRate)
{
@ -45,8 +44,6 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing
};
private TaikoDifficultyHitObjectRhythm getClosestRhythm(double ratio)
{
return common_rhythms.OrderBy(x => Math.Abs(x.Ratio - ratio)).First();
}
=> common_rhythms.OrderBy(x => Math.Abs(x.Ratio - ratio)).First();
}
}

View File

@ -12,11 +12,16 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills
{
public class Colour : Skill
{
private const int mono_history_max_length = 5;
protected override double SkillMultiplier => 1;
protected override double StrainDecayBase => 0.4;
private const int mono_history_max_length = 5;
/// <summary>
/// List of the last <see cref="mono_history_max_length"/> most recent mono patterns, with the most recent at the end of the list.
/// </summary>
private readonly LimitedCapacityQueue<int> monoHistory = new LimitedCapacityQueue<int>(mono_history_max_length);
private HitType? previousHitType;
/// <summary>
@ -24,11 +29,6 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills
/// </summary>
private int currentMonoLength = 1;
/// <summary>
/// List of the last <see cref="mono_history_max_length"/> most recent mono patterns, with the most recent at the end of the list.
/// </summary>
private readonly LimitedCapacityQueue<int> monoHistory = new LimitedCapacityQueue<int>(mono_history_max_length);
protected override double StrainValueOf(DifficultyHitObject current)
{
if (!(current.LastObject is Hit && current.BaseObject is Hit && current.DeltaTime < 1000))

View File

@ -14,17 +14,43 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills
{
protected override double SkillMultiplier => 10;
protected override double StrainDecayBase => 0;
private const double strain_decay = 0.96;
private double currentStrain;
private readonly LimitedCapacityQueue<TaikoDifficultyHitObject> rhythmHistory = new LimitedCapacityQueue<TaikoDifficultyHitObject>(rhythm_history_max_length);
private const double strain_decay = 0.96;
private const int rhythm_history_max_length = 8;
private readonly LimitedCapacityQueue<TaikoDifficultyHitObject> rhythmHistory = new LimitedCapacityQueue<TaikoDifficultyHitObject>(rhythm_history_max_length);
private double currentStrain;
private int notesSinceRhythmChange;
private double repetitionPenalty(int notesSince)
protected override double StrainValueOf(DifficultyHitObject current)
{
return Math.Min(1.0, 0.032 * notesSince);
if (!(current.BaseObject is Hit))
{
resetRhythmStrain();
return 0.0;
}
currentStrain *= strain_decay;
TaikoDifficultyHitObject hitobject = (TaikoDifficultyHitObject)current;
notesSinceRhythmChange += 1;
if (hitobject.Rhythm.Difficulty == 0.0)
{
return 0.0;
}
double objectStrain = hitobject.Rhythm.Difficulty;
objectStrain *= repetitionPenalties(hitobject);
objectStrain *= patternLengthPenalty(notesSinceRhythmChange);
objectStrain *= speedPenalty(hitobject.DeltaTime);
notesSinceRhythmChange = 0;
currentStrain += objectStrain;
return currentStrain;
}
// Finds repetitions and applies penalties
@ -61,6 +87,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills
return true;
}
private double repetitionPenalty(int notesSince) => Math.Min(1.0, 0.032 * notesSince);
private double patternLengthPenalty(int patternLength)
{
double shortPatternPenalty = Math.Min(0.15 * patternLength, 1.0);
@ -78,36 +106,6 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills
return 0.0;
}
protected override double StrainValueOf(DifficultyHitObject current)
{
if (!(current.BaseObject is Hit))
{
resetRhythmStrain();
return 0.0;
}
currentStrain *= strain_decay;
TaikoDifficultyHitObject hitobject = (TaikoDifficultyHitObject)current;
notesSinceRhythmChange += 1;
if (hitobject.Rhythm.Difficulty == 0.0)
{
return 0.0;
}
double objectStrain = hitobject.Rhythm.Difficulty;
objectStrain *= repetitionPenalties(hitobject);
objectStrain *= patternLengthPenalty(notesSinceRhythmChange);
objectStrain *= speedPenalty(hitobject.DeltaTime);
notesSinceRhythmChange = 0;
currentStrain += objectStrain;
return currentStrain;
}
private void resetRhythmStrain()
{
currentStrain = 0.0;

View File

@ -12,32 +12,19 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills
{
public class Stamina : Skill
{
private readonly int hand;
protected override double SkillMultiplier => 1;
protected override double StrainDecayBase => 0.4;
private const int max_history_length = 2;
private readonly int hand;
private readonly LimitedCapacityQueue<double> notePairDurationHistory = new LimitedCapacityQueue<double>(max_history_length);
private double offhandObjectDuration = double.MaxValue;
// Penalty for tl tap or roll
private double cheesePenalty(double notePairDuration)
public Stamina(bool rightHand)
{
if (notePairDuration > 125) return 1;
if (notePairDuration < 100) return 0.6;
return 0.6 + (notePairDuration - 100) * 0.016;
}
private double speedBonus(double notePairDuration)
{
if (notePairDuration >= 200) return 0;
double bonus = 200 - notePairDuration;
bonus *= bonus;
return bonus / 100000;
hand = rightHand ? 1 : 0;
}
protected override double StrainValueOf(DifficultyHitObject current)
@ -71,9 +58,22 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills
return 0;
}
public Stamina(bool rightHand)
// Penalty for tl tap or roll
private double cheesePenalty(double notePairDuration)
{
hand = rightHand ? 1 : 0;
if (notePairDuration > 125) return 1;
if (notePairDuration < 100) return 0.6;
return 0.6 + (notePairDuration - 100) * 0.016;
}
private double speedBonus(double notePairDuration)
{
if (notePairDuration >= 200) return 0;
double bonus = 200 - notePairDuration;
bonus *= bonus;
return bonus / 100000;
}
}
}

View File

@ -29,87 +29,21 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
{
}
private double simpleColourPenalty(double staminaDifficulty, double colorDifficulty)
protected override Skill[] CreateSkills(IBeatmap beatmap) => new Skill[]
{
if (colorDifficulty <= 0) return 0.79 - 0.25;
return 0.79 - Math.Atan(staminaDifficulty / colorDifficulty - 12) / Math.PI / 2;
}
private double norm(double p, params double[] values)
{
return Math.Pow(values.Sum(x => Math.Pow(x, p)), 1 / p);
}
private double rescale(double sr)
{
if (sr < 0) return sr;
return 10.43 * Math.Log(sr / 8 + 1);
}
private double locallyCombinedDifficulty(
double staminaPenalty, Colour colour, Rhythm rhythm, Stamina staminaRight, Stamina staminaLeft)
{
double difficulty = 0;
double weight = 1;
List<double> peaks = new List<double>();
for (int i = 0; i < colour.StrainPeaks.Count; i++)
{
double colourPeak = colour.StrainPeaks[i] * colour_skill_multiplier;
double rhythmPeak = rhythm.StrainPeaks[i] * rhythm_skill_multiplier;
double staminaPeak = (staminaRight.StrainPeaks[i] + staminaLeft.StrainPeaks[i]) * stamina_skill_multiplier * staminaPenalty;
peaks.Add(norm(2, colourPeak, rhythmPeak, staminaPeak));
}
foreach (double strain in peaks.OrderByDescending(d => d))
{
difficulty += strain * weight;
weight *= 0.9;
}
return difficulty;
}
protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate)
{
if (beatmap.HitObjects.Count == 0)
return new TaikoDifficultyAttributes { Mods = mods, Skills = skills };
var colour = (Colour)skills[0];
var rhythm = (Rhythm)skills[1];
var staminaRight = (Stamina)skills[2];
var staminaLeft = (Stamina)skills[3];
double colourRating = colour.DifficultyValue() * colour_skill_multiplier;
double rhythmRating = rhythm.DifficultyValue() * rhythm_skill_multiplier;
double staminaRating = (staminaRight.DifficultyValue() + staminaLeft.DifficultyValue()) * stamina_skill_multiplier;
double staminaPenalty = simpleColourPenalty(staminaRating, colourRating);
staminaRating *= staminaPenalty;
double combinedRating = locallyCombinedDifficulty(staminaPenalty, colour, rhythm, staminaRight, staminaLeft);
double separatedRating = norm(1.5, colourRating, rhythmRating, staminaRating);
double starRating = 1.4 * separatedRating + 0.5 * combinedRating;
starRating = rescale(starRating);
HitWindows hitWindows = new TaikoHitWindows();
hitWindows.SetDifficulty(beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty);
return new TaikoDifficultyAttributes
{
StarRating = starRating,
Mods = mods,
StaminaStrain = staminaRating,
RhythmStrain = rhythmRating,
ColourStrain = colourRating,
// Todo: This int cast is temporary to achieve 1:1 results with osu!stable, and should be removed in the future
GreatHitWindow = (int)hitWindows.WindowFor(HitResult.Great) / clockRate,
MaxCombo = beatmap.HitObjects.Count(h => h is Hit),
Skills = skills
new Colour(),
new Rhythm(),
new Stamina(true),
new Stamina(false),
};
protected override Mod[] DifficultyAdjustmentMods => new Mod[]
{
new TaikoModDoubleTime(),
new TaikoModHalfTime(),
new TaikoModEasy(),
new TaikoModHardRock(),
};
}
protected override IEnumerable<DifficultyHitObject> CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate)
{
@ -131,24 +65,89 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
}
}
new StaminaCheeseDetector().FindCheese(taikoDifficultyHitObjects);
new StaminaCheeseDetector(taikoDifficultyHitObjects).FindCheese();
return taikoDifficultyHitObjects;
}
protected override Skill[] CreateSkills(IBeatmap beatmap) => new Skill[]
protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate)
{
new Colour(),
new Rhythm(),
new Stamina(true),
new Stamina(false),
};
if (beatmap.HitObjects.Count == 0)
return new TaikoDifficultyAttributes { Mods = mods, Skills = skills };
protected override Mod[] DifficultyAdjustmentMods => new Mod[]
var colour = (Colour)skills[0];
var rhythm = (Rhythm)skills[1];
var staminaRight = (Stamina)skills[2];
var staminaLeft = (Stamina)skills[3];
double colourRating = colour.DifficultyValue() * colour_skill_multiplier;
double rhythmRating = rhythm.DifficultyValue() * rhythm_skill_multiplier;
double staminaRating = (staminaRight.DifficultyValue() + staminaLeft.DifficultyValue()) * stamina_skill_multiplier;
double staminaPenalty = simpleColourPenalty(staminaRating, colourRating);
staminaRating *= staminaPenalty;
double combinedRating = locallyCombinedDifficulty(colour, rhythm, staminaRight, staminaLeft, staminaPenalty);
double separatedRating = norm(1.5, colourRating, rhythmRating, staminaRating);
double starRating = 1.4 * separatedRating + 0.5 * combinedRating;
starRating = rescale(starRating);
HitWindows hitWindows = new TaikoHitWindows();
hitWindows.SetDifficulty(beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty);
return new TaikoDifficultyAttributes
{
new TaikoModDoubleTime(),
new TaikoModHalfTime(),
new TaikoModEasy(),
new TaikoModHardRock(),
StarRating = starRating,
Mods = mods,
StaminaStrain = staminaRating,
RhythmStrain = rhythmRating,
ColourStrain = colourRating,
// Todo: This int cast is temporary to achieve 1:1 results with osu!stable, and should be removed in the future
GreatHitWindow = (int)hitWindows.WindowFor(HitResult.Great) / clockRate,
MaxCombo = beatmap.HitObjects.Count(h => h is Hit),
Skills = skills
};
}
private double simpleColourPenalty(double staminaDifficulty, double colorDifficulty)
{
if (colorDifficulty <= 0) return 0.79 - 0.25;
return 0.79 - Math.Atan(staminaDifficulty / colorDifficulty - 12) / Math.PI / 2;
}
private double norm(double p, params double[] values)
{
return Math.Pow(values.Sum(x => Math.Pow(x, p)), 1 / p);
}
private double rescale(double sr)
{
if (sr < 0) return sr;
return 10.43 * Math.Log(sr / 8 + 1);
}
private double locallyCombinedDifficulty(Colour colour, Rhythm rhythm, Stamina staminaRight, Stamina staminaLeft, double staminaPenalty)
{
double difficulty = 0;
double weight = 1;
List<double> peaks = new List<double>();
for (int i = 0; i < colour.StrainPeaks.Count; i++)
{
double colourPeak = colour.StrainPeaks[i] * colour_skill_multiplier;
double rhythmPeak = rhythm.StrainPeaks[i] * rhythm_skill_multiplier;
double staminaPeak = (staminaRight.StrainPeaks[i] + staminaLeft.StrainPeaks[i]) * stamina_skill_multiplier * staminaPenalty;
peaks.Add(norm(2, colourPeak, rhythmPeak, staminaPeak));
}
foreach (double strain in peaks.OrderByDescending(d => d))
{
difficulty += strain * weight;
weight *= 0.9;
}
return difficulty;
}
}
}