-
Notifications
You must be signed in to change notification settings - Fork 2
/
Peaks.ts
98 lines (77 loc) · 3.04 KB
/
Peaks.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import { DifficultyHitObject, Skill } from 'osu-classes';
import { TaikoModCombination } from '../../Mods';
import { Rhythm } from './Rhythm';
import { Colour } from './Colour';
import { Stamina } from './Stamina';
export class Peaks extends Skill {
private static FINAL_MULTIPLIER = 0.0625;
private static RHYTHM_SKILL_MULTIPLIER = 0.2 * this.FINAL_MULTIPLIER;
private static COLOUR_SKILL_MULTIPLIER = 0.375 * this.FINAL_MULTIPLIER;
private static STAMINA_SKILL_MULTIPLIER = 0.375 * this.FINAL_MULTIPLIER;
readonly rhythm: Rhythm;
readonly colour: Colour;
readonly stamina: Stamina;
constructor(mods: TaikoModCombination) {
super(mods);
this.rhythm = new Rhythm(mods);
this.colour = new Colour(mods);
this.stamina = new Stamina(mods);
}
get colourDifficultyValue(): number {
return this.colour.difficultyValue * Peaks.COLOUR_SKILL_MULTIPLIER;
}
get rhythmDifficultyValue(): number {
return this.rhythm.difficultyValue * Peaks.RHYTHM_SKILL_MULTIPLIER;
}
get staminaDifficultyValue(): number {
return this.stamina.difficultyValue * Peaks.STAMINA_SKILL_MULTIPLIER;
}
/**
* Returns the p-norm of an n-dimensional vector.
* @param p The value of p to calculate the norm for.
* @param values The coefficients of the vector.
*/
private _norm(p: number, ...values: number[]) {
const sum = values.reduce((sum, x) => sum + Math.pow(x, p), 0);
return Math.pow(sum, 1 / p);
}
process(current: DifficultyHitObject): void {
this.rhythm.process(current);
this.colour.process(current);
this.stamina.process(current);
}
/**
* For each section, the peak strains of all separate skills
* are combined into a single peak strain for the section.
* The resulting partial rating of the beatmap is a weighted sum
* of the combined peaks (higher peaks are weighted more).
* @returns The combined star rating of the beatmap,
* calculated using peak strains from all sections of the map.
*/
get difficultyValue(): number {
const peaks: number[] = [];
const colourPeaks = [...this.colour.getCurrentStrainPeaks()];
const rhythmPeaks = [...this.rhythm.getCurrentStrainPeaks()];
const staminaPeaks = [...this.stamina.getCurrentStrainPeaks()];
for (let i = 0; i < colourPeaks.length; ++i) {
const colourPeak = colourPeaks[i] * Peaks.COLOUR_SKILL_MULTIPLIER;
const rhythmPeak = rhythmPeaks[i] * Peaks.RHYTHM_SKILL_MULTIPLIER;
const staminaPeak = staminaPeaks[i] * Peaks.STAMINA_SKILL_MULTIPLIER;
let peak = this._norm(1.5, colourPeak, staminaPeak);
peak = this._norm(2, peak, rhythmPeak);
/**
* Sections with 0 strain are excluded to avoid worst-case
* time complexity of the following sort (e.g. /b/2351871).
* These sections will not contribute to the difficulty.
*/
if (peak > 0) peaks.push(peak);
}
let difficulty = 0;
let weight = 1;
for (const strain of peaks.sort((a, b) => b - a)) {
difficulty += strain * weight;
weight *= 0.9;
}
return difficulty;
}
}