cube_core/cube/
cube.rs

1use core::f32;
2use std::collections::HashMap;
3
4use crate::{
5    utils::{
6        geometry::Point3D
7    },
8    cube::{
9        slice::CubeMove,
10        core::{
11            grid::{Grid, GridFace, GridSide},
12        }
13    },
14    game::render::{AnyFace, Renderable}
15};
16
17const CUBE_SIZE: f32 = 2.0;
18const TIEBRAKER_ROTATION: f32 = 0.00390625;
19
20#[derive(Clone)]
21pub struct Face {
22    pub corners: [Point3D; 4],
23    pub markers: Vec<Point3D>,
24    pub grid_face: GridFace,
25}
26
27impl Face {
28    pub fn new(corners: [Point3D; 4], grid_face: GridFace) -> Face {
29        let mut markers = Vec::with_capacity(16);
30        let diff = corners[3].subtract(&corners[0]).scalar_multiply(1.0 / 3.0);
31        for i in 0..4 {
32            Self::create_markers(&mut markers, 
33                corners[0].add(&diff.scalar_multiply(i as f32)), 
34                corners[1].add(&diff.scalar_multiply(i as f32)));
35        }
36
37        Face { corners, markers, grid_face }
38    }
39
40    fn create_markers(markers: &mut Vec<Point3D>, v1: Point3D, v2: Point3D) {
41        let diff = v2.subtract(&v1).scalar_multiply(1.0 / 3.0);
42        for i in 0..4 {
43            markers.push(v1.add(&diff.scalar_multiply(i as f32))); 
44        }
45    }
46
47    pub fn center(&self) -> Point3D {
48        let mut sum = Point3D { x: 0.0, y: 0.0, z: 0.0 };
49        for p in &self.corners {
50            sum.x += p.x;
51            sum.y += p.y;
52            sum.z += p.z;
53        }
54        Point3D {
55            x: sum.x / 4.0,
56            y: sum.y / 4.0,
57            z: sum.z / 4.0,
58        }
59    }
60
61    pub fn avg_z(&self) -> f32 {
62        (self.corners[0].z + self.corners[1].z + self.corners[2].z + self.corners[3].z) / 4.0
63    }
64}
65
66pub struct Cube {
67    pub position: Point3D,
68    pub faces: Vec<Face>,
69    side_map: HashMap<GridSide, GridSide>,
70}
71
72impl Cube {
73    pub fn new(position: (f32, f32, f32), rotation_y: f32, rotation_x: f32) -> Cube {
74        let (x, y, z) = position;
75        let position = Point3D {x, y, z};
76        let corners: Vec<Point3D> = Cube::initial_corners().into_iter()
77            .map(|p| p.translate(position))
78            .collect();
79        let faces = vec![
80            Face::new([corners[2], corners[3], corners[0], corners[1]], GridFace::empty()),
81            Face::new([corners[2], corners[1], corners[5], corners[6]], GridFace::empty()),
82            Face::new([corners[1], corners[0], corners[4], corners[5]], GridFace::empty()),
83            Face::new([corners[0], corners[3], corners[7], corners[4]], GridFace::empty()),
84            Face::new([corners[3], corners[2], corners[6], corners[7]], GridFace::empty()),
85            Face::new([corners[5], corners[4], corners[7], corners[6]], GridFace::empty()),
86        ];
87
88        let mut cube = Cube {
89            position,
90            faces,
91            side_map: HashMap::new(),
92        };
93        cube.rotate_y(rotation_y);
94        cube.rotate_x(rotation_x);
95        cube.update_side_map();
96        cube
97    }
98
99    pub fn update_side_map(&mut self) {
100        let mut side_map = HashMap::new();
101
102        self.rotate_x(-TIEBRAKER_ROTATION);
103        self.rotate_y(TIEBRAKER_ROTATION);
104
105        for &side in &[GridSide::Right, GridSide::Left, GridSide::Top, GridSide::Bottom, GridSide::Front, GridSide::Back] {
106            let (best_face_idx, _) = self.faces
107                .iter()
108                .enumerate()
109                .map(|(i, face)| {
110                    let center = face.center();
111                    let value = match side {
112                        GridSide::Right => center.x,
113                        GridSide::Left => -center.x,
114                        GridSide::Top => center.y,
115                        GridSide::Bottom => -center.y,
116                        GridSide::Front => -center.z,
117                        GridSide::Back => center.z,
118                        _ => panic!()
119                    };
120                    (i, value)
121                })
122                .max_by(|a, b| a.1.partial_cmp(&b.1).unwrap())
123                .unwrap();
124
125            let actual_side = GridSide::from_idx(best_face_idx);
126            side_map.insert(side, actual_side);
127        }
128
129        self.rotate_y(-TIEBRAKER_ROTATION);
130        self.rotate_x(TIEBRAKER_ROTATION);
131
132        self.side_map = side_map;
133    }
134
135    pub fn rotate_x(&mut self, angle: f32) {
136        let flipped_offset = self.position.scalar_multiply(-1.0);
137        for face in self.faces.iter_mut() {
138            for p in &mut face.corners {
139                *p = p.translate(flipped_offset);
140                *p = p.rotate_x(angle);
141                *p = p.translate(self.position);
142            }
143            for p in &mut face.markers {
144                *p = p.translate(flipped_offset);
145                *p = p.rotate_x(angle);
146                *p = p.translate(self.position);
147            }
148        }
149    }
150
151    pub fn rotate_y(&mut self, angle: f32) {
152        let flipped_offset = self.position.scalar_multiply(-1.0);
153        for face in self.faces.iter_mut() {
154            for p in &mut face.corners {
155                *p = p.translate(flipped_offset);
156                *p = p.rotate_y(angle);
157                *p = p.translate(self.position);
158            }
159            for p in &mut face.markers {
160                *p = p.translate(flipped_offset);
161                *p = p.rotate_y(angle);
162                *p = p.translate(self.position);
163            }
164        }
165    }
166
167    pub fn rotate_z(&mut self, angle: f32) {
168        let flipped_offset = self.position.scalar_multiply(-1.0);
169        for face in self.faces.iter_mut() {
170            for p in &mut face.corners {
171                *p = p.translate(flipped_offset);
172                *p = p.rotate_z(angle);
173                *p = p.translate(self.position);
174            }
175            for p in &mut face.markers {
176                *p = p.translate(flipped_offset);
177                *p = p.rotate_z(angle);
178                *p = p.translate(self.position);
179            }
180        }
181    }
182
183    pub fn apply_grid(&mut self, grid: &Grid) {
184        self.faces[0].grid_face = grid.faces[0].clone();
185        self.faces[1].grid_face = grid.faces[1].clone();
186        self.faces[2].grid_face = grid.faces[2].clone();
187        self.faces[3].grid_face = grid.faces[3].clone();
188        self.faces[4].grid_face = grid.faces[4].clone();
189        self.faces[5].grid_face = grid.faces[5].clone();
190    }
191
192    fn initial_corners() -> [Point3D; 8] {
193        let h = CUBE_SIZE / 2.0;
194        [
195            Point3D { x: h, y: h, z: -h },
196            Point3D { x: -h, y: h, z: -h },
197            Point3D { x: -h, y: h, z: h },
198            Point3D { x: h, y: h, z: h },
199            
200            Point3D { x: h, y: -h, z: -h },
201            Point3D { x: -h, y: -h, z: -h },
202            Point3D { x: -h, y: -h, z: h },
203            Point3D { x: h, y: -h, z: h },
204        ]
205    }
206
207    pub fn translate_move(&self, cube_move: CubeMove) -> CubeMove {
208        let side = cube_move.grid_side;
209        let mut direction = cube_move.direction;
210        let translated = self.side_map.get(&side.middle_layer_adjacent()).unwrap().clone();
211        if side.is_middle() {
212            let translated_middle = GridSide::middle_layer_from_axis(&translated.axis());
213            if translated.idx() != translated_middle.middle_layer_adjacent().idx() {
214                direction = direction.flip();
215            }
216            CubeMove::from_side(translated_middle, direction)
217        } else {
218            CubeMove::from_side(translated, direction)
219        }
220    }
221}
222
223impl Renderable for Cube {
224    fn get_visible_faces(&self) -> Vec<AnyFace> {
225        let mut faces_clone: Vec<AnyFace> = self.faces.clone()
226            .into_iter()
227            .map(|f| AnyFace::Face(f))
228            .collect();
229
230        faces_clone.sort_by(|a, b| a.avg_z().partial_cmp(&b.avg_z()).unwrap());
231        faces_clone
232    }
233
234    fn dist(&self) -> f32 {
235        let mut sum = 0.0;
236        for face in &self.faces {
237            sum += face.avg_z();
238        }
239
240        sum / 6.0
241    }
242}