Source code for circleguard.judgment

from enum import Enum, auto

import numpy as np

from circleguard.utils import check_param
from circleguard.hitobjects import Hitobject

[docs]class JudgmentType(Enum): Hit300 = auto() Hit100 = auto() Hit50 = auto() Miss = auto()
[docs]class Judgment: """ A judgment on a hitobject. A "judgment" is either a hit or a miss, with a hit being further classified as a 300, 100, or 50. Parameters ---------- hitobject: :class:`slider.beatmap.HitObject` The hitobject being judged. This is converted to a :class:`circleguard.hitobjects.Hitobject`. replay: :class:`circleguard.loadables.Replay` The replay this judgment was made on. beatmap: :class:`slider.beatmap.Beatmap` The beatmap this judgment was made on. type: :class:`JudgmentType` The type of this judgment (either Hit300, Hit100, or Hit50, or Miss). """ def __init__(self, hitobject, replay, beatmap, type_): # TODO remove `already_converted=True` when # https://github.com/llllllllll/slider/issues/80 is fixed self.hitobject = Hitobject.from_slider_hitobj(hitobject, replay, beatmap, True) self.type = type_
[docs]class Miss(Judgment): """ A miss on a hitobject when a replay is played against a beatmap. """ def __init__(self, hitobject, replay, beatmap): super().__init__(hitobject, replay, beatmap, JudgmentType.Miss)
[docs]class Hit(Judgment): """ A hit on a hitobject when a replay is played against a beatmap. Parameters ---------- hitobject: :class:`slider.beatmap.HitObject` The hitobject that was hit. This is converted to a :class:`circleguard.hitobjects.Hitobject`. t: float The time the hit occured. xy: list[float, float] The x and y position where the hit occured. replay: :class:`circleguard.loadables.Replay` The replay this hit was made on. beatmap: :class:`slider.beatmap.Beatmap` The beatmap this hit was made on. type: :class:`JudgmentType` The type of this hit (either Hit300, Hit100, or Hit50). """ def __init__(self, hitobject, t, xy, replay, beatmap, type_): super().__init__(hitobject, replay, beatmap, type_) # TODO remove ``t`` in core 6.0.0, ``time`` is more intuitive. ``x`` and # ``y`` are fine as is though since there's no longer name for them. self.t = t self.time = t self.xy = xy self.x = xy[0] self.y = xy[1] self.type = type_
[docs] def distance(self, *, to): """ The distance from this hit to either the center or edge of its hitobject. Parameters ---------- to: {"center", "edge"} If ``center``, the distance from this hit to the center of its hitobject is calculated. If ``edge``, the distance from this hit to the edge of its hitobject is calculated. Returns ------- float The distance from this hit to either the center or edge of its hitobject. """ check_param(to, ["center", "edge"]) hitobj_xy = self.hitobject.xy if to == "edge": dist = np.linalg.norm(self.xy - hitobj_xy) - self.hitobject.radius # value is negative since we're inside the hitobject, so take abs return abs(dist) if to == "center": return np.linalg.norm(self.xy - hitobj_xy)
[docs] def within(self, distance): """ Whether the hit was within ``distance`` of the edge of its hitobject. Parameters ---------- distance: float How close, in pixels, to the edge of the hitobject the hit has to be. Returns ------- bool Whether the hit was within ``distance`` of the edge of its hitobject. Notes ----- The lower the value, the closer to the edge the hit occurred. This value can never be greater than the radius of the hitobject. """ return self.distance(to="edge") < distance
[docs] def error(self): """ How many milliseconds off this hit was from being a perfectly on time hit. If negative, this was an early hit. If positive, this was a late hit. If 0, this was a perfect hit. Returns ------- float How many milliseconds off this hit was from being perfectly on time. """ return self.time - self.hitobject.time
def __eq__(self, other): return (self.hitobject == other.hitobject and self.t == other.t and self.xy == other.xy) def __hash__(self): return hash((self.hitobject, self.t, self.xy)) def __repr__(self): return f"Hit(hitobject={self.hitobject},t={self.t},xy={self.xy}" def __str__(self): return f"({self.x}, {self.y}) at t {self.t}"