feat: support dx rating of below A rank

This commit is contained in:
mokurin000
2025-08-14 22:22:29 +08:00
parent 2b6bb12dce
commit f78c631570
3 changed files with 44 additions and 81 deletions

View File

@@ -68,89 +68,47 @@ impl Level {
/// This will **NOT** ignore utage level, you can calculate a in-theory DX Rating. /// This will **NOT** ignore utage level, you can calculate a in-theory DX Rating.
/// ///
/// On invalid input, it returns 0. /// On invalid input, it returns 0.
pub fn dx_rating(&self, achievement: i32) -> u32 { pub fn dx_rating(&self, achievement: i32) -> (&'static str, u32) {
let achievement = Decimal::new(achievement as _, 4); 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 difficulty_rank: Decimal = self.difficulty.value;
let achievement = Decimal::new(achievement as _, 4);
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,
};
// when ach > 100.5%, calculate as 100.5% // 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() .floor()
.try_into() .try_into()
.unwrap_or_default() .unwrap_or_default();
(rank, rating)
} }
} }
const SSS_PLUS_THRESHOLD: Decimal = dec!(100.5); const RANKS: [(&'static str, i32, Decimal); 23] = [
const SSS_PLUS_FACTOR: Decimal = dec!(0.224); ("D", 0, dec!(0.0)),
("D", 100000, dec!(0.16)),
const SSS_PRO_THRESHOLD: Decimal = dec!(100.4999); ("D", 200000, dec!(0.32)),
const SSS_PRO_FACTOR: Decimal = dec!(0.222); ("D", 300000, dec!(0.48)),
("D", 400000, dec!(0.64)),
const SSS_THRESHOLD: Decimal = dec!(100); ("C", 500000, dec!(0.80)),
const SSS_FACTOR: Decimal = dec!(0.216); ("B", 600000, dec!(0.96)),
("BB", 700000, dec!(0.112)),
const SS_PLUS_PRO_THRESHOLD: Decimal = dec!(99.9999); ("BBB", 750000, dec!(0.120)),
const SS_PLUS_PRO_FACTOR: Decimal = dec!(0.214); ("BBB", 799999, dec!(0.128)),
("A", 800000, dec!(0.136)),
const SS_PLUS_THRESHOLD: Decimal = dec!(99.5); ("AA", 900000, dec!(0.152)),
const SS_PLUS_FACTOR: Decimal = dec!(0.211); ("AAA", 940000, dec!(0.168)),
("AAA", 969999, dec!(0.176)),
const SS_THRESHOLD: Decimal = dec!(99); ("S", 970000, dec!(0.200)),
const SS_FACTOR: Decimal = dec!(0.208); ("S+", 980000, dec!(0.203)),
("S+", 989999, dec!(0.206)),
const S_PLUS_PRO_THRESHOLD: Decimal = dec!(98.9999); ("SS", 990000, dec!(0.208)),
const S_PLUS_PRO_FACTOR: Decimal = dec!(0.206); ("SS+", 995000, dec!(0.211)),
("SS+", 999999, dec!(0.214)),
const S_PLUS_THRESHOLD: Decimal = dec!(98); ("SSS", 1000000, dec!(0.216)),
const S_PLUS_FACTOR: Decimal = dec!(0.203); ("SSS", 1004999, dec!(0.222)),
("SSS+", 1005000, dec!(0.224)),
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'],
*/

View File

@@ -141,8 +141,9 @@ impl Display for UserMusicDetail {
f.write_fmt(format_args!("DX 分数: \t{}\n", self.deluxscore_max))?; f.write_fmt(format_args!("DX 分数: \t{}\n", self.deluxscore_max))?;
if let Some(level) = query_music_level(self.music_id, self.level) { if let Some(level) = query_music_level(self.music_id, self.level) {
let rating = level.dx_rating(self.achievement as _); let (rank, rating) = level.dx_rating(self.achievement as _);
f.write_fmt(format_args!("DX RATING: \t{rating}"))?; f.write_fmt(format_args!("DX RATING: \t{rating}\n"))?;
f.write_fmt(format_args!("RANK: \t{rank}"))?;
} }
Ok(()) Ok(())

View File

@@ -182,6 +182,10 @@ impl MusicRating {
} }
pub fn dx_rating(&self) -> Option<u32> { pub fn dx_rating(&self) -> Option<u32> {
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,
)
} }
} }