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}