private string searchopt() { int maxprun1 = 0; int maxprun2 = 0; for (int i = 0; i < 6; i++) { node0[i, 0].calcPruning(false); if (i < 3) { maxprun1 = Math.Max(maxprun1, node0[i, 0].prun); } else { maxprun2 = Math.Max(maxprun2, node0[i, 0].prun); } } urfIdx = maxprun2 > maxprun1 ? 3 : 0; preIdx = 0; for (length1 = isRec ? length1 : 0; length1 < sol; length1++) { CoordCube ud = node0[0 + urfIdx, 0]; CoordCube rl = node0[1 + urfIdx, 0]; CoordCube fb = node0[2 + urfIdx, 0]; if (ud.prun <= length1 && rl.prun <= length1 && fb.prun <= length1 && phase1opt(ud, rl, fb, selfSym, length1, -1) == 0) { return(this.solution_ == null ? "Error 8" : this.solution_); } } return(this.solution_ == null ? "Error 7" : this.solution_); }
protected void set(CoordCube node) { this.twist = node.twist; this.tsym = node.tsym; this.flip = node.flip; this.fsym = node.fsym; this.slice = node.slice; this.prun = node.prun; }
//-1: no solution found // X: solution with X moves shorter than expectation. Hence, the length of the solution is depth - X private int phase2(int eidx, int esym, int cidx, int csym, int mid, int maxl, int depth, int lm) { if (eidx == 0 && cidx == 0 && mid == 0) { return(maxl); } for (int m = 0; m < 10; m++) { if (lm < 0 ? (m == -lm) : Util.ckmv2[lm, m]) { continue; } int midx = CoordCube.MPermMove[mid, m]; int cidxx = CoordCube.CPermMove[cidx, CubieCube.SymMove[csym, Util.ud2std[m]]]; int csymx = CubieCube.SymMult[cidxx & 0xf, csym]; cidxx >>= 4; if (CoordCube.getPruning(CoordCube.MCPermPrun, cidxx * 24 + CoordCube.MPermConj[midx, csymx]) >= maxl) { continue; } int eidxx = CoordCube.EPermMove[eidx, CubieCube.SymMoveUD[esym, m]]; int esymx = CubieCube.SymMult[eidxx & 0xf, esym]; eidxx >>= 4; if (CoordCube.getPruning(CoordCube.EPermCCombPrun, eidxx * 70 + CoordCube.CCombConj[CubieCube.Perm2Comb[cidxx], CubieCube.SymMultInv[esymx, csymx]]) >= maxl) { continue; } if (CoordCube.getPruning(CoordCube.MEPermPrun, eidxx * 24 + CoordCube.MPermConj[midx, esymx]) >= maxl) { continue; } int ret = phase2(eidxx, esymx, cidxx, csymx, midx, maxl - 1, depth + 1, (lm < 0 && m + lm == -5) ? -lm : m); if (ret >= 0) { move[depth] = Util.ud2std[m]; return(ret); } } return(-1); }
public static void init() { if (inited) { return; } CubieCube.initMove(); CubieCube.initSym(); if (EXTRA_PRUN_LEVEL > 0) { CoordCubeHuge.init(); } else { CoordCube.init(); } inited = true; }
/** * @return * 0: Success * 1: Try Next Power * 2: Try Next Axis */ internal virtual int doMovePrun(CoordCube cc, int m, bool isPhase1) { slice = UDSliceMove[cc.slice & 0x1ff, m] & 0x1ff; flip = FlipMove[cc.flip, CubieCube.Sym8Move[m << 3 | cc.fsym]]; fsym = CubieCube.Sym8Mult[flip & 7 | cc.fsym << 3]; flip >>= 3; twist = TwistMove[cc.twist, CubieCube.Sym8Move[m << 3 | cc.tsym]]; tsym = CubieCube.Sym8Mult[twist & 7 | cc.tsym << 3]; twist >>= 3; prun = Math.Max( Math.Max( getPruning(UDSliceTwistPrun, twist * N_SLICE + UDSliceConj[slice, tsym]), getPruning(UDSliceFlipPrun, flip * N_SLICE + UDSliceConj[slice, fsym])), Search.USE_TWIST_FLIP_PRUN ? getPruning(TwistFlipPrun, twist << 11 | CubieCube.FlipS2RF[flip << 3 | CubieCube.Sym8MultInv[fsym << 3 | tsym]]) : 0); return(prun); }
/** * @return * 0: Success * 1: Try Next Power * 2: Try Next Axis */ internal override int doMovePrun(CoordCube cc, int m, bool isPhase1) { twist = TwistMoveF[cc.twist, m]; flip = UDSliceFlipMove[cc.flip, CubieCube.SymMove[cc.fsym, m]]; fsym = CubieCube.SymMult[flip & 0xf, cc.fsym]; flip >>= 4; int prunm3; if (Search.EXTRA_PRUN_LEVEL > 1 && !isPhase1) { tsym = CCombMove[cc.tsym, m]; prunm3 = getPruningP(HugePrunP, flip * ((long)N_TWIST) * N_COMB + TwistConj[twist, fsym] * N_COMB + CCombConj[tsym, fsym], N_HUGE_5 * 4L); } else { prunm3 = getPruningP(UDSliceFlipTwistPrunP, flip * N_TWIST + TwistConj[twist, fsym], N_FULL_5 * 4); } prun = ((0x49249249 << prunm3 >> cc.prun) & 3) + cc.prun - 1; return(prun); }
/** * @return * 0: Found or Probe limit exceeded * 1: Try Next Power * 2: Try Next Axis */ private int initPhase2() { isRec = false; if (probe >= (this.solution_ == null ? probeMax : probeMin)) { return(0); } ++probe; int cidx = corn0[urfIdx, preIdx] >> 4; int csym = corn0[urfIdx, preIdx] & 0xf; int mid = node0[urfIdx, preIdx].slice; for (int i = 0; i < depth1; i++) { int m = move[i]; cidx = CoordCube.CPermMove[cidx, CubieCube.SymMove[csym, m]]; csym = CubieCube.SymMult[cidx & 0xf, csym]; cidx >>= 4; int cx = CoordCube.UDSliceMove[mid & 0x1ff, m]; mid = Util.permMult[mid >> 9, cx >> 9] << 9 | cx & 0x1ff; } mid >>= 9; int prun = CoordCube.getPruning(CoordCube.MCPermPrun, cidx * 24 + CoordCube.MPermConj[mid, csym]); if (prun >= maxDep2) { return(prun > maxDep2 ? 2 : 1); } int u4e = ud8e0[urfIdx, preIdx] >> 16; int d4e = ud8e0[urfIdx, preIdx] & 0xffff; for (int i = 0; i < depth1; i++) { int m = move[i]; int cx = CoordCube.UDSliceMove[u4e & 0x1ff, m]; u4e = Util.permMult[u4e >> 9, cx >> 9] << 9 | cx & 0x1ff; cx = CoordCube.UDSliceMove[d4e & 0x1ff, m]; d4e = Util.permMult[d4e >> 9, cx >> 9] << 9 | cx & 0x1ff; } int edge = CubieCube.MtoEPerm[494 - (u4e & 0x1ff) + (u4e >> 9) * 70 + (d4e >> 9) * 1680]; int esym = edge & 0xf; edge >>= 4; prun = Math.Max(prun, Math.Max( CoordCube.getPruning(CoordCube.MEPermPrun, edge * 24 + CoordCube.MPermConj[mid, esym]), CoordCube.getPruning(CoordCube.EPermCCombPrun, edge * 70 + CoordCube.CCombConj[CubieCube.Perm2Comb[cidx], CubieCube.SymMultInv[esym, csym]]))); if (prun >= maxDep2) { return(prun > maxDep2 ? 2 : 1); } int lm = 10; if (depth1 >= 2 && move[depth1 - 1] / 3 % 3 == move[depth1 - 2] / 3 % 3) { lm = Util.std2ud[Math.Max(move[depth1 - 1], move[depth1 - 2]) / 3 * 3 + 1]; } else if (depth1 >= 1) { lm = Util.std2ud[move[depth1 - 1] / 3 * 3 + 1]; if (move[depth1 - 1] > Util.Fx3) { lm = -lm; } } int depth2; for (depth2 = maxDep2 - 1; depth2 >= prun; depth2--) { int ret = phase2(edge, esym, cidx, csym, mid, depth2, depth1, lm); if (ret < 0) { break; } depth2 = depth2 - ret; sol = depth1 + depth2; if (preIdx != 0) { // assert depth2 > 0; //If depth2 == 0, the solution is optimal. In this case, we won't try preScramble to find shorter solutions. int axisPre = Util.preMove[preIdx] / 3; int axisLast = move[sol - 1] / 3; if (axisPre == axisLast) { int pow = (Util.preMove[preIdx] % 3 + move[sol - 1] % 3 + 1) % 4; move[sol - 1] = axisPre * 3 + pow; } else if (depth2 > 1 && axisPre % 3 == axisLast % 3 && move[sol - 2] / 3 == axisPre) { int pow = (Util.preMove[preIdx] % 3 + move[sol - 2] % 3 + 1) % 4; move[sol - 2] = axisPre * 3 + pow; } else { move[sol++] = Util.preMove[preIdx]; } } this.solution_ = solutionTostring(); } if (depth2 != maxDep2 - 1) { //At least one solution has been found. maxDep2 = Math.Min(MAX_DEPTH2, sol - length1); return(probe >= probeMin ? 0 : 1); } else { return(1); } }
/** * @return * 0: Found or Probe limit exceeded * 1: Try Next Power * 2: Try Next Axis */ private 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(initPhase2() == 0 ? 0 : 1); } int skipMoves = 0; int i = 1; for (long s = ssym; (s >>= 1) != 0; i++) { if ((s & 1) == 1) { skipMoves |= CubieCube.firstMoveSym[i]; } } for (int axis = 0; axis < 18; axis += 3) { if (axis == lm || axis == lm - 9 || (isRec && axis < move[length1 - maxl] - 2)) { continue; } for (int power = 0; power < 3; power++) { int m = axis + power; if (isRec && m != move[length1 - maxl] || ssym != 1 && (skipMoves & 1 << m) != 0) { continue; } // UD Axis int prun_ud = nodeUD[maxl].doMovePrun(ud, m, false); if (prun_ud > maxl) { break; } else if (prun_ud == maxl) { continue; } // RL Axis m = CubieCube.urfMove[2, m]; int prun_rl = nodeRL[maxl].doMovePrun(rl, m, false); if (prun_rl > maxl) { break; } else if (prun_rl == maxl) { continue; } // FB Axis m = CubieCube.urfMove[2, m]; int prun_fb = nodeFB[maxl].doMovePrun(fb, m, false); 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; int ret = phase1opt(nodeUD[maxl], nodeRL[maxl], nodeFB[maxl], ssym & CubieCube.moveCubeSym[m], maxl - 1, axis); if (ret == 0) { return(0); } else if (ret == 2) { break; } } } return(1); }
/** * @return * 0: Found or Probe limit exceeded * 1: Try Next Power * 2: Try Next Axis */ private int phase1(CoordCube node, long ssym, int maxl, int lm) { if (node.prun == 0 && maxl < 5) { if (maxl == 0) { int ret = initPhase2(); if (ret == 0 || preIdx == 0) { return(ret); } preIdx++; ret = Math.Min(initPhase2(), ret); preIdx--; return(ret); } else { return(1); } } int skipMoves = 0; int i = 1; for (long s = ssym; (s >>= 1) != 0; i++) { if ((s & 1) == 1) { skipMoves |= CubieCube.firstMoveSym[i]; } } for (int axis = 0; axis < 18; axis += 3) { if (axis == lm || axis == lm - 9 || (isRec && axis < move[depth1 - maxl] - 2)) { continue; } for (int power = 0; power < 3; power++) { int m = axis + power; if (isRec && m != move[depth1 - maxl] || ssym != 1 && (skipMoves & 1 << m) != 0) { continue; } int prun = nodeUD[maxl].doMovePrun(node, m, true); if (prun > maxl) { break; } else if (prun == maxl) { continue; } move[depth1 - maxl] = m; int ret = phase1(nodeUD[maxl], ssym & CubieCube.moveCubeSym[m], maxl - 1, axis); if (ret == 0) { return(0); } else if (ret == 2) { break; } } } return(1); }