bms_rs/bms/command/channel/
converter.rs

1//! For one-way converting key/channel, please see [`KeyConverter`] and [`PlayerSideKeyConverter`] traits.
2
3use std::collections::HashMap;
4
5use super::{Key, PlayerSide};
6use crate::bms::rng::JavaRandom;
7
8/// A trait for converting [`super::Key`]s in different layouts.
9///
10/// This trait provides a simple interface for converting keys without considering player sides.
11/// It operates on single keys, making it suitable for key-only transformations.
12pub trait KeyConverter {
13    /// Convert a single [`super::Key`] to another key layout.
14    fn convert(&mut self, key: Key) -> Key;
15}
16
17/// A trait for converting [`super::PlayerSide`] and [`super::Key`] pairs in different layouts.
18///
19/// This trait provides an interface for converting (PlayerSide, Key) pairs,
20/// making it suitable for transformations that need to consider both player side and key.
21pub trait PlayerSideKeyConverter {
22    /// Convert a single `(PlayerSide, Key)` pair to another layout.
23    fn convert(&mut self, pair: (PlayerSide, Key)) -> (PlayerSide, Key);
24}
25
26impl KeyMappingConvertMirror {
27    /// Create a new [`KeyMappingConvertMirror`] with the given [`super::Key`]s.
28    #[must_use]
29    pub const fn new(keys: Vec<Key>) -> Self {
30        Self { keys }
31    }
32}
33
34/// Mirror the keys within the specified key list.
35#[derive(Debug, Clone, PartialEq, Eq, Hash)]
36pub struct KeyMappingConvertMirror {
37    /// A list of [`super::Key`]s to mirror. Usually, it should be the keys that actually used in the song.
38    keys: Vec<Key>,
39}
40
41impl KeyConverter for KeyMappingConvertMirror {
42    fn convert(&mut self, key: Key) -> Key {
43        self.keys
44            .iter()
45            .position(|k| k == &key)
46            .and_then(|position| {
47                let mirror_index = self.keys.len().saturating_sub(position + 1);
48                self.keys.get(mirror_index)
49            })
50            .copied()
51            .unwrap_or(key)
52    }
53}
54
55/// A modifier that rotates the lanes of keys.
56#[derive(Debug, Clone)]
57pub struct KeyMappingConvertLaneRotateShuffle {
58    /// A map of [`super::Key`]s to their new [`super::Key`]s.
59    arrangement: HashMap<Key, Key>,
60}
61
62impl KeyMappingConvertLaneRotateShuffle {
63    /// Create a new [`KeyMappingConvertLaneRotateShuffle`] with the given [`super::Key`]s and seed.
64    #[must_use]
65    pub fn new(keys: &[Key], seed: i64) -> Self {
66        Self {
67            arrangement: Self::make_random(keys, seed),
68        }
69    }
70
71    fn make_random(keys: &[Key], seed: i64) -> HashMap<Key, Key> {
72        let mut rng = JavaRandom::new(seed);
73        let mut result: HashMap<Key, Key> = HashMap::new();
74        if keys.is_empty() {
75            return result;
76        }
77
78        let inc = rng.next_int_bound(2) == 1;
79        let start = rng.next_int_bound(keys.len() as i32 - 1) as usize + if inc { 1 } else { 0 };
80
81        let mut rlane = start;
82        for lane in 0..keys.len() {
83            result.insert(keys[lane], keys[rlane]);
84            rlane = if inc {
85                (rlane + 1) % keys.len()
86            } else {
87                (rlane + keys.len() - 1) % keys.len()
88            };
89        }
90        result
91    }
92}
93
94impl KeyConverter for KeyMappingConvertLaneRotateShuffle {
95    fn convert(&mut self, key: Key) -> Key {
96        self.arrangement.get(&key).copied().unwrap_or(key)
97    }
98}
99
100/// A modifier that shuffles the lanes of keys.
101///
102/// Its action is similar to beatoraja's lane shuffle.
103#[derive(Debug, Clone)]
104pub struct KeyMappingConvertLaneRandomShuffle {
105    /// A map of [`super::Key`]s to their new [`super::Key`]s.
106    arrangement: HashMap<Key, Key>,
107}
108
109impl KeyMappingConvertLaneRandomShuffle {
110    /// Create a new [`KeyMappingConvertLaneRandomShuffle`] with the given [`super::Key`]s and seed.
111    #[must_use]
112    pub fn new(keys: &[Key], seed: i64) -> Self {
113        Self {
114            arrangement: Self::make_random(keys, seed),
115        }
116    }
117
118    fn make_random(keys: &[Key], seed: i64) -> HashMap<Key, Key> {
119        let mut rng = JavaRandom::new(seed);
120        let mut result: HashMap<Key, Key> = HashMap::new();
121        if keys.is_empty() {
122            return result;
123        }
124
125        let mut l = keys.to_vec();
126        for &lane in keys {
127            let r = rng.next_int_bound(l.len() as i32) as usize;
128            result.insert(lane, l[r]);
129            l.remove(r);
130        }
131
132        result
133    }
134}
135
136impl KeyConverter for KeyMappingConvertLaneRandomShuffle {
137    fn convert(&mut self, key: Key) -> Key {
138        self.arrangement.get(&key).copied().unwrap_or(key)
139    }
140}
141
142/// A modifier that flips between PlayerSide::Player1 and PlayerSide::Player2.
143#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
144pub struct KeyMappingConvertFlip;
145
146impl PlayerSideKeyConverter for KeyMappingConvertFlip {
147    fn convert(&mut self, pair: (PlayerSide, Key)) -> (PlayerSide, Key) {
148        let (side, key) = pair;
149        let flipped_side = match side {
150            PlayerSide::Player1 => PlayerSide::Player2,
151            PlayerSide::Player2 => PlayerSide::Player1,
152        };
153        (flipped_side, key)
154    }
155}
156
157#[cfg(test)]
158mod channel_mode_tests {
159    use super::*;
160
161    #[test]
162    fn test_key_converter_mirror() {
163        // Test 1: 3 keys
164        let mut converter =
165            KeyMappingConvertMirror::new(vec![Key::Key(1), Key::Key(2), Key::Key(3)]);
166
167        // Test individual key conversions
168        let keys = vec![
169            Key::Key(1),
170            Key::Key(2),
171            Key::Key(3),
172            Key::Key(4),
173            Key::Key(5),
174        ];
175
176        // Expected keys (mirrored: 1->3, 2->2, 3->1, 4->4, 5->5)
177        let expected_keys = vec![
178            Key::Key(3),
179            Key::Key(2),
180            Key::Key(1),
181            Key::Key(4),
182            Key::Key(5),
183        ];
184
185        let result: Vec<_> = keys.into_iter().map(|key| converter.convert(key)).collect();
186        assert_eq!(result, expected_keys);
187    }
188
189    /// Parse test examples from string format to (list, seed) tuples.
190    fn parse_examples(examples_str: &[&str]) -> Vec<(Vec<usize>, i64)> {
191        examples_str
192            .iter()
193            .map(|s| {
194                let v = s.split_whitespace().collect::<Vec<_>>();
195                let [list, seed] = v.as_slice() else {
196                    println!("{:?}", v);
197                    panic!("Invalid input");
198                };
199                let list = list
200                    .chars()
201                    .map(|c| c.to_digit(10).unwrap() as usize)
202                    .collect::<Vec<_>>();
203                let seed = seed.parse::<i64>().unwrap();
204                (list, seed)
205            })
206            .collect::<Vec<_>>()
207    }
208
209    /// Convert a Key to its numeric value for testing.
210    fn key_to_value(key: Key) -> usize {
211        match key {
212            Key::Key(n) => n as usize,
213            Key::Scratch(n) => n as usize + 10,
214            Key::FootPedal => 20,
215            Key::FreeZone => 21,
216        }
217    }
218
219    /// Run a single shuffle test case with given keys.
220    fn run_shuffle_test_case<T>(
221        test_case_idx: usize,
222        expected_list: &[usize],
223        seed: i64,
224        keys: &[Key],
225        mut converter: T,
226    ) where
227        T: KeyConverter,
228    {
229        println!("Test case {}: seed = {}", test_case_idx, seed);
230
231        let result_values = keys
232            .iter()
233            .map(|&key| key_to_value(converter.convert(key)))
234            .collect::<Vec<_>>();
235
236        println!("  Expected: {:?}", expected_list);
237        println!("  Got:      {:?}", result_values);
238        println!("  Match:    {}", result_values == expected_list);
239
240        if result_values != expected_list {
241            println!("  FAILED!");
242        }
243        println!();
244    }
245
246    /// Test the random shuffle modifier.
247    ///
248    /// Source: <https://www.bilibili.com/opus/1033281595747860483>
249    #[test]
250    fn test_random_shuffle() {
251        let examples_str = [
252            "1234567 4752",
253            "1234576 2498",
254            "4372615 12728",
255            "4372651 9734",
256            "4375126 139",
257        ];
258        let examples = parse_examples(&examples_str);
259        let init_keys = [
260            Key::Key(1),
261            Key::Key(2),
262            Key::Key(3),
263            Key::Key(4),
264            Key::Key(5),
265            Key::Key(6),
266            Key::Key(7),
267        ];
268
269        for (i, (list, seed)) in examples.iter().enumerate() {
270            let rnd = KeyMappingConvertLaneRandomShuffle::new(&init_keys, *seed);
271            run_shuffle_test_case(i, list, *seed, &init_keys, rnd);
272        }
273    }
274
275    /// Test the lane rotate shuffle modifier.
276    #[test]
277    fn test_lane_rotate_shuffle() {
278        let examples_str = ["1765432 3581225"];
279        let examples = parse_examples(&examples_str);
280        let init_keys = [
281            Key::Key(1),
282            Key::Key(2),
283            Key::Key(3),
284            Key::Key(4),
285            Key::Key(5),
286            Key::Key(6),
287            Key::Key(7),
288        ];
289
290        for (i, (list, seed)) in examples.iter().enumerate() {
291            let rnd = KeyMappingConvertLaneRotateShuffle::new(&init_keys, *seed);
292            run_shuffle_test_case(i, list, *seed, &init_keys, rnd);
293        }
294    }
295
296    /// Test the flip modifier that swaps PlayerSide::Player1 and PlayerSide::Player2.
297    #[test]
298    fn test_player_side_key_converter_flip() {
299        let mut converter = KeyMappingConvertFlip;
300
301        // Test data: (PlayerSide, Key)
302        let test_cases = vec![
303            (PlayerSide::Player1, Key::Key(1)),
304            (PlayerSide::Player2, Key::Key(2)),
305            (PlayerSide::Player1, Key::Scratch(1)),
306            (PlayerSide::Player2, Key::FreeZone),
307        ];
308
309        // Test flip conversion
310        let input_pairs: Vec<_> = test_cases.clone();
311
312        let expected_pairs: Vec<_> = test_cases
313            .iter()
314            .map(|(side, key)| {
315                let flipped_side = match side {
316                    PlayerSide::Player1 => PlayerSide::Player2,
317                    PlayerSide::Player2 => PlayerSide::Player1,
318                };
319                (flipped_side, *key)
320            })
321            .collect();
322
323        let result: Vec<_> = input_pairs
324            .iter()
325            .map(|&pair| converter.convert(pair))
326            .collect();
327        assert_eq!(result, expected_pairs);
328
329        let result2: Vec<_> = result.iter().map(|&pair| converter.convert(pair)).collect();
330        assert_eq!(result2, input_pairs);
331    }
332}