1use crate::{
2 utils::{
3 cube_utils::{Axis, Color},
4 geometry::Point3D
5 },
6 cube::{
7 cube::Face,
8 core::{
9 grid::{GridSide, MoveDirection}
10 }
11 },
12 game::render::{AnyFace, Renderable}
13};
14
15const TIEBREAKER_WEIGHT: f32 = 0.001;
16const MAGIC_THINGY: f32 = 0.2;
17
18#[derive(Clone)]
19pub struct FaceSlice {
20 corners: [Point3D; 4],
21 pub markers: Vec<Point3D>,
22 pub colors: [Color; 3],
23}
24
25impl FaceSlice {
26 fn new(corners: [Point3D; 4], colors: [Color; 3]) -> FaceSlice {
27 let mut markers = Vec::with_capacity(8);
28 let diff = corners[3].subtract(&corners[0]).scalar_multiply(1.0 / 3.0);
29 for i in 0..4 {
30 markers.push(corners[0].add(&diff.scalar_multiply(i as f32)));
31 markers.push(corners[1].add(&diff.scalar_multiply(i as f32)));
32 };
33
34 FaceSlice { corners, markers, colors }
35 }
36
37 fn avg_x(&self) -> f32 {
38 (self.corners[0].x.abs() + self.corners[1].x.abs() + self.corners[2].x.abs() + self.corners[3].x.abs()) / 4.0
39 }
40
41 fn avg_y(&self) -> f32 {
42 (self.corners[0].y.abs() + self.corners[1].y.abs() + self.corners[2].y.abs() + self.corners[3].y.abs()) / 4.0
43 }
44
45 pub fn avg_z(&self) -> f32 {
46 (self.corners[0].z + self.corners[1].z + self.corners[2].z + self.corners[3].z) / 4.0 + MAGIC_THINGY
47 }
48}
49
50#[derive(Debug, Clone)]
51pub struct CubeMove {
52 pub axis: Axis,
53 pub grid_side: GridSide,
54 pub order: CubeSliceOrder,
55 pub direction: MoveDirection,
56}
57
58impl CubeMove {
59 pub fn from_side(grid_side: GridSide, direction: MoveDirection) -> CubeMove {
60 CubeMove { axis: grid_side.axis(), grid_side, order: grid_side.order(), direction }
61 }
62
63 pub fn from_str(mv: &str) -> Result<(GridSide, MoveDirection), String> {
64 let (side_char, suffix) = mv.split_at(1);
65
66 let grid_side= match side_char {
67 "R" => GridSide::Right,
68 "L" => GridSide::Left,
69 "U" => GridSide::Top,
70 "D" => GridSide::Bottom,
71 "F" => GridSide::Front,
72 "B" => GridSide::Back,
73 "M" => GridSide::MiddleX,
74 "E" => GridSide::MiddleY,
75 "S" => GridSide::MiddleZ,
76 _ => return Err(format!("Incorrect move '{}'", mv)),
77 };
78 let direction = match suffix {
79 "" => Ok(MoveDirection::Clockwise),
80 "'" => Ok(MoveDirection::CounterClockwise),
81 "2" => Ok(MoveDirection::Double),
82 _ => Err(format!("Incorrect move '{}'", mv)),
83 }?;
84
85 Ok((grid_side, direction))
86 }
87}
88
89#[derive(Debug, Clone)]
90pub enum CubeSliceOrder {
91 FIRST,
92 MIDDLE,
93 LAST,
94}
95
96impl CubeSliceOrder {
97 pub fn idx(&self) -> usize {
98 match self {
99 Self::FIRST => 0,
100 Self::MIDDLE => 1,
101 Self::LAST => 2,
102 }
103 }
104}
105
106#[derive(Clone)]
107pub struct CubeSlice {
108 pub global_cube_position: Point3D,
109 pub face_1: Face,
110 pub face_2: Face,
111 pub face_slices: [FaceSlice; 4],
112}
113
114impl CubeSlice {
115 pub fn new(
116 global_cube_position: Point3D,
117 face_1: Face,
118 face_2: Face,
119 mut colors: Vec<[Color; 3]>,
120 axis: &Axis,
121 order: CubeSliceOrder
122 ) -> CubeSlice {
123
124 Self::flip_colors(&mut colors, axis, order);
125
126 let face_slices = [
127 FaceSlice::new(
128 [
129 face_1.corners[0],
130 face_2.corners[1],
131 face_2.corners[0],
132 face_1.corners[1],
133 ],
134 *colors.get(0).unwrap()
135 ),
136 FaceSlice::new(
137 [
138 face_1.corners[1],
139 face_2.corners[0],
140 face_2.corners[3],
141 face_1.corners[2],
142 ],
143 *colors.get(1).unwrap()
144 ),
145 FaceSlice::new(
146 [
147 face_1.corners[2],
148 face_2.corners[3],
149 face_2.corners[2],
150 face_1.corners[3],
151 ],
152 *colors.get(2).unwrap()
153 ),
154 FaceSlice::new(
155 [
156 face_1.corners[3],
157 face_2.corners[2],
158 face_2.corners[1],
159 face_1.corners[0],
160 ],
161 *colors.get(3).unwrap()
162 ),
163 ];
164
165 CubeSlice { global_cube_position, face_1, face_2, face_slices }
166 }
167
168 fn flip_colors(
169 colors: &mut Vec<[Color; 3]>,
170 axis: &Axis,
171 order: CubeSliceOrder
172 ) {
173 match axis {
174 Axis::X => {
175 if let CubeSliceOrder::LAST = &order { } else {
176 for i in 0..4 {
177 if let Some(color) = colors.get_mut(i) {
178 color.reverse();
179 }
180 }
181 }
182 },
183 Axis::Y => {
184 if let CubeSliceOrder::LAST = &order {
185 colors.rotate_right(2);
186 } else {
187 for i in 0..4 {
188 if let Some(color) = colors.get_mut(i) {
189 color.reverse();
190 }
191 }
192 }
193 },
194 Axis::Z => {
195 if let CubeSliceOrder::LAST = &order { } else {
196 for i in 0..4 {
197 if let Some(color) = colors.get_mut(i) {
198 color.reverse();
199 }
200 }
201 }
202 }
203 }
204 }
205
206 pub fn rotate_around_own_axis(&mut self, angle_rad: f32) {
207 let center1 = self.face_1.center();
208 let center2 = self.face_2.center();
209 let axis = center2.subtract(¢er1);
210
211 for p in &mut self.face_1.corners {
212 *p = p.rotate_around_axis(axis, center1, angle_rad);
213 }
214 for p in &mut self.face_1.markers {
215 *p = p.rotate_around_axis(axis, center1, angle_rad);
216 }
217
218 for p in &mut self.face_2.corners {
219 *p = p.rotate_around_axis(axis, center1, angle_rad);
220 }
221 for p in &mut self.face_2.markers {
222 *p = p.rotate_around_axis(axis, center1, angle_rad);
223 }
224
225 for slice in &mut self.face_slices {
226 for p in &mut slice.corners {
227 *p = p.rotate_around_axis(axis, center1, angle_rad);
228 }
229 for p in &mut slice.markers {
230 *p = p.rotate_around_axis(axis, center1, angle_rad);
231 }
232 }
233 }
234
235 pub fn rotate(&mut self, axis: Axis, angle: f32) {
236 let rotate_fn: Box<dyn Fn(Point3D) -> Point3D> = match axis {
237 Axis::X => Box::new(move |p| p.rotate_x(angle)),
238 Axis::Y => Box::new(move |p| p.rotate_y(angle)),
239 Axis::Z => Box::new(move |p| p.rotate_z(angle)),
240 };
241
242 let flipped_offset = self.global_cube_position.scalar_multiply(-1.0);
243 for p in &mut self.face_1.corners {
244 *p = p.translate(flipped_offset);
245 *p = rotate_fn(*p);
246 *p = p.translate(self.global_cube_position);
247 }
248 for p in &mut self.face_1.markers {
249 *p = p.translate(flipped_offset);
250 *p = rotate_fn(*p);
251 *p = p.translate(self.global_cube_position);
252 }
253
254 for p in &mut self.face_2.corners {
255 *p = p.translate(flipped_offset);
256 *p = rotate_fn(*p);
257 *p = p.translate(self.global_cube_position);
258 }
259 for p in &mut self.face_2.markers {
260 *p = p.translate(flipped_offset);
261 *p = rotate_fn(*p);
262 *p = p.translate(self.global_cube_position);
263 }
264
265 for slice in &mut self.face_slices {
266 for p in &mut slice.corners {
267 *p = p.translate(flipped_offset);
268 *p = rotate_fn(*p);
269 *p = p.translate(self.global_cube_position);
270 }
271 for p in &mut slice.markers {
272 *p = p.translate(flipped_offset);
273 *p = rotate_fn(*p);
274 *p = p.translate(self.global_cube_position);
275 }
276 }
277 }
278}
279
280impl Renderable for CubeSlice {
281 fn get_visible_faces(&self) -> Vec<AnyFace> {
282 let mut faces = vec![
283 AnyFace::Face(self.face_1.clone()),
284 AnyFace::Face(self.face_2.clone()),
285 ];
286
287 faces.extend(self.face_slices.iter()
288 .cloned()
289 .map(AnyFace::FaceSlice));
290
291 faces.sort_by(|a, b| a.avg_z().partial_cmp(&b.avg_z()).unwrap());
292 faces
293 }
294
295 fn dist(&self) -> f32 {
296 let mut sum = 0.0;
297
298 sum += self.face_1.avg_z();
299 sum += self.face_2.avg_z();
300
301 for fs in &self.face_slices {
302 sum += fs.avg_z();
303 sum += fs.avg_y() * TIEBREAKER_WEIGHT; sum += fs.avg_x() * TIEBREAKER_WEIGHT; }
306
307 sum / 6.0
308 }
309}