public static DebugSongScore?DebugMap(BSMap map)
        {
            int len = (int)BSMath.Ceiling(map.Data.Notes.Max(x => (float?)x.Time) ?? 0);

            if (len == 0)
            {
                //throw new InvalidOperationException("Invalid Map");
                return(null);
            }

            var timedRed  = ProcessColor(map, NoteColor.Red);
            var timedBlue = ProcessColor(map, NoteColor.Blue);

            DebugHitScore[] DebugHits(IEnumerable <ScoredClusterHit> arr) => arr.Select(x => { var d = new DebugHitScore(); d.Set(x); return(d); }).ToArray();

            var debugRed  = DebugHits(timedRed);
            var debugBlue = DebugHits(timedBlue);

            return(new DebugSongScore {
                Name = map.Info.SongName,
                DifficultyName = map.MapInfo.Difficulty,
                DataRed = debugRed,
                DataBlue = debugBlue,
            });
        }
        public static SongScore AnalyzeMap(BSMap map)
        {
            int len = (int)BSMath.Ceiling(map.Data.Notes.Max(x => (float?)x.Time) ?? 0);

            if (len == 0)
            {
                return(new SongScore(average: 0, max: 0, graph: Array.Empty <AggregatedHit>()));
            }

            var scoredRed  = ProcessColor(map, NoteColor.Red);
            var scoredBlue = ProcessColor(map, NoteColor.Blue);

            var timedRed  = ConvertToFixedTimeBlocks(scoredRed, len);
            var timedBlue = ConvertToFixedTimeBlocks(scoredBlue, len);

            var combined = new AggregatedHit[len];

            for (int i = 0; i < len; i++)
            {
                int cnt = timedRed[i].HitDifficulty > 0 && timedBlue[i].HitDifficulty > 0 ? 2 : 1;
                combined[i] = (timedRed[i] + timedBlue[i]) / cnt;
            }

            var totalDifficulty = combined.Select(h => h.TotalDifficulty()).ToList();

            return(new SongScore
                   (
                       average: totalDifficulty.Average(),
                       max: totalDifficulty.Max(),
                       graph: combined
                   ));
        }