rosu_pattern_detector/mania/models/
base.rs1use crate::structs::CommonMeasure;
2use crate::mania::models::pattern::{Pattern, get_pattern_weight};
3
4#[derive(Debug, PartialEq, Eq, Hash, Clone)]
5pub enum Notes {
6 Single,
7 Jump,
8 Hand,
9 Quad,
10 Chord,
11 None
12}
13
14#[derive(Debug, Clone)]
15pub struct NotesStruct {
16 pub(crate) timestamp: i32,
17 pub(crate) notes: Vec<bool>,
18}
19
20impl NotesStruct {
21 pub fn to_display_string(&self) -> String {
22 let notes_str: String = self.notes
23 .iter()
24 .map(|&active| if active { 'O' } else { 'X' })
25 .collect();
26 format!("{}: {}", self.timestamp, notes_str)
27 }
28 pub fn get_pattern(&self) -> Notes {
29 let count = self.notes.iter().filter(|&&n| n).count();
30 match count {
31 1 => Notes::Single,
32 2 => Notes::Jump,
33 3 => Notes::Hand,
34 4 => Notes::Quad,
35 _ => Notes::Chord,
36 }
37 }
38}
39
40#[derive(Debug)]
41pub struct ManiaMeasure {
42 pub(crate) measure: CommonMeasure,
43 pub(crate) notes: Vec<NotesStruct>,
44 pub(crate) pattern: Pattern,
45 pub(crate) value: f64,
46}
47
48impl ManiaMeasure {
49
50 pub fn get_weight(&self, average_npm: f64) -> f64 {
51 match (self.measure.npm, average_npm) {
52 (npm, avg) if avg <= 0.0 => if npm > 0 { 1.0 } else { 0.0 },
53 (npm, _) if npm <= 0 => 0.0,
54 (npm, avg) => (npm as f64 / avg).clamp(0.0, 5.0), }
56 }
57
58 pub fn get_pattern_weight_modifier(&self, average_npm: f64) -> f64 {
59 self.get_weight(average_npm)*get_pattern_weight(&self.pattern)
60 }
61
62 pub fn detect_pattern(&mut self) -> Pattern {
63 if self.has_jack_pattern() {
64 Pattern::Jack(self.determine_jack_type())
65
66 } else if self.has_hand_notes() {
67 Pattern::Handstream(self.determine_handstream_type())
68 } else if self.has_jump_notes() {
69 Pattern::Jumpstream(self.determine_jumpstream_type())
70 } else if self.has_single_notes() {
71 Pattern::Singlestream(crate::mania::models::pattern::SinglestreamPattern::Singlestream)
72 } else {
73 Pattern::None
74 }
75 }
76
77 fn has_jack_pattern(&self) -> bool {
78 self.notes.windows(2).any(|w| {
79 w[0].notes.iter()
81 .zip(w[1].notes.iter())
82 .any(|(&prev, &curr)| prev && curr)
83 })
84 }
85
86 fn has_hand_notes(&self) -> bool {
87 self.notes.iter().any(|n| n.get_pattern() == Notes::Hand)
88 }
89
90 fn has_jump_notes(&self) -> bool {
91 self.notes.iter().any(|n| n.get_pattern() == Notes::Jump)
92 }
93
94 fn has_single_notes(&self) -> bool {
95 self.notes.iter().any(|n| n.get_pattern() == Notes::Single)
96 }
97
98 fn determine_jack_type(&mut self) -> crate::mania::models::pattern::JackPattern {
99 crate::mania::models::pattern::JackPattern::determine_jack_type(self)
100 }
101
102 fn determine_handstream_type(&mut self) -> crate::mania::models::pattern::HandstreamPattern {
103 crate::mania::models::pattern::HandstreamPattern::determine_hs_type(self)
104 }
105
106 fn determine_jumpstream_type(&mut self) -> crate::mania::models::pattern::JumpstreamPattern {
107 crate::mania::models::pattern::JumpstreamPattern::determine_js_type(self)
108 }
109
110
111 pub fn print_notes(&self) {
112 for note in &self.notes {
113 let line = note.to_display_string();
114 println!("{}", line);
115 }
116 }
117
118 pub fn t_notes(&self) -> i32 {
119 self.notes
120 .iter()
121 .flat_map(|v| v.notes.iter())
122 .filter(|&&b| b)
123 .count() as i32
124 }
125}