From f78c631570fb3f4516be0cca276df290f0cc1487 Mon Sep 17 00:00:00 2001 From: mokurin000 <1348292515a@gmail.com> Date: Thu, 14 Aug 2025 22:22:29 +0800 Subject: [PATCH] feat: support dx rating of below A rank --- music_db/src/lib.rs | 114 ++++++------------ .../src/title/model/get_user_music_api/mod.rs | 5 +- .../title/model/get_user_rating_api/mod.rs | 6 +- 3 files changed, 44 insertions(+), 81 deletions(-) diff --git a/music_db/src/lib.rs b/music_db/src/lib.rs index d004c00..e5e41e4 100644 --- a/music_db/src/lib.rs +++ b/music_db/src/lib.rs @@ -68,89 +68,47 @@ impl Level { /// This will **NOT** ignore utage level, you can calculate a in-theory DX Rating. /// /// On invalid input, it returns 0. - pub fn dx_rating(&self, achievement: i32) -> u32 { - let achievement = Decimal::new(achievement as _, 4); + pub fn dx_rating(&self, achievement: i32) -> (&'static str, u32) { + let achievement = achievement.min(1005000); // SSS+ case + let (rank, _, factor) = RANKS + .into_iter() + .rev() + .find(|&(_, threshold, _)| threshold <= achievement) + .unwrap(); // save here, due to zero threshold let difficulty_rank: Decimal = self.difficulty.value; - - let factor = match () { - // larger than best achievement - _ if achievement > dec!(101.0) => return 0, - - _ if achievement >= SSS_PLUS_THRESHOLD => SSS_PLUS_FACTOR, - _ if achievement >= SSS_PRO_THRESHOLD => SSS_PRO_FACTOR, - _ if achievement >= SSS_THRESHOLD => SSS_FACTOR, - _ if achievement >= SS_PLUS_PRO_THRESHOLD => SS_PLUS_PRO_FACTOR, - _ if achievement >= SS_PLUS_THRESHOLD => SS_PLUS_FACTOR, - _ if achievement >= SS_THRESHOLD => SS_FACTOR, - _ if achievement >= S_PLUS_PRO_THRESHOLD => S_PLUS_PRO_FACTOR, - _ if achievement >= S_PLUS_THRESHOLD => S_PLUS_FACTOR, - _ if achievement >= S_THRESHOLD => S_FACTOR, - _ if achievement >= AAA_PRO_THRESHOLD => AAA_PRO_FACTOR, - _ if achievement >= AAA_THRESHOLD => AAA_FACTOR, - _ if achievement >= AA_THRESHOLD => AA_FACTOR, - _ if achievement >= A_THRESHOLD => A_FACTOR, - - // lower than A rank, does not get rating. - _ => return 0, - }; + let achievement = Decimal::new(achievement as _, 4); // when ach > 100.5%, calculate as 100.5% - (factor * difficulty_rank * achievement.min(Decimal::new(1005, 1))) + let rating: u32 = (factor * difficulty_rank * achievement.min(dec!(100.5))) .floor() .try_into() - .unwrap_or_default() + .unwrap_or_default(); + (rank, rating) } } -const SSS_PLUS_THRESHOLD: Decimal = dec!(100.5); -const SSS_PLUS_FACTOR: Decimal = dec!(0.224); - -const SSS_PRO_THRESHOLD: Decimal = dec!(100.4999); -const SSS_PRO_FACTOR: Decimal = dec!(0.222); - -const SSS_THRESHOLD: Decimal = dec!(100); -const SSS_FACTOR: Decimal = dec!(0.216); - -const SS_PLUS_PRO_THRESHOLD: Decimal = dec!(99.9999); -const SS_PLUS_PRO_FACTOR: Decimal = dec!(0.214); - -const SS_PLUS_THRESHOLD: Decimal = dec!(99.5); -const SS_PLUS_FACTOR: Decimal = dec!(0.211); - -const SS_THRESHOLD: Decimal = dec!(99); -const SS_FACTOR: Decimal = dec!(0.208); - -const S_PLUS_PRO_THRESHOLD: Decimal = dec!(98.9999); -const S_PLUS_PRO_FACTOR: Decimal = dec!(0.206); - -const S_PLUS_THRESHOLD: Decimal = dec!(98); -const S_PLUS_FACTOR: Decimal = dec!(0.203); - -const S_THRESHOLD: Decimal = dec!(97); -const S_FACTOR: Decimal = dec!(0.2); - -const AAA_PRO_THRESHOLD: Decimal = dec!(96.9999); -const AAA_PRO_FACTOR: Decimal = dec!(0.176); - -const AAA_THRESHOLD: Decimal = dec!(94); -const AAA_FACTOR: Decimal = dec!(0.168); - -const AA_THRESHOLD: Decimal = dec!(90); -const AA_FACTOR: Decimal = dec!(0.152); - -const A_THRESHOLD: Decimal = dec!(80); -const A_FACTOR: Decimal = dec!(0.136); - -/* -TODO: calculate (below) BBB dx rating - [0, 0, 'd'], - [10, 1.6, 'd'], - [20, 3.2, 'd'], - [30, 4.8, 'd'], - [40, 6.4, 'd'], - [50, 8, 'c'], - [60, 9.6, 'b'], - [70, 11.2, 'bb'], - [75, 12.0, 'bbb'], - [79.9999, 12.8, 'bbb'], -*/ +const RANKS: [(&'static str, i32, Decimal); 23] = [ + ("D", 0, dec!(0.0)), + ("D", 100000, dec!(0.16)), + ("D", 200000, dec!(0.32)), + ("D", 300000, dec!(0.48)), + ("D", 400000, dec!(0.64)), + ("C", 500000, dec!(0.80)), + ("B", 600000, dec!(0.96)), + ("BB", 700000, dec!(0.112)), + ("BBB", 750000, dec!(0.120)), + ("BBB", 799999, dec!(0.128)), + ("A", 800000, dec!(0.136)), + ("AA", 900000, dec!(0.152)), + ("AAA", 940000, dec!(0.168)), + ("AAA", 969999, dec!(0.176)), + ("S", 970000, dec!(0.200)), + ("S+", 980000, dec!(0.203)), + ("S+", 989999, dec!(0.206)), + ("SS", 990000, dec!(0.208)), + ("SS+", 995000, dec!(0.211)), + ("SS+", 999999, dec!(0.214)), + ("SSS", 1000000, dec!(0.216)), + ("SSS", 1004999, dec!(0.222)), + ("SSS+", 1005000, dec!(0.224)), +]; diff --git a/sdgb-api/src/title/model/get_user_music_api/mod.rs b/sdgb-api/src/title/model/get_user_music_api/mod.rs index b3f8f29..a10fa3e 100644 --- a/sdgb-api/src/title/model/get_user_music_api/mod.rs +++ b/sdgb-api/src/title/model/get_user_music_api/mod.rs @@ -141,8 +141,9 @@ impl Display for UserMusicDetail { f.write_fmt(format_args!("DX 分数: \t{}\n", self.deluxscore_max))?; if let Some(level) = query_music_level(self.music_id, self.level) { - let rating = level.dx_rating(self.achievement as _); - f.write_fmt(format_args!("DX RATING: \t{rating}"))?; + let (rank, rating) = level.dx_rating(self.achievement as _); + f.write_fmt(format_args!("DX RATING: \t{rating}\n"))?; + f.write_fmt(format_args!("RANK: \t{rank}"))?; } Ok(()) diff --git a/sdgb-api/src/title/model/get_user_rating_api/mod.rs b/sdgb-api/src/title/model/get_user_rating_api/mod.rs index f70e808..9a83050 100644 --- a/sdgb-api/src/title/model/get_user_rating_api/mod.rs +++ b/sdgb-api/src/title/model/get_user_rating_api/mod.rs @@ -182,6 +182,10 @@ impl MusicRating { } pub fn dx_rating(&self) -> Option { - Some(query_music_level(self.music_id, self.level)?.dx_rating(self.achievement)) + Some( + query_music_level(self.music_id, self.level)? + .dx_rating(self.achievement) + .1, + ) } }