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        self.rotate_z(TIEBRAKER_ROTATION);
105
106        for &side in &[GridSide::Right, GridSide::Left, GridSide::Top, GridSide::Bottom, GridSide::Front, GridSide::Back] {
107            let (best_face_idx, _) = self.faces
108                .iter()
109                .enumerate()
110                .map(|(i, face)| {
111                    let center = face.center();
112                    let value = match side {
113                        GridSide::Right => center.x,
114                        GridSide::Left => -center.x,
115                        GridSide::Top => center.y,
116                        GridSide::Bottom => -center.y,
117                        GridSide::Front => -center.z,
118                        GridSide::Back => center.z,
119                        _ => panic!()
120                    };
121                    (i, value)
122                })
123                .max_by(|a, b| a.1.partial_cmp(&b.1).unwrap())
124                .unwrap();
125
126            let actual_side = GridSide::from_idx(best_face_idx);
127            side_map.insert(side, actual_side);
128        }
129
130        self.rotate_z(-TIEBRAKER_ROTATION);
131        self.rotate_y(-TIEBRAKER_ROTATION);
132        self.rotate_x(TIEBRAKER_ROTATION);
133
134        self.side_map = side_map;
135    }
136
137    pub fn rotate_x(&mut self, angle: f32) {
138        let flipped_offset = self.position.scalar_multiply(-1.0);
139        for face in self.faces.iter_mut() {
140            for p in &mut face.corners {
141                *p = p.translate(flipped_offset);
142                *p = p.rotate_x(angle);
143                *p = p.translate(self.position);
144            }
145            for p in &mut face.markers {
146                *p = p.translate(flipped_offset);
147                *p = p.rotate_x(angle);
148                *p = p.translate(self.position);
149            }
150        }
151    }
152
153    pub fn rotate_y(&mut self, angle: f32) {
154        let flipped_offset = self.position.scalar_multiply(-1.0);
155        for face in self.faces.iter_mut() {
156            for p in &mut face.corners {
157                *p = p.translate(flipped_offset);
158                *p = p.rotate_y(angle);
159                *p = p.translate(self.position);
160            }
161            for p in &mut face.markers {
162                *p = p.translate(flipped_offset);
163                *p = p.rotate_y(angle);
164                *p = p.translate(self.position);
165            }
166        }
167    }
168
169    pub fn rotate_z(&mut self, angle: f32) {
170        let flipped_offset = self.position.scalar_multiply(-1.0);
171        for face in self.faces.iter_mut() {
172            for p in &mut face.corners {
173                *p = p.translate(flipped_offset);
174                *p = p.rotate_z(angle);
175                *p = p.translate(self.position);
176            }
177            for p in &mut face.markers {
178                *p = p.translate(flipped_offset);
179                *p = p.rotate_z(angle);
180                *p = p.translate(self.position);
181            }
182        }
183    }
184
185    pub fn apply_grid(&mut self, grid: &Grid) {
186        self.faces[0].grid_face = grid.faces[0].clone();
187        self.faces[1].grid_face = grid.faces[1].clone();
188        self.faces[2].grid_face = grid.faces[2].clone();
189        self.faces[3].grid_face = grid.faces[3].clone();
190        self.faces[4].grid_face = grid.faces[4].clone();
191        self.faces[5].grid_face = grid.faces[5].clone();
192    }
193
194    fn initial_corners() -> [Point3D; 8] {
195        let h = CUBE_SIZE / 2.0;
196        [
197            Point3D { x: h, y: h, z: -h },
198            Point3D { x: -h, y: h, z: -h },
199            Point3D { x: -h, y: h, z: h },
200            Point3D { x: h, y: h, z: h },
201            
202            Point3D { x: h, y: -h, z: -h },
203            Point3D { x: -h, y: -h, z: -h },
204            Point3D { x: -h, y: -h, z: h },
205            Point3D { x: h, y: -h, z: h },
206        ]
207    }
208
209    pub fn translate_move(&self, cube_move: CubeMove) -> CubeMove {
210        let side = cube_move.grid_side;
211        let mut direction = cube_move.direction;
212        let translated = self.side_map.get(&side.middle_layer_adjacent()).unwrap().clone();
213        if side.is_middle() {
214            let translated_middle = GridSide::middle_layer_from_axis(&translated.axis());
215            if translated.idx() != translated_middle.middle_layer_adjacent().idx() {
216                direction = direction.flip();
217            }
218            CubeMove::from_side(translated_middle, direction)
219        } else {
220            CubeMove::from_side(translated, direction)
221        }
222    }
223}
224
225impl Renderable for Cube {
226    fn get_visible_faces(&self) -> Vec<AnyFace> {
227        let mut faces_clone: Vec<AnyFace> = self.faces.clone()
228            .into_iter()
229            .map(|f| AnyFace::Face(f))
230            .collect();
231
232        faces_clone.sort_by(|a, b| a.avg_z().partial_cmp(&b.avg_z()).unwrap());
233        faces_clone
234    }
235
236    fn dist(&self) -> f32 {
237        let mut sum = 0.0;
238        for face in &self.faces {
239            sum += face.avg_z();
240        }
241
242        sum / 6.0
243    }
244}