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
75
76
77
78
79
80
81
82
83
84
85
86
/// osu!catch hitresults.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct CatchHitResults {
/// Amount of current fruits (300s).
pub fruits: u32,
/// Amount of current droplets (100s).
pub droplets: u32,
/// Amount of current tiny droplets (50s).
pub tiny_droplets: u32,
/// Amount of current tiny droplet misses (katus).
pub tiny_droplet_misses: u32,
/// Amount of current misses (fruits and droplets).
pub misses: u32,
}
impl CatchHitResults {
/// Create a new empty score state.
pub const fn new() -> Self {
Self {
fruits: 0,
droplets: 0,
tiny_droplets: 0,
tiny_droplet_misses: 0,
misses: 0,
}
}
/// Return the total amount of hits by adding everything up.
pub const fn total_hits(&self) -> u32 {
self.fruits + self.droplets + self.tiny_droplets + self.tiny_droplet_misses + self.misses
}
/// Return the total amount of successful hits by adding up fruits,
/// droplets, and tiny droplets.
pub const fn total_successful_hits(&self) -> u32 {
self.fruits + self.droplets + self.tiny_droplets
}
/// Calculate the accuracy between `0.0` and `1.0` for this state.
pub fn accuracy(&self) -> f64 {
let total_hits = self.total_hits();
if total_hits == 0 {
return 0.0;
}
let numerator = self.total_successful_hits();
let denominator = total_hits;
f64::from(numerator) / f64::from(denominator)
}
}
impl Default for CatchHitResults {
fn default() -> Self {
Self::new()
}
}
/// Aggregation for a score's current state.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct CatchScoreState {
/// Maximum combo that the score has had so far.
/// **Not** the maximum possible combo of the map so far.
///
/// Note that only fruits and droplets are considered for osu!catch combo.
pub max_combo: u32,
/// Hitresults of a score.
pub hitresults: CatchHitResults,
}
impl CatchScoreState {
/// Create a new empty score state.
pub const fn new() -> Self {
Self {
max_combo: 0,
hitresults: CatchHitResults::new(),
}
}
}
impl Default for CatchScoreState {
fn default() -> Self {
Self::new()
}
}