def test_tap_offset_stdev(self): beatmap = BeatmapIO.open_beatmap('unit_tests\\maps\\mania\\playable\\DJ Genericname - Dear You (Taiwan-NAK) [S.Star\'s 4K HD+].osu') replay = ReplayIO.open_replay('unit_tests\\replays\\mania\\osu!topus! - DJ Genericname - Dear You [S.Star\'s 4K HD+] (2019-05-29) OsuMania.osr') map_data = ManiaActionData.get_action_data(beatmap) replay_data = ManiaActionData.get_action_data(replay) # osu!topus should have played all notes perfectly (0 std dev) score_data = ManiaScoreData.get_score_data(map_data, replay_data) # Include only hits score_data = score_data[score_data['type'] == ManiaScoreData.TYPE_HITP] tap_offset_stdev = ManiaScoreData.tap_offset_stdev(score_data) self.assertEqual(tap_offset_stdev, 0)
def test(replay1_filename, replay2_filename, press_release): replay1 = ReplayIO.open_replay(replay1_filename) replay2 = ReplayIO.open_replay(replay2_filename) map_data = ManiaActionData.get_action_data(beatmap) score_data1 = ManiaScoreData.get_score_data(map_data, ManiaActionData.get_action_data(replay1)) score_data2 = ManiaScoreData.get_score_data(map_data, ManiaActionData.get_action_data(replay2)) hit_type = ManiaScoreData.TYPE_HITP if press_release == 1 else ManiaScoreData.TYPE_HITR miss_type = ManiaScoreData.TYPE_MISSP if press_release == 1 else ManiaScoreData.TYPE_MISSR for c in range(score_data1.shape[1]): score_col1 = score_data1.loc[c] score_col2 = score_data2.loc[c] num_hits1 = score_col1['type'].values[score_col1['type'].values == hit_type].shape[0] num_miss1 = score_col1['type'].values[score_col1['type'].values == miss_type].shape[0] num_hits2 = score_col2['type'].values[score_col2['type'].values == hit_type].shape[0] num_miss2 = score_col2['type'].values[score_col2['type'].values == miss_type].shape[0] hitp_t1 = score_col1['map_t'].values[score_col1['type'].values == hit_type] miss_t1 = score_col1['map_t'].values[score_col1['type'].values == miss_type] notes_t1 = np.concatenate((hitp_t1, miss_t1), axis=None).astype(int) # All note timings in score 1 notes_t1 = np.sort(notes_t1) hitp_t2 = score_col2['map_t'].values[score_col2['type'].values == hit_type] miss_t2 = score_col2['map_t'].values[score_col2['type'].values == miss_type] notes_t2 = np.concatenate((hitp_t2, miss_t2), axis=None).astype(int) # All note timings in score 2 notes_t2 = np.sort(notes_t2) notes_count1 = np.zeros(max(np.max(notes_t1), np.max(notes_t2)) + 1) notes_count2 = np.zeros(max(np.max(notes_t1), np.max(notes_t2)) + 1) notes_count1[:np.max(notes_t1)+1] = np.bincount(notes_t1) # Integer histogram for timings of score 1 notes_count2[:np.max(notes_t2)+1] = np.bincount(notes_t2) # Integer histogram for timings of score 2 notes_mismatch = np.arange(max(np.max(notes_t1), np.max(notes_t2)) + 1)[notes_count1 != notes_count2] replay1_name = replay1_filename[replay1_filename.rfind("\\") + 1:] replay2_name = replay2_filename[replay2_filename.rfind("\\") + 1:] self.assertEqual(num_hits1 + num_miss1, num_hits2 + num_miss2, f'\n\tReplays: {replay1_name} {replay2_name}\n' f'\tTest for {"Press" if press_release == 1 else "Release"}\n' f'\tOne of two maps have missing or extra scoring points at column {c}\n' f'\tScore 1 hits & misses: {num_hits1} + {num_miss1} = {num_hits1 + num_miss1} score 2 hits & misses: {num_hits2} + {num_miss2} = {num_hits2 + num_miss2}\n' f'\tNote timings mismatched: {notes_mismatch} score 1 occurences: {notes_count1[notes_count1 != notes_count2]} score 2 occurences: {notes_count2[notes_count1 != notes_count2]}\n' )
def test_release__holdnote_release__noblank_lazy(self): # Time: -1000 ms -> 1000 ms # Scoring: Awaiting release at first singlenote (250 ms @ (col 3)) ManiaScoreData.blank_miss = False ManiaScoreData.lazy_sliders = True map_idx = 5 scorepoint_type = self.map_types[map_idx] self.assertEqual(scorepoint_type, ManiaActionData.RELEASE) for ms in range(-1000, 1000): column_data = {} offset = ms - self.map_times[map_idx] adv = ManiaScoreData._ManiaScoreData__process_release( column_data, ms, self.map_times, map_idx) self.assertEqual( adv, 1, f'Offset: {offset} ms; Replay: {ms} ms; Map: {self.map_times[map_idx]} ms' ) self.assertEqual( len(column_data), 0, f'Offset: {offset} ms; Replay: {ms} ms; Map: {self.map_times[map_idx]} ms' )
def test_tap_offset_mean_max(self): beatmap = BeatmapIO.open_beatmap('unit_tests\\maps\\mania\\playable\\DJ Genericname - Dear You (Taiwan-NAK) [S.Star\'s 4K HD+].osu') replay = ReplayIO.open_replay('unit_tests\\replays\\mania\\osu!topus! - DJ Genericname - Dear You [S.Star\'s 4K HD+] (2019-05-29) OsuMania.osr') timings = replay.get_time_data() timings[0] += ManiaScoreData.pos_hit_range - 1 map_data = ManiaActionData.get_action_data(beatmap) replay_data = ManiaActionData.get_action_data(replay) # osu!topus should have played all notes perfectly (0 mean + 150 ms offset) score_data = ManiaScoreData.get_score_data(map_data, replay_data) # Include only hits score_data = score_data[score_data['type'] == ManiaScoreData.TYPE_HITP] tap_offset_mean = ManiaScoreData.tap_offset_mean(score_data) self.assertEqual(tap_offset_mean, ManiaScoreData.pos_hit_range - 1)
def test_press_interval_mean(self): beatmap = BeatmapIO.open_beatmap('unit_tests\\maps\\mania\\playable\\DJ Genericname - Dear You (Taiwan-NAK) [S.Star\'s 4K HD+].osu') replay = ReplayIO.open_replay('unit_tests\\replays\\mania\\osu!topus! - DJ Genericname - Dear You [S.Star\'s 4K HD+] (2019-05-29) OsuMania.osr') map_data = ManiaActionData.get_action_data(beatmap) replay_data = ManiaActionData.get_action_data(replay) # osu!topus should have played all notes perfectly (1 ms press intervals) score_data = ManiaScoreData.get_score_data(map_data, replay_data)
def test_no_press__singlenote_press__noblank_nolazy(self): # Time: -1000 ms -> 1000 ms # Scoring: Awaiting press at first singlenote (50 ms @ (col 3)) ManiaScoreData.blank_miss = False ManiaScoreData.lazy_sliders = False map_idx = 0 scorepoint_type = self.map_types[map_idx] self.assertEqual(scorepoint_type, ManiaActionData.PRESS) for ms in range(-1000, 1000): column_data = {} offset = ms - self.map_times[map_idx] adv = ManiaScoreData._ManiaScoreData__process_free( column_data, scorepoint_type, ms, self.map_times, map_idx) if offset <= ManiaScoreData.pos_hit_miss_range: self.assertEqual( adv, 0, f'Offset: {offset} ms; Replay: {ms} ms; Map: {self.map_times[map_idx]} ms' ) self.assertEqual( len(column_data), 0, f'Offset: {offset} ms; Replay: {ms} ms; Map: {self.map_times[map_idx]} ms' ) else: self.assertEqual( adv, 2, f'Offset: {offset} ms; Replay: {ms} ms; Map: {self.map_times[map_idx]} ms' ) self.assertEqual( len(column_data), 1, f'Offset: {offset} ms; Replay: {ms} ms; Map: {self.map_times[map_idx]} ms' ) self.assertIn( 0, column_data, f'Offset: {offset} ms; Replay: {ms} ms; Map: {self.map_times[map_idx]} ms' ) self.assertEqual( column_data[0][0], ms, f'Offset: {offset} ms; Replay: {ms} ms; Map: {self.map_times[map_idx]} ms' ) self.assertEqual( column_data[0][1], self.map_times[map_idx], f'Offset: {offset} ms; Replay: {ms} ms; Map: {self.map_times[map_idx]} ms' ) self.assertEqual( column_data[0][2], ManiaScoreData.TYPE_MISSP, f'Offset: {offset} ms; Replay: {ms} ms; Map: {self.map_times[map_idx]} ms' ) self.assertEqual( column_data[0][3], map_idx, f'Offset: {offset} ms; Replay: {ms} ms; Map: {self.map_times[map_idx]} ms' )
def test_scoring_completeness(self): # Check if the score processor went through and recorded all of the timings beatmap = BeatmapIO.open_beatmap('unit_tests\\maps\\mania\\playable\\Various Artists - I Like This Chart, LOL vol. 2 (Fullereneshift) [LENK64 - Crazy Slav Dancers (HD) (Marathon)].osu') replay = ReplayIO.open_replay('unit_tests\\replays\\mania\\abraker - Various Artists - I Like This Chart, LOL vol. 2 [LENK64 - Crazy Slav Dancers (HD) (Marathon)] (2021-07-10) OsuMania.osr') map_data = ManiaActionData.get_action_data(beatmap) replay_data = ManiaActionData.get_action_data(replay) score_data = ManiaScoreData.get_score_data(map_data, replay_data) map_score_xor = np.setxor1d(score_data['map_t'].values, ManiaActionData.press_times(map_data)) # Hits that are not present in either map_score_xor = np.intersect1d(map_score_xor, ManiaActionData.press_times(map_data)) # Hits that are present in map but not score self.assertEqual(len(map_score_xor), 0, f'Timings mising: {map_score_xor}')
def test_perfect_score(self): beatmap = BeatmapIO.open_beatmap('unit_tests\\maps\\mania\\playable\\DJ Genericname - Dear You (Taiwan-NAK) [S.Star\'s 4K HD+].osu') replay = ReplayIO.open_replay('unit_tests\\replays\\mania\\osu!topus! - DJ Genericname - Dear You [S.Star\'s 4K HD+] (2019-05-29) OsuMania.osr') map_data = ManiaActionData.get_action_data(beatmap) replay_data = ManiaActionData.get_action_data(replay) # osu!topus should have played all notes perfectly (0 offset) score_data = ManiaScoreData.get_score_data(map_data, replay_data) score_types = score_data['type'].values self.assertEqual(len(score_types[score_types == ManiaScoreData.TYPE_MISSP]), 0) self.assertEqual(len(score_types[score_types == ManiaScoreData.TYPE_MISSR]), 0) # Mania auto releases hold notes 1 ms early offsets = (score_data['replay_t'] - score_data['map_t']).values self.assertEqual(len(offsets[~((offsets == 0) | (offsets == -1))]), 0)
def test_release__holdnote_release__noblank_nolazy(self): # Time: -1000 ms -> 1000 ms # Scoring: Awaiting release at first singlenote (250 ms @ (col 3)) ManiaScoreData.blank_miss = False ManiaScoreData.lazy_sliders = False map_idx = 5 scorepoint_type = self.map_types[map_idx] self.assertEqual(scorepoint_type, ManiaActionData.RELEASE) for ms in range(-1000, 1000): column_data = {} offset = ms - self.map_times[map_idx] adv = ManiaScoreData._ManiaScoreData__process_release( column_data, ms, self.map_times, map_idx) if offset <= -ManiaScoreData.neg_rel_miss_range: self.assertEqual( adv, 0, f'Offset: {offset} ms; Replay: {ms} ms; Map: {self.map_times[map_idx]} ms' ) self.assertEqual( len(column_data), 0, f'Offset: {offset} ms; Replay: {ms} ms; Map: {self.map_times[map_idx]} ms' ) elif -ManiaScoreData.neg_rel_miss_range < offset <= -ManiaScoreData.neg_rel_range: self.assertEqual( adv, 1, f'Offset: {offset} ms; Replay: {ms} ms; Map: {self.map_times[map_idx]} ms' ) self.assertEqual( len(column_data), 1, f'Offset: {offset} ms; Replay: {ms} ms; Map: {self.map_times[map_idx]} ms' ) self.assertIn( 0, column_data, f'Offset: {offset} ms; Replay: {ms} ms; Map: {self.map_times[map_idx]} ms' ) self.assertEqual( column_data[0][0], ms, f'Offset: {offset} ms; Replay: {ms} ms; Map: {self.map_times[map_idx]} ms' ) self.assertEqual( column_data[0][1], self.map_times[map_idx], f'Offset: {offset} ms; Replay: {ms} ms; Map: {self.map_times[map_idx]} ms' ) self.assertEqual( column_data[0][2], ManiaScoreData.TYPE_MISSR, f'Offset: {offset} ms; Replay: {ms} ms; Map: {self.map_times[map_idx]} ms' ) self.assertEqual( column_data[0][3], map_idx, f'Offset: {offset} ms; Replay: {ms} ms; Map: {self.map_times[map_idx]} ms' ) elif -ManiaScoreData.neg_rel_range < offset <= ManiaScoreData.pos_rel_range: self.assertEqual( adv, 1, f'Offset: {offset} ms; Replay: {ms} ms; Map: {self.map_times[map_idx]} ms' ) self.assertEqual( len(column_data), 1, f'Offset: {offset} ms; Replay: {ms} ms; Map: {self.map_times[map_idx]} ms' ) self.assertIn( 0, column_data, f'Offset: {offset} ms; Replay: {ms} ms; Map: {self.map_times[map_idx]} ms' ) self.assertEqual( column_data[0][0], ms, f'Offset: {offset} ms; Replay: {ms} ms; Map: {self.map_times[map_idx]} ms' ) self.assertEqual( column_data[0][1], self.map_times[map_idx], f'Offset: {offset} ms; Replay: {ms} ms; Map: {self.map_times[map_idx]} ms' ) self.assertEqual( column_data[0][2], ManiaScoreData.TYPE_HITR, f'Offset: {offset} ms; Replay: {ms} ms; Map: {self.map_times[map_idx]} ms' ) self.assertEqual( column_data[0][3], map_idx, f'Offset: {offset} ms; Replay: {ms} ms; Map: {self.map_times[map_idx]} ms' ) elif ManiaScoreData.pos_rel_range < offset <= ManiaScoreData.pos_rel_miss_range: self.assertEqual( adv, 1, f'Offset: {offset} ms; Replay: {ms} ms; Map: {self.map_times[map_idx]} ms' ) self.assertEqual( len(column_data), 1, f'Offset: {offset} ms; Replay: {ms} ms; Map: {self.map_times[map_idx]} ms' ) self.assertIn( 0, column_data, f'Offset: {offset} ms; Replay: {ms} ms; Map: {self.map_times[map_idx]} ms' ) self.assertEqual( column_data[0][0], ms, f'Offset: {offset} ms; Replay: {ms} ms; Map: {self.map_times[map_idx]} ms' ) self.assertEqual( column_data[0][1], self.map_times[map_idx], f'Offset: {offset} ms; Replay: {ms} ms; Map: {self.map_times[map_idx]} ms' ) self.assertEqual( column_data[0][2], ManiaScoreData.TYPE_MISSR, f'Offset: {offset} ms; Replay: {ms} ms; Map: {self.map_times[map_idx]} ms' ) self.assertEqual( column_data[0][3], map_idx, f'Offset: {offset} ms; Replay: {ms} ms; Map: {self.map_times[map_idx]} ms' ) elif ManiaScoreData.pos_rel_miss_range < offset: self.assertEqual( adv, 0, f'Offset: {offset} ms; Replay: {ms} ms; Map: {self.map_times[map_idx]} ms' ) self.assertEqual( len(column_data), 0, f'Offset: {offset} ms; Replay: {ms} ms; Map: {self.map_times[map_idx]} ms' ) else: self.fail( f'Unexpected condition | Offset: {offset} ms; Replay: {ms} ms; Map: {self.map_times[map_idx]} ms' )