public static double CalcRating(BeatmapInfo map) { // Call PatternAnalyzer to find Jacks / Spams. var analyzer = new PatternAnalyzer(map.Notes, map.LNs, map.Data.Keys, map.Data.SpecialStyle); var jacks = analyzer.GetJackRatio(); var spams = analyzer.GetSpamRatio(); // Spam correction. // Deduct 'Corrected Max Density' and 'Corrected Average Density' by exponential function. var corMaxDen = map.CorMaxDen * (1 - (Math.Pow(78, spams) - 1) / 100); var corAvgDen = map.CorAvgDen * (1 - (Math.Pow(78, spams) - 1) / 100); // Start from 'Corrected Max Density' var result = corMaxDen; // Density correction. // If 'Corrected Average Density' is really close with 'Corrected Max Density', if (corMaxDen <= corAvgDen * 1.1) { // then it means it's quite hard compared with its max density. // Get bonus score. result += corAvgDen * 0.1; } // If 'Corrected Average Density' is too low than 'Corrected Max Density', else if (corMaxDen >= 3 && corMaxDen >= corAvgDen * 1.5) { // then it means it's quite easy compared with its max density. // Deduct rating score. result -= corMaxDen * 0.1; } // General correction for density. var correction = Math.Pow(6, Math.Log(corMaxDen, corAvgDen + corMaxDen)) - 1; result *= 1 - correction / 10; // Jack correction. // Increase Rating by exponential function. result *= 1 + (Math.Pow(101, jacks) - 1) / 100; // Key correction. // Standard: 6k. // Other key modes' rating value is set to 6k like '(key + 1) / 7'. // If it's special style, than key -= 1. var specialStyle = map.Data.Keys == 8 && (double)(analyzer.Notes[0].Count + analyzer.LNs[0].Count) / analyzer.Count < 0.06; result *= (double)((specialStyle ? map.Data.Keys - 1 : map.Data.Keys) + 1) / 7; // Multiply it only for convenience. result *= 1.6; return(result); }
private static void CalcCorrectedDensityList(ref List <Note> notes, ref List <LongNote> lns, int key, out List <double> density) { int Key; var pat = new PatternAnalyzer(notes, lns, key, false); var corNotes = new List <NoteCount>(); var corLNs = new List <LongNoteCount>(); var Notes = new List <Note>(); var LNs = new List <LongNote>(); density = new List <double>(); var specialStyle = key == 8 && (double)(pat.Notes[0].Count + pat.LNs[0].Count) / pat.Count < 0.06; if (!specialStyle) { Notes = notes; LNs = lns; Key = key; } else { Notes.AddRange(notes.Where(cur => cur.Line != 0)); LNs.AddRange(lns.Where(cur => cur.Line != 0)); Key = key - 1; } var(startPeriod, endPeriod) = GetPeriods(ref notes, ref lns); for (var i = startPeriod; i < endPeriod - 1000; i += 250) { corNotes.Clear(); corLNs.Clear(); // Get the notes in current period. corNotes.AddRange(from cur in Notes where cur.Time >= i && cur.Time <= i + 1000 select new NoteCount(cur.Time, cur.Line, 0)); corLNs.AddRange( from cur in LNs where (cur.Time >= i && cur.Time <= i + 1000) || (cur.Endtime >= i && cur.Endtime <= i + 1000) || (cur.Time <= i && cur.Endtime >= i + 1000) select new LongNoteCount(cur.Time, cur.Endtime, cur.Line, 0)); // Count the LN-count for each notes. foreach (var cur in corLNs) { foreach (var note in corNotes) { if (note.Time >= cur.Time && note.Time < cur.Endtime) { note.LNs++; } } for (var j = corLNs.IndexOf(cur) + 1; j < corLNs.Count; j++) { if ((corLNs[j].Time >= cur.Time && corLNs[j].Time < cur.Endtime) || (corLNs[j].Endtime >= cur.Time && corLNs[j].Endtime <= cur.Endtime) || (corLNs[j].Time <= cur.Time && corLNs[j].Endtime >= cur.Endtime)) { corLNs[j].LNs++; } } } // Correct the density. var den = (corNotes.Sum(cur => (double)Key / (Key - cur.LNs)) + corLNs.Sum(cur => (double)Key / (Key - cur.LNs) * 1.1)) / Key; density.Add(den); } }