package cs.min2phase;
import java.util.HashMap;
class Util {
/* //Edges
static final byte UR = 0;
static final byte UF = 1;
static final byte UL = 2;
static final byte UB = 3;
static final byte DR = 4;
static final byte DF = 5;
static final byte DL = 6;
static final byte DB = 7;
static final byte FR = 8;
static final byte FL = 9;
static final byte BL = 10;
static final byte BR = 11;
//Corners
static final byte URF = 0;
static final byte UFL = 1;
static final byte ULB = 2;
static final byte UBR = 3;
static final byte DFR = 4;
static final byte DLF = 5;
static final byte DBL = 6;
static final byte DRB = 7;
*/
//Moves
static final byte Ux1 = 0;
static final byte Ux2 = 1;
static final byte Ux3 = 2;
static final byte Rx1 = 3;
static final byte Rx2 = 4;
static final byte Rx3 = 5;
static final byte Fx1 = 6;
static final byte Fx2 = 7;
static final byte Fx3 = 8;
static final byte Dx1 = 9;
static final byte Dx2 = 10;
static final byte Dx3 = 11;
static final byte Lx1 = 12;
static final byte Lx2 = 13;
static final byte Lx3 = 14;
static final byte Bx1 = 15;
static final byte Bx2 = 16;
static final byte Bx3 = 17;
//Facelets
static final byte U1 = 0;
static final byte U2 = 1;
static final byte U3 = 2;
static final byte U4 = 3;
static final byte U5 = 4;
static final byte U6 = 5;
static final byte U7 = 6;
static final byte U8 = 7;
static final byte U9 = 8;
static final byte R1 = 9;
static final byte R2 = 10;
static final byte R3 = 11;
static final byte R4 = 12;
static final byte R5 = 13;
static final byte R6 = 14;
static final byte R7 = 15;
static final byte R8 = 16;
static final byte R9 = 17;
static final byte F1 = 18;
static final byte F2 = 19;
static final byte F3 = 20;
static final byte F4 = 21;
static final byte F5 = 22;
static final byte F6 = 23;
static final byte F7 = 24;
static final byte F8 = 25;
static final byte F9 = 26;
static final byte D1 = 27;
static final byte D2 = 28;
static final byte D3 = 29;
static final byte D4 = 30;
static final byte D5 = 31;
static final byte D6 = 32;
static final byte D7 = 33;
static final byte D8 = 34;
static final byte D9 = 35;
static final byte L1 = 36;
static final byte L2 = 37;
static final byte L3 = 38;
static final byte L4 = 39;
static final byte L5 = 40;
static final byte L6 = 41;
static final byte L7 = 42;
static final byte L8 = 43;
static final byte L9 = 44;
static final byte B1 = 45;
static final byte B2 = 46;
static final byte B3 = 47;
static final byte B4 = 48;
static final byte B5 = 49;
static final byte B6 = 50;
static final byte B7 = 51;
static final byte B8 = 52;
static final byte B9 = 53;
//Colors
static final byte U = 0;
static final byte R = 1;
static final byte F = 2;
static final byte D = 3;
static final byte L = 4;
static final byte B = 5;
static final byte[][] cornerFacelet = { { U9, R1, F3 }, { U7, F1, L3 }, { U1, L1, B3 }, { U3, B1, R3 },
{ D3, F9, R7 }, { D1, L9, F7 }, { D7, B9, L7 }, { D9, R9, B7 } };
static final byte[][] edgeFacelet = { { U6, R2 }, { U8, F2 }, { U4, L2 }, { U2, B2 }, { D6, R8 }, { D2, F8 },
{ D4, L8 }, { D8, B8 }, { F6, R4 }, { F4, L6 }, { B6, L4 }, { B4, R6 } };
static int[][] Cnk = new int[12][12];
static int[] fact = new int[13];
static int[][] permMult = new int[24][24];
static String[] move2str = {"U", "U2", "U'", "R", "R2", "R'", "F", "F2", "F'",
"D", "D2", "D'", "L", "L2", "L'", "B", "B2", "B'"};
static HashMap<String, Integer> str2move = new HashMap<String, Integer>();
static {
for(int i = 0; i < move2str.length; i++) {
str2move.put(move2str[i], i);
}
}
static int[] ud2std = {Ux1, Ux2, Ux3, Rx2, Fx2, Dx1, Dx2, Dx3, Lx2, Bx2};
static int[] std2ud = new int[18];
static boolean[][] ckmv2 = new boolean[11][10];
static void toCubieCube(byte[] f, CubieCube ccRet) {
byte ori;
for (int i = 0; i < 8; i++)
ccRet.cp[i] = 0;// invalidate corners
for (int i = 0; i < 12; i++)
ccRet.ep[i] = 0;// and edges
byte col1, col2;
for (byte i=0; i<8; i++) {
// get the colors of the cubie at corner i, starting with U/D
for (ori = 0; ori < 3; ori++)
if (f[cornerFacelet[i][ori]] == U || f[cornerFacelet[i][ori]] == D)
break;
col1 = f[cornerFacelet[i][(ori + 1) % 3]];
col2 = f[cornerFacelet[i][(ori + 2) % 3]];
for (byte j=0; j<8; j++) {
if (col1 == cornerFacelet[j][1]/9 && col2 == cornerFacelet[j][2]/9) {
// in cornerposition i we have cornercubie j
ccRet.cp[i] = j;
ccRet.co[i] = (byte) (ori % 3);
break;
}
}
}
for (byte i=0; i<12; i++) {
for (byte j=0; j<12; j++) {
if (f[edgeFacelet[i][0]] == edgeFacelet[j][0]/9
&& f[edgeFacelet[i][1]] == edgeFacelet[j][1]/9) {
ccRet.ep[i] = j;
ccRet.eo[i] = 0;
break;
}
if (f[edgeFacelet[i][0]] == edgeFacelet[j][1]/9
&& f[edgeFacelet[i][1]] == edgeFacelet[j][0]/9) {
ccRet.ep[i] = j;
ccRet.eo[i] = 1;
break;
}
}
}
}
static String toFaceCube(CubieCube cc) {
char[] f = new char[54];
char[] ts = {'U', 'R', 'F', 'D', 'L', 'B'};
for (int i=0; i<54; i++) {
f[i] = ts[i/9];
}
for (byte c=0; c<8; c++) {
byte j = cc.cp[c];// cornercubie with index j is at
// cornerposition with index c
byte ori = cc.co[c];// Orientation of this cubie
for (byte n=0; n<3; n++)
f[cornerFacelet[c][(n + ori) % 3]] = ts[cornerFacelet[j][n]/9];
}
for (byte e=0; e<12; e++) {
byte j = cc.ep[e];// edgecubie with index j is at edgeposition
// with index e
byte ori = cc.eo[e];// Orientation of this cubie
for (byte n=0; n<2; n++)
f[edgeFacelet[e][(n + ori) % 2]] = ts[edgeFacelet[j][n]/9];
}
return new String(f);
}
static int binarySearch(char[] arr, int key) {
int length = arr.length;
if (key <= arr[length-1]) {
int l = 0;
int r = length-1;
while (l <= r) {
int mid = (l+r)>>>1;
char val = arr[mid];
if (key > val) {
l = mid + 1;
} else if (key < val) {
r = mid - 1;
} else {
return mid;
}
}
}
return 0xffff;
}
static int getNParity(int idx, int n) {
int p = 0;
for (int i=n-2; i>=0; i--) {
p ^= idx % (n-i);
idx /= (n-i);
}
return p & 1;
}
static void set8Perm(byte[] arr, int idx) {
int val = 0x76543210;
for (int i=0; i<7; i++) {
int p = fact[7-i];
int v = idx / p;
idx -= v*p;
v <<= 2;
arr[i] = (byte) ((val >> v) & 07);
int m = (1 << v) - 1;
val = (val & m) + ((val >> 4) & ~m);
}
arr[7] = (byte)val;
}
static int get8Perm(byte[] arr) {
int idx = 0;
int val = 0x76543210;
for (int i=0; i<7; i++) {
int v = arr[i] << 2;
idx = (8 - i) * idx + ((val >> v) & 07);
val -= 0x11111110 << v;
}
return idx;
}
static void setNPerm(byte[] arr, int idx, int n) {
arr[n-1] = 0;
for (int i=n-2; i>=0; i--) {
arr[i] = (byte) (idx % (n-i));
idx /= (n-i);
for (int j=i+1; j<n; j++) {
if (arr[j] >= arr[i])
arr[j]++;
}
}
}
static int getNPerm(byte[] arr, int n) {
int idx=0;
for (int i=0; i<n; i++) {
idx *= (n-i);
for (int j=i+1; j<n; j++) {
if (arr[j] < arr[i]) {
idx++;
}
}
}
return idx;
}
static int getComb(byte[] arr, int mask) {
int idxC = 0, idxP = 0, r = 4, val = 0x123;
for (int i=11; i>=0; i--) {
if ((arr[i] & 0xc) == mask) {
int v = (arr[i] & 3) << 2;
idxP = r * idxP + ((val >> v) & 0x0f);
val -= 0x0111 >> (12-v);
idxC += Cnk[i][r--];
}
}
return idxP << 9 | (494 - idxC);
}
static void setComb(byte[] arr, int idx, int mask) {
int r = 4, fill = 11, val = 0x123;
int idxC = 494 - (idx & 0x1ff);
int idxP = idx >>> 9;
for (int i=11; i>=0; i--) {
if (idxC >= Cnk[i][r]) {
idxC -= Cnk[i][r--];
int p = fact[r & 3];
int v = idxP / p << 2;
idxP %= p;
arr[i] = (byte) ((val >> v) & 3 | mask);
int m = (1 << v) - 1;
val = (val & m) + ((val >> 4) & ~m);
} else {
if ((fill & 0xc) == mask) {
fill -= 4;
}
arr[i] = (byte) (fill--);
}
}
}
static {
for (int i=0; i<10; i++) {
std2ud[ud2std[i]] = i;
}
for (int i=0; i<10; i++) {
for (int j=0; j<10; j++) {
int ix = ud2std[i];
int jx = ud2std[j];
ckmv2[i][j] = (ix/3 == jx/3) || ((ix/3%3 == jx/3%3) && (ix>=jx));
}
ckmv2[10][i] = false;
}
fact[0] = 1;
for (int i=0; i<12; i++) {
Cnk[i][0] = Cnk[i][i] = 1;
fact[i+1] = fact[i] * (i+1);
for (int j=1; j<i; j++) {
Cnk[i][j] = Cnk[i-1][j-1] + Cnk[i-1][j];
}
}
byte[] arr1 = new byte[4];
byte[] arr2 = new byte[4];
byte[] arr3 = new byte[4];
for (int i=0; i<24; i++) {
for (int j=0; j<24; j++) {
setNPerm(arr1, i, 4);
setNPerm(arr2, j, 4);
for (int k=0; k<4; k++) {
arr3[k] = arr1[arr2[k]];
}
permMult[i][j] = getNPerm(arr3, 4);
}
}
}
}