public List <KeyValuePair <HitFrame, HitFrame> > checkTappingConsistency()
        {
            var times = new List <KeyValuePair <HitFrame, HitFrame> >();

            double limit = (90 * (replay.Mods.HasFlag(Mods.DoubleTime) ? 1.5 : 1));

            for (int i = 0; i < hits.Count - 1; ++i)
            {
                HitFrame hit1 = hits[i], hit2 = hits[i + 1];

                if (((hit2.frame.Time - hit1.frame.Time <= limit) || (hit2.note.StartTime - hit1.note.StartTime <= limit)) && ((hit1.key & hit2.key) > 0))
                {
                    times.Add(new KeyValuePair <HitFrame, HitFrame>(hit1, hit2));
                }
            }

            return(times);
        }
        private void associateHits()
        {
            int        keyIndex = 0;
            Keys       lastKey;
            KeyCounter keyCounter = new KeyCounter();

            if ((replay.Mods & Mods.HardRock) > 0)
            {
                applyHardrock();
            }

            int breakIndex = 0;
            int combo      = 0;

            for (int i = 0; i < beatmap.HitObjects.Count; ++i)
            {
                CircleObject note                 = beatmap.HitObjects[i];
                bool         noteHitFlag          = false;
                bool         noteAttemptedHitFlag = false;

                if ((note.Type.HasFlag(HitObjectType.Spinner)))
                {
                    continue;
                }

                for (int j = keyIndex; j < replay.ReplayFrames.Count; ++j)
                {
                    ReplayFrame frame = replay.ReplayFrames[j];
                    lastKey = j > 0 ? replay.ReplayFrames[j - 1].Keys : Keys.None;

                    Keys pressedKey = Utils.getKey(lastKey, frame.Keys);

                    if (breakIndex < breaks.Count && frame.Time > breaks[breakIndex].EndTime)
                    {
                        ++breakIndex;
                    }

                    if (frame.Time >= beatmap.HitObjects[0].StartTime - hitTimeWindow && (breakIndex >= breaks.Count || frame.Time < this.breaks[breakIndex].StartTime - hitTimeWindow))
                    {
                        keyCounter.Update(lastKey, frame.Keys);
                    }

                    frame.keyCounter = new KeyCounter(keyCounter);

                    if (frame.Time - note.StartTime > hitTimeWindow)
                    {
                        break;
                    }

                    if (pressedKey > 0 && Math.Abs(frame.Time - note.StartTime) <= hitTimeWindow)
                    {
                        if (note.ContainsPoint(new BMAPI.Point2(frame.X, frame.Y)))
                        {
                            noteAttemptedHitFlag = true;
                            ++combo;
                            frame.combo = combo;
                            noteHitFlag = true;
                            HitFrame hitFrame = new HitFrame(note, frame, pressedKey);
                            hits.Add(hitFrame);
                            lastKey  = frame.Keys;
                            keyIndex = j + 1;
                            break;
                        }
                        else
                        {
                            if (Utils.dist(note.Location.X, note.Location.Y, frame.X, frame.Y) > 150)
                            {
                                extraHits.Add(new ClickFrame(frame, Utils.getKey(lastKey, frame.Keys)));
                            }
                            else
                            {
                                noteAttemptedHitFlag = true;
                                attemptedHits.Add(new HitFrame(note, frame, pressedKey));
                            }
                        }
                    }
                    if (pressedKey > 0 && Math.Abs(frame.Time - note.StartTime) <= 3 * hitTimeWindow && note.ContainsPoint(new BMAPI.Point2(frame.X, frame.Y)))
                    {
                        noteAttemptedHitFlag = true;
                        attemptedHits.Add(new HitFrame(note, frame, pressedKey));
                    }

                    lastKey = frame.Keys;

                    frame.combo = combo;
                }

                if (!noteHitFlag)
                {
                    misses.Add(new ReplayMissFrame(replay.ReplayFrames[keyIndex], keyIndex, note));
                }
                if (!noteAttemptedHitFlag)
                {
                    effortlessMisses.Add(note);
                }
            }
        }