public override double Calculate(Dictionary <string, double> categoryDifficulty = null) { OsuDifficultyBeatmap beatmap = new OsuDifficultyBeatmap((List <OsuHitObject>)Beatmap.HitObjects, TimeRate); Skill[] skills = { new Aim(), new Speed() }; double sectionLength = section_length * TimeRate; // The first object doesn't generate a strain, so we begin with an incremented section end double currentSectionEnd = 2 * sectionLength; foreach (OsuDifficultyHitObject h in beatmap) { while (h.BaseObject.StartTime > currentSectionEnd) { foreach (Skill s in skills) { s.SaveCurrentPeak(); s.StartNewSectionFrom(currentSectionEnd); } currentSectionEnd += sectionLength; } foreach (Skill s in skills) { s.Process(h); } } double aimRating = Math.Sqrt(skills[0].DifficultyValue()) * difficulty_multiplier; double speedRating = Math.Sqrt(skills[1].DifficultyValue()) * difficulty_multiplier; double avgAimRating = skills[0].AverageDifficultyValue() * aimRating; double avgSpeedRating = skills[1].AverageDifficultyValue() * speedRating; double starRating = aimRating + speedRating + Math.Abs(aimRating - speedRating) / 2; double avgStarRating = avgAimRating + avgSpeedRating + Math.Abs(avgAimRating - avgSpeedRating) / 2; if (categoryDifficulty != null) { categoryDifficulty.Add("Aim", aimRating); categoryDifficulty.Add("Speed", speedRating); // categoryDifficulty.Add("Average Aim", avgAimRating); //categoryDifficulty.Add("Average Speed", avgSpeedRating); categoryDifficulty.Add("Average Star", avgStarRating); } return(starRating); }
public override double Calculate(Dictionary <string, double> categoryDifficulty = null) { OsuDifficultyBeatmap beatmap = new OsuDifficultyBeatmap(Beatmap.HitObjects, TimeRate); Skill[] skills = { new Jump(), new Speed(), new Flow(), }; double sectionEnd = section_length / TimeRate; foreach (OsuDifficultyHitObject h in beatmap) { while (h.BaseObject.StartTime > sectionEnd) { foreach (Skill s in skills) { s.SaveCurrentPeak(); s.StartNewSectionFrom(sectionEnd); } sectionEnd += section_length; } foreach (Skill s in skills) { s.Process(h); } } double jumpRating = Math.Sqrt(skills[0].DifficultyValue()) * difficulty_multiplier; double speedRating = Math.Sqrt(skills[1].DifficultyValue()) * difficulty_multiplier; double flowRating = Math.Sqrt(skills[2].DifficultyValue()) * difficulty_multiplier; double[] list = { jumpRating, speedRating, flowRating }; double max = System.Linq.Enumerable.Max <double>(list); double min = System.Linq.Enumerable.Min <double>(list); double starRating = (jumpRating + speedRating + flowRating) * 2 / 3 + Math.Abs(max - min) / 2; if (categoryDifficulty != null) { categoryDifficulty.Add("Jump", jumpRating); categoryDifficulty.Add("Speed", speedRating); categoryDifficulty.Add("Flow", flowRating); } return(starRating); }
public override double Calculate(Dictionary <string, double> categoryDifficulty = null) { OsuDifficultyBeatmap beatmap = new OsuDifficultyBeatmap(Beatmap.HitObjects, TimeRate); Skill[] skills = { new Aim(), new Speed() }; double sectionEnd = section_length / TimeRate; foreach (OsuDifficultyHitObject h in beatmap) { while (h.BaseObject.StartTime > sectionEnd) { foreach (Skill s in skills) { s.SaveCurrentPeak(); s.StartNewSectionFrom(sectionEnd); } sectionEnd += section_length; } foreach (Skill s in skills) { s.Process(h); } } double aimRating = Math.Sqrt(skills[0].DifficultyValue()) * difficulty_multiplier; double speedRating = Math.Sqrt(skills[1].DifficultyValue()) * difficulty_multiplier; double starRating = aimRating + speedRating + Math.Abs(aimRating - speedRating) / 2; if (categoryDifficulty != null) { categoryDifficulty.Add("Aim", aimRating); categoryDifficulty.Add("Speed", speedRating); } return(starRating); }
protected override DifficultyAttributes Calculate(IBeatmap beatmap, Mod[] mods, double timeRate) { OsuDifficultyBeatmap difficultyBeatmap = new OsuDifficultyBeatmap(beatmap.HitObjects.Cast <OsuHitObject>().ToList(), timeRate); Skill[] skills = { new Aim(), new Speed() }; double sectionLength = section_length * timeRate; // The first object doesn't generate a strain, so we begin with an incremented section end double currentSectionEnd = 2 * sectionLength; foreach (OsuDifficultyHitObject h in difficultyBeatmap) { while (h.BaseObject.StartTime > currentSectionEnd) { foreach (Skill s in skills) { s.SaveCurrentPeak(); s.StartNewSectionFrom(currentSectionEnd); } currentSectionEnd += sectionLength; } foreach (Skill s in skills) { s.Process(h); } } double aimRating = Math.Sqrt(skills[0].DifficultyValue()) * difficulty_multiplier; double speedRating = Math.Sqrt(skills[1].DifficultyValue()) * difficulty_multiplier; double starRating = aimRating + speedRating + Math.Abs(aimRating - speedRating) / 2; return(new OsuDifficultyAttributes(mods, starRating) { AimStrain = aimRating, SpeedStrain = speedRating }); }
protected override DifficultyAttributes Calculate(IBeatmap beatmap, Mod[] mods, double timeRate) { if (!beatmap.HitObjects.Any()) { return(new OsuDifficultyAttributes(mods, 0)); } OsuDifficultyBeatmap difficultyBeatmap = new OsuDifficultyBeatmap(beatmap.HitObjects.Cast <OsuHitObject>().ToList(), timeRate); Skill[] skills = { new Aim(), new Speed() }; double sectionLength = section_length * timeRate; // The first object doesn't generate a strain, so we begin with an incremented section end double currentSectionEnd = Math.Ceiling(beatmap.HitObjects.First().StartTime / sectionLength) * sectionLength; foreach (OsuDifficultyHitObject h in difficultyBeatmap) { while (h.BaseObject.StartTime > currentSectionEnd) { foreach (Skill s in skills) { s.SaveCurrentPeak(); s.StartNewSectionFrom(currentSectionEnd); } currentSectionEnd += sectionLength; } foreach (Skill s in skills) { s.Process(h); } } // The peak strain will not be saved for the last section in the above loop foreach (Skill s in skills) { s.SaveCurrentPeak(); } double aimRating = Math.Sqrt(skills[0].DifficultyValue()) * difficulty_multiplier; double speedRating = Math.Sqrt(skills[1].DifficultyValue()) * difficulty_multiplier; double starRating = aimRating + speedRating + Math.Abs(aimRating - speedRating) / 2; // Todo: These int casts are temporary to achieve 1:1 results with osu!stable, and should be removed in the future double hitWindowGreat = (int)(beatmap.HitObjects.First().HitWindows.Great / 2) / timeRate; double preempt = (int)BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450) / timeRate; int maxCombo = beatmap.HitObjects.Count; // Add the ticks + tail of the slider. 1 is subtracted because the head circle would be counted twice (once for the slider itself in the line above) maxCombo += beatmap.HitObjects.OfType <Slider>().Sum(s => s.NestedHitObjects.Count - 1); return(new OsuDifficultyAttributes(mods, starRating) { AimStrain = aimRating, SpeedStrain = speedRating, ApproachRate = preempt > 1200 ? (1800 - preempt) / 120 : (1200 - preempt) / 150 + 5, OverallDifficulty = (80 - hitWindowGreat) / 6, MaxCombo = maxCombo }); }