-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtaiko_ur_estimator.py
74 lines (52 loc) · 1.69 KB
/
taiko_ur_estimator.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
from scipy.optimize import minimize_scalar
from math import erfc, log, pi, isinf, log1p, exp
from ossapi.models import Score
from ossapi.mod import Mod
def log_erfc(x):
if x < 5:
return log(erfc(x))
else:
return -x ** 2 - log(x * pi ** 0.5)
def log_diff(first_log, second_log):
max_val = max(first_log, second_log)
if isinf(max_val):
return max_val
return first_log + log1p(-exp(-(first_log - second_log)))
def unstable_rate(
j: Score.statistics,
beatmap: Score.beatmap,
mods: Mod
) -> float:
n_judgements = j.count_300 + j.count_100
if n_judgements == 0:
return float('inf')
od = beatmap.accuracy
if Mod.HR in mods:
od = min(od * 1.4, 10)
elif Mod.EZ in mods:
od = od * 0.5
multiplier = 1
if Mod.DT in mods:
multiplier = 2 / 3.0
elif Mod.HT in mods:
multiplier = 4 / 3.0
# We need the size of every hit window in order to calculate deviation accurately.
h_300 = (50 - 3 * od) * multiplier
if od < 5:
h_100 = (120 - 6 * od) * multiplier
else:
h_100 = (80 - 8 * (od - 5)) * multiplier
root2 = 2 ** 0.5
# Returns the likelihood of any deviation resulting in the play
def likelihood_gradient(d: float):
if d <= 0:
return float('inf')
p_300 = log_diff(0, log_erfc(h_300 / (d * root2)))
p_100 = log_diff(log_erfc(h_300 / (d * root2)), log_erfc(h_100 / (d * root2)))
gradient = exp(
(p_300 * j.count_300 +
p_100 * (j.count_100 + 0.5)) / n_judgements
)
return -gradient
results = minimize_scalar(likelihood_gradient)
return results.x * 10