public long SelfSymmetry() { CubieCube c = new CubieCube(this); CubieCube d = new CubieCube(); long sym = 0L; for (int i = 0; i < 96; i++) { CornConjugate(c, SymMultInv[0, i % 16], d); if (System.Linq.Enumerable.SequenceEqual(d.ca, ca)) { EdgeConjugate(c, SymMultInv[0, i % 16], d); if (System.Linq.Enumerable.SequenceEqual(d.ea, ea)) { sym |= 1L << Math.Min(i, 48); } } if (i % 16 == 15) { c.URFConjugate(); } if (i % 48 == 47) { c.InvCubieCube(); } } return(sym); }
protected int InitPhase2Pre() { isRec = false; if (probe >= (solution == null ? probeMax : probeMin)) { return(0); } ++probe; for (int i = valid1; i < depth1; i++) { CubieCube.CornMult(phase1Cubie[i], CubieCube.moveCube[move[i]], phase1Cubie[i + 1]); CubieCube.EdgeMult(phase1Cubie[i], CubieCube.moveCube[move[i]], phase1Cubie[i + 1]); } valid1 = depth1; phase2Cubie = phase1Cubie[depth1]; int ret = InitPhase2(); if (ret == 0 || preMoveLen == 0 || ret == 2) { return(ret); } int m = preMoves[preMoveLen - 1] / 3 * 3 + 1; phase2Cubie = new CubieCube(); CubieCube.CornMult(CubieCube.moveCube[m], phase1Cubie[depth1], phase2Cubie); CubieCube.EdgeMult(CubieCube.moveCube[m], phase1Cubie[depth1], phase2Cubie); preMoves[preMoveLen - 1] += 2 - preMoves[preMoveLen - 1] % 3 * 2; ret = InitPhase2(); preMoves[preMoveLen - 1] += 2 - preMoves[preMoveLen - 1] % 3 * 2; return(ret); }
/** * prod = a * b, Edge Only. */ public static void EdgeMult(CubieCube a, CubieCube b, CubieCube prod) { for (int ed = 0; ed < 12; ed++) { prod.ea[ed] = (sbyte)(a.ea[b.ea[ed] >> 1] ^ (b.ea[ed] & 1)); } }
public static void InitUDSliceMoveConj() { CubieCube c = new CubieCube(); CubieCube d = new CubieCube(); for (int i = 0; i < N_SLICE; i++) { c.SetUDSlice(i); for (int j = 0; j < N_MOVES; j += 3) { CubieCube.EdgeMult(c, CubieCube.moveCube[j], d); UDSliceMove[i, j] = (char)d.GetUDSlice(); } for (int j = 0; j < 16; j += 2) { CubieCube.EdgeConjugate(c, CubieCube.SymMultInv[0, j], d); UDSliceConj[i, j >> 1] = (char)d.GetUDSlice(); } } for (int i = 0; i < N_SLICE; i++) { for (int j = 0; j < N_MOVES; j += 3) { int udslice = UDSliceMove[i, j]; for (int k = 1; k < 3; k++) { udslice = UDSliceMove[udslice, j]; UDSliceMove[i, j + k] = (char)udslice; } } } }
/** * this = S_urf^-1 * this * S_urf. */ public void URFConjugate() { temps = temps ?? new CubieCube(); CornMult(urf2, this, temps); CornMult(temps, urf1, this); EdgeMult(urf2, this, temps); EdgeMult(temps, urf1, this); }
/** * b = S_idx^-1 * a * S_idx, Edge Only. */ public static void EdgeConjugate(CubieCube a, int idx, CubieCube b) { CubieCube sinv = CubeSym[SymMultInv[0, idx]]; CubieCube s = CubeSym[idx]; for (int ed = 0; ed < 12; ed++) { b.ea[ed] = (sbyte)(sinv.ea[a.ea[s.ea[ed] >> 1] >> 1] ^ (a.ea[s.ea[ed] >> 1] & 1) ^ (s.ea[ed] & 1)); } }
///<returns> ///<para>-1: no solution found</para> ///<para>X: solution with X moves shorter than expectation. ///Hence, the length of the solution is depth - X</para> ///</returns> protected int Phase2(int edge, int esym, int corn, int csym, int mid, int maxl, int depth, int lm) { if (edge == 0 && corn == 0 && mid == 0) { return(maxl); } int moveMask = Util.ckmv2bit[lm]; for (int m = 0; m < 10; m++) { if ((moveMask >> m & 1) != 0) { m += 0x42 >> m & 3; continue; } int midx = CoordCube.MPermMove[mid, m]; int cornx = CoordCube.CPermMove[corn, CubieCube.SymMoveUD[csym, m]]; int csymx = CubieCube.SymMult[cornx & 0xf, csym]; cornx >>= 4; int edgex = CoordCube.EPermMove[edge, CubieCube.SymMoveUD[esym, m]]; int esymx = CubieCube.SymMult[edgex & 0xf, esym]; edgex >>= 4; int edgei = CubieCube.GetPermSymInv(edgex, esymx, false); int corni = CubieCube.GetPermSymInv(cornx, csymx, true); int prun = CoordCube.GetPruning(CoordCube.EPermCCombPPrun, (edgei >> 4) * CoordCube.N_COMB + CoordCube.CCombPConj[CubieCube.Perm2CombP[corni >> 4] & 0xff, CubieCube.SymMultInv[edgei & 0xf, corni & 0xf]]); if (prun > maxl + 1) { break; } else if (prun >= maxl) { m += 0x42 >> m & 3 & (maxl - prun); continue; } prun = Math.Max( CoordCube.GetPruning(CoordCube.MCPermPrun, cornx * CoordCube.N_MPERM + CoordCube.MPermConj[midx, csymx]), CoordCube.GetPruning(CoordCube.EPermCCombPPrun, edgex * CoordCube.N_COMB + CoordCube.CCombPConj[CubieCube.Perm2CombP[cornx] & 0xff, CubieCube.SymMultInv[esymx, csymx]])); if (prun >= maxl) { m += 0x42 >> m & 3 & (maxl - prun); continue; } int ret = Phase2(edgex, esymx, cornx, csymx, midx, maxl - 1, depth + 1, m); if (ret >= 0) { move[depth] = Util.ud2std[m]; return(ret); } } return(-1); }
public void Copy(CubieCube c) { for (int i = 0; i < 8; i++) { this.ca[i] = c.ca[i]; } for (int i = 0; i < 12; i++) { this.ea[i] = c.ea[i]; } }
public int GetCPermSym() { int k = ESym2CSym(CoordCube.GetPruning(EPermR2S, GetCPerm())) & 0xf; temps = temps ?? new CubieCube(); CornConjugate(this, SymMultInv[0, k], temps); int idx = Array.BinarySearch(EPermS2R, (char)temps.GetCPerm()); //assert idx >= 0; return(idx << 4 | k); }
/** * prod = a * b, Corner Only. */ public static void CornMult(CubieCube a, CubieCube b, CubieCube prod) { for (int corn = 0; corn < 8; corn++) { int oriA = a.ca[b.ca[corn] & 7] >> 3; int oriB = b.ca[corn] >> 3; int ori = oriA + ((oriA < 3) ? oriB : 6 - oriB); ori = ori % 3 + ((oriA < 3) == (oriB < 3) ? 0 : 3); prod.ca[corn] = (sbyte)(a.ca[b.ca[corn] & 7] & 7 | ori << 3); } }
public int GetEPermSym() { int raw = GetEPerm(); int k = CoordCube.GetPruning(EPermR2S, raw); temps = temps ?? new CubieCube(); EdgeConjugate(this, SymMultInv[0, k], temps); int idx = Array.BinarySearch(EPermS2R, (char)temps.GetEPerm()); //assert idx >= 0; return(idx << 4 | k); }
protected int Phase1PreMoves(int maxl, int lm, CubieCube cc, int ssym) { preMoveLen = maxPreMoves - maxl; if (isRec ? depth1 == length1 - preMoveLen : (preMoveLen == 0 || (0x36FB7 >> lm & 1) == 0)) { depth1 = length1 - preMoveLen; phase1Cubie[0] = cc; allowShorter = depth1 == MIN_P1LENGTH_PRE && preMoveLen != 0; if (nodeUD[depth1 + 1].SetWithPrun(cc, depth1) && Phase1(nodeUD[depth1 + 1], ssym, depth1, -1) == 0) { return(0); } } if (maxl == 0 || preMoveLen + MIN_P1LENGTH_PRE >= length1) { return(1); } int skipMoves = CubieCube.GetSkipMoves(ssym); if (maxl == 1 || preMoveLen + 1 + MIN_P1LENGTH_PRE >= length1) { //last pre move skipMoves |= 0x36FB7; // 11 0110 1111 1011 0111 } lm = lm / 3 * 3; for (int m = 0; m < 18; m++) { if (m == lm || m == lm - 9 || m == lm + 9) { m += 2; continue; } if (isRec && m != preMoves[maxPreMoves - maxl] || (skipMoves & 1 << m) != 0) { continue; } CubieCube.CornMult(CubieCube.moveCube[m], cc, preMoveCubes[maxl]); CubieCube.EdgeMult(CubieCube.moveCube[m], cc, preMoveCubes[maxl]); preMoves[maxPreMoves - maxl] = m; int ret = Phase1PreMoves(maxl - 1, m, preMoveCubes[maxl], ssym & (int)CubieCube.moveCubeSym[m]); if (ret == 0) { return(0); } } return(1); }
public void InvCubieCube() { temps = temps ?? new CubieCube(); for (sbyte edge = 0; edge < 12; edge++) { temps.ea[ea[edge] >> 1] = (sbyte)(edge << 1 | ea[edge] & 1); } for (sbyte corn = 0; corn < 8; corn++) { temps.ca[ca[corn] & 0x7] = (sbyte)(corn | (sbyte)(0x20 >> (ca[corn] >> 3) & 0x18)); } Copy(temps); }
/** * b = S_idx^-1 * a * S_idx, Corner Only. */ public static void CornConjugate(CubieCube a, int idx, CubieCube b) { CubieCube sinv = CubeSym[SymMultInv[0, idx]]; CubieCube s = CubeSym[idx]; for (int corn = 0; corn < 8; corn++) { int oriA = sinv.ca[a.ca[s.ca[corn] & 7] & 7] >> 3; int oriB = a.ca[s.ca[corn] & 7] >> 3; int ori = (oriA < 3) ? oriB : (3 - oriB) % 3; b.ca[corn] = (sbyte)(sinv.ca[a.ca[s.ca[corn] & 7] & 7] & 7 | ori << 3); } }
public static void InitPermSym2Raw() { InitSym2Raw(CoordCube.N_PERM, EPermS2R, EPermR2S, SymStatePerm = new char[CoordCube.N_PERM_SYM], 2); CubieCube cc = new CubieCube(); for (int i = 0; i < CoordCube.N_PERM_SYM; i++) { cc.SetEPerm(EPermS2R[i]); Perm2CombP[i] = (sbyte)(Util.GetComb(cc.ea, 0, true) + (Search.USE_COMBP_PRUN ? Util.GetNParity(EPermS2R[i], 8) * 70 : 0)); cc.InvCubieCube(); PermInvEdgeSym[i] = (char)cc.GetEPermSym(); } }
public static void InitTwistMove() { CubieCube c = new CubieCube(); CubieCube d = new CubieCube(); for (int i = 0; i < N_TWIST_SYM; i++) { c.SetTwist(CubieCube.TwistS2R[i]); for (int j = 0; j < N_MOVES; j++) { CubieCube.CornMult(c, CubieCube.moveCube[j], d); TwistMove[i, j] = (char)d.GetTwistSym(); } } }
public static void InitEPermMove() { CubieCube c = new CubieCube(); CubieCube d = new CubieCube(); for (int i = 0; i < N_PERM_SYM; i++) { c.SetEPerm(CubieCube.EPermS2R[i]); for (int j = 0; j < N_MOVES2; j++) { CubieCube.EdgeMult(c, CubieCube.moveCube[Util.ud2std[j]], d); EPermMove[i, j] = (char)d.GetEPermSym(); } } }
public static void InitFlipMove() { CubieCube c = new CubieCube(); CubieCube d = new CubieCube(); for (int i = 0; i < N_FLIP_SYM; i++) { c.SetFlip(CubieCube.FlipS2R[i]); for (int j = 0; j < N_MOVES; j++) { CubieCube.EdgeMult(c, CubieCube.moveCube[j], d); FlipMove[i, j] = (char)d.GetFlipSym(); } } }
// ********************************************* Initialization functions ********************************************* public static void InitMove() { moveCube[0] = new CubieCube(15120, 0, 119750400, 0); moveCube[3] = new CubieCube(21021, 1494, 323403417, 0); moveCube[6] = new CubieCube(8064, 1236, 29441808, 550); moveCube[9] = new CubieCube(9, 0, 5880, 0); moveCube[12] = new CubieCube(1230, 412, 2949660, 0); moveCube[15] = new CubieCube(224, 137, 328552, 137); for (int a = 0; a < 18; a += 3) { for (int p = 0; p < 2; p++) { moveCube[a + p + 1] = new CubieCube(); EdgeMult(moveCube[a + p], moveCube[a], moveCube[a + p + 1]); CornMult(moveCube[a + p], moveCube[a], moveCube[a + p + 1]); } } }
public Search() { for (int i = 0; i < 21; i++) { nodeUD[i] = new CoordCube(); nodeRL[i] = new CoordCube(); nodeFB[i] = new CoordCube(); phase1Cubie[i] = new CubieCube(); } for (int i = 0; i < 6; i++) { urfCubieCube[i] = new CubieCube(); urfCoordCube[i] = new CoordCube(); } for (int i = 0; i < MAX_PRE_MOVES; i++) { preMoveCubes[i + 1] = new CubieCube(); } }
public bool SetWithPrun(CubieCube cc, int depth) { twist = cc.GetTwistSym(); flip = cc.GetFlipSym(); tsym = twist & 7; twist = twist >> 3; prun = Search.USE_TWIST_FLIP_PRUN ? GetPruning(TwistFlipPrun, twist << 11 | CubieCube.FlipS2RF[flip ^ tsym]) : 0; if (prun > depth) { return(false); } fsym = flip & 7; flip = flip >> 3; slice = cc.GetUDSlice(); prun = Math.Max(prun, Math.Max( GetPruning(UDSliceTwistPrun, twist * N_SLICE + UDSliceConj[slice, tsym]), GetPruning(UDSliceFlipPrun, flip * N_SLICE + UDSliceConj[slice, fsym]))); if (prun > depth) { return(false); } if (Search.USE_CONJ_PRUN) { CubieCube pc = new CubieCube(); CubieCube.CornConjugate(cc, 1, pc); CubieCube.EdgeConjugate(cc, 1, pc); twistc = pc.GetTwistSym(); flipc = pc.GetFlipSym(); prun = Math.Max(prun, GetPruning(TwistFlipPrun, (twistc >> 3) << 11 | CubieCube.FlipS2RF[flipc ^ (twistc & 7)])); } return(prun <= depth); }
public static void InitMPermMoveConj() { CubieCube c = new CubieCube(); CubieCube d = new CubieCube(); for (int i = 0; i < N_MPERM; i++) { c.SetMPerm(i); for (int j = 0; j < N_MOVES2; j++) { CubieCube.EdgeMult(c, CubieCube.moveCube[Util.ud2std[j]], d); MPermMove[i, j] = (char)d.GetMPerm(); } for (int j = 0; j < 16; j++) { CubieCube.EdgeConjugate(c, CubieCube.SymMultInv[0, j], d); MPermConj[i, j] = (char)d.GetMPerm(); } } }
public static void InitCombPMoveConj() { CubieCube c = new CubieCube(); CubieCube d = new CubieCube(); CCombPMove = new char[N_COMB, N_MOVES2]; for (int i = 0; i < N_COMB; i++) { c.SetCComb(i % 70); for (int j = 0; j < N_MOVES2; j++) { CubieCube.CornMult(c, CubieCube.moveCube[Util.ud2std[j]], d); CCombPMove[i, j] = (char)(d.GetCComb() + 70 * ((P2_PARITY_MOVE >> j & 1) ^ (i / 70))); } for (int j = 0; j < 16; j++) { CubieCube.CornConjugate(c, CubieCube.SymMultInv[0, j], d); CCombPConj[i, j] = (char)(d.GetCComb() + 70 * (i / 70)); } } }
public static void Init() { if (initLevel == 2) { return; } if (initLevel == 0) { CubieCube.InitPermSym2Raw(); InitCPermMove(); InitEPermMove(); InitMPermMoveConj(); InitCombPMoveConj(); CubieCube.InitFlipSym2Raw(); CubieCube.InitTwistSym2Raw(); InitFlipMove(); InitTwistMove(); InitUDSliceMoveConj(); } if (InitPruning(initLevel == 0)) { initLevel = 2; //clean up CubieCube.SymStateTwist = null; CubieCube.SymStateFlip = null; CubieCube.SymStatePerm = null; CCombPMove = null; } else { initLevel = 1; } // System.out.println("initLevel: " + initLevel); }
public static void InitSym() { CubieCube c = new CubieCube(); CubieCube d = new CubieCube(); CubieCube t; CubieCube f2 = new CubieCube(28783, 0, 259268407, 0); CubieCube u4 = new CubieCube(15138, 0, 119765538, 7); CubieCube lr2 = new CubieCube(5167, 0, 83473207, 0); for (int i = 0; i < 8; i++) { lr2.ca[i] |= 3 << 3; } for (int i = 0; i < 16; i++) { CubeSym[i] = new CubieCube(c); CornMult(c, u4, d); EdgeMult(c, u4, d); t = d; d = c; c = t; if (i % 4 == 3) { CornMult(c, lr2, d); EdgeMult(c, lr2, d); t = d; d = c; c = t; } if (i % 8 == 7) { CornMult(c, f2, d); EdgeMult(c, f2, d); t = d; d = c; c = t; } } for (int i = 0; i < 16; i++) { for (int j = 0; j < 16; j++) { CornMult(CubeSym[i], CubeSym[j], c); for (int k = 0; k < 16; k++) { if (System.Linq.Enumerable.SequenceEqual(CubeSym[k].ca, c.ca)) { SymMult[i, j] = k; // SymMult[i,j] = (k ^ i ^ j ^ (0x14ab4 >> j & i << 1 & 2))); SymMultInv[k, j] = i; // i * j = k => k * j^-1 = i break; } } } } for (int j = 0; j < 18; j++) { for (int s = 0; s < 16; s++) { CornConjugate(moveCube[j], SymMultInv[0, s], c); for (int m = 0; m < 18; m++) { if (System.Linq.Enumerable.SequenceEqual(moveCube[m].ca, c.ca)) { SymMove[s, j] = m; SymMoveUD[s, Util.std2ud[j]] = Util.std2ud[m]; break; } } if (s % 2 == 0) { Sym8Move[j << 3 | s >> 1] = SymMove[s, j]; } } } for (int i = 0; i < 18; i++) { moveCubeSym[i] = moveCube[i].SelfSymmetry(); int j = i; for (int s = 0; s < 48; s++) { if (SymMove[s % 16, j] < i) { firstMoveSym[s] |= 1 << i; } if (s % 16 == 15) { j = urfMove[2, j]; } } } }
/** <returns> * <para>0: Found or Probe limit exceeded</para> * <para>1: Try Next Power</para> * <para>2: Try Next Axis</para> * </returns> */ protected int Phase1opt(CoordCube ud, CoordCube rl, CoordCube fb, long ssym, int maxl, int lm) { if (ud.prun == 0 && rl.prun == 0 && fb.prun == 0 && maxl < 5) { maxDep2 = maxl + 1; depth1 = length1 - maxl; return(InitPhase2Pre() == 0 ? 0 : 1); } int skipMoves = CubieCube.GetSkipMoves(ssym); for (int axis = 0; axis < 18; axis += 3) { if (axis == lm || axis == lm - 9) { continue; } for (int power = 0; power < 3; power++) { int m = axis + power; if (isRec && m != move[length1 - maxl] || skipMoves != 0 && (skipMoves & 1 << m) != 0) { continue; } // UD Axis int prun_ud = Math.Max(nodeUD[maxl].DoMovePrun(ud, m, false), USE_CONJ_PRUN ? nodeUD[maxl].DoMovePrunConj(ud, m) : 0); if (prun_ud > maxl) { break; } else if (prun_ud == maxl) { continue; } // RL Axis m = CubieCube.urfMove[2, m]; int prun_rl = Math.Max(nodeRL[maxl].DoMovePrun(rl, m, false), USE_CONJ_PRUN ? nodeRL[maxl].DoMovePrunConj(rl, m) : 0); if (prun_rl > maxl) { break; } else if (prun_rl == maxl) { continue; } // FB Axis m = CubieCube.urfMove[2, m]; int prun_fb = Math.Max(nodeFB[maxl].DoMovePrun(fb, m, false), USE_CONJ_PRUN ? nodeFB[maxl].DoMovePrunConj(fb, m) : 0); if (prun_ud == prun_rl && prun_rl == prun_fb && prun_fb != 0) { prun_fb++; } if (prun_fb > maxl) { break; } else if (prun_fb == maxl) { continue; } m = CubieCube.urfMove[2, m]; move[length1 - maxl] = m; valid1 = Math.Min(valid1, length1 - maxl); int ret = Phase1opt(nodeUD[maxl], nodeRL[maxl], nodeFB[maxl], ssym & CubieCube.moveCubeSym[m], maxl - 1, axis); if (ret == 0) { return(0); } } } return(1); }
/** * <returns> * <para>0: Found or Probe limit exceeded</para> * <para>1: Try Next Power</para> * <para>2: Try Next Axis</para> * </returns> */ protected int Phase1(CoordCube node, int ssym, int maxl, int lm) { if (node.prun == 0 && maxl < 5) { if (allowShorter || maxl == 0) { depth1 -= maxl; int ret = InitPhase2Pre(); depth1 += maxl; return(ret); } else { return(1); } } int skipMoves = CubieCube.GetSkipMoves(ssym); for (int axis = 0; axis < 18; axis += 3) { if (axis == lm || axis == lm - 9) { continue; } for (int power = 0; power < 3; power++) { int m = axis + power; if (isRec && m != move[depth1 - maxl] || skipMoves != 0 && (skipMoves & 1 << m) != 0) { continue; } int prun = nodeUD[maxl].DoMovePrun(node, m, true); if (prun > maxl) { break; } else if (prun == maxl) { continue; } if (USE_CONJ_PRUN) { prun = nodeUD[maxl].DoMovePrunConj(node, m); if (prun > maxl) { break; } else if (prun == maxl) { continue; } } move[depth1 - maxl] = m; valid1 = Math.Min(valid1, depth1 - maxl); int ret = Phase1(nodeUD[maxl], ssym & (int)CubieCube.moveCubeSym[m], maxl - 1, axis); if (ret == 0) { return(0); } else if (ret == 2) { break; } } } return(1); }
public static int InitSym2Raw(int N_RAW, char[] Sym2Raw, sbyte[] Raw2Sym, char[] SymState, int coord) { int N_RAW_HALF = (N_RAW + 1) / 2; CubieCube c = new CubieCube(); CubieCube d = new CubieCube(); int count = 0, idx = 0; int sym_inc = coord >= 2 ? 1 : 2; bool isEdge = coord != 1; for (int i = 0; i < N_RAW; i++) { if (CoordCube.GetPruning(Raw2Sym, i) != 0) { continue; } switch (coord) { case 0: c.SetFlip(i); break; case 1: c.SetTwist(i); break; case 2: c.SetEPerm(i); break; } for (int s = 0; s < 16; s += sym_inc) { if (isEdge) { EdgeConjugate(c, s, d); } else { CornConjugate(c, s, d); } switch (coord) { case 0: idx = d.GetFlip(); break; case 1: idx = d.GetTwist(); break; case 2: idx = d.GetEPerm(); break; } if (coord == 0 && Search.USE_TWIST_FLIP_PRUN) { FlipS2RF[count << 3 | s >> 1] = (char)idx; } if (idx == i) { SymState[count] |= (char)(1 << (s / sym_inc)); } int symIdx = (count << 4 | s) / sym_inc; if (CoordCube.GetPruning(Raw2Sym, idx) == 0) { CoordCube.SetPruning(Raw2Sym, idx, symIdx & 0xf); if (coord != 2) { Raw2Sym[idx + N_RAW_HALF] = (sbyte)(symIdx >> 4); } } } Sym2Raw[count++] = (char)i; } return(count); }
public CubieCube(CubieCube c) { Copy(c); }
static Search() { CubieCube.InitMove(); CubieCube.InitSym(); }