1use serde::Deserialize;
2use thousands::Separable;
3
4type XP = f64;
10type Level = u64;
11type Rank = u64;
12
13#[derive(Debug, Copy, Clone, PartialEq, Deserialize)]
14pub struct Skill {
15 pub rank: Rank,
16 pub level: Level,
17 pub xp: XP
18}
19
20impl Skill {
21 pub fn xp_till_200_mill(self) -> XP {
22 200_000_000f64 - self.xp
23 }
24
25 pub fn xp_at_level(level: Level) -> XP {
26 let prev_level_sum: f64 = (1..level).into_iter()
27 .map(|n: u64| n as f64 + 300.0 * 2f64.powf(n as f64/7.0))
28 .sum();
29
30 (1.0/4.0) * prev_level_sum
31 }
32
33 pub fn xp_till_level(self, level: Level) -> XP {
34 if level < self.level {
35 panic!("Your level is higher than the provided level")
36 }
37
38 Self::xp_at_level(level) - self.xp
39 }
40}
41
42impl Into<Skill> for (Rank, Level, XP) {
43 fn into(self) -> Skill {
44 Skill {
45 rank: self.0,
46 level: self.1,
47 xp: self.2
48 }
49 }
50}
51
52impl std::fmt::Display for Skill {
54 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55 let rank = self.rank.separate_with_commas();
56 let level = self.level.separate_with_commas();
57 let xp = self.xp.separate_with_commas();
58
59 write!(f, "({}, {}, {})", rank, level, xp)
60 }
61}
62
63
64
65impl Default for Skill {
66 fn default() -> Self {
67 Skill {
68 rank: 0,
69 level: 0,
70 xp: 0f64
71 }
72 }
73}
74
75#[cfg(test)]
76mod tests {
77 use super::*;
78
79 #[test]
82 fn test_xp_at_level() {
83 assert_eq!(Skill::xp_at_level(50), 101_333f64);
84 }
85
86 #[test]
87 fn test_xp_till_200_mill() {
88 let skill_1 = Skill {
89 rank: 20_000,
90 level: 33,
91 xp: 19_000f64
92 };
93
94 assert_eq!(skill_1.xp_till_200_mill(), 200_000_000f64 - skill_1.xp);
95 }
96
97 #[test]
98 fn test_xp_till_level() {
99 let skill_1 = Skill {
100 rank: 20_000,
101 level: 33,
102 xp: 19_000f64
103 };
104
105 assert_eq!(skill_1.xp_till_level(50), 101_333f64 - 19_000f64);
106 }
107}
108