manabrew_engine/mana/
mana_conversion_matrix.rs1use forge_foundation::mana::ManaAtom;
2
3const MANA_TYPES: [u16; 6] = [
5 ManaAtom::WHITE,
6 ManaAtom::BLUE,
7 ManaAtom::BLACK,
8 ManaAtom::RED,
9 ManaAtom::GREEN,
10 ManaAtom::COLORLESS,
11];
12
13const IDENTITY: [u8; 6] = [
15 ManaAtom::WHITE as u8,
16 ManaAtom::BLUE as u8,
17 ManaAtom::BLACK as u8,
18 ManaAtom::RED as u8,
19 ManaAtom::GREEN as u8,
20 ManaAtom::COLORLESS as u8,
21];
22
23#[derive(Debug, Clone)]
30pub struct ManaConversionMatrix {
31 color_conversion_matrix: [u8; 6],
33 color_restriction_matrix: [u8; 6],
35 snow_for_color: bool,
37}
38
39impl Default for ManaConversionMatrix {
40 fn default() -> Self {
41 let mut m = Self {
42 color_conversion_matrix: [0; 6],
43 color_restriction_matrix: [0xFF; 6],
44 snow_for_color: false,
45 };
46 m.restore_color_replacements();
47 m
48 }
49}
50
51impl ManaConversionMatrix {
52 pub fn new() -> Self {
55 Self::default()
56 }
57
58 pub fn get_possible_color_uses(&self, color: u8) -> u8 {
61 let idx = get_index_of_first_mana_type(color);
62 let matrix_idx = if idx < 0 { 5 } else { idx as usize };
63 self.color_conversion_matrix[matrix_idx] & self.color_restriction_matrix[matrix_idx]
64 }
65
66 pub fn adjust_color_replacement(&mut self, original: u8, replacement: u8, additive: bool) {
69 let row_idx = get_index_of_first_mana_type(original);
70 let idx = if row_idx < 0 { 5 } else { row_idx as usize };
71 if additive {
72 self.color_conversion_matrix[idx] |= replacement;
73 } else {
74 self.color_restriction_matrix[idx] &= replacement;
75 }
76 }
77
78 pub fn apply_card_matrix(&mut self, other: &ManaConversionMatrix) {
81 for i in 0..6 {
82 self.color_conversion_matrix[i] |= other.color_conversion_matrix[i];
83 }
84 for i in 0..6 {
85 self.color_restriction_matrix[i] &= other.color_restriction_matrix[i];
86 }
87 self.snow_for_color = other.snow_for_color;
88 }
89
90 pub fn restore_color_replacements(&mut self) {
93 self.color_conversion_matrix = IDENTITY;
94 self.color_restriction_matrix = [ManaAtom::ALL_MANA_TYPES as u8; 6];
95 self.snow_for_color = false;
96 }
97
98 pub fn is_snow_for_color(&self) -> bool {
101 self.snow_for_color
102 }
103
104 pub fn set_snow_for_color(&mut self, value: bool) {
107 self.snow_for_color = value;
108 }
109}
110
111fn get_index_of_first_mana_type(color: u8) -> i32 {
114 for (i, &mt) in MANA_TYPES.iter().enumerate() {
115 if (color as u16 & mt) != 0 {
116 return i as i32;
117 }
118 }
119 -1
120}
121
122#[cfg(test)]
123mod tests {
124 use super::*;
125
126 #[test]
127 fn identity_matrix_maps_each_color_to_itself() {
128 let m = ManaConversionMatrix::new();
129 assert_eq!(
130 m.get_possible_color_uses(ManaAtom::WHITE as u8),
131 ManaAtom::WHITE as u8
132 );
133 assert_eq!(
134 m.get_possible_color_uses(ManaAtom::BLUE as u8),
135 ManaAtom::BLUE as u8
136 );
137 assert_eq!(
138 m.get_possible_color_uses(ManaAtom::COLORLESS as u8),
139 ManaAtom::COLORLESS as u8
140 );
141 }
142
143 #[test]
144 fn additive_replacement_broadens_uses() {
145 let mut m = ManaConversionMatrix::new();
146 m.adjust_color_replacement(ManaAtom::WHITE as u8, ManaAtom::BLUE as u8, true);
147 let uses = m.get_possible_color_uses(ManaAtom::WHITE as u8);
148 assert_ne!(uses & ManaAtom::WHITE as u8, 0);
149 assert_ne!(uses & ManaAtom::BLUE as u8, 0);
150 }
151
152 #[test]
153 fn restrictive_replacement_narrows_uses() {
154 let mut m = ManaConversionMatrix::new();
155 m.adjust_color_replacement(ManaAtom::WHITE as u8, ManaAtom::WHITE as u8, false);
157 let uses = m.get_possible_color_uses(ManaAtom::WHITE as u8);
158 assert_eq!(uses, ManaAtom::WHITE as u8);
159 }
160
161 #[test]
162 fn restore_resets_matrix() {
163 let mut m = ManaConversionMatrix::new();
164 m.adjust_color_replacement(ManaAtom::RED as u8, ManaAtom::GREEN as u8, true);
165 m.restore_color_replacements();
166 let uses = m.get_possible_color_uses(ManaAtom::RED as u8);
167 assert_eq!(uses, ManaAtom::RED as u8);
168 }
169}