manabrew_engine/phase/
phase_type.rs1pub use forge_foundation::PhaseType;
8
9use std::collections::HashSet;
10
11pub fn phase_group_index(phase: PhaseType) -> usize {
17 match phase {
18 PhaseType::Untap | PhaseType::Upkeep | PhaseType::Draw => 0,
19 PhaseType::Main1 => 1,
20 PhaseType::CombatBegin
21 | PhaseType::CombatDeclareAttackers
22 | PhaseType::CombatDeclareBlockers
23 | PhaseType::CombatFirstStrikeDamage
24 | PhaseType::CombatDamage
25 | PhaseType::CombatEnd => 2,
26 PhaseType::Main2 => 3,
27 PhaseType::EndOfTurn => 4,
28 PhaseType::Cleanup => 5,
29 }
30}
31
32pub fn parse_range(values: &str) -> HashSet<PhaseType> {
36 let mut result = HashSet::new();
37 for s in values.split(',') {
38 let s = s.trim();
39 if let Some(idx) = s.find("->") {
40 let from_str = &s[..idx];
41 let to_str = &s[idx + 2..];
42 let from = smart_value_of(from_str);
43 let to = if to_str.trim().is_empty() {
44 Some(PhaseType::Cleanup)
45 } else {
46 smart_value_of(to_str)
47 };
48 if let (Some(from), Some(to)) = (from, to) {
49 let from_idx = from.index();
50 let to_idx = to.index();
51 for &phase in &PhaseType::TURN_ORDER[from_idx..=to_idx] {
52 result.insert(phase);
53 }
54 }
55 } else if s.eq_ignore_ascii_case("Main") {
56 result.insert(PhaseType::Main1);
57 result.insert(PhaseType::Main2);
58 } else if let Some(phase) = smart_value_of(s) {
59 result.insert(phase);
60 }
61 }
62 result
63}
64
65pub fn smart_value_of(value: &str) -> Option<PhaseType> {
68 PhaseType::from_script_name(value)
69}
70
71pub fn is_last(phase: PhaseType) -> bool {
74 phase == PhaseType::Cleanup
75}
76
77pub fn get_next(phase: PhaseType, is_topsy: bool) -> PhaseType {
80 if is_topsy {
81 let idx = phase.index();
82 if idx == 0 {
83 PhaseType::TURN_ORDER[PhaseType::TURN_ORDER.len() - 1]
84 } else {
85 PhaseType::TURN_ORDER[idx - 1]
86 }
87 } else {
88 phase.next()
89 }
90}
91
92#[cfg(test)]
93mod tests {
94 use super::*;
95
96 #[test]
97 fn parse_range_simple() {
98 let result = parse_range("Upkeep");
99 assert!(result.contains(&PhaseType::Upkeep));
100 assert_eq!(result.len(), 1);
101 }
102
103 #[test]
104 fn parse_range_main_alias() {
105 let result = parse_range("Main");
106 assert!(result.contains(&PhaseType::Main1));
107 assert!(result.contains(&PhaseType::Main2));
108 assert_eq!(result.len(), 2);
109 }
110
111 #[test]
112 fn parse_range_arrow() {
113 let result = parse_range("Upkeep->Main1");
114 assert!(result.contains(&PhaseType::Upkeep));
115 assert!(result.contains(&PhaseType::Draw));
116 assert!(result.contains(&PhaseType::Main1));
117 assert_eq!(result.len(), 3);
118 }
119
120 #[test]
121 fn smart_value_of_test() {
122 assert_eq!(smart_value_of("BeginCombat"), Some(PhaseType::CombatBegin));
123 assert_eq!(smart_value_of("End of Turn"), Some(PhaseType::EndOfTurn));
124 }
125
126 #[test]
127 fn is_last_test() {
128 assert!(is_last(PhaseType::Cleanup));
129 assert!(!is_last(PhaseType::EndOfTurn));
130 }
131
132 #[test]
133 fn get_next_normal() {
134 assert_eq!(get_next(PhaseType::Untap, false), PhaseType::Upkeep);
135 assert_eq!(get_next(PhaseType::Cleanup, false), PhaseType::Untap);
136 }
137
138 #[test]
139 fn get_next_topsy() {
140 assert_eq!(get_next(PhaseType::Upkeep, true), PhaseType::Untap);
141 assert_eq!(get_next(PhaseType::Untap, true), PhaseType::Cleanup);
142 }
143}