1use rand::random;
2use static_init::dynamic;
3use std::fmt;
4use std::ops::Mul;
5
6use self::{Corner::*, Edge::*, Move::*};
7use crate::constants::*;
8use crate::error::Error;
9use crate::{facelet::*, moves::*};
10
11#[rustfmt::skip]
15#[allow(clippy::upper_case_acronyms)]
16#[derive(Debug, PartialEq, PartialOrd, Clone, Copy)]
17pub enum Corner {
18 URF, UFL, ULB, UBR, DFR, DLF, DBL, DRB,
19}
20
21impl fmt::Display for Corner {
22 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23 write!(f, "{:?}", self)
24 }
25}
26
27impl TryFrom<u8> for Corner {
28 type Error = Error;
29
30 fn try_from(value: u8) -> Result<Self, Self::Error> {
31 match value {
32 0 => Ok(URF),
33 1 => Ok(UFL),
34 2 => Ok(ULB),
35 3 => Ok(UBR),
36 4 => Ok(DFR),
37 5 => Ok(DLF),
38 6 => Ok(DBL),
39 7 => Ok(DRB),
40 _ => Err(Error::InvalidCorner),
41 }
42 }
43}
44
45impl TryFrom<&str> for Corner {
46 type Error = Error;
47
48 fn try_from(value: &str) -> Result<Self, Self::Error> {
49 match value {
50 "URF" => Ok(URF),
51 "UFL" => Ok(UFL),
52 "ULB" => Ok(ULB),
53 "UBR" => Ok(UBR),
54 "DFR" => Ok(DFR),
55 "DLF" => Ok(DLF),
56 "DBL" => Ok(DBL),
57 "DRB" => Ok(DRB),
58 _ => Err(Error::InvalidCorner),
59 }
60 }
61}
62#[rustfmt::skip]
66#[allow(clippy::upper_case_acronyms)]
67#[derive(Debug, PartialEq, PartialOrd, Clone, Copy, Eq, Hash)]
68pub enum Edge {
69 UR, UF, UL, UB, DR, DF, DL, DB, FR, FL, BL, BR,
70}
71
72impl fmt::Display for Edge {
73 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74 write!(f, "{:?}", self)
75 }
76}
77
78impl TryFrom<u8> for Edge {
79 type Error = Error;
80
81 fn try_from(value: u8) -> Result<Self, Self::Error> {
82 match value {
83 0 => Ok(UR),
84 1 => Ok(UF),
85 2 => Ok(UL),
86 3 => Ok(UB),
87 4 => Ok(DR),
88 5 => Ok(DF),
89 6 => Ok(DL),
90 7 => Ok(DB),
91 8 => Ok(FR),
92 9 => Ok(FL),
93 10 => Ok(BL),
94 11 => Ok(BR),
95 _ => Err(Error::InvalidEdge),
96 }
97 }
98}
99
100impl TryFrom<&str> for Edge {
101 type Error = Error;
102
103 fn try_from(value: &str) -> Result<Self, Self::Error> {
104 match value {
105 "UR" => Ok(UR),
106 "UF" => Ok(UF),
107 "UL" => Ok(UL),
108 "UB" => Ok(UB),
109 "DR" => Ok(DR),
110 "DF" => Ok(DF),
111 "DL" => Ok(DL),
112 "DB" => Ok(DB),
113 "FR" => Ok(FR),
114 "FL" => Ok(FL),
115 "BL" => Ok(BL),
116 "BR" => Ok(BR),
117 _ => Err(Error::InvalidEdge),
118 }
119 }
120}
121
122#[derive(Debug, PartialEq, Clone, Copy)]
124pub struct CubieCube {
125 pub center: [Color; 6],
127 pub cp: [Corner; 8],
129 pub co: [u8; 8],
131 pub ep: [Edge; 12],
133 pub eo: [u8; 12],
135}
136
137pub const SOLVED_CUBIE_CUBE: CubieCube = CubieCube {
139 center: [Color::U, Color::R, Color::F, Color::D, Color::L, Color::B],
140 cp: [URF, UFL, ULB, UBR, DFR, DLF, DBL, DRB],
141 co: [0, 0, 0, 0, 0, 0, 0, 0],
142 ep: [UR, UF, UL, UB, DR, DF, DL, DB, FR, FL, BL, BR],
143 eo: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
144};
145
146impl Default for CubieCube {
147 fn default() -> Self {
148 SOLVED_CUBIE_CUBE
149 }
150}
151
152impl Mul for CubieCube {
153 type Output = Self;
154
155 fn mul(self, rhs: CubieCube) -> Self::Output {
156 let mut res = CubieCube::default();
157 for i in 0..8 {
161 res.cp[i] = self.cp[rhs.cp[i] as usize];
162 res.co[i] = (self.co[rhs.cp[i] as usize] + rhs.co[i]) % 3;
163 }
164
165 for i in 0..12 {
166 res.ep[i] = self.ep[rhs.ep[i] as usize];
167 res.eo[i] = (self.eo[rhs.ep[i] as usize] + rhs.eo[i]) % 2;
168 }
169
170 for i in 0..6 {
171 res.center[i] = self.center[rhs.center[i] as usize];
172 }
173 res
174 }
175}
176
177impl fmt::Display for CubieCube {
178 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
179 let mut s = String::new();
181 for i in 0..8 {
182 let cs: String = format!("({},{})", self.cp[i], self.co[i]);
183 s.push_str(&cs);
184 }
185 for i in 0..12 {
186 let es: String = format!("({},{})", self.ep[i], self.eo[i]);
187 s.push_str(&es);
188 }
189 write!(f, "{s}")
190 }
191}
192
193impl From<&Vec<Move>> for CubieCube {
194 fn from(moves: &Vec<Move>) -> Self {
195 CubieCube::default().apply_moves(moves)
196 }
197}
198
199impl TryFrom<&FaceCube> for CubieCube {
201 type Error = Error;
202 fn try_from(face_cube: &FaceCube) -> Result<Self, Self::Error> {
203 let mut state = CubieCube::default();
204 let mut ori: usize = 0;
205 let mut col1;
206 let mut col2;
207
208 for i in 0..8 {
209 let i = Corner::try_from(i)?;
210 for index in 0..3 {
212 ori = index;
213 if face_cube.f[CORNER_FACELET[i as usize][ori] as usize] == Color::U
214 || face_cube.f[CORNER_FACELET[i as usize][ori] as usize] == Color::D
215 {
216 break;
217 }
218 }
219
220 col1 = face_cube.f[CORNER_FACELET[i as usize][(ori + 1) % 3] as usize];
221 col2 = face_cube.f[CORNER_FACELET[i as usize][(ori + 2) % 3] as usize];
222
223 for j in 0..8 {
224 let j = Corner::try_from(j)?;
225 if col1 == CORNER_COLOR[j as usize][1] && col2 == CORNER_COLOR[j as usize][2] {
226 state.cp[i as usize] = j;
228 state.co[i as usize] = ori as u8 % 3;
229 break;
230 }
231 }
232 }
233
234 for i in 0..12 {
235 let i = Edge::try_from(i)?;
236 for j in 0..12 {
237 let j = Edge::try_from(j)?;
238 if face_cube.f[EDGE_FACELET[i as usize][0] as usize] == EDGE_COLOR[j as usize][0]
239 && face_cube.f[EDGE_FACELET[i as usize][1] as usize]
240 == EDGE_COLOR[j as usize][1]
241 {
242 state.ep[i as usize] = j;
243 state.eo[i as usize] = 0;
244 break;
245 }
246 if face_cube.f[EDGE_FACELET[i as usize][0] as usize] == EDGE_COLOR[j as usize][1]
247 && face_cube.f[EDGE_FACELET[i as usize][1] as usize]
248 == EDGE_COLOR[j as usize][0]
249 {
250 state.ep[i as usize] = j;
251 state.eo[i as usize] = 1;
252 break;
253 }
254 }
255 }
256
257 if !state.is_solvable() {
258 Err(Error::InvalidFaceletValue)
259 } else {
260 Ok(state)
261 }
262 }
263}
264
265impl CubieCube {
266 pub fn apply_move(self, move_name: Move) -> Self {
268 let move_state = match move_name {
269 N => N_MOVE,
270 U => U_MOVE,
271 U2 => U_MOVE * U_MOVE,
272 U3 => U_MOVE * U_MOVE * U_MOVE,
273 D => D_MOVE,
274 D2 => D_MOVE * D_MOVE,
275 D3 => D_MOVE * D_MOVE * D_MOVE,
276 R => R_MOVE,
277 R2 => R_MOVE * R_MOVE,
278 R3 => R_MOVE * R_MOVE * R_MOVE,
279 L => L_MOVE,
280 L2 => L_MOVE * L_MOVE,
281 L3 => L_MOVE * L_MOVE * L_MOVE,
282 F => F_MOVE,
283 F2 => F_MOVE * F_MOVE,
284 F3 => F_MOVE * F_MOVE * F_MOVE,
285 B => B_MOVE,
286 B2 => B_MOVE * B_MOVE,
287 B3 => B_MOVE * B_MOVE * B_MOVE,
288 M => M_MOVE,
289 M2 => M_MOVE * M_MOVE,
290 M3 => M_MOVE * M_MOVE * M_MOVE,
291 E => E_MOVE,
292 E2 => E_MOVE * E_MOVE,
293 E3 => E_MOVE * E_MOVE * E_MOVE,
294 S => S_MOVE,
295 S2 => S_MOVE * S_MOVE,
296 S3 => S_MOVE * S_MOVE * S_MOVE,
297 Uw => U_MOVE * E_MOVE * E_MOVE * E_MOVE,
298 Uw2 => U_MOVE * U_MOVE * E_MOVE * E_MOVE,
299 Uw3 => U_MOVE * U_MOVE * U_MOVE * E_MOVE,
300 Dw => D_MOVE * E_MOVE,
301 Dw2 => D_MOVE * D_MOVE * E_MOVE * E_MOVE,
302 Dw3 => D_MOVE * D_MOVE * D_MOVE * E_MOVE * E_MOVE * E_MOVE,
303 Rw => R_MOVE * M_MOVE * M_MOVE * M_MOVE,
304 Rw2 => R_MOVE * R_MOVE * M_MOVE * M_MOVE,
305 Rw3 => R_MOVE * R_MOVE * R_MOVE * M_MOVE,
306 Lw => L_MOVE * M_MOVE,
307 Lw2 => L_MOVE * L_MOVE * M_MOVE * M_MOVE,
308 Lw3 => L_MOVE * L_MOVE * L_MOVE * M_MOVE * M_MOVE * M_MOVE,
309 Fw => F_MOVE * S_MOVE,
310 Fw2 => F_MOVE * F_MOVE * S_MOVE * S_MOVE,
311 Fw3 => F_MOVE * F_MOVE * F_MOVE * S_MOVE * S_MOVE * S_MOVE,
312 Bw => B_MOVE * S_MOVE * S_MOVE * S_MOVE,
313 Bw2 => B_MOVE * B_MOVE * S_MOVE * S_MOVE,
314 Bw3 => B_MOVE * B_MOVE * B_MOVE * S_MOVE,
315 x => R_MOVE * M_MOVE * M_MOVE * M_MOVE * L_MOVE * L_MOVE * L_MOVE,
316 x2 => R_MOVE * R_MOVE * M_MOVE * M_MOVE * L_MOVE * L_MOVE,
317 x3 => R_MOVE * R_MOVE * R_MOVE * M_MOVE * L_MOVE,
318 y => U_MOVE * E_MOVE * E_MOVE * E_MOVE * D_MOVE * D_MOVE * D_MOVE,
319 y2 => U_MOVE * U_MOVE * E_MOVE * E_MOVE * D_MOVE * D_MOVE,
320 y3 => U_MOVE * U_MOVE * U_MOVE * E_MOVE * D_MOVE,
321 z => F_MOVE * S_MOVE * B_MOVE * B_MOVE * B_MOVE,
322 z2 => F_MOVE * F_MOVE * S_MOVE * S_MOVE * B_MOVE * B_MOVE,
323 z3 => F_MOVE * F_MOVE * F_MOVE * S_MOVE * S_MOVE * S_MOVE * B_MOVE,
324 };
325
326 self * move_state
327 }
328
329 pub fn apply_moves(&self, moves: &[Move]) -> Self {
331 moves.iter().fold(*self, |acc, &m| acc.apply_move(m))
332 }
333
334 pub fn apply_formula(&self, formula: &Formula) -> Self {
336 formula
337 .moves
338 .iter()
339 .fold(*self, |acc, &m| acc.apply_move(m))
340 }
341
342 pub fn corner_multiply(&mut self, b: CubieCube) {
344 let mut c_perm = [URF; 8];
345 let mut c_ori = [0; 8];
346 let mut ori = 0;
347 for ci in ALL_CORNERS {
348 let c = ci as usize;
349 c_perm[c] = self.cp[b.cp[c] as usize];
350 let ori_a = self.co[b.cp[c] as usize];
351 let ori_b = b.co[c];
352 if ori_a < 3 && ori_b < 3 {
353 ori = ori_a + ori_b;
355 if ori >= 3 {
356 ori -= 3;
357 }
358 } else if ori_a < 3 && 3 <= ori_b {
359 ori = ori_a + ori_b;
361 if ori >= 6 {
362 ori -= 3; }
364 } else if ori_a >= 3 && 3 > ori_b {
365 ori = ori_a - ori_b;
367 if ori < 3 {
368 ori += 3; }
370 } else if ori_a >= 3 && ori_b >= 3 {
371 if ori_a >= ori_b {
373 ori = ori_a - ori_b;
374 } else {
375 ori = ori_b - ori_a;
376 ori = 3 - ori; }
378 }
379 c_ori[c] = ori;
380 }
381 for c in ALL_CORNERS {
382 let ci = c as usize;
383 self.cp[ci] = c_perm[ci];
384 self.co[ci] = c_ori[ci];
385 }
386 }
387
388 pub fn edge_multiply(&mut self, b: CubieCube) {
390 let mut e_perm: [Edge; 12] = [UR; 12];
391 let mut e_ori = [0; 12];
392 for ei in ALL_EDGES {
393 let e = ei as usize;
394 e_perm[e] = self.ep[b.ep[e] as usize];
395 e_ori[e] = (b.eo[e] + self.eo[b.ep[e] as usize]) % 2;
396 }
397 for ei in ALL_EDGES {
398 let e = ei as usize;
399 self.ep[e] = e_perm[e];
400 self.eo[e] = e_ori[e];
401 }
402 }
403
404 pub fn multiply(&mut self, b: CubieCube) {
406 self.corner_multiply(b);
407 self.edge_multiply(b);
408 }
409
410 pub fn multiply_move(&mut self, m: Move) {
412 self.multiply(AMCT.amc[m as usize]);
413 }
414
415 pub fn multiply_moves(&mut self, moves: &Vec<Move>) {
417 moves
418 .iter()
419 .for_each(|&m| self.multiply(AMCT.amc[m as usize]));
420 }
421
422 pub fn set_twist(&mut self, twist: u16) {
424 let mut twistparity = 0;
425 let mut twist = twist;
426 for i in ((URF as usize)..(DRB as usize)).rev() {
427 self.co[i] = (twist % 3) as u8;
428 twistparity += self.co[i];
429 twist /= 3;
430 }
431 self.co[DRB as usize] = (3 - twistparity % 3) % 3;
432 }
433
434 pub fn set_flip(&mut self, flip: u16) {
436 let mut flipparity = 0;
437 let mut flip = flip;
438 for i in ((UR as usize)..(BR as usize)).rev() {
439 self.eo[i] = (flip % 2) as u8;
440 flipparity += self.eo[i];
441 flip /= 2;
442 }
443 self.eo[BR as usize] = (2 - flipparity % 2) % 2;
444 }
445
446 pub fn get_slice(&self) -> u16 {
450 let mut a = 0;
451 let mut _x = 0;
452 for j in ((UR as usize)..=(BR as usize)).rev() {
454 if FR <= self.ep[j] && self.ep[j] <= BR {
455 a += c_nk((11 - j) as u32, _x + 1);
456 _x += 1;
457 }
458 }
459 a as u16
460 }
461
462 pub fn set_slice(&mut self, idx: u16) {
466 let slice_edge = [FR, FL, BL, BR];
467 let other_edge = [UR, UF, UL, UB, DR, DF, DL, DB];
468 let mut a = idx; let mut ep = [-1; 12];
470
471 let mut _x: i32 = 4; for j in ALL_EDGES {
473 if a >= c_nk((11 - j as u32) as u32, _x as u32) as u16 {
474 self.ep[j as usize] = slice_edge[(4 - _x) as usize];
475 ep[j as usize] = slice_edge[(4 - _x) as usize] as i32;
476 a -= c_nk(11 - j as u32, _x as u32) as u16;
477 _x -= 1;
478 }
479 }
480 let mut _x = 0; for j in ALL_EDGES {
482 if ep[j as usize] == -1 {
483 self.ep[j as usize] = other_edge[_x];
484 _x += 1;
485 }
486 }
487 }
488
489 pub fn set_corners(&mut self, idx: u16) {
495 self.cp = ALL_CORNERS.clone();
496 let mut idx = idx;
497 for j in ALL_CORNERS {
498 let mut k = idx % (j as u16 + 1);
499 idx /= j as u16 + 1;
500 while k > 0 {
501 rotate_right(&mut self.cp, 0, j as usize);
502 k -= 1;
503 }
504 }
505 }
506
507 pub fn randomize(&mut self) {
509 let mut idx = random::<usize>() % 479001600; self.cp = ALL_CORNERS.clone();
512 for j in ALL_EDGES {
513 let mut k = idx % (j as usize + 1);
514 idx /= j as usize + 1;
515 while k > 0 {
516 rotate_right(&mut self.ep, 0, j as usize);
517 k -= 1;
518 }
519 }
520 let p = self.edge_parity();
521 loop {
522 self.set_corners(random::<u16>() % 40320); if p == self.corner_parity() {
524 break;
526 }
527 }
528 self.set_flip(random::<u16>() % 2048); self.set_twist(random::<u16>() % 2187); }
531
532 pub fn count_corner_twist(&self) -> u8 {
534 self.co.iter().fold(0, |acc, co| acc + ((3 - co) % 3))
535 }
536
537 pub fn count_edge_twist(&self) -> u8 {
539 self.eo.iter().sum()
540 }
541
542 pub fn count_corner_perm(&self) -> u8 {
544 let mut count = 0;
545 let mut cp = self.cp;
546
547 for i in 0..8 {
548 if cp[i] as usize != i {
549 if let Some(j) = (i + 1..8).find(|&j| cp[j] as usize == i) {
550 cp.swap(i, j);
551 count += 1;
552 }
553 }
554 }
555
556 count
557 }
558
559 pub fn count_edge_perm(&self) -> u8 {
561 let mut count = 0;
562 let mut ep = self.ep;
563
564 for i in 0..12 {
565 if ep[i] as usize != i {
566 if let Some(j) = (i + 1..12).find(|&j| ep[j] as usize == i) {
567 ep.swap(i, j);
568 count += 1;
569 }
570 }
571 }
572
573 count
574 }
575
576 pub fn is_solvable(&self) -> bool {
578 let c_perm = self.count_corner_perm();
579 let e_perm = self.count_edge_perm();
580 let c_twist = self.count_corner_twist();
581 let e_twist = self.count_edge_twist();
582 let has_even_permutation = c_perm % 2 == e_perm % 2;
583 let has_valid_twist = c_twist % 3 == 0 && e_twist % 2 == 0;
584
585 has_even_permutation && has_valid_twist
586 }
587
588 pub fn inverse_cubie_cube(&self) -> Self {
590 let mut d = CubieCube::default();
591 for ei in ALL_EDGES {
592 let e: usize = ei as usize;
593 d.ep[self.ep[e] as usize] = ei;
594 }
595 for ei in ALL_EDGES {
596 let e: usize = ei as usize;
597 d.eo[e] = self.eo[d.ep[e] as usize];
598 }
599
600 for ci in ALL_CORNERS {
601 let c = ci as usize;
602 d.cp[self.cp[c] as usize] = ci;
603 }
604 for ci in ALL_CORNERS {
605 let c = ci as usize;
606 let ori = self.co[d.cp[c] as usize];
607 if ori >= 3 {
608 d.co[c] = ori;
609 } else {
610 d.co[c] = 3 - ori;
611 if d.co[c] == 3 {
612 d.co[c] = 0;
613 }
614 }
615 }
616 d
617 }
618
619 pub fn corner_parity(&self) -> bool {
621 let mut s = 0;
622 for i in ((URF as usize + 1)..=(DRB as usize)).rev() {
623 for j in ((URF as usize)..=(i - 1)).rev() {
624 if self.cp[j] > self.cp[i] {
625 s += 1
626 }
627 }
628 }
629 (s % 2) == 0
630 }
631
632 pub fn edge_parity(&self) -> bool {
634 let mut s = 0;
635 for i in ((UR as usize + 1)..=(BR as usize)).rev() {
636 for j in ((UR as usize)..=(i - 1)).rev() {
637 if self.ep[j] > self.ep[i] {
638 s += 1;
639 }
640 }
641 }
642 (s % 2) == 0
643 }
644
645 pub fn verify(&self) -> Result<bool, Error> {
647 let mut edge_count = [0; 12];
648 for i in ALL_EDGES {
649 edge_count[self.ep[i as usize] as usize] += 1;
650 }
651 for i in ALL_EDGES {
652 if edge_count[i as usize] != 1 {
653 return Err(Error::InvalidEdge);
654 }
655 }
656 let mut s = 0;
657 for i in ALL_EDGES {
658 s += self.eo[i as usize];
659 }
660 if s % 2 != 0 {
661 return Err(Error::InvalidEdge);
662 }
663
664 let mut corner_count = [0; 8];
665 for i in ALL_CORNERS {
666 corner_count[self.cp[i as usize] as usize] += 1;
667 }
668 for i in ALL_CORNERS {
669 if corner_count[i as usize] != 1 {
670 return Err(Error::InvalidCorner);
671 }
672 }
673 let mut s = 0;
674 for i in ALL_CORNERS {
675 s += self.co[i as usize];
676 }
677 if s % 3 != 0 {
678 return Err(Error::InvalidCorner);
679 }
680
681 if self.edge_parity() != self.corner_parity() {
682 return Err(Error::InvalidCubieValue);
683 }
684 Ok(true)
685 }
686
687 pub fn get_edges_d(&self) -> Vec<(Edge, u8, u8)> {
688 let mut i: u8 = 0;
689 let mut result = Vec::new();
690 for e in self.ep {
691 match e {
692 DR | DF | DL | DB => result.push((e, i, self.eo[i as usize])),
693 _ => {}
694 }
695 i += 1;
696 }
697 result
698 }
699}
700
701struct AllMoveCubeTables {
720 amc: [CubieCube; 55],
721}
722impl AllMoveCubeTables {
723 pub fn new() -> Self {
724 let mut amc = [CubieCube::default(); 55];
725 for i in 0..55 {
726 amc[i] = amc[i].apply_move(ALL_MOVES_FULL[i]);
727 }
728 Self { amc }
729 }
730}
731
732#[dynamic]
735static AMCT: AllMoveCubeTables = AllMoveCubeTables::new();
736
737pub fn rotate_right<T: Copy>(arr: &mut [T], left: usize, right: usize) {
739 let temp = arr[right];
740 for i in (left + 1..=right).rev() {
741 arr[i] = arr[i - 1];
742 }
743 arr[left] = temp;
744}
745
746pub fn rotate_left<T: Copy>(arr: &mut [T], left: usize, right: usize) {
748 let temp = arr[left];
749 for i in left..right {
750 arr[i] = arr[i + 1];
751 }
752 arr[right] = temp;
753}
754
755pub fn c_nk(n: u32, k: u32) -> u32 {
757 let mut k = k;
758 if n < k {
759 return 0;
760 }
761 if k > (n / 2) {
762 k = n - k;
763 }
764 let mut s = 1;
765 let mut i = n;
766 let mut j = 1;
767 while i != n - k {
768 s *= i;
769 s /= j;
770 i -= 1;
771 j += 1;
772 }
773 s
774}
775
776#[cfg(test)]
777mod tests {
778 use crate::cubie::*;
779 #[cfg(feature = "term")]
780 use crate::printer::print_facelet;
781
782 #[test]
783 fn test_eq() {
784 let state = CubieCube::default();
785 let state2 = CubieCube::default();
786 assert_eq!(state, state2);
787 }
788
789 #[test]
790 fn test_inverse() {
791 let state = CubieCube {
792 center: [Color::U, Color::R, Color::F, Color::D, Color::L, Color::B],
793 cp: [DLF, ULB, DBL, DRB, UBR, UFL, DFR, URF],
794 co: [2, 1, 2, 1, 2, 2, 0, 2],
795 ep: [BR, BL, UB, UR, DR, FR, FL, UF, DF, DL, DB, UL],
796 eo: [1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1],
797 };
798 let ic = state.inverse_cubie_cube();
799 let d = CubieCube {
800 center: [Color::U, Color::R, Color::F, Color::D, Color::L, Color::B],
801 cp: [DRB, DLF, UFL, DFR, DBL, URF, ULB, UBR],
802 co: [1, 1, 2, 1, 0, 1, 1, 2],
803 ep: [UB, DB, BR, UL, DR, FR, FL, BL, DF, DL, UF, UR],
804 eo: [0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1],
805 };
806 assert_eq!(ic, d);
807 let d2 = ic.inverse_cubie_cube();
808 assert_eq!(state, d2);
809 }
810
811 #[test]
812 fn test_parity() {
813 let state = CubieCube::default();
814
815 assert_eq!(state.corner_parity(), true);
816 assert_eq!(state.edge_parity(), true);
817
818 let state = CubieCube::from(&vec![R, U, R3, U3, R3, F, R, F3]);
819
820 assert_eq!(state.corner_parity(), true);
821 assert_eq!(state.edge_parity(), true);
822 }
823
824 #[test]
825 fn test_mult() {
826 let state = CubieCube::default().apply_move(R);
827 assert_eq!(state, R_MOVE);
828
829 let r2_state = CubieCube::default().apply_move(R).apply_move(R);
830 assert_eq!(r2_state, R_MOVE * R_MOVE);
831
832 let r3_state = r2_state.apply_move(R);
833 assert_eq!(r3_state, r2_state * R_MOVE);
834
835 let fr_state = CubieCube {
836 center: [Color::U, Color::R, Color::F, Color::D, Color::L, Color::B],
837 cp: [URF, DLF, ULB, UFL, DRB, DFR, DBL, UBR],
839 co: [1, 2, 0, 2, 1, 1, 0, 2],
840 ep: [UF, FL, UL, UB, BR, FR, DL, DB, DR, DF, BL, UR],
841 eo: [1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0],
842 };
843
844 assert_eq!(F_MOVE * R_MOVE, fr_state);
845 }
846
847 #[test]
848 fn test_move_mes() {
849 let moves: Vec<Move> = vec![M2, E2, S2];
850 let state = CubieCube::default().apply_moves(&moves);
851 #[cfg(feature = "term")]
852 let fc = FaceCube::try_from(&state).unwrap();
853 #[cfg(feature = "term")]
854 let _ = print_facelet(&fc);
855 assert_eq!(state, M_MOVE * M_MOVE * E_MOVE * E_MOVE * S_MOVE * S_MOVE);
856 }
857
858 #[test]
859 fn test_moves() {
860 let empty_move = Vec::new();
861 let cc = CubieCube::default();
862 let cc = cc.apply_moves(&empty_move);
863 assert_eq!(cc, CubieCube::default());
864 let moves = vec![R, U, R3, U3, M, S, E, M, x, R, U, R3, U3, L, F, R, y, z];
865 let _state = CubieCube::default().apply_moves(&moves);
866 #[cfg(feature = "term")]
867 let _fc = FaceCube::try_from(&_state).unwrap();
868 #[cfg(feature = "term")]
869 let _ = print_facelet(&_fc);
870 }
871
872 #[test]
873 fn test_move_n() {
874 let cc = CubieCube::default();
875 let cc = cc.apply_move(N);
876 assert_eq!(cc, CubieCube::default());
877 let moves = vec![R, U, R3, U3];
878 let cc = cc.apply_moves(&moves);
879 let nc = cc.apply_move(N);
880 assert_eq!(nc, cc);
881 let moves = vec![R, U, R3, U3, N, R, U, R3];
882 let cc = CubieCube::default();
883 let ncc = cc.apply_moves(&moves);
884 let moves = vec![R, U, R3, U3, R, U, R3];
885 let cc = cc.apply_moves(&moves);
886 assert_eq!(ncc, cc);
887 }
888
889 #[test]
890 fn test_move_sequence() {
891 let moves = vec![
893 R, U, R3, U3, R, U, R3, U3, R, U, R3, U3, R, U, R3, U3, R, U, R3, U3, R, U, R3, U3,
894 ];
895 let state = CubieCube::default().apply_moves(&moves);
896
897 assert_eq!(state, SOLVED_CUBIE_CUBE);
898 }
899
900 #[test]
901 fn test_scramble() {
902 let scramble = vec![
904 U, F3, D3, F2, D, B2, D3, R2, U3, F2, R2, D2, R2, U3, L, B, L, R, F3, D, B3,
905 ];
906 let state = CubieCube::default().apply_moves(&scramble);
907
908 let expected = CubieCube {
909 center: [Color::U, Color::R, Color::F, Color::D, Color::L, Color::B],
910 cp: [DFR, UBR, DLF, ULB, DRB, UFL, URF, DBL],
911 co: [2, 0, 1, 2, 0, 0, 2, 2],
912 ep: [DF, UB, FL, BL, BR, UL, DR, FR, DL, DB, UF, UR],
913 eo: [1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1],
914 };
915
916 assert_eq!(state, expected);
917 }
918
919 #[test]
920 fn test_get_edges_d() {
921 let cc = CubieCube::default();
922 let cc = cc.apply_moves(&vec![R, U, R3, U3, F, L]);
923 let d_edges = cc.get_edges_d();
924 println!("{:?}", d_edges);
925 }
926
927 #[test]
928 fn test_perm_count() {
929 let state = CubieCube::default();
930
931 assert_eq!(state.count_corner_perm(), 0);
932 assert_eq!(state.count_edge_perm(), 0);
933
934 let state = CubieCube::from(&vec![R, U, R3, U3]);
935
936 assert_eq!(state.count_corner_perm(), 2);
937 assert_eq!(state.count_edge_perm(), 2);
938
939 let state = CubieCube::from(&vec![
940 R, U3, R3, U3, R, U, R, D, R3, U3, R, D3, R3, U2, R3, U3,
941 ]);
942
943 assert_eq!(state.count_corner_perm(), 1);
944 assert_eq!(state.count_edge_perm(), 1);
945 }
946
947 #[test]
948 fn test_twist_count() {
949 let state = CubieCube::default();
950
951 assert_eq!(state.count_corner_twist(), 0);
952 assert_eq!(state.count_edge_twist(), 0);
953
954 let state = CubieCube::from(&vec![R, U, R3, U3, R3, F, R, F3]);
955
956 assert_eq!(state.count_corner_twist(), 3);
957 assert_eq!(state.count_edge_twist(), 2);
958 }
959}