cube_lib/
lib.rs

1use std::time::SystemTime;
2
3use rand::random;
4
5pub use types::Face;
6use utils::rot;
7
8use crate::utils::make_svg;
9
10mod utils;
11mod types;
12mod resvg;
13
14const CUBE_OPERATIONS_CODE: [char; 12] = [
15    'F', 'f', 'B', 'b', 'L', 'l', 'R', 'r', 'U', 'u', 'D', 'd'];
16
17pub struct Cube {
18    pub start_time: u128,
19    pub last_step: String,
20    pub front: Face,
21    pub back: Face,
22    pub left: Face,
23    pub right: Face,
24    pub up: Face,
25    pub down: Face,
26}
27impl Cube {
28    pub fn new() -> Cube {
29        let start_time = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_millis();
30        let last_step = String::from("");
31        Cube {
32            start_time,
33            last_step,
34            front: [[1, 2, 3], [4, 5, 6], [7, 8, 9]],
35            back: [[10, 11, 12], [13, 14, 15], [16, 17, 18]],
36            left: [[19, 20, 21], [22, 23, 24], [25, 26, 27]],
37            right: [[28, 29, 30], [31, 32, 33], [34, 35, 36]],
38            up: [[37, 38, 39], [40, 41, 42], [43, 44, 45]],
39            down: [[46, 47, 48], [49, 50, 51], [52, 53, 54]],
40        }
41    }
42    pub fn reset(&mut self) {
43        self.start_time = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_millis();
44        self.front = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
45        self.back = [[10, 11, 12], [13, 14, 15], [16, 17, 18]];
46        self.left = [[19, 20, 21], [22, 23, 24], [25, 26, 27]];
47        self.right = [[28, 29, 30], [31, 32, 33], [34, 35, 36]];
48        self.up = [[37, 38, 39], [40, 41, 42], [43, 44, 45]];
49        self.down = [[46, 47, 48], [49, 50, 51], [52, 53, 54]];
50    }
51
52    fn rot_front(&mut self, rev: bool) {
53        let temp_left = self.left;
54        let temp_up = self.up[2];
55        let temp_right = self.right;
56        self.front = rot(self.front, rev);
57        let temp_down = self.down[0];
58        if rev {
59            for i in 0..3 {
60                self.left[i][2] = temp_up[2 - i];
61                self.right[i][0] = temp_down[2 - i];
62                self.up[2][i] = temp_right[i][0];
63                self.down[0][i] = temp_left[i][2];
64            }
65        } else {
66            for i in 0..3 {
67                self.left[i][2] = temp_down[i];
68                self.right[i][0] = temp_up[i];
69                self.up[2][i] = temp_left[2 - i][2];
70                self.down[0][i] = temp_right[2 - i][0];
71            }
72        }
73    }
74    fn rot_back(&mut self, rev: bool) {
75        let temp_left = self.left;
76        let temp_up = self.up[0];
77        let temp_right = self.right;
78        self.back = rot(self.back, rev);
79        let temp_down = self.down[2];
80        if rev {
81            for i in 0..3 {
82                self.left[i][0] = temp_down[i];
83                self.right[i][2] = temp_up[i];
84                self.up[0][i] = temp_left[2 - i][0];
85                self.down[2][i] = temp_right[2 - i][2];
86            }
87        } else {
88            for i in 0..3 {
89                self.left[i][0] = temp_up[2 - i];
90                self.right[i][2] = temp_down[2 - i];
91                self.up[0][i] = temp_right[i][2];
92                self.down[2][i] = temp_left[i][0];
93            }
94        }
95    }
96    fn rot_left(&mut self, rev: bool) {
97        let temp_front = self.front;
98        let temp_up = self.up;
99        let temp_back = self.back;
100        let temp_down = self.down;
101        self.left = rot(self.left, rev);
102        if rev {
103            for i in 0..3 {
104                self.front[i][0] = temp_down[i][0];
105                self.back[i][2] = temp_up[2 - i][0];
106                self.down[i][0] = temp_back[2 - i][2];
107                self.up[i][0] = temp_front[i][0];
108            }
109        } else {
110            for i in 0..3 {
111                self.front[i][0] = temp_up[i][0];
112                self.up[i][0] = temp_back[2 - i][2];
113                self.back[i][2] = temp_down[2 - i][0];
114                self.down[i][0] = temp_front[i][0];
115            }
116        }
117    }
118    fn rot_right(&mut self, rev: bool) {
119        let temp_front = self.front;
120        let temp_up = self.up;
121        let temp_back = self.back;
122        let temp_down = self.down;
123        self.right = rot(self.right, rev);
124        if rev {
125            for i in 0..3 {
126                self.front[i][2] = temp_up[i][2];
127                self.back[i][0] = temp_down[2 - i][2];
128                self.down[i][2] = temp_front[i][2];
129                self.up[i][2] = temp_back[2 - i][0];
130            }
131        } else {
132            for i in 0..3 {
133                self.front[i][2] = temp_down[i][2];
134                self.up[i][2] = temp_front[i][2];
135                self.back[i][0] = temp_up[2 - i][2];
136                self.down[i][2] = temp_back[2 - i][0];
137            }
138        }
139    }
140    fn rot_up(&mut self, rev: bool) {
141        let temp_front = self.front;
142        let temp_left = self.left;
143        let temp_back = self.back;
144        let temp_right = self.right;
145        self.up = rot(self.up, rev);
146        if rev {
147            for i in 0..3 {
148                self.front[0][i] = temp_left[0][i];
149                self.left[0][i] = temp_back[0][i];
150                self.back[0][i] = temp_right[0][i];
151                self.right[0][i] = temp_front[0][i];
152            }
153        } else {
154            for i in 0..3 {
155                self.front[0][i] = temp_right[0][i];
156                self.left[0][i] = temp_front[0][i];
157                self.back[0][i] = temp_left[0][i];
158                self.right[0][i] = temp_back[0][i];
159            }
160        }
161    }
162    fn rot_down(&mut self, rev: bool) {
163        let temp_front = self.front;
164        let temp_left = self.left;
165        let temp_back = self.back;
166        let temp_right = self.right;
167        self.down = rot(self.down, rev);
168        if rev {
169            for i in 0..3 {
170                self.front[2][i] = temp_right[2][i];
171                self.left[2][i] = temp_front[2][i];
172                self.back[2][i] = temp_left[2][i];
173                self.right[2][i] = temp_back[2][i];
174            }
175        } else {
176            for i in 0..3 {
177                self.front[2][i] = temp_left[2][i];
178                self.left[2][i] = temp_back[2][i];
179                self.back[2][i] = temp_right[2][i];
180                self.right[2][i] = temp_front[2][i];
181            }
182        }
183    }
184
185    pub fn is_solved(&self) -> bool {
186        for i in 0..3 {
187            for j in 0..3 {
188                match self.front[i][j] {
189                    1..=9 => (),
190                    _ => return false,
191                }
192                match self.back[i][j] {
193                    10..=18 => (),
194                    _ => return false,
195                }
196                match self.left[i][j] {
197                    19..=27 => (),
198                    _ => return false,
199                }
200                match self.right[i][j] {
201                    28..=36 => (),
202                    _ => return false,
203                }
204                match self.up[i][j] {
205                    37..=45 => (),
206                    _ => return false,
207                }
208                match self.down[i][j] {
209                    46..=54 => (),
210                    _ => return false,
211                }
212            }
213        }
214        true
215    }
216
217    pub fn rot(&mut self, operation: char) {
218        match operation {
219            'F' => self.rot_front(true),
220            'f' => self.rot_front(false),
221            'B' => self.rot_back(true),
222            'b' => self.rot_back(false),
223            'L' => self.rot_left(true),
224            'l' => self.rot_left(false),
225            'R' => self.rot_right(true),
226            'r' => self.rot_right(false),
227            'U' => self.rot_up(true),
228            'u' => self.rot_up(false),
229            'D' => self.rot_down(true),
230            'd' => self.rot_down(false),
231            _ => (),
232        }
233    }
234
235    pub fn scramble(&mut self, steps: u32) {
236        for _ in 0..steps {
237            let operation = random::<u8>() % 12;
238            self.rot(CUBE_OPERATIONS_CODE[operation as usize]);
239        }
240    }
241
242    pub fn rots(&mut self, operations: &str) {
243        self.last_step.clear();
244        for operation in operations.chars() {
245            if CUBE_OPERATIONS_CODE.contains(&operation) {
246                self.rot(operation);
247                self.last_step.push(operation);
248            }
249        }
250    }
251
252    pub fn get_svg(&self) -> String {
253        let cube: [[[i8; 3]; 3]; 9] = [self.left, self.front, self.up, self.down, self.right, self.back, self.front, self.up, self.right];
254        make_svg(cube)
255    }
256
257    pub fn get_svg_base64_png(&self) -> String {
258        let svg = self.get_svg();
259        resvg::render(svg)
260    }
261}
262
263#[cfg(test)]
264mod tests {
265    use super::*;
266
267    #[test]
268    fn it_works_rot_front() {
269        let mut cube = Cube::new();
270        cube.rot_front(false);
271
272        // down: [
273        // [46, 47, 48],
274        // [49, 50, 51],
275        // [52, 53, 54]],
276        assert_eq!(cube.left, [
277            [19, 20, 46],
278            [22, 23, 47],
279            [25, 26, 48]]);
280        // left: [
281        // [19, 20, 21],
282        // [22, 23, 24],
283        // [25, 26, 27]],
284        assert_eq!(cube.up, [
285            [37, 38, 39],
286            [40, 41, 42],
287            [27, 24, 21]]);
288        // up: [
289        // [37, 38, 39],
290        // [40, 41, 42],
291        // [43, 44, 45]],
292        assert_eq!(cube.right, [
293            [43, 29, 30],
294            [44, 32, 33],
295            [45, 35, 36]]);
296        // right: [
297        // [28, 29, 30],
298        // [31, 32, 33],
299        // [34, 35, 36]],
300        assert_eq!(cube.down, [
301            [34, 31, 28],
302            [49, 50, 51],
303            [52, 53, 54]]);
304    }
305    #[test]
306    fn it_works_rot_front_rev() {
307        let mut cube = Cube::new();
308        cube.rot_front(true);
309        // up: [
310        // [37, 38, 39],
311        // [40, 41, 42],
312        // [43, 44, 45]],
313        assert_eq!(cube.left, [
314            [19, 20, 45],
315            [22, 23, 44],
316            [25, 26, 43]]);
317        // right: [
318        // [28, 29, 30],
319        // [31, 32, 33],
320        // [34, 35, 36]],
321        assert_eq!(cube.up, [
322            [37, 38, 39],
323            [40, 41, 42],
324            [28, 31, 34]]);
325        // down: [
326        // [46, 47, 48],
327        // [49, 50, 51],
328        // [52, 53, 54]],
329        assert_eq!(cube.right, [
330            [48, 29, 30],
331            [47, 32, 33],
332            [46, 35, 36]]);
333        // left: [
334        // [19, 20, 21],
335        // [22, 23, 24],
336        // [25, 26, 27]],
337        assert_eq!(cube.down, [
338            [21, 24, 27],
339            [49, 50, 51],
340            [52, 53, 54]]);
341    }
342
343    #[test]
344    fn it_works_rot_back() {
345        let mut cube = Cube::new();
346        cube.rot_back(false);
347        // up: [
348        // [37, 38, 39],
349        // [40, 41, 42],
350        // [43, 44, 45]],
351        assert_eq!(cube.left, [
352            [39, 20, 21],
353            [38, 23, 24],
354            [37, 26, 27]]);
355        // right: [
356        // [28, 29, 30],
357        // [31, 32, 33],
358        // [34, 35, 36]],
359        assert_eq!(cube.up, [
360            [30, 33, 36],
361            [40, 41, 42],
362            [43, 44, 45]]);
363        // down: [
364        // [46, 47, 48],
365        // [49, 50, 51],
366        // [52, 53, 54]],
367        assert_eq!(cube.right, [
368            [28, 29, 54],
369            [31, 32, 53],
370            [34, 35, 52]]);
371        // left: [
372        // [19, 20, 21],
373        // [22, 23, 24],
374        // [25, 26, 27]],
375        assert_eq!(cube.down, [
376            [46, 47, 48],
377            [49, 50, 51],
378            [19, 22, 25]]);
379    }
380    #[test]
381    fn it_works_rot_back_rev() {
382        let mut cube = Cube::new();
383        cube.rot_back(true);
384        // down: [
385        // [46, 47, 48],
386        // [49, 50, 51],
387        // [52, 53, 54]],
388        assert_eq!(cube.left, [
389            [52, 20, 21],
390            [53, 23, 24],
391            [54, 26, 27]]);
392        // left: [
393        // [19, 20, 21],
394        // [22, 23, 24],
395        // [25, 26, 27]],
396        assert_eq!(cube.up, [
397            [25, 22, 19],
398            [40, 41, 42],
399            [43, 44, 45]]);
400        // up: [
401        // [37, 38, 39],
402        // [40, 41, 42],
403        // [43, 44, 45]],
404        assert_eq!(cube.right, [
405            [28, 29, 37],
406            [31, 32, 38],
407            [34, 35, 39]]);
408        // right: [
409        // [28, 29, 30],
410        // [31, 32, 33],
411        // [34, 35, 36]],
412        assert_eq!(cube.down, [
413            [46, 47, 48],
414            [49, 50, 51],
415            [36, 33, 30]]);
416    }
417    #[test]
418    fn it_works_rot_left() {
419        let mut cube = Cube::new();
420        cube.rot_left(false);
421        // back: [
422        // [10, 11, 12],
423        // [13, 14, 15],
424        // [16, 17, 18]],
425        assert_eq!(cube.up, [
426            [18, 38, 39],
427            [15, 41, 42],
428            [12, 44, 45]]);
429        // front: [
430        // [1, 2, 3],
431        // [4, 5, 6],
432        // [7, 8, 9]],
433        assert_eq!(cube.down, [
434            [1, 47, 48],
435            [4, 50, 51],
436            [7, 53, 54]]);
437        // up: [
438        // [37, 38, 39],
439        // [40, 41, 42],
440        // [43, 44, 45]],
441        assert_eq!(cube.front, [
442            [37, 2, 3],
443            [40, 5, 6],
444            [43, 8, 9]]);
445        // down: [
446        // [46, 47, 48],
447        // [49, 50, 51],
448        // [52, 53, 54]],
449        assert_eq!(cube.back, [
450            [10, 11, 52],
451            [13, 14, 49],
452            [16, 17, 46]]);
453    }
454
455    #[test]
456    fn it_works_rot_left_rev() {
457        let mut cube = Cube::new();
458        cube.rot_left(true);
459        // front: [
460        // [1, 2, 3],
461        // [4, 5, 6],
462        // [7, 8, 9]],
463        assert_eq!(cube.up, [
464            [1, 38, 39],
465            [4, 41, 42],
466            [7, 44, 45]]);
467        // back: [
468        // [10, 11, 12],
469        // [13, 14, 15],
470        // [16, 17, 18]],
471        assert_eq!(cube.down, [
472            [18, 47, 48],
473            [15, 50, 51],
474            [12, 53, 54]]);
475        // down: [
476        // [46, 47, 48],
477        // [49, 50, 51],
478        // [52, 53, 54]],
479        assert_eq!(cube.front, [
480            [46, 2, 3],
481            [49, 5, 6],
482            [52, 8, 9]]);
483        // up: [
484        // [37, 38, 39],
485        // [40, 41, 42],
486        // [43, 44, 45]],
487        assert_eq!(cube.back, [
488            [10, 11, 43],
489            [13, 14, 40],
490            [16, 17, 37]]);
491    }
492    #[test]
493    fn it_works_rot_right() {
494        let mut cube = Cube::new();
495        cube.rot_right(false);
496        // front: [
497        // [1, 2, 3],
498        // [4, 5, 6],
499        // [7, 8, 9]],
500        assert_eq!(cube.up, [
501            [37, 38, 3],
502            [40, 41, 6],
503            [43, 44, 9]]);
504        // back: [
505        // [10, 11, 12],
506        // [13, 14, 15],
507        // [16, 17, 18]],
508        assert_eq!(cube.down, [
509            [46, 47, 16],
510            [49, 50, 13],
511            [52, 53, 10]]);
512        // down: [
513        // [46, 47, 48],
514        // [49, 50, 51],
515        // [52, 53, 54]],
516        assert_eq!(cube.front, [
517            [1, 2, 48],
518            [4, 5, 51],
519            [7, 8, 54]]);
520        // up: [
521        // [37, 38, 39],
522        // [40, 41, 42],
523        // [43, 44, 45]],
524        assert_eq!(cube.back, [
525            [45, 11, 12],
526            [42, 14, 15],
527            [39, 17, 18]]);
528    }
529    #[test]
530    fn it_works_rot_right_rev() {
531        let mut cube = Cube::new();
532        cube.rot_right(true);
533        // back: [
534        // [10, 11, 12],
535        // [13, 14, 15],
536        // [16, 17, 18]],
537        assert_eq!(cube.up, [
538            [37, 38, 16],
539            [40, 41, 13],
540            [43, 44, 10]]);
541        // front: [
542        // [1, 2, 3],
543        // [4, 5, 6],
544        // [7, 8, 9]],
545        assert_eq!(cube.down, [
546            [46, 47, 3],
547            [49, 50, 6],
548            [52, 53, 9]]);
549        // up: [
550        // [37, 38, 39],
551        // [40, 41, 42],
552        // [43, 44, 45]],
553        assert_eq!(cube.front, [
554            [1, 2, 39],
555            [4, 5, 42],
556            [7, 8, 45]]);
557        // down: [
558        // [46, 47, 48],
559        // [49, 50, 51],
560        // [52, 53, 54]],
561        assert_eq!(cube.back, [
562            [54, 11, 12],
563            [51, 14, 15],
564            [48, 17, 18]]);
565    }
566    #[test]
567    fn it_works_rot_up() {
568        let mut cube = Cube::new();
569        cube.rot_up(false);
570        // right: [
571        // [28, 29, 30],
572        // [31, 32, 33],
573        // [34, 35, 36]],
574        assert_eq!(cube.front, [
575            [28, 29, 30],
576            [4, 5, 6],
577            [7, 8, 9]]);
578        // left: [
579        // [19, 20, 21],
580        // [22, 23, 24],
581        // [25, 26, 27]],
582        assert_eq!(cube.back, [
583            [19, 20, 21],
584            [13, 14, 15],
585            [16, 17, 18]]);
586        // front: [
587        // [1, 2, 3],
588        // [4, 5, 6],
589        // [7, 8, 9]],
590        assert_eq!(cube.left, [
591            [1, 2, 3],
592            [22, 23, 24],
593            [25, 26, 27]]);
594        // back: [
595        // [10, 11, 12],
596        // [13, 14, 15],
597        // [16, 17, 18]],
598        assert_eq!(cube.right, [
599            [10, 11, 12],
600            [31, 32, 33],
601            [34, 35, 36]]);
602    }
603    #[test]
604    fn it_works_rot_up_rev() {
605        let mut cube = Cube::new();
606        cube.rot_up(true);
607        // left: [
608        // [19, 20, 21],
609        // [22, 23, 24],
610        // [25, 26, 27]],
611        assert_eq!(cube.front, [
612            [19, 20, 21],
613            [4, 5, 6],
614            [7, 8, 9]]);
615        // right: [
616        // [28, 29, 30],
617        // [31, 32, 33],
618        // [34, 35, 36]],
619        assert_eq!(cube.back, [
620            [28, 29, 30],
621            [13, 14, 15],
622            [16, 17, 18]]);
623        // back: [
624        // [10, 11, 12],
625        // [13, 14, 15],
626        // [16, 17, 18]],
627        assert_eq!(cube.left, [
628            [10, 11, 12],
629            [22, 23, 24],
630            [25, 26, 27]]);
631        // front: [
632        // [1, 2, 3],
633        // [4, 5, 6],
634        // [7, 8, 9]],
635        assert_eq!(cube.right, [
636            [1, 2, 3],
637            [31, 32, 33],
638            [34, 35, 36]]);
639    }
640    #[test]
641    fn it_works_rot_down() {
642        let mut cube = Cube::new();
643        cube.rot_down(false);
644        // left: [
645        // [19, 20, 21],
646        // [22, 23, 24],
647        // [25, 26, 27]],
648        assert_eq!(cube.front, [
649            [1, 2, 3],
650            [4, 5, 6],
651            [25, 26, 27]]);
652        // right: [
653        // [28, 29, 30],
654        // [31, 32, 33],
655        // [34, 35, 36]],
656        assert_eq!(cube.back, [
657            [10, 11, 12],
658            [13, 14, 15],
659            [34, 35, 36]]);
660        // back: [
661        // [10, 11, 12],
662        // [13, 14, 15],
663        // [16, 17, 18]],
664        assert_eq!(cube.left, [
665            [19, 20, 21],
666            [22, 23, 24],
667            [16, 17, 18]]);
668        // front: [
669        // [1, 2, 3],
670        // [4, 5, 6],
671        // [7, 8, 9]],
672        assert_eq!(cube.right, [
673            [28, 29, 30],
674            [31, 32, 33],
675            [7, 8, 9]]);
676    }
677    #[test]
678    fn it_works_rot_down_rev() {
679        let mut cube = Cube::new();
680        cube.rot_down(true);
681        // right: [
682        // [28, 29, 30],
683        // [31, 32, 33],
684        // [34, 35, 36]],
685        assert_eq!(cube.front, [
686            [1, 2, 3],
687            [4, 5, 6],
688            [34, 35, 36]]);
689        // left: [
690        // [19, 20, 21],
691        // [22, 23, 24],
692        // [25, 26, 27]],
693        assert_eq!(cube.back, [
694            [10, 11, 12],
695            [13, 14, 15],
696            [25, 26, 27]]);
697        // front: [
698        // [1, 2, 3],
699        // [4, 5, 6],
700        // [7, 8, 9]],
701        assert_eq!(cube.left, [
702            [19, 20, 21],
703            [22, 23, 24],
704            [7, 8, 9]]);
705        // back: [
706        // [10, 11, 12],
707        // [13, 14, 15],
708        // [16, 17, 18]],
709        assert_eq!(cube.right, [
710            [28, 29, 30],
711            [31, 32, 33],
712            [16, 17, 18]]);
713    }
714    #[test]
715    fn it_works_is_solved() {
716        let mut cube = Cube::new();
717        cube.rot_back(false);
718        cube.rot_back(true);
719        assert_eq!(cube.is_solved(), true);
720        cube.rot_back(true);
721        assert_eq!(cube.is_solved(), false);
722    }
723
724    #[test]
725    fn it_works_rot() {
726        let mut cube = Cube::new();
727        cube.rot('F');
728        cube.rot('f');
729        assert_eq!(cube.is_solved(), true);
730    }
731
732    #[test]
733    fn it_works_get_svg() {
734        let mut cube = Cube::new();
735        cube.get_svg();
736        assert_eq!(true, true)
737    }
738
739    #[test]
740    fn it_works_get_svg_base64_png() {
741        let mut cube = Cube::new();
742        let base64 = cube.get_svg_base64_png();
743        println!("{}", base64);
744        assert_eq!(true, true)
745    }
746}