use std::hash::Hash;
pub type CubeSize = i32;
pub trait Cube: Clone + Eq + Hash + PartialEq {
fn new(size: CubeSize) -> Self;
fn size(&self) -> CubeSize;
fn state(&self) -> Vec<Face>;
fn is_solved(&self) -> bool {
fn all_equal<T: Clone + PartialEq>(arr: &[T]) -> bool {
arr.iter().all(|x| *x == arr[0])
}
let face_length = (self.size() * self.size()) as usize;
let state = self.state();
let mut is_solved = true;
for i in 0..6 {
let face_start = i * face_length;
let face_end = face_start + face_length;
is_solved = is_solved && all_equal(&state[face_start..face_end]);
}
is_solved
}
fn mask(&self, mask: &dyn Fn(CubeSize, Face) -> Face) -> Self;
fn apply_move(&self, mv: Move) -> Self;
fn apply_moves(&self, mvs: &[Move]) -> Self
where
Self: Sized,
{
let mut cube = self.clone();
for mv in mvs {
cube = cube.apply_move(*mv);
}
cube
}
}
use derive_more::Display;
#[derive(Clone, Copy, Debug, Display, Eq, Hash, PartialEq)]
pub enum Face {
U,
L,
F,
R,
B,
D,
X,
}
pub const ORDERED_FACES: [Face; 6] = [Face::U, Face::R, Face::F, Face::D, Face::L, Face::B];
pub fn sticker_index(size: CubeSize, face: Face, index: CubeSize) -> CubeSize {
(ORDERED_FACES.iter().position(|&f| f == face).unwrap() as CubeSize)
* size * size + index - 1 as CubeSize
}
#[allow(dead_code)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum Move {
U(MoveVariant),
L(MoveVariant),
F(MoveVariant),
R(MoveVariant),
B(MoveVariant),
D(MoveVariant),
Uw(CubeSize, MoveVariant),
Lw(CubeSize, MoveVariant),
Fw(CubeSize, MoveVariant),
Rw(CubeSize, MoveVariant),
Bw(CubeSize, MoveVariant),
Dw(CubeSize, MoveVariant),
X(MoveVariant),
Y(MoveVariant),
Z(MoveVariant),
}
impl Move {
pub fn get_variant(&self) -> MoveVariant {
match self {
Move::U(v)
| Move::L(v)
| Move::F(v)
| Move::R(v)
| Move::B(v)
| Move::D(v)
| Move::X(v)
| Move::Y(v)
| Move::Z(v)
| Move::Uw(_, v)
| Move::Lw(_, v)
| Move::Fw(_, v)
| Move::Rw(_, v)
| Move::Bw(_, v)
| Move::Dw(_, v) => *v,
}
}
pub fn with_variant(&self, variant: MoveVariant) -> Move {
match self {
Move::U(_) => Move::U(variant),
Move::L(_) => Move::L(variant),
Move::F(_) => Move::F(variant),
Move::R(_) => Move::R(variant),
Move::B(_) => Move::B(variant),
Move::D(_) => Move::D(variant),
Move::Uw(n, _) => Move::Uw(*n, variant),
Move::Lw(n, _) => Move::Lw(*n, variant),
Move::Fw(n, _) => Move::Fw(*n, variant),
Move::Rw(n, _) => Move::Rw(*n, variant),
Move::Bw(n, _) => Move::Bw(*n, variant),
Move::Dw(n, _) => Move::Dw(*n, variant),
Move::X(_) => Move::X(variant),
Move::Y(_) => Move::Y(variant),
Move::Z(_) => Move::Z(variant),
}
}
}
#[allow(dead_code)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum MoveVariant {
Standard = 1,
Double,
Inverse,
}
pub fn solved_state(size: CubeSize) -> Vec<Face> {
ORDERED_FACES
.iter()
.flat_map(|&face| vec![face; (size * size) as usize])
.collect()
}
pub fn all_moves(size: CubeSize) -> Vec<Move> {
use Move::*;
use MoveVariant::*;
let mut moveset = Vec::new();
for mv in [U, R, F, L, D, B] {
for variant in [Standard, Double, Inverse] {
moveset.push(mv(variant));
}
}
for mv in [Uw, Lw, Fw, Rw, Bw, Dw] {
for variant in [Standard, Double, Inverse] {
for slice in 1..=(size / 2) {
moveset.push(mv(slice, variant));
}
}
}
moveset
}