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}