cubesim 0.0.7

Rubik's Cube simulation and solving library.
Documentation
use std::sync::Mutex;
use rustc_hash::FxHashMap;
use cached::proc_macro::cached;
use lazy_static::lazy_static;
use cgmath::Vector3;

use crate::generic_cube::{Cube, Move, CubeSize};
use crate::generic_cube::Move::*;
use crate::generic_cube::MoveVariant::*;
use crate::geometric_cube::{GeoCube, Sticker};

pub struct FaceletMove(pub Vec<(u16, u16)>);

pub fn compute_permutation<T: Clone + Copy>(old_faces: &[T], size: CubeSize, mv: Move) -> Vec<T> {
    lazy_static! {
        static ref CACHE: Mutex<FxHashMap<(CubeSize, Move), FaceletMove>> = Mutex::new(FxHashMap::default());
    }

    let mut cache = CACHE.lock().unwrap();

    let facelet_move = if let Some(res) = cache.get(&(size, mv)) {
        res
    } else {
        cache.insert((size, mv), convert_move(size, mv));
        cache.get(&(size, mv)).unwrap()
    };

    let mut new_faces = old_faces.to_owned();

    for (x, y) in &facelet_move.0 {
        new_faces[*y as usize] = old_faces[*x as usize];
    }

    new_faces
}

fn convert_move(size: CubeSize, mv: Move) -> FaceletMove {
    let index_map = create_piece_map(size);

    FaceletMove(
        GeoCube::new(size)
                .apply_move(mv)
                .stickers()
                .iter()
                .map(|s| (index_map[(&s.initial)] as u16, index_map[(&s.current)] as u16))
                .filter(|x| x.0 != x.1)
                .collect()
    )
}

#[cached]
fn create_piece_map(size: CubeSize) -> FxHashMap<Vector3<CubeSize>, u16> {
    let mut map = FxHashMap::default();

    let face_rotating_moves = vec![
        vec![],
        vec![X(Inverse), Y(Inverse)],
        vec![X(Inverse)],
        vec![X(Double)],
        vec![X(Inverse), Y(Standard)],
        vec![X(Inverse), Y(Double)]
    ];

    let mut idx = 0;
    for rotation in face_rotating_moves {
        for z in GeoCube::range(size) {
            for x in GeoCube::range(size) {
                let first_sticker = GeoCube {
                    size,
                    stickers: vec![(Sticker::new(size, x, size, z), 0)],
                }.apply_moves(&rotation).stickers()[0];
                map.insert(first_sticker.current, idx);
                idx += 1;
            }
        }
    }

    map
}