lean_ctx/core/buddy/
evolution.rs1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
4pub enum EvolutionStage {
5 #[default]
6 Egg,
7 Baby,
8 Teen,
9 Adult,
10 Mythic,
11}
12
13impl EvolutionStage {
14 pub fn from_level(level: u32) -> Self {
15 match level {
16 0..=4 => Self::Egg,
17 5..=14 => Self::Baby,
18 15..=34 => Self::Teen,
19 35..=64 => Self::Adult,
20 _ => Self::Mythic,
21 }
22 }
23
24 pub fn label(&self) -> &'static str {
25 match self {
26 Self::Egg => "Egg",
27 Self::Baby => "Baby",
28 Self::Teen => "Teen",
29 Self::Adult => "Adult",
30 Self::Mythic => "Mythic",
31 }
32 }
33
34 pub fn icon(&self) -> &'static str {
35 match self {
36 Self::Egg => "🥚",
37 Self::Baby => "🐣",
38 Self::Teen => "🌱",
39 Self::Adult => "⚔️",
40 Self::Mythic => "✨",
41 }
42 }
43
44 pub fn sprite_height(&self) -> usize {
45 match self {
46 Self::Egg => 3,
47 Self::Baby => 8,
48 Self::Teen => 10,
49 Self::Adult => 12,
50 Self::Mythic => 15,
51 }
52 }
53
54 pub fn next(&self) -> Option<Self> {
56 match self {
57 Self::Egg => Some(Self::Baby),
58 Self::Baby => Some(Self::Teen),
59 Self::Teen => Some(Self::Adult),
60 Self::Adult => Some(Self::Mythic),
61 Self::Mythic => None,
62 }
63 }
64
65 pub fn min_level(&self) -> u32 {
67 match self {
68 Self::Egg => 0,
69 Self::Baby => 5,
70 Self::Teen => 15,
71 Self::Adult => 35,
72 Self::Mythic => 65,
73 }
74 }
75
76 pub fn progress(&self, level: u32) -> f64 {
78 let Some(next) = self.next() else {
79 return 1.0;
80 };
81 let range = next.min_level() - self.min_level();
82 let within = level.saturating_sub(self.min_level());
83 (within as f64 / range as f64).min(1.0)
84 }
85}
86
87#[cfg(test)]
88mod tests {
89 use super::*;
90
91 #[test]
92 fn stage_from_level() {
93 assert_eq!(EvolutionStage::from_level(0), EvolutionStage::Egg);
94 assert_eq!(EvolutionStage::from_level(4), EvolutionStage::Egg);
95 assert_eq!(EvolutionStage::from_level(5), EvolutionStage::Baby);
96 assert_eq!(EvolutionStage::from_level(14), EvolutionStage::Baby);
97 assert_eq!(EvolutionStage::from_level(15), EvolutionStage::Teen);
98 assert_eq!(EvolutionStage::from_level(34), EvolutionStage::Teen);
99 assert_eq!(EvolutionStage::from_level(35), EvolutionStage::Adult);
100 assert_eq!(EvolutionStage::from_level(64), EvolutionStage::Adult);
101 assert_eq!(EvolutionStage::from_level(65), EvolutionStage::Mythic);
102 assert_eq!(EvolutionStage::from_level(99), EvolutionStage::Mythic);
103 }
104
105 #[test]
106 fn progress_within_stage() {
107 let stage = EvolutionStage::Egg;
108 assert!((stage.progress(0) - 0.0).abs() < 0.01);
109 assert!((stage.progress(4) - 0.8).abs() < 0.01);
110 assert_eq!(EvolutionStage::Mythic.progress(99), 1.0);
111 }
112
113 #[test]
114 fn next_chain() {
115 let mut s = EvolutionStage::Egg;
116 let chain: Vec<_> = std::iter::from_fn(|| {
117 let next = s.next()?;
118 s = next;
119 Some(next)
120 })
121 .collect();
122 assert_eq!(chain.len(), 4);
123 assert_eq!(chain[3], EvolutionStage::Mythic);
124 }
125}