use rand::random;
use crate::{
cubie::{Corner, CubieCube, Edge},
facelet::Color,
};
pub struct Generator {}
impl Generator {
const RANDOM: i8 = -1;
const SOLVED: i8 = -2;
fn fill_perm(arr: &[i8]) -> Vec<u8> {
let cnt = arr.len();
let mut res = vec![0; cnt];
for i in 0..cnt {
if arr[i] != Generator::SOLVED && arr[i] != Generator::RANDOM {
res[i] = arr[i] as u8;
}
if arr[i] == Generator::SOLVED {
res[i] = i as u8;
}
}
while Generator::verify_perm(&res) != true {
for i in 0..cnt {
if arr[i] == Generator::RANDOM {
res[i] = (random::<usize>() % cnt) as u8;
}
}
}
res
}
fn verify_perm(arr: &Vec<u8>) -> bool {
let cnt = arr.len();
let mut arr = arr.clone();
arr.sort();
for i in 0..cnt {
if arr[i] != i as u8 {
return false;
}
}
true
}
fn fill_ori(arr: &[i8]) -> Vec<u8> {
let cnt = arr.len();
let mut res = vec![0; cnt];
let ori = match cnt {
8 => 3,
_ => 2,
};
loop {
for i in 0..cnt {
match arr[i] {
Generator::RANDOM => res[i] = random::<u8>() % ori,
_ => res[i] = arr[i] as u8,
};
}
if res.iter().fold(0, |acc, x| acc + x) % ori as u8 == 0 {
break;
}
}
res
}
fn fix_parity(cc: &mut CubieCube, cp: &[i8; 8], ep: &[i8; 12]) {
if cp == &[Generator::SOLVED; 8] {
Generator::swap_edge(&mut cc.ep, ep);
return;
}
if ep == &[Generator::SOLVED; 12] {
Generator::swap_corner(&mut cc.cp, cp);
return;
}
match random::<u8>() % 2 == 0 {
true => Generator::swap_edge(&mut cc.ep, ep),
false => Generator::swap_corner(&mut cc.cp, cp),
}
}
fn swap_corner(cp: &mut [Corner; 8], cp_o: &[i8; 8]) {
let idxx = Generator::get_unfill(cp_o);
let m = idxx.len();
let p1 = random::<usize>() % m;
let mut p2 = random::<usize>() % m;
while p1 == p2 {
p2 = random::<usize>() % m;
}
cp.swap(idxx[p1], idxx[p2]);
}
fn swap_edge(ep: &mut [Edge; 12], ep_o: &[i8; 12]) {
let idxx = Generator::get_unfill(ep_o);
let m = idxx.len();
let p1 = random::<usize>() % m;
let mut p2 = random::<usize>() % m;
while p1 == p2 {
p2 = random::<usize>() % m;
}
ep.swap(idxx[p1], idxx[p2]);
}
fn get_unfill(arr: &[i8]) -> Vec<usize> {
let mut r = Vec::new();
for i in 0..arr.len() {
if arr[i] == Generator::RANDOM {
r.push(i);
}
}
r
}
fn gen_edge(ep: [i8; 12], eo: [i8; 12]) -> ([Edge; 12], [u8; 12]) {
let epv = Generator::fill_perm(&ep);
let mut ep = [Edge::UR; 12];
for i in 0..12 {
ep[i] = Edge::try_from(epv[i]).unwrap();
}
let eo = Generator::fill_ori(&eo);
let eo: [u8; 12] = eo.try_into().unwrap();
(ep, eo)
}
fn gen_corner(cp: [i8; 8], co: [i8; 8]) -> ([Corner; 8], [u8; 8]) {
let cpv = Generator::fill_perm(&cp);
let mut cp = [Corner::URF; 8];
for i in 0..8 {
cp[i] = Corner::try_from(cpv[i]).unwrap();
}
let co = Generator::fill_ori(&co);
let co: [u8; 8] = co.try_into().unwrap();
(cp, co)
}
pub fn gen_state(cpv: [i8; 8], cov: [i8; 8], epv: [i8; 12], eov: [i8; 12]) -> CubieCube {
let (cp, co) = Generator::gen_corner(cpv, cov);
let (ep, eo) = Generator::gen_edge(epv, eov);
let center = [Color::U, Color::R, Color::F, Color::D, Color::L, Color::B];
let mut cc = CubieCube {
center,
cp,
co,
ep,
eo,
};
if cc.verify().is_err() {
Generator::fix_parity(&mut cc, &cpv, &epv);
}
cc
}
pub fn random() -> CubieCube {
let mut cc = CubieCube::default();
cc.randomize();
cc
}
pub fn random2() -> CubieCube {
let cp = [-1; 8];
let co = [-1; 8];
let ep = [-1; 12];
let eo = [-1; 12];
Generator::gen_state(cp, co, ep, eo)
}
pub fn corss_solved() -> CubieCube {
let cp = [Generator::RANDOM; 8];
let co = [Generator::RANDOM; 8];
let ep = [-1, -1, -1, -1, 4, 5, 6, 7, -1, -1, -1, -1];
let eo = [-1, -1, -1, -1, 0, 0, 0, 0, -1, -1, -1, -1];
Generator::gen_state(cp, co, ep, eo)
}
pub fn f2l_solved() -> CubieCube {
let cp = [-1, -1, -1, -1, 4, 5, 6, 7];
let co = [-1, -1, -1, -1, 0, 0, 0, 0];
let ep = [-1, -1, -1, -1, 4, 5, 6, 7, 8, 9, 10, 11];
let eo = [-1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0];
Generator::gen_state(cp, co, ep, eo)
}
pub fn pll() -> CubieCube {
let cp = [-1, -1, -1, -1, 4, 5, 6, 7];
let co = [0; 8];
let ep = [-1, -1, -1, -1, 4, 5, 6, 7, 8, 9, 10, 11];
let eo = [0; 12];
Generator::gen_state(cp, co, ep, eo)
}
pub fn lastslot() -> CubieCube {
let cp = [-1, -1, -1, -1, -1, 5, 6, 7];
let co = [-1, -1, -1, -1, -1, 0, 0, 0];
let ep = [-1, -1, -1, -1, 4, 5, 6, 7, -1, 9, 10, 11];
let eo = [-1, -1, -1, -1, 0, 0, 0, 0, -1, 0, 0, 0];
Generator::gen_state(cp, co, ep, eo)
}
pub fn edge_ll() -> CubieCube {
let cp = [Generator::SOLVED; 8];
let co = [0; 8];
let ep = [-1, -1, -1, -1, 4, 5, 6, 7, 8, 9, 10, 11];
let eo = [-1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0];
Generator::gen_state(cp, co, ep, eo)
}
pub fn corner_ll() -> CubieCube {
let cp = [-1, -1, -1, -1, 4, 5, 6, 7];
let co = [-1, -1, -1, -1, 0, 0, 0, 0];
let ep = [Generator::SOLVED; 12];
let eo = [0; 12];
Generator::gen_state(cp, co, ep, eo)
}
pub fn superflip() -> CubieCube {
let cp = [Generator::SOLVED; 8];
let co = [0; 8];
let ep = [Generator::SOLVED; 12];
let eo = [1; 12];
Generator::gen_state(cp, co, ep, eo)
}
pub fn roux_fb_solved() -> CubieCube {
let cp = [-1, -1, -1, -1, -1, 5, 6, -1];
let co = [-1, -1, -1, -1, -1, 0, 0, -1];
let ep = [-1, -1, -1, -1, -1, -1, 6, -1, -1, 9, 10, -1];
let eo = [-1, -1, -1, -1, -1, -1, 0, -1, -1, 0, 0, -1];
Generator::gen_state(cp, co, ep, eo)
}
pub fn roux_fb_sb_solved() -> CubieCube {
let cp = [-1, -1, -1, -1, 4, 5, 6, 7];
let co = [-1, -1, -1, -1, 0, 0, 0, 0];
let ep = [-1, -1, -1, -1, 4, -1, 6, -1, 8, 9, 10, 11];
let eo = [-1, -1, -1, -1, 0, -1, 0, -1, 0, 0, 0, 0];
Generator::gen_state(cp, co, ep, eo)
}
}
#[cfg(test)]
mod tests {
use crate::{facelet::FaceCube, printer::print_facelet};
use super::Generator;
#[test]
fn test_generator() {
let cc = Generator::roux_fb_sb_solved();
let fc = FaceCube::try_from(&cc).unwrap();
println!("{}", fc.to_string());
let _ = print_facelet(&fc);
}
}