pub mod moves;
pub mod subset;
mod cycle;
use rand::distributions::{Distribution, Standard};
use rand::Rng;
use std::fmt;
use std::iter::Iterator;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Axis {
X,
Y,
Z,
}
impl Axis {
pub fn top(&self) -> Face {
use Face::*;
match self {
Axis::X => R,
Axis::Y => U,
Axis::Z => F,
}
}
pub fn bottom(&self) -> Face {
use Face::*;
match self {
Axis::X => L,
Axis::Y => D,
Axis::Z => B,
}
}
pub fn complements(&self) -> [Self; 2] {
match self {
Self::X => [Self::Y, Self::Z],
Self::Y => [Self::X, Self::Z],
Self::Z => [Self::X, Self::Y],
}
}
pub fn complement(a: Self, b: Self) -> Option<Self> {
match a {
Self::X => match b {
Self::X => None,
Self::Y => Some(Self::Z),
Self::Z => Some(Self::Y),
},
Self::Y => match b {
Self::X => Some(Self::Z),
Self::Y => None,
Self::Z => Some(Self::X),
},
Self::Z => match b {
Self::X => Some(Self::Y),
Self::Y => Some(Self::X),
Self::Z => None,
},
}
}
pub fn belt(&self) -> &'static [usize; 4] {
match self {
Axis::X => &[0, 8, 10, 2],
Axis::Y => &[4, 5, 6, 7],
Axis::Z => &[3, 1, 9, 11],
}
}
}
impl fmt::Display for Axis {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}",
match self {
Axis::X => "x",
Axis::Y => "y",
Axis::Z => "z",
}
)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Face {
U,
D,
R,
L,
F,
B,
}
impl Distribution<Face> for Standard {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Face {
use Face::*;
[U, D, R, L, F, B][rng.gen_range(0..6)]
}
}
impl Face {
pub fn opposite(&self) -> Face {
match self {
Face::U => Face::D,
Face::D => Face::U,
Face::R => Face::L,
Face::L => Face::R,
Face::F => Face::B,
Face::B => Face::F,
}
}
pub fn is_top(&self) -> bool {
match self {
Face::U => true,
Face::D => false,
Face::R => true,
Face::L => false,
Face::F => true,
Face::B => false,
}
}
pub fn axis(&self) -> Axis {
match self {
Face::U => Axis::Y,
Face::D => Axis::Y,
Face::R => Axis::X,
Face::L => Axis::X,
Face::F => Axis::Z,
Face::B => Axis::Z,
}
}
pub fn corner_cycle(&self) -> &'static [usize; 4] {
use cycle::corner::*;
match &self {
Face::U => &U,
Face::D => &D,
Face::R => &R,
Face::L => &L,
Face::F => &F,
Face::B => &B,
}
}
pub fn corner_cycle_matches(&self, cp: &[usize; 4]) -> bool {
let mut cycle = self.corner_cycle().clone();
if cycle == *cp {
return true;
}
for _ in 1..4 {
cycle.rotate_left(1);
if cycle == *cp {
return true;
}
}
false
}
pub fn edge_cycle(&self) -> &'static [usize; 4] {
use cycle::edge::*;
match &self {
Face::U => &U,
Face::D => &D,
Face::R => &R,
Face::L => &L,
Face::F => &F,
Face::B => &B,
}
}
}
impl fmt::Display for Face {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}",
match self {
Face::U => "U",
Face::D => "D",
Face::R => "R",
Face::L => "L",
Face::F => "F",
Face::B => "B",
}
)
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Direction {
Clockwise,
CounterClockwise,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Move {
pub face: Face,
pub amount: i32,
}
impl fmt::Display for Move {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}{}{}",
self.face,
match self.amount {
1 | -1 => "".to_string(),
x => x.abs().to_string(),
},
if self.amount < 0 { "'" } else { "" },
)
}
}
impl Distribution<Move> for Standard {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Move {
let face = rng.gen();
let amount = [-1, 1, 2][rng.gen_range(0..3)];
Move { face, amount }
}
}
pub struct RandomMoves {
exclude_face: Option<Face>,
exclude_axis: Option<Axis>,
rng: rand::rngs::ThreadRng,
}
impl RandomMoves {
pub fn new() -> Self {
RandomMoves {
rng: rand::thread_rng(),
exclude_face: None,
exclude_axis: None,
}
}
pub fn new_from(last_face: Option<Face>, last_axis: Option<Axis>) -> Self {
RandomMoves {
rng: rand::thread_rng(),
exclude_face: last_face,
exclude_axis: last_axis,
}
}
}
impl Iterator for RandomMoves {
type Item = Move;
fn next(&mut self) -> Option<Self::Item> {
'find_next: loop {
let next: Move = self.rng.gen();
if let Some(face) = self.exclude_face {
if face == next.face {
continue 'find_next;
}
}
if let Some(axis) = self.exclude_axis {
if axis == next.face.axis() {
continue 'find_next;
}
}
if let Some(face) = self.exclude_face {
self.exclude_axis = if face == next.face.opposite() {
Some(next.face.axis())
} else {
None
}
}
self.exclude_face = Some(next.face);
return Some(next);
}
}
}