From d48abf32de5c6bdc34d26ba403c149738534f35b Mon Sep 17 00:00:00 2001 From: Gregor Billing Date: Thu, 24 Nov 2022 18:52:31 +0900 Subject: [PATCH 1/4] Add cube555 code copy from cs0x7f GitHub --- cube555/.gitignore | 8 + cube555/build.gradle.kts | 22 + .../src/main/java/cs/cube555/CubieCube.java | 659 ++++++++++++++ .../main/java/cs/cube555/Phase1Center.java | 161 ++++ .../main/java/cs/cube555/Phase1Search.java | 195 ++++ .../main/java/cs/cube555/Phase2Center.java | 107 +++ .../main/java/cs/cube555/Phase2Search.java | 86 ++ .../main/java/cs/cube555/Phase3Center.java | 132 +++ .../src/main/java/cs/cube555/Phase3Edge.java | 193 ++++ .../main/java/cs/cube555/Phase3Search.java | 217 +++++ .../main/java/cs/cube555/Phase4Center.java | 197 ++++ .../src/main/java/cs/cube555/Phase4Edge.java | 200 ++++ .../main/java/cs/cube555/Phase4Search.java | 329 +++++++ .../main/java/cs/cube555/Phase5Center.java | 168 ++++ .../src/main/java/cs/cube555/Phase5Edge.java | 164 ++++ .../main/java/cs/cube555/Phase5Search.java | 219 +++++ .../src/main/java/cs/cube555/PhaseSearch.java | 121 +++ cube555/src/main/java/cs/cube555/README.md | 24 + cube555/src/main/java/cs/cube555/Search.java | 179 ++++ .../main/java/cs/cube555/SolutionChecker.java | 29 + .../src/main/java/cs/cube555/SolvingCube.java | 101 ++ cube555/src/main/java/cs/cube555/Tools.java | 80 ++ cube555/src/main/java/cs/cube555/Util.java | 861 ++++++++++++++++++ settings.gradle.kts | 1 + 24 files changed, 4453 insertions(+) create mode 100644 cube555/.gitignore create mode 100644 cube555/build.gradle.kts create mode 100644 cube555/src/main/java/cs/cube555/CubieCube.java create mode 100755 cube555/src/main/java/cs/cube555/Phase1Center.java create mode 100755 cube555/src/main/java/cs/cube555/Phase1Search.java create mode 100755 cube555/src/main/java/cs/cube555/Phase2Center.java create mode 100755 cube555/src/main/java/cs/cube555/Phase2Search.java create mode 100644 cube555/src/main/java/cs/cube555/Phase3Center.java create mode 100644 cube555/src/main/java/cs/cube555/Phase3Edge.java create mode 100644 cube555/src/main/java/cs/cube555/Phase3Search.java create mode 100644 cube555/src/main/java/cs/cube555/Phase4Center.java create mode 100644 cube555/src/main/java/cs/cube555/Phase4Edge.java create mode 100644 cube555/src/main/java/cs/cube555/Phase4Search.java create mode 100644 cube555/src/main/java/cs/cube555/Phase5Center.java create mode 100644 cube555/src/main/java/cs/cube555/Phase5Edge.java create mode 100644 cube555/src/main/java/cs/cube555/Phase5Search.java create mode 100755 cube555/src/main/java/cs/cube555/PhaseSearch.java create mode 100644 cube555/src/main/java/cs/cube555/README.md create mode 100755 cube555/src/main/java/cs/cube555/Search.java create mode 100755 cube555/src/main/java/cs/cube555/SolutionChecker.java create mode 100755 cube555/src/main/java/cs/cube555/SolvingCube.java create mode 100755 cube555/src/main/java/cs/cube555/Tools.java create mode 100644 cube555/src/main/java/cs/cube555/Util.java diff --git a/cube555/.gitignore b/cube555/.gitignore new file mode 100644 index 00000000..7350eed0 --- /dev/null +++ b/cube555/.gitignore @@ -0,0 +1,8 @@ +CACHED_THREEPHASE_TABLES_DELETE_TO_RECREATE + +*.class + +# Package Files # +*.jar +*.war +*.ear diff --git a/cube555/build.gradle.kts b/cube555/build.gradle.kts new file mode 100644 index 00000000..1ff143bc --- /dev/null +++ b/cube555/build.gradle.kts @@ -0,0 +1,22 @@ +import configurations.Languages.attachRemoteRepositories +import configurations.Languages.configureJava +import configurations.Publications.configureMavenPublication +import configurations.Publications.configureSignatures + +description = "A copy of Chen Shuang's 5x5 scrambler." + +plugins { + `java-library` + `maven-publish` + signing +} + +configureJava() +configureMavenPublication("scrambler-cube555") +configureSignatures(publishing) + +attachRemoteRepositories() + +dependencies { + implementation(libs.logback.classic) +} diff --git a/cube555/src/main/java/cs/cube555/CubieCube.java b/cube555/src/main/java/cs/cube555/CubieCube.java new file mode 100644 index 00000000..f91fa20c --- /dev/null +++ b/cube555/src/main/java/cs/cube555/CubieCube.java @@ -0,0 +1,659 @@ +package cs.cube555; + +import static cs.cube555.Util.*; + +/* + +Facelet: + U1 U2 U3 U4 U5 + U6 U7 U8 U9 U10 + U11 U12 U13 U14 U15 + U16 U17 U18 U19 U20 + U21 U22 U23 U24 U25 + +L1 L2 L3 L4 L5 F1 F2 F3 F4 F5 R1 R2 R3 R4 R5 B1 B2 B3 B4 B5 +L6 L7 L8 L9 L10 F6 F7 F8 F9 F10 R6 R7 R8 R9 R10 B6 B7 B8 B9 B10 +L11 L12 L13 L14 L15 F11 F12 F13 F14 F15 R11 R12 R13 R14 R15 B11 B12 B13 B14 B15 +L16 L17 L18 L19 L20 F16 F17 F18 F19 F20 R16 R17 R18 R19 R20 B16 B17 B18 B19 B20 +L21 L22 L23 L24 L25 F21 F22 F23 F24 F25 R21 R22 R23 R24 R25 B21 B22 B23 B24 B25 + + D1 D2 D3 D4 D5 + D6 D7 D8 D9 D10 + D11 D12 D13 D14 D15 + D16 D17 D18 D19 D20 + D21 D22 D23 D24 D25 + +Center: + 0 0 1 + 3 1 + 3 2 2 + +20 20 21 8 8 9 16 16 17 12 12 13 +23 21 11 9 19 17 15 13 +23 22 22 11 10 10 19 18 18 15 14 14 + + 4 4 5 + 7 5 + 7 6 6 + +Edge: + 13 1 + 4 17 + 16 5 + 0 12 + 4 16 0 12 5 17 1 13 +9 20 20 11 11 22 22 9 +21 8 8 23 23 10 10 21 + 19 7 15 3 18 6 14 2 + 15 3 + 7 18 + 19 6 + 2 14 + */ + +class CubieCube { + + // For pretty print + static int[] PRINT_FACELET = new int[] { + U1, U2, U3, U4, U5, + U6, U7, U8, U9, U10, + U11, U12, U13, U14, U15, + U16, U17, U18, U19, U20, + U21, U22, U23, U24, U25, + L1, L2, L3, L4, L5, F1, F2, F3, F4, F5, R1, R2, R3, R4, R5, B1, B2, B3, B4, B5, + L6, L7, L8, L9, L10, F6, F7, F8, F9, F10, R6, R7, R8, R9, R10, B6, B7, B8, B9, B10, + L11, L12, L13, L14, L15, F11, F12, F13, F14, F15, R11, R12, R13, R14, R15, B11, B12, B13, B14, B15, + L16, L17, L18, L19, L20, F16, F17, F18, F19, F20, R16, R17, R18, R19, R20, B16, B17, B18, B19, B20, + L21, L22, L23, L24, L25, F21, F22, F23, F24, F25, R21, R22, R23, R24, R25, B21, B22, B23, B24, B25, + D1, D2, D3, D4, D5, + D6, D7, D8, D9, D10, + D11, D12, D13, D14, D15, + D16, D17, D18, D19, D20, + D21, D22, D23, D24, D25 + }; + + static int[] MAP333_FACELET = new int[] { + U1, U3, U5, U11, U13, U15, U21, U23, U25, + R1, R3, R5, R11, R13, R15, R21, R23, R25, + F1, F3, F5, F11, F13, F15, F21, F23, F25, + D1, D3, D5, D11, D13, D15, D21, D23, D25, + L1, L3, L5, L11, L13, L15, L21, L23, L25, + B1, B3, B5, B11, B13, B15, B21, B23, B25 + }; + + static int[] TCENTER = new int[] { + U8, U14, U18, U12, + D8, D14, D18, D12, + F8, F14, F18, F12, + B8, B14, B18, B12, + R8, R14, R18, R12, + L8, L14, L18, L12 + }; + + static int[] XCENTER = new int[] { + U7, U9, U19, U17, + D7, D9, D19, D17, + F7, F9, F19, F17, + B7, B9, B19, B17, + R7, R9, R19, R17, + L7, L9, L19, L17 + }; + + static int[][] MEDGE = new int[][] { + {U23, F3}, {U3, B3}, {D23, B23}, {D3, F23}, + {U11, L3}, {U15, R3}, {D15, R23}, {D11, L23}, + {L15, F11}, {L11, B15}, {R15, B11}, {R11, F15} + }; + + static int[][] WEDGE = new int[][] { + {U22, F2}, {U4, B2}, {D22, B24}, {D4, F24}, + {U6, L2}, {U20, R2}, {D20, R24}, {D6, L24}, + {L20, F16}, {L6, B10}, {R20, B16}, {R6, F10}, + {F4, U24}, {B4, U2}, {B22, D24}, {F22, D2}, + {L4, U16}, {R4, U10}, {R22, D10}, {L22, D16}, + {F6, L10}, {B20, L16}, {B6, R10}, {F20, R16} + }; + + static int[][] CORNER = new int[][] { + {U25, R1, F5}, {U21, F1, L5}, {U1, L1, B5}, {U5, B1, R5}, + {D5, F25, R21}, {D1, L25, F21}, {D21, B25, L21}, {D25, R25, B21} + }; + + static CubieCube SOLVED = new CubieCube(); + + int[] tCenter = new int[24]; + int[] xCenter = new int[24]; + int[] mEdge = new int[12]; + int[] wEdge = new int[24]; + CornerCube corner = new CornerCube(); + + CubieCube() { + for (int i = 0; i < 24; i++) { + tCenter[i] = TCENTER[i] / 25; + xCenter[i] = XCENTER[i] / 25; + wEdge[i] = i; + } + for (int i = 0; i < 12; i++) { + mEdge[i] = i << 1; + } + } + + CubieCube(CubieCube cc) { + copy(cc); + } + + void copy(CubieCube cc) { + for (int i = 0; i < 24; i++) { + tCenter[i] = cc.tCenter[i]; + xCenter[i] = cc.xCenter[i]; + wEdge[i] = cc.wEdge[i]; + } + for (int i = 0; i < 12; i++) { + mEdge[i] = cc.mEdge[i]; + } + } + + static String to333Facelet(String facelet) { + StringBuffer sb = new StringBuffer(); + for (int i : MAP333_FACELET) { + sb.append(facelet.charAt(i)); + } + return sb.toString(); + } + + static String fill333Facelet(String facelet, String facelet333) { + StringBuffer sb = new StringBuffer(facelet); + for (int i = 0; i < MAP333_FACELET.length; i++) { + sb.setCharAt(MAP333_FACELET[i], facelet333.charAt(i)); + } + return sb.toString(); + } + + int fromFacelet(String facelet) { + int[] face = new int[150]; + long colorCnt = 0; + try { + String colors = new String( + new char[] { + facelet.charAt(U13), facelet.charAt(R13), facelet.charAt(F13), + facelet.charAt(D13), facelet.charAt(L13), facelet.charAt(B13) + } + ); + for (int i = 0; i < 150; i++) { + face[i] = colors.indexOf(facelet.charAt(i)); + if (face[i] == -1) { + return -1; + } + colorCnt += 1L << face[i] * 8; + } + } catch (Exception e) { + return -1; + } + int tCenterCnt = 0; + int xCenterCnt = 0; + for (int i = 0; i < 24; i++) { + tCenter[i] = face[TCENTER[i]]; + xCenter[i] = face[XCENTER[i]]; + tCenterCnt += 1 << (tCenter[i] << 2); + xCenterCnt += 1 << (xCenter[i] << 2); + } + int mEdgeCnt = 0; + int mEdgeChk = 0; + for (int i = 0; i < 12; i++) { + for (int j = 0; j < 12; j++) { + if (face[MEDGE[i][0]] == MEDGE[j][0] / 25 + && face[MEDGE[i][1]] == MEDGE[j][1] / 25 + || face[MEDGE[i][0]] == MEDGE[j][1] / 25 + && face[MEDGE[i][1]] == MEDGE[j][0] / 25 + ) { + int ori = face[MEDGE[i][0]] == MEDGE[j][0] / 25 ? 0 : 1; + mEdge[i] = j << 1 | ori; + mEdgeCnt |= 1 << j; + mEdgeChk ^= ori; + break; + } + } + } + int wEdgeCnt = 0; + for (int i = 0; i < 24; i++) { + for (int j = 0; j < 24; j++) { + if (face[WEDGE[i][0]] == WEDGE[j][0] / 25 + && face[WEDGE[i][1]] == WEDGE[j][1] / 25) { + wEdge[i] = j; + wEdgeCnt |= 1 << j; + break; + } + } + } + int ori = 0; + int cornerCnt = 0; + int cornerChk = 0; + for (int i = 0; i < 8; i++) { + for (ori = 0; ori < 3; ori++) { + if (face[CORNER[i][ori]] == 0 || face[CORNER[i][ori]] == 3) { + break; + } + } + int col1 = face[CORNER[i][(ori + 1) % 3]]; + int col2 = face[CORNER[i][(ori + 2) % 3]]; + for (int j = 0; j < 8; j++) { + if (col1 == CORNER[j][1] / 25 && col2 == CORNER[j][2] / 25) { + corner.cp[i] = j; + corner.co[i] = ori; + cornerChk += ori; + cornerCnt |= 1 << j; + break; + } + } + } + int[] ep = new int[12]; + for (int i = 0; i < 12; i++) { + ep[i] = mEdge[i] >> 1; + } + if (colorCnt != 0x191919191919L) { + return -1; + } else if (tCenterCnt != 0x444444) { + return -2; + } else if (xCenterCnt != 0x444444) { + return -3; + } else if (mEdgeCnt != 0xfff) { + return -4; + } else if (wEdgeCnt != 0xffffff) { + return -5; + } else if (cornerCnt != 0xff) { + return -6; + } else if (mEdgeChk != 0) { + return -7; + } else if (cornerChk % 3 != 0) { + return -8; + } else if (getParity(ep) != getParity(corner.cp)) { + return -9; + } + return 0; + } + + String toFacelet() { + char[] face = new char[150]; + String colors = "URFDLB"; + for (int i = 0; i < 150; i++) { + face[i] = i % 25 == 12 ? colors.charAt(i / 25) : '-'; + } + for (int i = 0; i < 24; i++) { + face[TCENTER[i]] = colors.charAt(tCenter[i]); + face[XCENTER[i]] = colors.charAt(xCenter[i]); + for (int j = 0; j < 2; j++) { + face[WEDGE[i][j]] = colors.charAt(WEDGE[wEdge[i]][j] / 25); + } + } + for (int i = 0; i < 12; i++) { + int perm = mEdge[i] >> 1; + int ori = mEdge[i] & 1;// Orientation of this cubie + for (int j = 0; j < 2; j++) { + face[MEDGE[i][j ^ ori]] = colors.charAt(MEDGE[perm][j] / 25); + } + } + for (int i = 0; i < 8; i++) { + int j = corner.cp[i]; + int ori = corner.co[i]; + for (int n = 0; n < 3; n++) { + face[CORNER[i][(n + ori) % 3]] = colors.charAt(CORNER[j][n] / 25); + } + } + return new String(face); + } + + public String toString() { + String facelet = toFacelet(); + String colors = "URFDLB-"; + String[] controls = new String[] { + "\033[37m", "\033[31m", "\033[32m", "\033[33m", "\033[35m", "\033[34m", "\033[30m" + }; + String[] arr = new String[150]; + for (int i = 0; i < 150; i++) { + char val = facelet.charAt(PRINT_FACELET[i]); + arr[i] = controls[colors.indexOf(val)] + " " + val + "\033[0m"; + } + return String.format( + " %s%s%s%s%s\n" + + " %s%s%s%s%s\n" + + " %s%s%s%s%s\n" + + " %s%s%s%s%s\n" + + " %s%s%s%s%s\n" + + "%s%s%s%s%s %s%s%s%s%s %s%s%s%s%s %s%s%s%s%s\n" + + "%s%s%s%s%s %s%s%s%s%s %s%s%s%s%s %s%s%s%s%s\n" + + "%s%s%s%s%s %s%s%s%s%s %s%s%s%s%s %s%s%s%s%s\n" + + "%s%s%s%s%s %s%s%s%s%s %s%s%s%s%s %s%s%s%s%s\n" + + "%s%s%s%s%s %s%s%s%s%s %s%s%s%s%s %s%s%s%s%s\n" + + " %s%s%s%s%s\n" + + " %s%s%s%s%s\n" + + " %s%s%s%s%s\n" + + " %s%s%s%s%s\n" + + " %s%s%s%s%s\033[0m\n", + (Object []) arr); + } + + void doCornerMove(int... moves) { + for (int move : moves) { + corner.doMove(move % 18); + } + } + + void doMove(int... moves) { + for (int move : moves) { + int pow = move % 3; + switch (move) { + case ux1: + case ux2: + case ux3: + swap(xCenter, 8, 20, 12, 16, pow); + swap(xCenter, 9, 21, 13, 17, pow); + swap(tCenter, 8, 20, 12, 16, pow); + swap(wEdge, 9, 22, 11, 20, pow); + case Ux1: + case Ux2: + case Ux3: + swap(xCenter, 0, 1, 2, 3, pow); + swap(tCenter, 0, 1, 2, 3, pow); + swap(mEdge, 0, 4, 1, 5, pow); + swap(wEdge, 0, 4, 1, 5, pow); + swap(wEdge, 12, 16, 13, 17, pow); + break; + case rx1: + case rx2: + case rx3: + swap(xCenter, 1, 15, 5, 9, pow); + swap(xCenter, 2, 12, 6, 10, pow); + swap(tCenter, 1, 15, 5, 9, pow); + swap(wEdge, 1, 14, 3, 12, pow); + case Rx1: + case Rx2: + case Rx3: + swap(xCenter, 16, 17, 18, 19, pow); + swap(tCenter, 16, 17, 18, 19, pow); + swap(mEdge, 5, 10, 6, 11, pow, true); + swap(wEdge, 5, 22, 6, 23, pow); + swap(wEdge, 17, 10, 18, 11, pow); + break; + case fx1: + case fx2: + case fx3: + swap(xCenter, 2, 19, 4, 21, pow); + swap(xCenter, 3, 16, 5, 22, pow); + swap(tCenter, 2, 19, 4, 21, pow); + swap(wEdge, 5, 18, 7, 16, pow); + case Fx1: + case Fx2: + case Fx3: + swap(xCenter, 8, 9, 10, 11, pow); + swap(tCenter, 8, 9, 10, 11, pow); + swap(mEdge, 0, 11, 3, 8, pow); + swap(wEdge, 0, 11, 3, 8, pow); + swap(wEdge, 12, 23, 15, 20, pow); + break; + case dx1: + case dx2: + case dx3: + swap(xCenter, 10, 18, 14, 22, pow); + swap(xCenter, 11, 19, 15, 23, pow); + swap(tCenter, 10, 18, 14, 22, pow); + swap(wEdge, 8, 23, 10, 21, pow); + case Dx1: + case Dx2: + case Dx3: + swap(xCenter, 4, 5, 6, 7, pow); + swap(tCenter, 4, 5, 6, 7, pow); + swap(mEdge, 2, 7, 3, 6, pow); + swap(wEdge, 2, 7, 3, 6, pow); + swap(wEdge, 14, 19, 15, 18, pow); + break; + case lx1: + case lx2: + case lx3: + swap(xCenter, 0, 8, 4, 14, pow); + swap(xCenter, 3, 11, 7, 13, pow); + swap(tCenter, 3, 11, 7, 13, pow); + swap(wEdge, 0, 15, 2, 13, pow); + case Lx1: + case Lx2: + case Lx3: + swap(xCenter, 20, 21, 22, 23, pow); + swap(tCenter, 20, 21, 22, 23, pow); + swap(mEdge, 4, 8, 7, 9, pow, true); + swap(wEdge, 4, 20, 7, 21, pow); + swap(wEdge, 16, 8, 19, 9, pow); + break; + case bx1: + case bx2: + case bx3: + swap(xCenter, 1, 20, 7, 18, pow); + swap(xCenter, 0, 23, 6, 17, pow); + swap(tCenter, 0, 23, 6, 17, pow); + swap(wEdge, 4, 19, 6, 17, pow); + case Bx1: + case Bx2: + case Bx3: + swap(xCenter, 12, 13, 14, 15, pow); + swap(tCenter, 12, 13, 14, 15, pow); + swap(mEdge, 1, 9, 2, 10, pow); + swap(wEdge, 1, 9, 2, 10, pow); + swap(wEdge, 13, 21, 14, 22, pow); + break; + } + } + } + + void doConj(int idx) { + CubieCube a = new CubieCube(this); + CubieCube sinv = CubeSym[SymMultInv[0][idx]]; + CubieCube s = CubeSym[idx]; + for (int i = 0; i < 12; i++) { + this.mEdge[i] = sinv.mEdge[a.mEdge[s.mEdge[i] >> 1] >> 1] + ^ (a.mEdge[s.mEdge[i] >> 1] & 1) + ^ (s.mEdge[i] & 1); + } + for (int i = 0; i < 24; i++) { + this.tCenter[i] = SOLVED.tCenter[sinv.tCenter[COLOR_TO_CENTER[a.tCenter[s.tCenter[i]]]]]; + this.xCenter[i] = SOLVED.xCenter[sinv.xCenter[COLOR_TO_CENTER[a.xCenter[s.xCenter[i]]]]]; + this.wEdge[i] = sinv.wEdge[a.wEdge[s.wEdge[i]]]; + } + } + + static CubieCube[] CubeSym = new CubieCube[48]; + static int[][] SymMult = new int[48][48]; + static int[][] SymMultInv = new int[48][48]; + static int[][] SymMove = new int[48][36]; + + static void CubeMult(CubieCube a, CubieCube b, CubieCube prod) { + for (int i = 0; i < 12; i++) { + prod.mEdge[i] = a.mEdge[b.mEdge[i] >> 1] ^ (b.mEdge[i] & 1); + } + for (int i = 0; i < 24; i++) { + prod.tCenter[i] = a.tCenter[b.tCenter[i]]; + prod.xCenter[i] = a.xCenter[b.xCenter[i]]; + prod.wEdge[i] = a.wEdge[b.wEdge[i]]; + } + } + + static int[] COLOR_TO_CENTER = new int[] {0, 16, 8, 4, 20, 12}; + + static void init() { + CornerCube.initMove(); + CubieCube c = new CubieCube(); + for (int i = 0; i < 24; i++) { + c.tCenter[i] = i; + c.xCenter[i] = i; + } + for (int i = 0; i < 48; i++) { + CubeSym[i] = new CubieCube(c); + + // x + c.doMove(rx1, lx3); + swap(c.tCenter, 0, 14, 4, 8, 0); + swap(c.tCenter, 2, 12, 6, 10, 0); + swap(c.mEdge, 0, 1, 2, 3, 0, true); + + if ((i & 0x3) == 0x3) { + // y2 + c.doMove(ux2, dx2); + swap(c.tCenter, 9, 21, 13, 17, 1); + swap(c.tCenter, 11, 23, 15, 19, 1); + swap(c.mEdge, 8, 9, 10, 11, 1, true); + } + if ((i & 0x7) == 0x7) { + // lr mirror + swap(c.tCenter, 1, 3); + swap(c.tCenter, 5, 7); + swap(c.tCenter, 9, 11); + swap(c.tCenter, 13, 15); + swap(c.tCenter, 16, 20); + swap(c.tCenter, 17, 23); + swap(c.tCenter, 18, 22); + swap(c.tCenter, 19, 21); + swap(c.xCenter, 0, 1); + swap(c.xCenter, 2, 3); + swap(c.xCenter, 4, 5); + swap(c.xCenter, 6, 7); + swap(c.xCenter, 8, 9); + swap(c.xCenter, 10, 11); + swap(c.xCenter, 12, 13); + swap(c.xCenter, 14, 15); + swap(c.xCenter, 16, 21); + swap(c.xCenter, 17, 20); + swap(c.xCenter, 18, 23); + swap(c.xCenter, 19, 22); + swap(c.wEdge, 0, 12); + swap(c.wEdge, 1, 13); + swap(c.wEdge, 2, 14); + swap(c.wEdge, 3, 15); + swap(c.wEdge, 4, 17); + swap(c.wEdge, 5, 16); + swap(c.wEdge, 6, 19); + swap(c.wEdge, 7, 18); + swap(c.wEdge, 8, 23); + swap(c.wEdge, 9, 22); + swap(c.wEdge, 10, 21); + swap(c.wEdge, 11, 20); + swap(c.mEdge, 4, 5); + swap(c.mEdge, 6, 7); + swap(c.mEdge, 8, 11); + swap(c.mEdge, 9, 10); + } + if ((i & 0xf) == 0xf) { + // URF -> RFU <=> x y + c.doMove(rx1, lx3); + swap(c.tCenter, 0, 14, 4, 8, 0); + swap(c.tCenter, 2, 12, 6, 10, 0); + swap(c.mEdge, 0, 1, 2, 3, 0, true); + c.doMove(ux1, dx3); + swap(c.tCenter, 9, 21, 13, 17, 0); + swap(c.tCenter, 11, 23, 15, 19, 0); + swap(c.mEdge, 8, 9, 10, 11, 0, true); + } + } + for (int i = 0; i < 48; i++) { + for (int j = 0; j < 48; j++) { + CubeMult(CubeSym[i], CubeSym[j], c); + for (int k = 0; k < 48; k++) { + if (java.util.Arrays.equals(CubeSym[k].wEdge, c.wEdge)) { + SymMult[i][j] = k; + SymMultInv[k][j] = i; + break; + } + } + } + } + + for (int move = 0; move < 36; move++) { + for (int s = 0; s < 48; s++) { + c = new CubieCube(); + c.doMove(move); + c.doConj(SymMultInv[0][s]); + for (int move2 = 0; move2 < 36; move2++) { + CubieCube d = new CubieCube(); + d.doMove(move2); + if (java.util.Arrays.equals(c.wEdge, d.wEdge)) { + SymMove[s][move] = move2; + break; + } + } + } + } + } + + static int[][] getSymMove(int[] moves, int nsym) { + int[] symList = new int[nsym]; + for (int i = 0; i < nsym; i++) { + symList[i] = i; + } + return getSymMove(moves, symList); + } + + static int[][] getSymMove(int[] moves, int[] symList) { + int[][] ret = new int[symList.length][moves.length]; + for (int s = 0; s < symList.length; s++) { + for (int m = 0; m < moves.length; m++) { + ret[s][m] = indexOf(moves, SymMove[symList[s]][moves[m]]); + } + } + return ret; + } + + static class CornerCube { + + private static CornerCube[] moveCube = new CornerCube[18]; + + int[] cp = {0, 1, 2, 3, 4, 5, 6, 7}; + int[] co = {0, 0, 0, 0, 0, 0, 0, 0}; + + CornerCube() {} + + CornerCube(int cperm, int twist) { + setPerm(cp, cperm); + int twst = 0; + for (int i = 6; i >= 0; i--) { + twst += co[i] = twist % 3; + twist /= 3; + } + co[7] = (15 - twst) % 3; + } + + CornerCube(CornerCube c) { + copy(c); + } + + void copy(CornerCube c) { + for (int i = 0; i < 8; i++) { + this.cp[i] = c.cp[i]; + this.co[i] = c.co[i]; + } + } + + static void CornMult(CornerCube a, CornerCube b, CornerCube prod) { + for (int corn = 0; corn < 8; corn++) { + prod.cp[corn] = a.cp[b.cp[corn]]; + prod.co[corn] = (a.co[b.cp[corn]] + b.co[corn]) % 3; + } + } + + void doMove(int move) { + CornerCube cc = new CornerCube(); + CornMult(this, moveCube[move], cc); + copy(cc); + } + + static void initMove() { + moveCube[0] = new CornerCube(15120, 0); + moveCube[3] = new CornerCube(21021, 1494); + moveCube[6] = new CornerCube(8064, 1236); + moveCube[9] = new CornerCube(9, 0); + moveCube[12] = new CornerCube(1230, 412); + moveCube[15] = new CornerCube(224, 137); + for (int a = 0; a < 18; a += 3) { + for (int p = 0; p < 2; p++) { + moveCube[a + p + 1] = new CornerCube(); + CornMult(moveCube[a + p], moveCube[a], moveCube[a + p + 1]); + } + } + } + } +} \ No newline at end of file diff --git a/cube555/src/main/java/cs/cube555/Phase1Center.java b/cube555/src/main/java/cs/cube555/Phase1Center.java new file mode 100755 index 00000000..31abe924 --- /dev/null +++ b/cube555/src/main/java/cs/cube555/Phase1Center.java @@ -0,0 +1,161 @@ +package cs.cube555; + +import static cs.cube555.Util.*; + +/* + 0 0 1 + 3 1 + 3 2 2 + +20 20 21 8 8 9 16 16 17 12 12 13 +23 21 11 9 19 17 15 13 +23 22 22 11 10 10 19 18 18 15 14 14 + + 4 4 5 + 7 5 + 7 6 6 +*/ + +class Phase1Center { + + int[] tCenter = new int[24]; + int[] xCenter = new int[24]; + + Phase1Center() { + setTCenter(0); + setXCenter(0); + } + + void setTCenter(int idx) { + setComb(tCenter, 735470 - idx, 8); + } + + int getTCenter() { + return 735470 - getComb(tCenter, 8); + } + + void setXCenter(int idx) { + setComb(xCenter, 735470 - idx, 8); + } + + int getXCenter() { + return 735470 - getComb(xCenter, 8); + } + + void doMove(int move) { + int pow = move % 3; + switch (move) { + case ux1: + case ux2: + case ux3: + swap(xCenter, 8, 20, 12, 16, pow); + swap(xCenter, 9, 21, 13, 17, pow); + swap(tCenter, 8, 20, 12, 16, pow); + case Ux1: + case Ux2: + case Ux3: + swap(xCenter, 0, 1, 2, 3, pow); + swap(tCenter, 0, 1, 2, 3, pow); + break; + case rx1: + case rx2: + case rx3: + swap(xCenter, 1, 15, 5, 9, pow); + swap(xCenter, 2, 12, 6, 10, pow); + swap(tCenter, 1, 15, 5, 9, pow); + case Rx1: + case Rx2: + case Rx3: + swap(xCenter, 16, 17, 18, 19, pow); + swap(tCenter, 16, 17, 18, 19, pow); + break; + case fx1: + case fx2: + case fx3: + swap(xCenter, 2, 19, 4, 21, pow); + swap(xCenter, 3, 16, 5, 22, pow); + swap(tCenter, 2, 19, 4, 21, pow); + case Fx1: + case Fx2: + case Fx3: + swap(xCenter, 8, 9, 10, 11, pow); + swap(tCenter, 8, 9, 10, 11, pow); + break; + case dx1: + case dx2: + case dx3: + swap(xCenter, 10, 18, 14, 22, pow); + swap(xCenter, 11, 19, 15, 23, pow); + swap(tCenter, 10, 18, 14, 22, pow); + case Dx1: + case Dx2: + case Dx3: + swap(xCenter, 4, 5, 6, 7, pow); + swap(tCenter, 4, 5, 6, 7, pow); + break; + case lx1: + case lx2: + case lx3: + swap(xCenter, 0, 8, 4, 14, pow); + swap(xCenter, 3, 11, 7, 13, pow); + swap(tCenter, 3, 11, 7, 13, pow); + case Lx1: + case Lx2: + case Lx3: + swap(xCenter, 20, 21, 22, 23, pow); + swap(tCenter, 20, 21, 22, 23, pow); + break; + case bx1: + case bx2: + case bx3: + swap(xCenter, 1, 20, 7, 18, pow); + swap(xCenter, 0, 23, 6, 17, pow); + swap(tCenter, 0, 23, 6, 17, pow); + case Bx1: + case Bx2: + case Bx3: + swap(xCenter, 12, 13, 14, 15, pow); + swap(tCenter, 12, 13, 14, 15, pow); + break; + } + } + + void doConj(int conj) { + switch (conj) { + case 0: //x + doMove(rx1); + doMove(lx3); + swap(tCenter, 0, 14, 4, 8, 0); + swap(tCenter, 2, 12, 6, 10, 0); + + break; + case 1: //y2 + doMove(ux2); + doMove(dx2); + swap(tCenter, 9, 21, 13, 17, 1); + swap(tCenter, 11, 23, 15, 19, 1); + break; + case 2: //lr mirror + swap(tCenter, 1, 3); + swap(tCenter, 5, 7); + swap(tCenter, 9, 11); + swap(tCenter, 13, 15); + swap(tCenter, 16, 20); + swap(tCenter, 17, 23); + swap(tCenter, 18, 22); + swap(tCenter, 19, 21); + swap(xCenter, 0, 1); + swap(xCenter, 2, 3); + swap(xCenter, 4, 5); + swap(xCenter, 6, 7); + swap(xCenter, 8, 9); + swap(xCenter, 10, 11); + swap(xCenter, 12, 13); + swap(xCenter, 14, 15); + swap(xCenter, 16, 21); + swap(xCenter, 17, 20); + swap(xCenter, 18, 23); + swap(xCenter, 19, 22); + } + } +} \ No newline at end of file diff --git a/cube555/src/main/java/cs/cube555/Phase1Search.java b/cube555/src/main/java/cs/cube555/Phase1Search.java new file mode 100755 index 00000000..655230dc --- /dev/null +++ b/cube555/src/main/java/cs/cube555/Phase1Search.java @@ -0,0 +1,195 @@ +package cs.cube555; + +import static cs.cube555.Util.*; + +/* + 0 0 1 + 3 1 + 3 2 2 + +20 20 21 8 8 9 16 16 17 12 12 13 +23 21 11 9 19 17 15 13 +23 22 22 11 10 10 19 18 18 15 14 14 + + 4 4 5 + 7 5 + 7 6 6 +*/ + +class Phase1Search extends PhaseSearch { + + static int[] VALID_MOVES = new int[] { + Ux1, Ux2, Ux3, Rx1, Rx2, Rx3, Fx1, Fx2, Fx3, Dx1, Dx2, Dx3, Lx1, Lx2, Lx3, Bx1, Bx2, Bx3, + ux1, ux2, ux3, rx1, rx2, rx3, fx1, fx2, fx3, dx1, dx2, dx3, lx1, lx2, lx3, bx1, bx2, bx3 + }; + + static PruningTable TCenterPrun; + static PruningTable XCenterPrun; + static PruningTable CenterSymPrun; + + static PruningTable TCenterSymPrun; + static PruningTable XCenterSymPrun; + static int[] TCenterSym2RawF; + static int[] TCenterRaw2Sym; + static int[][] TCenterSymMove; + static int[] XCenterSym2Raw; + static int[] XCenterRaw2Sym; + static int[][] XCenterSymMove; + + static int[][] SymMove; + + static void init() { + initCenter(); + } + + static void initCenter() { + Phase1Center center = new Phase1Center(); + int symCnt = 0; + TCenterSym2RawF = new int[46935 * 16]; + TCenterRaw2Sym = new int[735471]; + int[] TCenterSelfSym = new int[46935]; + for (int i = 0; i < TCenterRaw2Sym.length; i++) { + if (TCenterRaw2Sym[i] != 0) { + continue; + } + center.setTCenter(i); + for (int sym = 0; sym < 16; sym++) { + int idx = center.getTCenter(); + TCenterRaw2Sym[idx] = symCnt << 4 | sym; + TCenterSym2RawF[symCnt << 4 | sym] = idx; + if (idx == i) { + TCenterSelfSym[symCnt] |= 1 << sym; + } + center.doConj(0); + if ((sym & 3) == 3) { + center.doConj(1); + } + if ((sym & 7) == 7) { + center.doConj(2); + } + } + symCnt++; + } + TCenterSymMove = new int[symCnt][VALID_MOVES.length]; + for (int i = 0; i < symCnt; i++) { + for (int m = 0; m < VALID_MOVES.length; m++) { + center.setTCenter(TCenterSym2RawF[i << 4]); + center.doMove(m); + TCenterSymMove[i][m] = TCenterRaw2Sym[center.getTCenter()]; + } + } + + symCnt = 0; + XCenterSym2Raw = new int[46371]; + XCenterRaw2Sym = new int[735471]; + int[] XCenterSelfSym = new int[46371]; + for (int i = 0; i < XCenterRaw2Sym.length; i++) { + if (XCenterRaw2Sym[i] != 0) { + continue; + } + center.setXCenter(i); + for (int sym = 0; sym < 16; sym++) { + int idx = center.getXCenter(); + XCenterRaw2Sym[idx] = symCnt << 4 | sym; + if (idx == i) { + XCenterSelfSym[symCnt] |= 1 << sym; + } + center.doConj(0); + if ((sym & 3) == 3) { + center.doConj(1); + } + if ((sym & 7) == 7) { + center.doConj(2); + } + } + XCenterSym2Raw[symCnt] = i; + symCnt++; + } + XCenterSymMove = new int[symCnt][VALID_MOVES.length]; + for (int i = 0; i < symCnt; i++) { + for (int m = 0; m < VALID_MOVES.length; m++) { + center.setXCenter(XCenterSym2Raw[i]); + center.doMove(m); + XCenterSymMove[i][m] = XCenterRaw2Sym[center.getXCenter()]; + } + } + + SymCoord XCenterSymCoord = new TableSymCoord(XCenterSymMove, XCenterSelfSym, 16); + + TCenterSymPrun = new PruningTable( + new TableSymCoord(TCenterSymMove, TCenterSelfSym, 16), + null, "Phase1TCenterSym"); + + XCenterSymPrun = new PruningTable( + XCenterSymCoord, + null, "Phase1XCenterSym"); + + SymMove = CubieCube.getSymMove(VALID_MOVES, 16); + + CenterSymPrun = new PruningTable(XCenterSymCoord, + new RawCoord() { + { + N_IDX = 735471; + } + void set(int idx) { + this.idx = TCenterRaw2Sym[idx]; + } + int getMoved(int move) { + int ret = TCenterSymMove[idx >> 4][SymMove[idx & 0xf][move]]; + ret = ret & ~0xf | CubieCube.SymMult[ret & 0xf][idx & 0xf]; + return TCenterSym2RawF[ret]; + } + int getConj(int idx, int conj) { + idx = TCenterRaw2Sym[idx]; + idx = idx & ~0xf | CubieCube.SymMultInv[idx & 0xf][conj]; + return TCenterSym2RawF[idx]; + } + }, null, 7, 1 << 26, "Phase1CenterSym"); + } + + static class Phase1Node extends Node { + int tCenter; + int xCenter; + int getPrun() { + return Math.max( + Math.max( + TCenterSymPrun.getPrun(tCenter >> 4), + XCenterSymPrun.getPrun(xCenter >> 4)), + CenterSymPrun.getPrun(xCenter >> 4, TCenterSym2RawF[tCenter & ~0xf | CubieCube.SymMultInv[tCenter & 0xf][xCenter & 0xf]])); + } + int doMovePrun(Node node0, int move, int maxl) { + Phase1Node node = (Phase1Node) node0; + + tCenter = TCenterSymMove[node.tCenter >> 4][SymMove[node.tCenter & 0xf][move]]; + tCenter = tCenter & ~0xf | CubieCube.SymMult[tCenter & 0xf][node.tCenter & 0xf]; + + xCenter = XCenterSymMove[node.xCenter >> 4][SymMove[node.xCenter & 0xf][move]]; + xCenter = xCenter & ~0xf | CubieCube.SymMult[xCenter & 0xf][node.xCenter & 0xf]; + + return getPrun(); + } + } + + Phase1Search() { + super.VALID_MOVES = VALID_MOVES; + super.MIN_BACK_DEPTH = 5; + for (int i = 0; i < searchNode.length; i++) { + searchNode[i] = new Phase1Node(); + } + } + + Node[] initFrom(CubieCube cc) { + if (SymMove == null) { + SymMove = CubieCube.getSymMove(VALID_MOVES, 16); + } + Phase1Center ct = new Phase1Center(); + for (int i = 0; i < 24; i++) { + ct.xCenter[i] = cc.xCenter[i] == 1 || cc.xCenter[i] == 4 ? 0 : -1; + ct.tCenter[i] = cc.tCenter[i] == 1 || cc.tCenter[i] == 4 ? 0 : -1; + } + Phase1Node node = new Phase1Node(); + node.xCenter = XCenterRaw2Sym[ct.getXCenter()]; + node.tCenter = TCenterRaw2Sym[ct.getTCenter()]; + return new Node[] {node}; + } +} \ No newline at end of file diff --git a/cube555/src/main/java/cs/cube555/Phase2Center.java b/cube555/src/main/java/cs/cube555/Phase2Center.java new file mode 100755 index 00000000..8e3cc916 --- /dev/null +++ b/cube555/src/main/java/cs/cube555/Phase2Center.java @@ -0,0 +1,107 @@ +package cs.cube555; + +import static cs.cube555.Util.*; +import static cs.cube555.Phase2Search.VALID_MOVES; + +/* + 0 0 1 + 3 1 + 3 2 2 + +20 20 21 8 8 9 16 16 17 12 12 13 +23 21 11 9 19 17 15 13 +23 22 22 11 10 10 19 18 18 15 14 14 + + 4 4 5 + 7 5 + 7 6 6 +*/ + +class Phase2Center { + + static int[] eParityDiff = new int[] { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 1, 0, 0, 1, 0, 1, 0 + }; + + int[] tCenter = new int[16]; + int[] xCenter = new int[16]; + int eParity = 0; + + void setTCenter(int idx) { + setComb(tCenter, idx, 8); + } + + int getTCenter() { + return getComb(tCenter, 8); + } + + void setXCenter(int idx) { + setComb(xCenter, idx, 8); + } + + int getXCenter() { + return getComb(xCenter, 8); + } + + void setEParity(int idx) { + eParity = idx; + } + + int getEParity() { + return eParity; + } + + void doMove(int move) { + eParity ^= eParityDiff[move]; + move = VALID_MOVES[move]; + int axis = move / 3; + int pow = move % 3; + switch (axis) { + case 6: //Uw + swap(xCenter, 8, 12); + swap(xCenter, 9, 13); + swap(tCenter, 8, 12); + case 0: //U + swap(xCenter, 0, 1, 2, 3, pow); + swap(tCenter, 0, 1, 2, 3, pow); + break; + case 7: //Rw + swap(xCenter, 1, 15, 5, 9, pow); + swap(xCenter, 2, 12, 6, 10, pow); + swap(tCenter, 1, 15, 5, 9, pow); + case 1: //R + break; + case 8: //Fw + swap(xCenter, 2, 4); + swap(xCenter, 3, 5); + swap(tCenter, 2, 4); + case 2: //F + swap(xCenter, 8, 9, 10, 11, pow); + swap(tCenter, 8, 9, 10, 11, pow); + break; + case 9: //Dw + swap(xCenter, 10, 14); + swap(xCenter, 11, 15); + swap(tCenter, 10, 14); + case 3: //D + swap(xCenter, 4, 5, 6, 7, pow); + swap(tCenter, 4, 5, 6, 7, pow); + break; + case 10: //Lw + swap(xCenter, 0, 8, 4, 14, pow); + swap(xCenter, 3, 11, 7, 13, pow); + swap(tCenter, 3, 11, 7, 13, pow); + case 4: //L + break; + case 11: //Bw + swap(xCenter, 1, 7); + swap(xCenter, 0, 6); + swap(tCenter, 0, 6); + case 5: //B + swap(xCenter, 12, 13, 14, 15, pow); + swap(tCenter, 12, 13, 14, 15, pow); + break; + } + } +} \ No newline at end of file diff --git a/cube555/src/main/java/cs/cube555/Phase2Search.java b/cube555/src/main/java/cs/cube555/Phase2Search.java new file mode 100755 index 00000000..9c4c6840 --- /dev/null +++ b/cube555/src/main/java/cs/cube555/Phase2Search.java @@ -0,0 +1,86 @@ +package cs.cube555; + +import static cs.cube555.Util.*; + +class Phase2Search extends PhaseSearch { + + static int[] VALID_MOVES = new int[] { + Ux1, Ux2, Ux3, Fx1, Fx2, Fx3, Dx1, Dx2, Dx3, Bx1, Bx2, Bx3, + ux2, rx1, rx2, rx3, fx2, dx2, lx1, lx2, lx3, bx2 + }; + + static long[] SKIP_MOVES = genSkipMoves(VALID_MOVES); + + static int[][] TCenterMove; + static int[][] XCenterMove; + static PruningTable prunTCenter; + static PruningTable prunXCenter; + + static void init() { + initCenterMove(); + initCenterPrun(); + } + + static void initCenterMove() { + Phase2Center ct = new Phase2Center(); + TCenterMove = new int[12870][VALID_MOVES.length]; + XCenterMove = new int[12870][VALID_MOVES.length]; + for (int i = 0; i < 12870; i++) { + for (int m = 0; m < VALID_MOVES.length; m++) { + ct.setTCenter(i); + ct.setXCenter(i); + ct.doMove(m); + TCenterMove[i][m] = ct.getTCenter(); + XCenterMove[i][m] = ct.getXCenter(); + } + } + } + + static void initCenterPrun() { + int[][] EParityMove = new int[2][VALID_MOVES.length]; + for (int i = 0; i < VALID_MOVES.length; i++) { + EParityMove[0][i] = 0 ^ Phase2Center.eParityDiff[i]; + EParityMove[1][i] = 1 ^ Phase2Center.eParityDiff[i]; + } + prunTCenter = new PruningTable(TCenterMove, EParityMove, null, null, "Phase2TCenter"); + prunXCenter = new PruningTable(XCenterMove, EParityMove, null, null, "Phase2XCenter"); + } + + static class Phase2Node extends Node { + int tCenter; + int xCenter; + int eParity; + int getPrun() { + return Math.max(prunTCenter.getPrun(tCenter, eParity), + prunXCenter.getPrun(xCenter, eParity)); + } + int doMovePrun(Node node0, int move, int maxl) { + Phase2Node node = (Phase2Node) node0; + tCenter = TCenterMove[node.tCenter][move]; + xCenter = XCenterMove[node.xCenter][move]; + eParity = node.eParity ^ Phase2Center.eParityDiff[move]; + return getPrun(); + } + } + + Phase2Search() { + super.VALID_MOVES = VALID_MOVES; + super.MIN_BACK_DEPTH = 5; + for (int i = 0; i < searchNode.length; i++) { + searchNode[i] = new Phase2Node(); + } + } + + Node[] initFrom(CubieCube cc) { + Phase2Center ct = new Phase2Center(); + for (int i = 0; i < 16; i++) { + ct.xCenter[i] = cc.xCenter[i] == 0 || cc.xCenter[i] == 3 ? 0 : -1; + ct.tCenter[i] = cc.tCenter[i] == 0 || cc.tCenter[i] == 3 ? 0 : -1; + } + Phase2Node node = new Phase2Node(); + node.xCenter = ct.getXCenter(); + node.tCenter = ct.getTCenter(); + node.eParity = getParity(cc.wEdge); + return new Node[] {node}; + } +} \ No newline at end of file diff --git a/cube555/src/main/java/cs/cube555/Phase3Center.java b/cube555/src/main/java/cs/cube555/Phase3Center.java new file mode 100644 index 00000000..d729fc6f --- /dev/null +++ b/cube555/src/main/java/cs/cube555/Phase3Center.java @@ -0,0 +1,132 @@ +package cs.cube555; + +import static cs.cube555.Util.*; +import static cs.cube555.Phase3Search.VALID_MOVES; + +/* + +7 7 4 3 3 0 +6 4 2 0 +6 5 5 2 1 1 +*/ + +class Phase3Center { + + static int[] SOLVED_XCENTER = new int[] {0, 9, 14, 23, 27, 28}; + static int[] SOLVED_TCENTER = new int[] {0, 2, 4, 5, 7, 9, 11, 12, 14, 16, 18, 23, 25, 27, 28, 30, 32, 34}; + static int[] SOLVED_CENTER = new int[108]; + static { + for (int i = 0; i < 6; i++) { + for (int j = 0; j < 18; j++) { + SOLVED_CENTER[i * 18 + j] = SOLVED_XCENTER[i] * 35 + SOLVED_TCENTER[j]; + } + } + } + + int[] tCenter = new int[8]; + int[] xCenter = new int[8]; + + Phase3Center() { + } + + public String toString() { + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < 8; i++) { + sb.append(tCenter[i]).append(' '); + } + sb.append('|'); + for (int i = 0; i < 8; i++) { + sb.append(xCenter[i]).append(' '); + } + return sb.toString(); + } + + void setCenter(int idx) { + setComb(xCenter, idx / 35, 4); + setComb(tCenter, idx % 35, 4); + } + + int getCenter() { + return getSComb(xCenter) * 35 + getSComb(tCenter); + } + + void doMove(int move) { + move = VALID_MOVES[move]; + int pow = move % 3; + switch (move) { + case ux2: + swap(tCenter, 3, 7); + swap(xCenter, 3, 7); + swap(xCenter, 0, 4); + case Ux1: + case Ux2: + case Ux3: + break; + case rx2: + case Rx1: + case Rx2: + case Rx3: + swap(tCenter, 0, 1, 2, 3, pow); + swap(xCenter, 0, 1, 2, 3, pow); + break; + case fx2: + swap(tCenter, 2, 4); + swap(xCenter, 2, 4); + swap(xCenter, 3, 5); + case Fx1: + case Fx2: + case Fx3: + break; + case dx2: + swap(tCenter, 1, 5); + swap(xCenter, 1, 5); + swap(xCenter, 2, 6); + case Dx1: + case Dx2: + case Dx3: + break; + case lx2: + case Lx1: + case Lx2: + case Lx3: + swap(tCenter, 4, 5, 6, 7, pow); + swap(xCenter, 4, 5, 6, 7, pow); + break; + case bx2: + swap(tCenter, 0, 6); + swap(xCenter, 0, 6); + swap(xCenter, 1, 7); + case Bx2: + break; + } + } + + void doConj(int conj) { + switch (conj) { + case 0: //x + doMove(Rx1); + doMove(Lx3); + break; + case 1: //y2 + swap(tCenter, 0, 4); + swap(tCenter, 1, 5); + swap(tCenter, 2, 6); + swap(tCenter, 3, 7); + swap(xCenter, 0, 4); + swap(xCenter, 1, 5); + swap(xCenter, 2, 6); + swap(xCenter, 3, 7); + break; + case 2: //lr2 + swap(tCenter, 0, 6); + swap(tCenter, 1, 5); + swap(tCenter, 2, 4); + swap(tCenter, 3, 7); + swap(xCenter, 0, 7); + swap(xCenter, 1, 6); + swap(xCenter, 2, 5); + swap(xCenter, 3, 4); + break; + } + } +} \ No newline at end of file diff --git a/cube555/src/main/java/cs/cube555/Phase3Edge.java b/cube555/src/main/java/cs/cube555/Phase3Edge.java new file mode 100644 index 00000000..35d1498f --- /dev/null +++ b/cube555/src/main/java/cs/cube555/Phase3Edge.java @@ -0,0 +1,193 @@ +package cs.cube555; + +import static cs.cube555.Util.*; +import static cs.cube555.Phase3Search.VALID_MOVES; + +/* + 13 1 + 4 17 + 16 5 + 0 12 + 4 16 0 12 5 17 1 13 +9 20 20 11 11 22 22 9 +21 8 8 23 23 10 10 21 + 19 7 15 3 18 6 14 2 + 15 3 + 7 18 + 19 6 + 2 14 + */ + +class Phase3Edge { + + int[] mEdge = new int[12]; + int[] wEdge = new int[24]; + + Phase3Edge() { + for (int i = 0; i < 12; i++) { + mEdge[i] = 0; + wEdge[i] = 0; + wEdge[i + 12] = -1; + } + } + + public String toString() { + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < 12; i++) { + sb.append(mEdge[i]).append(' '); + } + sb.append('|'); + for (int i = 0; i < 24; i++) { + sb.append(wEdge[i]).append(' '); + } + return sb.toString(); + } + + void setMEdge(int idx) { + int parity = 0; + for (int i = 0; i < 11; i++) { + mEdge[i] = idx & 1; + idx >>= 1; + parity ^= mEdge[i]; + } + mEdge[11] = parity; + } + + int getMEdge() { + int idx = 0; + for (int i = 0; i < 11; i++) { + idx |= mEdge[i] << i; + } + return idx; + } + + void setWEdge(int idx) { + setComb(wEdge, idx, 12); + } + + int getWEdge() { + return getComb(wEdge, 12); + } + + void doMove(int move) { + move = VALID_MOVES[move]; + int pow = move % 3; + switch (move) { + case ux2: + swap(wEdge, 9, 22, 11, 20, pow); + case Ux1: + case Ux2: + case Ux3: + swap(mEdge, 0, 4, 1, 5, pow); + swap(wEdge, 0, 4, 1, 5, pow); + swap(wEdge, 12, 16, 13, 17, pow); + break; + case rx2: + swap(wEdge, 1, 14, 3, 12, pow); + case Rx1: + case Rx2: + case Rx3: + swap(mEdge, 5, 10, 6, 11, pow, true); + swap(wEdge, 5, 22, 6, 23, pow); + swap(wEdge, 17, 10, 18, 11, pow); + break; + case fx2: + swap(wEdge, 5, 18, 7, 16, pow); + case Fx1: + case Fx2: + case Fx3: + swap(mEdge, 0, 11, 3, 8, pow); + swap(wEdge, 0, 11, 3, 8, pow); + swap(wEdge, 12, 23, 15, 20, pow); + break; + case dx2: + swap(wEdge, 8, 23, 10, 21, pow); + case Dx1: + case Dx2: + case Dx3: + swap(mEdge, 2, 7, 3, 6, pow); + swap(wEdge, 2, 7, 3, 6, pow); + swap(wEdge, 14, 19, 15, 18, pow); + break; + case lx2: + swap(wEdge, 0, 15, 2, 13, pow); + case Lx1: + case Lx2: + case Lx3: + swap(mEdge, 4, 8, 7, 9, pow, true); + swap(wEdge, 4, 20, 7, 21, pow); + swap(wEdge, 16, 8, 19, 9, pow); + break; + case bx2: + swap(wEdge, 4, 19, 6, 17, pow); + case Bx1: + case Bx2: + case Bx3: + swap(mEdge, 1, 9, 2, 10, pow); + swap(wEdge, 1, 9, 2, 10, pow); + swap(wEdge, 13, 21, 14, 22, pow); + break; + } + } + + void doConj(int conj) { + switch (conj) { + case 0: //x + swap(wEdge, 1, 14, 3, 12, 0); + swap(wEdge, 5, 22, 6, 23, 0); + swap(wEdge, 17, 10, 18, 11, 0); + swap(wEdge, 0, 15, 2, 13, 2); + swap(wEdge, 4, 20, 7, 21, 2); + swap(wEdge, 16, 8, 19, 9, 2); + swap(mEdge, 5, 10, 6, 11, 0, true); + swap(mEdge, 4, 8, 7, 9, 2, true); + swap(mEdge, 0, 1, 2, 3, 0, true); + for (int i = 0; i < 12; i++) { + mEdge[i] ^= 1; + wEdge[i] = -1 - wEdge[i]; + wEdge[i + 12] = -1 - wEdge[i + 12]; + } + break; + case 1: //y2 + swap(wEdge, 9, 22, 11, 20, 1); + swap(wEdge, 0, 4, 1, 5, 1); + swap(wEdge, 12, 16, 13, 17, 1); + swap(wEdge, 8, 23, 10, 21, 1); + swap(wEdge, 2, 7, 3, 6, 1); + swap(wEdge, 14, 19, 15, 18, 1); + swap(mEdge, 0, 4, 1, 5, 1); + swap(mEdge, 2, 7, 3, 6, 1); + swap(mEdge, 8, 9, 10, 11, 1, true); + break; + case 2: //lr2 + swap(wEdge, 0, 12); + swap(wEdge, 1, 13); + swap(wEdge, 2, 14); + swap(wEdge, 3, 15); + swap(wEdge, 4, 17); + swap(wEdge, 5, 16); + swap(wEdge, 6, 19); + swap(wEdge, 7, 18); + swap(wEdge, 8, 23); + swap(wEdge, 9, 22); + swap(wEdge, 10, 21); + swap(wEdge, 11, 20); + swap(mEdge, 4, 5); + swap(mEdge, 6, 7); + swap(mEdge, 8, 11); + swap(mEdge, 9, 10); + for (int i = 0; i < 24; i++) { + wEdge[i] = -1 - wEdge[i]; + } + break; + case 3: //change lh edges + for (int i = 0; i < 24; i++) { + wEdge[i] = -1 - wEdge[i]; + } + for (int i = 0; i < 12; i++) { + mEdge[i] ^= 1; + } + break; + } + } +} \ No newline at end of file diff --git a/cube555/src/main/java/cs/cube555/Phase3Search.java b/cube555/src/main/java/cs/cube555/Phase3Search.java new file mode 100644 index 00000000..9e40c3f7 --- /dev/null +++ b/cube555/src/main/java/cs/cube555/Phase3Search.java @@ -0,0 +1,217 @@ +package cs.cube555; + +import static cs.cube555.Util.*; + +class Phase3Search extends PhaseSearch { + + static int[] VALID_MOVES = new int[] { + Ux1, Ux2, Ux3, Rx1, Rx2, Rx3, Fx1, Fx2, Fx3, Dx1, Dx2, Dx3, Lx1, Lx2, Lx3, Bx1, Bx2, Bx3, + ux2, rx2, fx2, dx2, lx2, bx2 + }; + + static int[][] SymMove; + + static long[] SKIP_MOVES = genSkipMoves(VALID_MOVES); + static int NEXT_AXIS = 0x12492; + + static int[][] CenterMove; + static int[][] MEdgeMove; + static int[][] MEdgeConj; + static PruningTable CenterMEdgePrun; + + static int[][] WEdgeSymMove; + static int[] WEdgeSym2Raw; + static int[] WEdgeSelfSym; + static int[] WEdgeRaw2Sym; + + static void init() { + initWEdgeSymMove(); + initMEdgeMove(); + initCenterMove(); + initPrun(); + } + + static void initWEdgeSymMove() { + Phase3Edge edge = new Phase3Edge(); + int symCnt = 0; + WEdgeSym2Raw = new int[86048]; + WEdgeSelfSym = new int[86048]; + WEdgeRaw2Sym = new int[2704156]; + for (int i = 0; i < WEdgeRaw2Sym.length; i++) { + if (WEdgeRaw2Sym[i] != 0) { + continue; + } + edge.setWEdge(i); + for (int sym = 0; sym < 32; sym++) { + int idx = edge.getWEdge(); + WEdgeRaw2Sym[idx] = symCnt << 5 | sym; + if (idx == i) { + WEdgeSelfSym[symCnt] |= 1 << sym; + } + edge.doConj(0); + if ((sym & 3) == 3) { + edge.doConj(1); + } + if ((sym & 7) == 7) { + edge.doConj(2); + } + if ((sym & 0xf) == 0xf) { + edge.doConj(3); + } + } + WEdgeSym2Raw[symCnt] = i; + symCnt++; + } + WEdgeSymMove = new int[symCnt][VALID_MOVES.length]; + for (int i = 0; i < symCnt; i++) { + for (int m = 0; m < VALID_MOVES.length; m++) { + edge.setWEdge(WEdgeSym2Raw[i]); + edge.doMove(m); + WEdgeSymMove[i][m] = WEdgeRaw2Sym[edge.getWEdge()]; + } + } + } + + static void initMEdgeMove() { + Phase3Edge edge = new Phase3Edge(); + MEdgeMove = new int[2048][VALID_MOVES.length]; + MEdgeConj = new int[2048][32]; + for (int i = 0; i < 2048; i++) { + for (int m = 0; m < VALID_MOVES.length; m++) { + edge.setMEdge(i); + edge.doMove(m); + MEdgeMove[i][m] = edge.getMEdge(); + } + + edge.setMEdge(i); + for (int sym = 0; sym < 32; sym++) { + MEdgeConj[i][CubieCube.SymMultInv[0][sym & 0xf] | sym & 0x10] = edge.getMEdge(); + edge.doConj(0); + if ((sym & 3) == 3) { + edge.doConj(1); + } + if ((sym & 7) == 7) { + edge.doConj(2); + } + if ((sym & 0xf) == 0xf) { + edge.doConj(3); + } + } + } + } + + static void initCenterMove() { + Phase3Center center = new Phase3Center(); + CenterMove = new int[1225][VALID_MOVES.length]; + for (int i = 0; i < 1225; i++) { + for (int m = 0; m < VALID_MOVES.length; m++) { + center.setCenter(i); + center.doMove(m); + CenterMove[i][m] = center.getCenter(); + } + } + } + + static PruningTable WMEdgeSymPrun; + + static void initPrun() { + CenterMEdgePrun = new PruningTable( + CenterMove, MEdgeMove, + Phase3Center.SOLVED_CENTER, new int[] {0, 2047}, + "Phase3CenterMEdge"); + + final int[] mEdgeFlip = new int[1]; + WMEdgeSymPrun = new PruningTable(new SymCoord() { + { + N_IDX = 86048; + N_MOVES = VALID_MOVES.length; + N_SYM = 16; + SelfSym = WEdgeSelfSym; + } + int getMoved(int move) { + int val = WEdgeSymMove[idx][move]; + mEdgeFlip[0] = (val & 0x10) == 0 ? 0 : 0x7ff; + return val >> 1 & ~0xf | val & 0xf; + } + }, new RawCoord() { + { + N_IDX = 2048; + } + int getMoved(int move) { + return MEdgeMove[idx][move] ^ mEdgeFlip[0]; + } + int getConj(int idx, int conj) { + return MEdgeConj[idx][conj]; + } + }, null, "Phase3MWEdgeSym"); + } + + static class Phase3Node extends Node { + int center; + int mEdge; + int wEdge; + int getPrun() { + return Math.max( + CenterMEdgePrun.getPrun(center, mEdge), + WMEdgeSymPrun.getPrun(wEdge >> 5, MEdgeConj[mEdge][wEdge & 0x1f])); + } + int doMovePrun(Node node0, int move, int maxl) { + Phase3Node node = (Phase3Node) node0; + center = CenterMove[node.center][move]; + mEdge = MEdgeMove[node.mEdge][move]; + wEdge = WEdgeSymMove[node.wEdge >> 5][SymMove[node.wEdge & 0xf][move]] ^ (node.wEdge & 0x10); + wEdge = wEdge & ~0xf | CubieCube.SymMult[wEdge & 0xf][node.wEdge & 0xf]; + return getPrun(); + } + } + + Phase3Search() { + super.VALID_MOVES = VALID_MOVES; + for (int i = 0; i < searchNode.length; i++) { + searchNode[i] = new Phase3Node(); + } + } + + Node[] initFrom(CubieCube cc) { + if (SymMove == null) { + SymMove = CubieCube.getSymMove(VALID_MOVES, 16); + } + Phase3Center ct = new Phase3Center(); + Phase3Edge ed = new Phase3Edge(); + for (int i = 0; i < 8; i++) { + ct.xCenter[i] = cc.xCenter[16 + (i & 4) + (i + 1) % 4] == 1 ? 0 : -1; + ct.tCenter[i] = cc.tCenter[16 + (i & 4) + (i + 1) % 4] == 1 ? 0 : -1; + } + int center = ct.getCenter(); + java.util.ArrayList nodes = new java.util.ArrayList(); + for (int filter = 8; nodes.size() == 0; filter++) { + for (int idx = 0; idx < 1024; idx++) { + Phase3Node node = new Phase3Node(); + int flip = idx << 1 | (Integer.bitCount(idx) & 1); + flip = (flip ^ 0xfff) << 12 | flip; + for (int i = 0; i < 12; i++) { + ed.mEdge[i] = cc.mEdge[i] & 1; + ed.mEdge[i] ^= flip >> (cc.mEdge[i] >> 1) & 1; + } + for (int i = 0; i < 24; i++) { + ed.wEdge[i] = (flip >> cc.wEdge[i] & 1) == 0 ? 0 : -1; + } + node.mEdge = ed.getMEdge(); + node.wEdge = WEdgeRaw2Sym[ed.getWEdge()]; + node.center = center; + if (node.getPrun() > filter) { + continue; + } + nodes.add(node); + } + } + return nodes.toArray(new Node[0]); + } + + public static void main(String[] args) { + initMEdgeMove(); + initCenterMove(); + initWEdgeSymMove(); + initPrun(); + } +} \ No newline at end of file diff --git a/cube555/src/main/java/cs/cube555/Phase4Center.java b/cube555/src/main/java/cs/cube555/Phase4Center.java new file mode 100644 index 00000000..4e2482ab --- /dev/null +++ b/cube555/src/main/java/cs/cube555/Phase4Center.java @@ -0,0 +1,197 @@ +package cs.cube555; + +import static cs.cube555.Util.*; +import static cs.cube555.Phase4Search.VALID_MOVES; + +/* + 0 0 1 + 3 1 + 3 2 2 + +7 7 4 3 3 0 +6 4 2 0 +6 5 5 2 1 1 + + 4 4 5 + 7 5 + 7 6 6 +*/ + +class Phase4Center { + + int[] udtCenter = new int[8]; + int[] udxCenter = new int[8]; + int[] rltCenter = new int[8]; + int[] rlxCenter = new int[8]; + + Phase4Center() { + } + + public String toString() { + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < 8; i++) { + sb.append(udtCenter[i]).append(' '); + } + sb.append('|'); + for (int i = 0; i < 8; i++) { + sb.append(udxCenter[i]).append(' '); + } + sb.append('|'); + for (int i = 0; i < 8; i++) { + sb.append(rltCenter[i]).append(' '); + } + sb.append('|'); + for (int i = 0; i < 8; i++) { + sb.append(rlxCenter[i]).append(' '); + } + return sb.toString(); + } + + void setUDCenter(int idx) { + setComb(udxCenter, idx / 70, 4); + setComb(udtCenter, idx % 70, 4); + } + + int getUDCenter() { + return getComb(udxCenter, 4) * 70 + getComb(udtCenter, 4); + } + + void setRLCenter(int idx) { + setComb(rlxCenter, idx / 70, 4); + setComb(rltCenter, idx % 70, 4); + } + + int getRLCenter() { + if (rlxCenter[7] != -1) { + for (int i = 0; i < 8; i++) { + rlxCenter[i] = -1 - rlxCenter[i]; + } + for (int i = 0; i < 4; i++) { + rltCenter[i << 1 | 1] = -1 - rltCenter[i << 1 | 1]; + } + } + return getComb(rlxCenter, 4) * 70 + getComb(rltCenter, 4); + } + + void doMove(int move) { + move = VALID_MOVES[move]; + int pow = move % 3; + switch (move) { + case ux2: + swap(rltCenter, 3, 7); + swap(rlxCenter, 3, 7); + swap(rlxCenter, 0, 4); + case Ux1: + case Ux2: + case Ux3: + swap(udtCenter, 0, 1, 2, 3, pow); + swap(udxCenter, 0, 1, 2, 3, pow); + break; + case rx2: + swap(udtCenter, 1, 5); + swap(udxCenter, 1, 5); + swap(udxCenter, 2, 6); + case Rx2: + swap(rltCenter, 0, 1, 2, 3, pow); + swap(rlxCenter, 0, 1, 2, 3, pow); + break; + case fx2: + swap(udtCenter, 2, 4); + swap(udxCenter, 2, 4); + swap(udxCenter, 3, 5); + swap(rltCenter, 2, 4); + swap(rlxCenter, 2, 4); + swap(rlxCenter, 3, 5); + case Fx2: + break; + case dx2: + swap(rltCenter, 1, 5); + swap(rlxCenter, 1, 5); + swap(rlxCenter, 2, 6); + case Dx1: + case Dx2: + case Dx3: + swap(udtCenter, 4, 5, 6, 7, pow); + swap(udxCenter, 4, 5, 6, 7, pow); + break; + case lx2: + swap(udtCenter, 3, 7); + swap(udxCenter, 3, 7); + swap(udxCenter, 0, 4); + case Lx2: + swap(rltCenter, 4, 5, 6, 7, pow); + swap(rlxCenter, 4, 5, 6, 7, pow); + break; + case bx2: + swap(udtCenter, 0, 6); + swap(udxCenter, 0, 6); + swap(udxCenter, 1, 7); + swap(rltCenter, 0, 6); + swap(rlxCenter, 0, 6); + swap(rlxCenter, 1, 7); + case Bx2: + break; + } + } + + void doConj(int conj) { + switch (conj) { + case 0: //x2 + swap(udtCenter, 0, 4); + swap(udtCenter, 1, 5); + swap(udtCenter, 2, 6); + swap(udtCenter, 3, 7); + swap(udxCenter, 0, 4); + swap(udxCenter, 1, 5); + swap(udxCenter, 2, 6); + swap(udxCenter, 3, 7); + swap(rltCenter, 0, 1, 2, 3, 1); + swap(rltCenter, 4, 5, 6, 7, 1); + swap(rlxCenter, 0, 1, 2, 3, 1); + swap(rlxCenter, 4, 5, 6, 7, 1); + for (int i = 0; i < 8; i++) { + udtCenter[i] = -1 - udtCenter[i]; + udxCenter[i] = -1 - udxCenter[i]; + } + break; + case 1: //y2 + swap(rltCenter, 0, 4); + swap(rltCenter, 1, 5); + swap(rltCenter, 2, 6); + swap(rltCenter, 3, 7); + swap(rlxCenter, 0, 4); + swap(rlxCenter, 1, 5); + swap(rlxCenter, 2, 6); + swap(rlxCenter, 3, 7); + swap(udtCenter, 0, 1, 2, 3, 1); + swap(udxCenter, 0, 1, 2, 3, 1); + swap(udtCenter, 4, 5, 6, 7, 1); + swap(udxCenter, 4, 5, 6, 7, 1); + for (int i = 0; i < 8; i++) { + rltCenter[i] = -1 - rltCenter[i]; + rlxCenter[i] = -1 - rlxCenter[i]; + } + break; + case 2: //lr mirror + swap(udtCenter, 1, 3); + swap(udtCenter, 5, 7); + swap(udxCenter, 0, 1); + swap(udxCenter, 2, 3); + swap(udxCenter, 4, 5); + swap(udxCenter, 6, 7); + swap(rltCenter, 0, 6); + swap(rltCenter, 1, 5); + swap(rltCenter, 2, 4); + swap(rltCenter, 3, 7); + swap(rlxCenter, 0, 7); + swap(rlxCenter, 1, 6); + swap(rlxCenter, 2, 5); + swap(rlxCenter, 3, 4); + for (int i = 0; i < 8; i++) { + rltCenter[i] = -1 - rltCenter[i]; + rlxCenter[i] = -1 - rlxCenter[i]; + } + break; + } + } +} \ No newline at end of file diff --git a/cube555/src/main/java/cs/cube555/Phase4Edge.java b/cube555/src/main/java/cs/cube555/Phase4Edge.java new file mode 100644 index 00000000..64483515 --- /dev/null +++ b/cube555/src/main/java/cs/cube555/Phase4Edge.java @@ -0,0 +1,200 @@ +package cs.cube555; + +import static cs.cube555.Util.*; +import static cs.cube555.Phase4Search.VALID_MOVES; + +/* + 13 1 +4 17 +16 5 + 0 12 + 0 12 +* * +* * + 15 3 + 15 3 +7 18 +19 6 + 2 14 + */ + +class Phase4Edge { + + int[] mEdge = new int[8]; + int[] lEdge = new int[8]; // 0 ~ 7 + int[] hEdge = new int[8]; // 12 ~ 19 + boolean isStd = true; + + Phase4Edge() { + for (int i = 0; i < 4; i++) { + mEdge[i] = -1; + hEdge[i] = -1; + lEdge[i] = -1; + mEdge[i + 4] = i; + hEdge[i + 4] = i; + lEdge[i + 4] = i; + } + } + + private void setEdge(int[] arr, int idx) { + standardlize(); + Util.setComb(arr, 69 - idx / 24, 4); + int[] tmp = new int[] {0, 1, 2, 3}; + setPerm(tmp, idx % 24); + copyToComb(tmp, arr); + } + + private int getEdge(int[] arr) { + standardlize(); + int comb = 69 - Util.getComb(arr, 4); + int[] tmp = new int[4]; + copyFromComb(arr, tmp); + return comb * 24 + getPerm(tmp); + } + + void setLEdge(int idx) { + setEdge(lEdge, idx); + } + + int getLEdge() { + return getEdge(lEdge); + } + + void setHEdge(int idx) { + setEdge(hEdge, idx); + } + + int getHEdge() { + return getEdge(hEdge); + } + + void setMEdge(int idx) { + setEdge(mEdge, idx * 24); + } + + int getMEdge() { + return getEdge(mEdge) / 24; + } + + void standardlize() { + if (isStd) { + return; + } + int[] mEdge = new int[4]; + int[] lEdge = new int[4]; + int[] hEdge = new int[4]; + copyFromComb(this.mEdge, mEdge); + copyFromComb(this.lEdge, lEdge); + copyFromComb(this.hEdge, hEdge); + int[] mEdgeInv = new int[4]; + for (int i = 0; i < 4; i++) { + mEdgeInv[mEdge[i]] = i; + } + for (int i = 0; i < 4; i++) { + mEdge[i] = i; + lEdge[i] = mEdgeInv[lEdge[i]]; + hEdge[i] = mEdgeInv[hEdge[i]]; + } + copyToComb(mEdge, this.mEdge); + copyToComb(lEdge, this.lEdge); + copyToComb(hEdge, this.hEdge); + isStd = true; + } + + void doMove(int move) { + move = VALID_MOVES[move]; + int pow = move % 3; + isStd = false; + switch (move) { + case ux2: + case Ux1: + case Ux2: + case Ux3: + swap(mEdge, 0, 4, 1, 5, pow); + swap(lEdge, 0, 4, 1, 5, pow); + swap(hEdge, 0, 4, 1, 5, pow); + break; + case rx2: + swap(lEdge, 1, 3); + swap(hEdge, 0, 2); + case Rx2: + swap(mEdge, 5, 6); + swap(lEdge, 5, 6); + swap(hEdge, 5, 6); + break; + case fx2: + swap(lEdge, 5, 7); + swap(hEdge, 4, 6); + case Fx2: + swap(mEdge, 0, 3); + swap(lEdge, 0, 3); + swap(hEdge, 0, 3); + break; + case dx2: + case Dx1: + case Dx2: + case Dx3: + swap(mEdge, 2, 7, 3, 6, pow); + swap(lEdge, 2, 7, 3, 6, pow); + swap(hEdge, 2, 7, 3, 6, pow); + break; + case lx2: + swap(lEdge, 0, 2); + swap(hEdge, 1, 3); + case Lx2: + swap(mEdge, 4, 7); + swap(lEdge, 4, 7); + swap(hEdge, 4, 7); + break; + case bx2: + swap(lEdge, 4, 6); + swap(hEdge, 5, 7); + case Bx2: + swap(mEdge, 1, 2); + swap(lEdge, 1, 2); + swap(hEdge, 1, 2); + break; + } + } + + void doConj(int conj) { + isStd = false; + switch (conj) { + case 0: //x2 + swap(mEdge, 0, 2); + swap(lEdge, 0, 2); + swap(hEdge, 0, 2); + swap(mEdge, 1, 3); + swap(lEdge, 1, 3); + swap(hEdge, 1, 3); + swap(mEdge, 4, 7); + swap(hEdge, 4, 7); + swap(lEdge, 4, 7); + swap(mEdge, 5, 6); + swap(hEdge, 5, 6); + swap(lEdge, 5, 6); + break; + case 1: //y2 + swap(mEdge, 0, 4, 1, 5, 1); + swap(mEdge, 2, 7, 3, 6, 1); + swap(lEdge, 0, 4, 1, 5, 1); + swap(lEdge, 2, 7, 3, 6, 1); + swap(hEdge, 0, 4, 1, 5, 1); + swap(hEdge, 2, 7, 3, 6, 1); + break; + case 2: //lr mirror + for (int i = 0; i < 8; i++) { + int tmp = lEdge[i]; + lEdge[i] = hEdge[i]; + hEdge[i] = tmp; + } + swap(mEdge, 4, 5); + swap(lEdge, 4, 5); + swap(hEdge, 4, 5); + swap(mEdge, 6, 7); + swap(lEdge, 6, 7); + swap(hEdge, 6, 7); + break; + } + } +} \ No newline at end of file diff --git a/cube555/src/main/java/cs/cube555/Phase4Search.java b/cube555/src/main/java/cs/cube555/Phase4Search.java new file mode 100644 index 00000000..ed083c31 --- /dev/null +++ b/cube555/src/main/java/cs/cube555/Phase4Search.java @@ -0,0 +1,329 @@ +package cs.cube555; + +import static cs.cube555.Util.*; + +class Phase4Search extends PhaseSearch { + static int[] VALID_MOVES = new int[] { + Ux1, Ux2, Ux3, Rx2, Fx2, Dx1, Dx2, Dx3, Lx2, Bx2, + ux2, rx2, fx2, dx2, lx2, bx2 + }; + + static long[] SKIP_MOVES = genSkipMoves(VALID_MOVES); + + static int[][] MEdgeMove = new int[70][VALID_MOVES.length]; + static int[][] HEdgeMove = new int[70 * 1680][VALID_MOVES.length]; + static int[][] LEdgeMove = new int[70 * 1680][VALID_MOVES.length]; + static int[][] HEdgeConj = new int[70 * 1680][4]; + static int[] RLCenter2Half; + static int[] Half2RLCenter; + static int[][] UDCenterMove; + static int[][] UDCenterConj; + static int[][] RLCenterMove; + static int[][] RLCenterConj; + static int[][] MLEdgeSymMove; + static int[] MLEdgeSym2RawF; + static int[] MLEdgeSelfSym; + static int[] MLEdgeRaw2Sym; + static int[] MLEdgeMirror; + static PruningTable EdgePrunSym; + static PruningTable CenterPrun; + static PruningTable MLEdgeSymUDCenterPrun; + static PruningTable MLEdgeSymRLCenterPrun; + + static void init() { + initCenterMove(); + initEdgeMove(); + initMLEdgeSymMove(); + initPrun(); + } + + static void initEdgeMove() { + Phase4Edge edge = new Phase4Edge(); + for (int mEdge = 0; mEdge < 70; mEdge++) { + for (int i = 0; i < 1680; i++) { + for (int m = 0; m < VALID_MOVES.length; m++) { + edge.setMEdge(mEdge); + edge.setHEdge(i); + edge.setLEdge(i); + edge.doMove(m); + MEdgeMove[mEdge][m] = edge.getMEdge(); + HEdgeMove[mEdge * 1680 + i][m] = edge.getHEdge(); + LEdgeMove[mEdge * 1680 + i][m] = edge.getLEdge(); + } + + edge.setMEdge(mEdge); + edge.setHEdge(i); + for (int sym = 0; sym < 4; sym++) { + HEdgeConj[mEdge * 1680 + i][sym] = edge.getHEdge(); + edge.doConj(0); + if ((sym & 1) == 1) { + edge.doConj(1); + } + } + } + } + } + + static void initMLEdgeSymMove() { + Phase4Edge edge = new Phase4Edge(); + + MLEdgeMirror = new int[70 * 1680]; + for (int i = 0; i < MLEdgeMirror.length; i++) { + edge.setMEdge(i % 70); + edge.setLEdge(i / 70); + edge.doConj(2); + MLEdgeMirror[i] = edge.getHEdge() * 70 + edge.getMEdge(); + } + + int symCnt = 0; + MLEdgeSym2RawF = new int[29616 * 4]; + MLEdgeSelfSym = new int[29616]; + MLEdgeRaw2Sym = new int[70 * 1680]; + for (int i = 0; i < MLEdgeRaw2Sym.length; i++) { + if (MLEdgeRaw2Sym[i] != 0) { + continue; + } + edge.setMEdge(i % 70); + edge.setLEdge(i / 70); + for (int sym = 0; sym < 4; sym++) { + int idx = edge.getLEdge() * 70 + edge.getMEdge(); + MLEdgeRaw2Sym[idx] = symCnt << 2 | sym; + MLEdgeSym2RawF[symCnt << 2 | sym] = idx; + if (idx == i) { + MLEdgeSelfSym[symCnt] |= 1 << sym; + } + edge.doConj(0); + if ((sym & 1) == 1) { + edge.doConj(1); + } + } + symCnt++; + } + MLEdgeSymMove = new int[symCnt][VALID_MOVES.length]; + for (int i = 0; i < symCnt; i++) { + for (int m = 0; m < VALID_MOVES.length; m++) { + edge.setMEdge(MLEdgeSym2RawF[i << 2] % 70); + edge.setLEdge(MLEdgeSym2RawF[i << 2] / 70); + edge.doMove(m); + MLEdgeSymMove[i][m] = MLEdgeRaw2Sym[edge.getLEdge() * 70 + edge.getMEdge()]; + } + } + + final int[] mEdge = new int[2]; + EdgePrunSym = new PruningTable(new SymCoord() { + { + N_IDX = 29616; + N_MOVES = VALID_MOVES.length; + N_SYM = 4; + SelfSym = MLEdgeSelfSym; + } + @Override + void set(int idx) { + this.idx = idx; + mEdge[0] = MLEdgeSym2RawF[idx << 2] % 70; + } + int getMoved(int move) { + mEdge[1] = MLEdgeSym2RawF[MLEdgeSymMove[idx][move]] % 70; + return MLEdgeSymMove[idx][move]; + } + }, new RawCoord() { + { + N_IDX = 1680; + } + @Override + int getMoved(int move) { + return Phase4Search.HEdgeMove[mEdge[0] * 1680 + idx][move]; + } + @Override + int getConj(int idx, int conj) { + return Phase4Search.HEdgeConj[mEdge[1] * 1680 + idx][conj]; + } + }, null, "Phase4EdgeSym"); + } + + static void initCenterMove() { + Phase4Center center = new Phase4Center(); + RLCenter2Half = new int[2450]; + Half2RLCenter = new int[216]; + for (int i = 0; i < RLCenter2Half.length; i++) { + RLCenter2Half[i] = -1; + } + int tail = 0; + Half2RLCenter[0] = 0; + RLCenter2Half[0] = tail++; + while (tail < 216) { + for (int i = 0; i < RLCenter2Half.length; i++) { + if (RLCenter2Half[i] == -1) { + continue; + } + for (int m = 10; m < VALID_MOVES.length; m++) { + center.setRLCenter(i); + center.doMove(m); + int idx = center.getRLCenter(); + if (RLCenter2Half[idx] == -1) { + Half2RLCenter[tail] = idx; + RLCenter2Half[idx] = tail++; + } + } + } + } + UDCenterMove = new int[4900][VALID_MOVES.length]; + RLCenterMove = new int[216][VALID_MOVES.length]; + UDCenterConj = new int[4900][8]; + RLCenterConj = new int[216][8]; + for (int i = 0; i < 4900; i++) { + for (int m = 0; m < VALID_MOVES.length; m++) { + center.setUDCenter(i); + center.doMove(m); + UDCenterMove[i][m] = center.getUDCenter(); + } + center.setUDCenter(i); + for (int sym = 0; sym < 8; sym++) { + UDCenterConj[i][sym] = center.getUDCenter(); + center.doConj(0); + if ((sym & 1) == 1) { + center.doConj(1); + } + if ((sym & 3) == 3) { + center.doConj(2); + } + } + } + for (int i = 0; i < 216; i++) { + for (int m = 0; m < VALID_MOVES.length; m++) { + center.setRLCenter(Half2RLCenter[i]); + center.doMove(m); + RLCenterMove[i][m] = RLCenter2Half[center.getRLCenter()]; + } + center.setRLCenter(Half2RLCenter[i]); + for (int sym = 0; sym < 8; sym++) { + RLCenterConj[i][sym] = RLCenter2Half[center.getRLCenter()]; + center.doConj(0); + if ((sym & 1) == 1) { + center.doConj(1); + } + if ((sym & 3) == 3) { + center.doConj(2); + } + } + } + } + + static void initPrun() { + int[] UDSOLVED = new int[] {0, 1895, 1967, 2905, 2977, 4876}; + int[] RLSOLVED = new int[UDSOLVED.length / 2]; + for (int i = 0; i < UDSOLVED.length / 2; i++) { + RLSOLVED[i] = RLCenter2Half[UDSOLVED[i]]; + } + SymCoord MLEdgeSymCoord = new TableSymCoord(MLEdgeSymMove, MLEdgeSelfSym, 4); + CenterPrun = new PruningTable(RLCenterMove, UDCenterMove, RLSOLVED, UDSOLVED, "Phase4Center"); + MLEdgeSymUDCenterPrun = new PruningTable(MLEdgeSymCoord, new TableRawCoord(UDCenterMove, UDCenterConj), packSolved(null, UDSOLVED), "Phase4MLEdgeSymUDCenter"); + MLEdgeSymRLCenterPrun = new PruningTable(MLEdgeSymCoord, new TableRawCoord(RLCenterMove, RLCenterConj), packSolved(null, RLSOLVED), "Phase4MLEdgeSymRLCenter"); + } + + static class Phase4Node extends Node { + int rlCenter; + int udCenter; + int mEdge; + int lEdge; + int hEdge; + int getPrun() { + int mlEdges = MLEdgeRaw2Sym[lEdge * 70 + mEdge]; + int mhEdges = MLEdgeRaw2Sym[MLEdgeMirror[hEdge * 70 + mEdge]]; + int prun = CenterPrun.getPrun(rlCenter, udCenter); + prun = Math.max(prun, + EdgePrunSym.getPrun(mlEdges >> 2, HEdgeConj[mEdge * 1680 + hEdge][mlEdges & 0x3])); + prun = Math.max(prun, + MLEdgeSymRLCenterPrun.getPrun(mlEdges >> 2, RLCenterConj[rlCenter][mlEdges & 3])); + prun = Math.max(prun, + MLEdgeSymRLCenterPrun.getPrun(mhEdges >> 2, RLCenterConj[rlCenter][mhEdges & 3 | 4])); + prun = Math.max(prun, + MLEdgeSymUDCenterPrun.getPrun(mlEdges >> 2, UDCenterConj[udCenter][mlEdges & 3])); + return Math.max(prun, + MLEdgeSymUDCenterPrun.getPrun(mhEdges >> 2, UDCenterConj[udCenter][mhEdges & 3 | 4])); + } + int doMovePrun(Node node0, int move, int maxl) { + Phase4Node node = (Phase4Node) node0; + rlCenter = RLCenterMove[node.rlCenter][move]; + udCenter = UDCenterMove[node.udCenter][move]; + mEdge = MEdgeMove[node.mEdge][move]; + lEdge = LEdgeMove[node.mEdge * 1680 + node.lEdge][move]; + hEdge = HEdgeMove[node.mEdge * 1680 + node.hEdge][move]; + int mlEdges = MLEdgeRaw2Sym[lEdge * 70 + mEdge]; + int mhEdges = MLEdgeRaw2Sym[MLEdgeMirror[hEdge * 70 + mEdge]]; + + if (maxl <= EdgePrunSym.getPrun(mlEdges >> 2, HEdgeConj[mEdge * 1680 + hEdge][mlEdges & 0x3])) { + return maxl; + } else if (maxl <= MLEdgeSymRLCenterPrun.getPrun(mlEdges >> 2, RLCenterConj[rlCenter][mlEdges & 3])) { + return maxl; + } else if (maxl <= MLEdgeSymRLCenterPrun.getPrun(mhEdges >> 2, RLCenterConj[rlCenter][mhEdges & 3 | 4])) { + return maxl; + } else if (maxl <= MLEdgeSymUDCenterPrun.getPrun(mlEdges >> 2, UDCenterConj[udCenter][mlEdges & 3])) { + return maxl; + } else if (maxl <= MLEdgeSymUDCenterPrun.getPrun(mhEdges >> 2, UDCenterConj[udCenter][mhEdges & 3 | 4])) { + return maxl; + } else if (maxl <= CenterPrun.getPrun(rlCenter, udCenter)) { + return maxl; + } + return maxl - 1; + } + } + + Phase4Search() { + super.VALID_MOVES = VALID_MOVES; + for (int i = 0; i < searchNode.length; i++) { + searchNode[i] = new Phase4Node(); + } + } + + Node[] initFrom(CubieCube cc) { + Phase4Edge edge = new Phase4Edge(); + Phase4Center center = new Phase4Center(); + + for (int i = 0; i < 8; i++) { + center.udxCenter[i] = cc.xCenter[i] == 0 ? 0 : -1; + center.udtCenter[i] = cc.tCenter[i] == 0 ? 0 : -1; + center.rlxCenter[i] = cc.xCenter[16 + (i & 4) + (i + 1) % 4] == 1 ? 0 : -1; + center.rltCenter[i] = cc.tCenter[16 + (i & 4) + (i + 1) % 4] == 1 ? 0 : -1; + } + int rlCenter = RLCenter2Half[center.getRLCenter()]; + int udCenter = center.getUDCenter(); + + int maskY = 0; + for (int i = 0; i < 4; i++) { + maskY |= 1 << (cc.wEdge[8 + i] % 12); + maskY |= 1 << (cc.wEdge[8 + i + 12] % 12); + maskY |= 1 << (cc.mEdge[8 + i] >> 1); + } + maskY ^= 0xfff; + int bitCnt = Integer.bitCount(maskY); + + Node[] nodes = new Node[Cnk[bitCnt][4]]; + // System.out.println(nodes.length); + int idx = 0; + for (int mask = maskY; mask != 0; mask = mask - 1 & maskY) { + if (Integer.bitCount(mask) != 4) { + continue; + } + for (int i = 0; i < 8; i++) { + int e = cc.mEdge[i] >> 1; + edge.mEdge[i] = (mask >> e & 1) == 0 ? -1 : Integer.bitCount(mask & ((1 << e) - 1)); + e = cc.wEdge[i] % 12; + edge.lEdge[i] = (mask >> e & 1) == 0 ? -1 : Integer.bitCount(mask & ((1 << e) - 1)); + e = cc.wEdge[i + 12] % 12; + edge.hEdge[i] = (mask >> e & 1) == 0 ? -1 : Integer.bitCount(mask & ((1 << e) - 1)); + } + edge.isStd = false; + Phase4Node node = new Phase4Node(); + node.mEdge = edge.getMEdge(); + node.lEdge = edge.getLEdge(); + node.hEdge = edge.getHEdge(); + node.rlCenter = rlCenter; + node.udCenter = udCenter; + nodes[idx] = node; + idx++; + } + + return nodes; + } +} \ No newline at end of file diff --git a/cube555/src/main/java/cs/cube555/Phase5Center.java b/cube555/src/main/java/cs/cube555/Phase5Center.java new file mode 100644 index 00000000..aaba54e9 --- /dev/null +++ b/cube555/src/main/java/cs/cube555/Phase5Center.java @@ -0,0 +1,168 @@ +package cs.cube555; + +import static cs.cube555.Util.*; +import static cs.cube555.Phase5Search.VALID_MOVES; + +/* + 0 0 1 + 3 1 + 3 2 2 + +7 6 1 0 5 4 3 2 + + 4 4 5 + 7 5 + 7 6 6 +*/ + +class Phase5Center { + int[] tCenter = new int[8]; + int[] xCenter = new int[8]; + int[] rflbCenter = new int[8]; + + Phase5Center() { + setRFLBCenter(0); + setXCenter(0); + setTCenter(0); + } + + void setRFLBCenter(int idx) { + int[] fbCenter = new int[4]; + int[] rlCenter = new int[4]; + setComb(fbCenter, idx % 6, 2); + setComb(rlCenter, idx / 6, 2); + for (int i = 0; i < 4; i++) { + rflbCenter[i] = fbCenter[i]; + rflbCenter[i + 4] = rlCenter[i]; + } + } + + int getRFLBCenter() { + int[] fbCenter = new int[4]; + int[] rlCenter = new int[4]; + for (int i = 0; i < 4; i++) { + fbCenter[i] = rflbCenter[i]; + rlCenter[i] = rflbCenter[i + 4]; + } + return getComb(rlCenter, 2) * 6 + getComb(fbCenter, 2); + } + + void setXCenter(int idx) { + setComb(xCenter, idx, 4); + } + + int getXCenter() { + return getComb(xCenter, 4); + } + + void setTCenter(int idx) { + setComb(tCenter, idx, 4); + } + + int getTCenter() { + return getComb(tCenter, 4); + } + + void doMove(int move) { + move = VALID_MOVES[move]; + int pow = move % 3; + switch (move) { + case Ux1: + case Ux2: + case Ux3: + swap(tCenter, 0, 1, 2, 3, pow); + swap(xCenter, 0, 1, 2, 3, pow); + break; + case rx2: + swap(tCenter, 1, 5); + swap(xCenter, 1, 5); + swap(xCenter, 2, 6); + swap(rflbCenter, 0, 3); + case Rx2: + swap(rflbCenter, 4, 5); + break; + case fx2: + swap(tCenter, 2, 4); + swap(xCenter, 2, 4); + swap(xCenter, 3, 5); + swap(rflbCenter, 5, 6); + case Fx2: + swap(rflbCenter, 0, 1); + break; + case Dx1: + case Dx2: + case Dx3: + swap(tCenter, 4, 5, 6, 7, pow); + swap(xCenter, 4, 5, 6, 7, pow); + break; + case lx2: + swap(tCenter, 3, 7); + swap(xCenter, 3, 7); + swap(xCenter, 0, 4); + swap(rflbCenter, 1, 2); + case Lx2: + swap(rflbCenter, 6, 7); + break; + case bx2: + swap(tCenter, 0, 6); + swap(xCenter, 0, 6); + swap(xCenter, 1, 7); + swap(rflbCenter, 4, 7); + case Bx2: + swap(rflbCenter, 2, 3); + break; + } + } + + void doConj(int conj) { + switch (conj) { + case 0: //y + swap(tCenter, 0, 1, 2, 3, 0); + swap(xCenter, 0, 1, 2, 3, 0); + swap(tCenter, 4, 5, 6, 7, 2); + swap(xCenter, 4, 5, 6, 7, 2); + for (int i = 0; i < 4; i++) { + rflbCenter[i] = -1 - rflbCenter[i]; + } + swap(rflbCenter, 1, 7, 3, 5, 0); + swap(rflbCenter, 0, 6, 2, 4, 0); + break; + case 1: //x2 + swap(tCenter, 0, 4); + swap(tCenter, 1, 5); + swap(tCenter, 2, 6); + swap(tCenter, 3, 7); + swap(xCenter, 0, 4); + swap(xCenter, 1, 5); + swap(xCenter, 2, 6); + swap(xCenter, 3, 7); + swap(rflbCenter, 0, 3); + swap(rflbCenter, 4, 5); + swap(rflbCenter, 1, 2); + swap(rflbCenter, 6, 7); + for (int i = 0; i < 8; i++) { + tCenter[i] = -1 - tCenter[i]; + xCenter[i] = -1 - xCenter[i]; + } + for (int i = 0; i < 4; i++) { + rflbCenter[i] = -1 - rflbCenter[i]; + } + break; + case 2: //lr mirror + swap(tCenter, 1, 3); + swap(tCenter, 5, 7); + swap(xCenter, 0, 1); + swap(xCenter, 2, 3); + swap(xCenter, 4, 5); + swap(xCenter, 6, 7); + swap(rflbCenter, 0, 1); + swap(rflbCenter, 2, 3); + swap(rflbCenter, 4, 7); + swap(rflbCenter, 5, 6); + for (int i = 4; i < 8; i++) { + rflbCenter[i] = -1 - rflbCenter[i]; + } + break; + } + } +} \ No newline at end of file diff --git a/cube555/src/main/java/cs/cube555/Phase5Edge.java b/cube555/src/main/java/cs/cube555/Phase5Edge.java new file mode 100644 index 00000000..9706d63b --- /dev/null +++ b/cube555/src/main/java/cs/cube555/Phase5Edge.java @@ -0,0 +1,164 @@ +package cs.cube555; + +import static cs.cube555.Util.*; +import static cs.cube555.Phase5Search.VALID_MOVES; + +/* + 13 1 + 4 17 + 16 5 + 0 12 + + 15 3 + 7 18 + 19 6 + 2 14 + */ + +class Phase5Edge { + + int[] mEdge = new int[8]; + int[] lEdge = new int[8]; // 0 ~ 7 + int[] hEdge = new int[8]; // 12 ~ 19 + boolean isStd = true; + + Phase5Edge() { + for (int i = 0; i < 8; i++) { + mEdge[i] = i; + hEdge[i] = i; + lEdge[i] = i; + } + } + + void setLEdge(int idx) { + standardlize(); + setPerm(lEdge, idx); + } + + void setHEdge(int idx) { + standardlize(); + setPerm(hEdge, idx); + } + + int getLEdge() { + standardlize(); + return getPerm(lEdge); + } + + int getHEdge() { + standardlize(); + return getPerm(hEdge); + } + + void standardlize() { + if (isStd) { + return; + } + int[] mEdgeInv = new int[8]; + for (int i = 0; i < 8; i++) { + mEdgeInv[mEdge[i]] = i; + } + + for (int i = 0; i < 8; i++) { + mEdge[i] = i; + lEdge[i] = mEdgeInv[lEdge[i]]; + hEdge[i] = mEdgeInv[hEdge[i]]; + } + isStd = true; + } + + void doMove(int move) { + move = VALID_MOVES[move]; + int pow = move % 3; + isStd = false; + switch (move) { + case Ux1: + case Ux2: + case Ux3: + swap(mEdge, 0, 4, 1, 5, pow); + swap(lEdge, 0, 4, 1, 5, pow); + swap(hEdge, 0, 4, 1, 5, pow); + break; + case rx2: + swap(lEdge, 1, 3); + swap(hEdge, 0, 2); + case Rx2: + swap(mEdge, 5, 6); + swap(lEdge, 5, 6); + swap(hEdge, 5, 6); + break; + case fx2: + swap(lEdge, 5, 7); + swap(hEdge, 4, 6); + case Fx2: + swap(mEdge, 0, 3); + swap(lEdge, 0, 3); + swap(hEdge, 0, 3); + break; + case Dx1: + case Dx2: + case Dx3: + swap(mEdge, 2, 7, 3, 6, pow); + swap(lEdge, 2, 7, 3, 6, pow); + swap(hEdge, 2, 7, 3, 6, pow); + break; + case lx2: + swap(lEdge, 0, 2); + swap(hEdge, 1, 3); + case Lx2: + swap(mEdge, 4, 7); + swap(lEdge, 4, 7); + swap(hEdge, 4, 7); + break; + case bx2: + swap(lEdge, 4, 6); + swap(hEdge, 5, 7); + case Bx2: + swap(mEdge, 1, 2); + swap(lEdge, 1, 2); + swap(hEdge, 1, 2); + break; + } + } + + void doConj(int conj) { + isStd = false; + switch (conj) { + case 0: //y + swap(mEdge, 0, 4, 1, 5, 0); + swap(lEdge, 0, 4, 1, 5, 0); + swap(hEdge, 0, 4, 1, 5, 0); + swap(mEdge, 2, 7, 3, 6, 2); + swap(lEdge, 2, 7, 3, 6, 2); + swap(hEdge, 2, 7, 3, 6, 2); + break; + case 1: //x2 + swap(mEdge, 0, 2); + swap(lEdge, 0, 2); + swap(hEdge, 0, 2); + swap(mEdge, 1, 3); + swap(lEdge, 1, 3); + swap(hEdge, 1, 3); + swap(mEdge, 4, 7); + swap(hEdge, 4, 7); + swap(lEdge, 4, 7); + swap(mEdge, 5, 6); + swap(hEdge, 5, 6); + swap(lEdge, 5, 6); + break; + case 2: //lr mirror + for (int i = 0; i < 8; i++) { + int tmp = lEdge[i]; + lEdge[i] = hEdge[i]; + hEdge[i] = tmp; + } + swap(mEdge, 4, 5); + swap(lEdge, 4, 5); + swap(hEdge, 4, 5); + swap(mEdge, 6, 7); + swap(lEdge, 6, 7); + swap(hEdge, 6, 7); + break; + } + } +} \ No newline at end of file diff --git a/cube555/src/main/java/cs/cube555/Phase5Search.java b/cube555/src/main/java/cs/cube555/Phase5Search.java new file mode 100644 index 00000000..7ad85112 --- /dev/null +++ b/cube555/src/main/java/cs/cube555/Phase5Search.java @@ -0,0 +1,219 @@ +package cs.cube555; + +import static cs.cube555.Util.*; + +class Phase5Search extends PhaseSearch { + static int[] VALID_MOVES = new int[] { + Ux1, Ux2, Ux3, Rx2, Fx2, Dx1, Dx2, Dx3, Lx2, Bx2, + rx2, fx2, lx2, bx2 + }; + + static long[] SKIP_MOVES = genSkipMoves(VALID_MOVES); + + static int[][] LEdgeMove; + static int[] LEdgeSym2Raw; + static int[] LEdgeSelfSym; + static int[] LEdgeRaw2Sym; + static int[][] LEdgeSymMove; + static int[] LEdgeMirror; + static int[] UDCenterMirror; + static int[][] CenterMove; + static int[][] UDCenterConj; + static PruningTable CenterPrun; + static PruningTable LEdgeSymCenterPrun; + + static void init() { + initLEdgeSymMove(); + initCenterMove(); + initEdgeMove(); + initPrun(); + } + + static void initEdgeMove() { + LEdgeMove = new int[40320][VALID_MOVES.length]; + Phase5Edge edge = new Phase5Edge(); + for (int i = 0; i < 40320; i++) { + for (int m = 0; m < VALID_MOVES.length; m++) { + edge.setLEdge(i); + edge.doMove(m); + LEdgeMove[i][m] = edge.getLEdge(); + } + } + } + + static void initLEdgeSymMove() { + Phase5Edge edge = new Phase5Edge(); + + LEdgeMirror = new int[40320]; + for (int i = 0; i < LEdgeMirror.length; i++) { + edge.setLEdge(i); + edge.doConj(2); + LEdgeMirror[i] = edge.getHEdge(); + } + + int symCnt = 0; + LEdgeSym2Raw = new int[5288 * 8]; + LEdgeSelfSym = new int[5288]; + LEdgeRaw2Sym = new int[40320]; + for (int i = 0; i < LEdgeRaw2Sym.length; i++) { + if (LEdgeRaw2Sym[i] != 0) { + continue; + } + edge.setLEdge(i); + for (int sym = 0; sym < 8; sym++) { + int idx = edge.getLEdge(); + LEdgeRaw2Sym[idx] = symCnt << 3 | sym; + if (idx == i) { + LEdgeSelfSym[symCnt] |= 1 << sym; + } + edge.doConj(0); + if ((sym & 3) == 3) { + edge.doConj(1); + } + } + LEdgeSym2Raw[symCnt] = i; + symCnt++; + } + LEdgeSymMove = new int[symCnt][VALID_MOVES.length]; + for (int i = 0; i < symCnt; i++) { + for (int m = 0; m < VALID_MOVES.length; m++) { + edge.setLEdge(LEdgeSym2Raw[i]); + edge.doMove(m); + LEdgeSymMove[i][m] = LEdgeRaw2Sym[edge.getLEdge()]; + } + } + } + + static void initCenterMove() { + int[][] RFLBMove = new int[36][VALID_MOVES.length]; + int[][] TMove = new int[70][VALID_MOVES.length]; + int[][] XMove = new int[70][VALID_MOVES.length]; + int[][] TConj = new int[70][8]; + int[][] XConj = new int[70][8]; + Phase5Center center = new Phase5Center(); + for (int i = 0; i < 70; i++) { + for (int m = 0; m < VALID_MOVES.length; m++) { + center.setTCenter(i); + center.setXCenter(i); + center.doMove(m); + TMove[i][m] = center.getTCenter(); + XMove[i][m] = center.getXCenter(); + } + center.setTCenter(i); + center.setXCenter(i); + for (int sym = 0; sym < 8; sym++) { + TConj[i][CubieCube.SymMultInv[0][sym]] = center.getTCenter(); + XConj[i][CubieCube.SymMultInv[0][sym]] = center.getXCenter(); + center.doConj(0); + if ((sym & 3) == 3) { + center.doConj(1); + } + } + } + for (int i = 0; i < 36; i++) { + for (int m = 0; m < VALID_MOVES.length; m++) { + center.setRFLBCenter(i); + center.doMove(m); + RFLBMove[i][m] = center.getRFLBCenter(); + } + } + + CenterMove = new int[70 * 70 * 36][VALID_MOVES.length]; + for (int i = 0; i < 70 * 70 * 36; i++) { + int tCenter = i % 70; + int xCenter = i / 70 % 70; + int rflbCenter = i / 70 / 70; + for (int m = 0; m < VALID_MOVES.length; m++) { + CenterMove[i][m] = (RFLBMove[rflbCenter][m] * 70 + XMove[xCenter][m]) * 70 + TMove[tCenter][m]; + } + } + + UDCenterMirror = new int[4900]; + UDCenterConj = new int[70 * 70][8]; + for (int i = 0; i < 4900; i++) { + int tCenter = i % 70; + int xCenter = i / 70 % 70; + center.setTCenter(tCenter); + center.setXCenter(xCenter); + center.doConj(2); + UDCenterMirror[i] = center.getXCenter() * 70 + center.getTCenter(); + for (int s = 0; s < 8; s++) { + UDCenterConj[i][s] = XConj[xCenter][s] * 70 + TConj[tCenter][s]; + } + } + } + + static void initPrun() { + int[][] UDCenterMove = new int[4900][VALID_MOVES.length]; + for (int i = 0; i < 4900; i++) { + for (int j = 0; j < VALID_MOVES.length; j++) { + UDCenterMove[i][j] = CenterMove[i][j] % 4900; + } + } + CenterPrun = new PruningTable(CenterMove, null, "Phase5Center"); + LEdgeSymCenterPrun = new PruningTable( + new TableSymCoord(LEdgeSymMove, LEdgeSelfSym, 8), + new TableRawCoord(UDCenterMove, UDCenterConj), + null, "Phase5LEdgeSymCenter"); + } + + static class Phase5Node extends Node { + int lEdge; + int hEdgem; + int center; + int getPrun() { + int lEdges = LEdgeRaw2Sym[lEdge]; + int hEdges = LEdgeRaw2Sym[hEdgem]; + return Math.max( + CenterPrun.getPrun(center), + Math.max(LEdgeSymCenterPrun.getPrun(lEdges >> 3, UDCenterConj[center % 4900][lEdges & 0x7]), + LEdgeSymCenterPrun.getPrun(hEdges >> 3, UDCenterConj[UDCenterMirror[center % 4900]][hEdges & 0x7])) + ); + } + int doMovePrun(Node node0, int move, int maxl) { + Phase5Node node = (Phase5Node) node0; + center = CenterMove[node.center][move]; + lEdge = LEdgeMove[node.lEdge][move]; + hEdgem = LEdgeMove[node.hEdgem][SymMove[8][move]]; + return getPrun(); + } + } + + static int[][] SymMove; + + Phase5Search() { + super.VALID_MOVES = VALID_MOVES; + for (int i = 0; i < searchNode.length; i++) { + searchNode[i] = new Phase5Node(); + } + } + + Node[] initFrom(CubieCube cc) { + if (SymMove == null) { + SymMove = CubieCube.getSymMove(VALID_MOVES, 16); + } + Phase5Edge edge = new Phase5Edge(); + Phase5Center center = new Phase5Center(); + int mask = 0; + for (int i = 0; i < 8; i++) { + mask |= 1 << (cc.mEdge[i] >> 1); + } + for (int i = 0; i < 8; i++) { + int e = cc.mEdge[i] >> 1; + edge.mEdge[i] = Integer.bitCount(mask & ((1 << e) - 1)); + e = cc.wEdge[i] % 12; + edge.lEdge[i] = Integer.bitCount(mask & ((1 << e) - 1)); + e = cc.wEdge[i + 12] % 12; + edge.hEdge[i] = Integer.bitCount(mask & ((1 << e) - 1)); + center.xCenter[i] = cc.xCenter[i] == 0 ? 0 : -1; + center.tCenter[i] = cc.tCenter[i] == 0 ? 0 : -1; + center.rflbCenter[i] = cc.tCenter[9 + i * 2] == 1 || cc.tCenter[9 + i * 2] == 2 ? 0 : -1; + } + edge.isStd = false; + Phase5Node node = new Phase5Node(); + node.lEdge = edge.getLEdge(); + node.hEdgem = LEdgeMirror[edge.getHEdge()]; + node.center = (center.getRFLBCenter() * 70 + center.getXCenter()) * 70 + center.getTCenter(); + return new Node[] {node}; + } +} \ No newline at end of file diff --git a/cube555/src/main/java/cs/cube555/PhaseSearch.java b/cube555/src/main/java/cs/cube555/PhaseSearch.java new file mode 100755 index 00000000..34cc9761 --- /dev/null +++ b/cube555/src/main/java/cs/cube555/PhaseSearch.java @@ -0,0 +1,121 @@ +package cs.cube555; + +import java.util.ArrayList; +import java.util.TreeSet; +import static cs.cube555.Util.*; + +class PhaseSearch { + SolutionChecker callback = null; + int[] solution = new int[255]; + int ccidx; + + class PhaseEntry implements Comparable { + Node node; + int prun; + int cumCost; + int estCost; + int ccidx; + + @Override public int compareTo(PhaseEntry entry) { + if (this == entry) { + return 0; + } + if (estCost != entry.estCost) { + return estCost - entry.estCost; + } + if (cumCost != entry.cumCost) { + return cumCost - entry.cumCost; + } + return 1; + } + } + + void solve(SolvingCube[] cc, SolutionChecker callback) { + solve(cc, callback, Integer.MAX_VALUE); + } + + void solve(SolvingCube[] cc, SolutionChecker callback, int trySize) { + if (SKIP_MOVES == null) { + SKIP_MOVES = genSkipMoves(VALID_MOVES); + NEXT_AXIS = genNextAxis(VALID_MOVES); + } + this.callback = callback; + long startTime = System.nanoTime(); + + TreeSet entries = new TreeSet(); + for (ccidx = 0; ccidx < cc.length; ccidx++) { + Node[] nodes = initFrom(cc[ccidx]); + int cumCost = cc[ccidx].length(); + for (int i = 0; i < nodes.length; i++) { + PhaseEntry entry = new PhaseEntry(); + entry.node = nodes[i]; + entry.prun = nodes[i].getPrun(); + entry.cumCost = cumCost; + entry.estCost = cumCost + entry.prun; + entry.ccidx = ccidx; + entries.add(entry); + if (entries.size() > trySize) { + entries.pollLast(); + } + } + } + // nodeCnt = 0; + out: for (int maxl = 0; maxl < 100; maxl++) { + for (PhaseEntry entry : entries) { + ccidx = entry.ccidx; + if (maxl >= entry.estCost && + idaSearch(entry.node, 0, maxl - entry.cumCost, VALID_MOVES.length, entry.prun) == 0) { + break out; + } + } + } + // System.out.println(nodeCnt); + } + + Node[] initFrom(CubieCube cc) { + return null; + } + + abstract static class Node { + /** + * other requirements besides getPrun() == 0 + */ + boolean isSolved() { + return true; + } + abstract int doMovePrun(Node node, int move, int maxl); + abstract int getPrun(); + } + + Node[] searchNode = new Node[30]; + // static int nodeCnt = 0; + + private int idaSearch(Node node, int depth, int maxl, int lm, int prun) { + if (prun == 0 && node.isSolved() && maxl < MIN_BACK_DEPTH) { + return maxl != 0 ? 1 : callback.check(solution, depth, ccidx); + } + long skipMoves = SKIP_MOVES[lm]; + for (int move = 0; move < VALID_MOVES.length; move++) { + if ((skipMoves >> move & 1) != 0) { + continue; + } + // nodeCnt++; + prun = searchNode[depth].doMovePrun(node, move, maxl); + if (prun >= maxl) { + move += NEXT_AXIS >> move & 3 & (maxl - prun); + continue; + } + solution[depth] = VALID_MOVES[move]; + int ret = idaSearch(searchNode[depth], depth + 1, maxl - 1, move, prun); + if (ret == 0) { + return 0; + } + } + return 1; + } + + long[] SKIP_MOVES; + int[] VALID_MOVES; + long NEXT_AXIS; + int MIN_BACK_DEPTH = 1; +} \ No newline at end of file diff --git a/cube555/src/main/java/cs/cube555/README.md b/cube555/src/main/java/cs/cube555/README.md new file mode 100644 index 00000000..21cd1d75 --- /dev/null +++ b/cube555/src/main/java/cs/cube555/README.md @@ -0,0 +1,24 @@ +# cube555 + +Five-phase-reduction 5x5x5 solver + +# Benchmark + +Average solution length for reduction: 51 ~ 52 moves + +Average solving time: 1 ~ 2 seconds + +Memory required: <= 500MB + +# Usage + +Demo with a simple GUI + +``` +git clone https://github.com/cs0x7f/cube555.git +cd cube555 +mkdir dist +make run +``` + +At first execution, some pruning tables (about 240MB) are written to disk for cache. diff --git a/cube555/src/main/java/cs/cube555/Search.java b/cube555/src/main/java/cs/cube555/Search.java new file mode 100755 index 00000000..44075c92 --- /dev/null +++ b/cube555/src/main/java/cs/cube555/Search.java @@ -0,0 +1,179 @@ +package cs.cube555; + +import java.util.ArrayList; +import static cs.cube555.Util.*; + +public class Search { + + public static final int USE_SEPARATOR = 0x1; + + static int phase1SolsSize = 200; + static int phase2SolsSize = 500; + static int phase3SolsSize = 500; + static int phase4SolsSize = 500; + static int phase5SolsSize = 1; + + public static class Logger { + final static boolean DEBUG = true; + static long startTime; + static long cumSolLen = 0; + static long[] cumPhaseT = new long[5]; + static void start() { + startTime = System.nanoTime(); + } + static void logTime(int phase) { + cumPhaseT[phase] += System.nanoTime() - startTime; + System.out.println(String.format("Phase%d Finished in %d ms", phase + 1, (System.nanoTime() - startTime) / 1000000)); + startTime = System.nanoTime(); + } + public static void print(int div) { + System.out.println( + String.format( + "AvgLen=%.2f P1T=%4dms P2T=%4dms P3T=%4dms P4T=%4dms P5T=%4dms TOT=%4dms", + cumSolLen * 1.0 / div, + cumPhaseT[0] / div / 1000000, + cumPhaseT[1] / div / 1000000, + cumPhaseT[2] / div / 1000000, + cumPhaseT[3] / div / 1000000, + cumPhaseT[4] / div / 1000000, + (cumPhaseT[0] + cumPhaseT[1] + cumPhaseT[2] + cumPhaseT[3] + cumPhaseT[4]) / div / 1000000 + )); + } + } + + static boolean isInited = false; + + public static synchronized void init() { + if (isInited) { + return; + } + CubieCube.init(); + Phase1Search.init(); + Phase2Search.init(); + Phase3Search.init(); + Phase4Search.init(); + Phase5Search.init(); + isInited = true; + } + + Phase1Search p1search = new Phase1Search(); + Phase2Search p2search = new Phase2Search(); + Phase3Search p3search = new Phase3Search(); + Phase4Search p4search = new Phase4Search(); + Phase5Search p5search = new Phase5Search(); + ArrayList p1sols = new ArrayList(); + ArrayList p2sols = new ArrayList(); + ArrayList p3sols = new ArrayList(); + ArrayList p4sols = new ArrayList(); + ArrayList p5sols = new ArrayList(); + SolvingCube[] p1cc; + SolvingCube[] p2cc; + SolvingCube[] p3cc; + SolvingCube[] p4cc; + SolvingCube[] p5cc; + + public synchronized String[] solveReduction(String facelet, int verbose) { + CubieCube cc = new CubieCube(); + int verifyReduction = cc.fromFacelet(facelet); + if (verifyReduction != 0) { + System.out.println(verifyReduction); + return new String[] {"Error " + verifyReduction, null}; + } + p1sols.clear(); + p2sols.clear(); + p3sols.clear(); + p4sols.clear(); + p5sols.clear(); + + Logger.start(); + System.out.println(cc); + + SolvingCube sc = new SolvingCube(cc); + + SolvingCube[] p1cc = new SolvingCube[3]; + for (int i = 0; i < 3; i++) { + p1cc[i] = new SolvingCube(sc); + sc.doConj(16); + } + p1search.solve(p1cc, new SolutionChecker(p1cc) { + @Override + int check(SolvingCube sc) { + p1sols.add(sc); + return p1sols.size() >= phase1SolsSize ? 0 : 1; + } + }); + Logger.logTime(0); + + p2cc = p1sols.toArray(new SolvingCube[0]); + p2search.solve(p2cc, new SolutionChecker(p2cc) { + @Override + int check(SolvingCube sc) { + for (int i = 0; i < 3; i++) { + p2sols.add(new SolvingCube(sc)); + sc.doConj(16); + } + return p2sols.size() >= phase2SolsSize ? 0 : 1; + } + }); + Logger.logTime(1); + + p3cc = p2sols.toArray(new SolvingCube[0]); + p3search.solve(p3cc, new SolutionChecker(p3cc) { + @Override + int check(SolvingCube sc) { + int maskY = 0; + int maskZ = 0; + for (int i = 0; i < 4; i++) { + maskY |= 1 << (sc.wEdge[8 + i] % 12); + maskY |= 1 << (sc.wEdge[8 + i + 12] % 12); + maskY |= 1 << (sc.mEdge[8 + i] >> 1); + maskZ |= 1 << (sc.wEdge[4 + i] % 12); + maskZ |= 1 << (sc.wEdge[4 + i + 12] % 12); + maskZ |= 1 << (sc.mEdge[4 + i] >> 1); + } + if (Integer.bitCount(maskY) <= 8) { + p3sols.add(sc); + } + if (Integer.bitCount(maskZ) <= 8) { + sc.doConj(1); + p3sols.add(new SolvingCube(sc)); + } + return p3sols.size() >= phase3SolsSize ? 0 : 1; + } + }); + Logger.logTime(2); + + p4cc = p3sols.toArray(new SolvingCube[0]); + p4search.solve(p4cc, new SolutionChecker(p4cc) { + @Override + int check(SolvingCube sc) { + sc.doConj(1); + p4sols.add(sc); + return p4sols.size() >= phase4SolsSize ? 0 : 1; + } + }); + Logger.logTime(3); + + p5cc = p4sols.toArray(new SolvingCube[0]); + p5search.solve(p5cc, new SolutionChecker(p5cc) { + @Override + int check(SolvingCube sc) { + p5sols.add(sc); + return p5sols.size() >= phase5SolsSize ? 0 : 1; + } + }); + Logger.logTime(4); + + sc = p5sols.get(0); + System.out.println(sc); + System.out.println("Reduction: " + sc.length()); + Logger.cumSolLen += sc.length(); + + cc.doMove(sc.getSolution()); + cc.doCornerMove(sc.getSolution()); + String[] ret = new String[2]; + ret[0] = sc.toSolutionString(verbose); + ret[1] = CubieCube.to333Facelet(cc.toFacelet()); + return ret; + } +} \ No newline at end of file diff --git a/cube555/src/main/java/cs/cube555/SolutionChecker.java b/cube555/src/main/java/cs/cube555/SolutionChecker.java new file mode 100755 index 00000000..83a3e4bd --- /dev/null +++ b/cube555/src/main/java/cs/cube555/SolutionChecker.java @@ -0,0 +1,29 @@ +package cs.cube555; + +class SolutionChecker { + + SolvingCube[] ccList; + + SolutionChecker(SolvingCube[] ccList) { + this.ccList = ccList; + } + + int check(int[] solution, int length, int ccidx) { + SolvingCube sc = new SolvingCube(ccList[ccidx]); + sc.doMove(copySolution(solution, length)); + sc.addCheckPoint(); + return check(sc); + } + + int check(SolvingCube sc) { + return 0; + } + + static int[] copySolution(int[] solution, int length) { + int[] solutionCopy = new int[length]; + for (int i = 0; i < length; i++) { + solutionCopy[i] = solution[i]; + } + return solutionCopy; + } +} \ No newline at end of file diff --git a/cube555/src/main/java/cs/cube555/SolvingCube.java b/cube555/src/main/java/cs/cube555/SolvingCube.java new file mode 100755 index 00000000..3cce2837 --- /dev/null +++ b/cube555/src/main/java/cs/cube555/SolvingCube.java @@ -0,0 +1,101 @@ +package cs.cube555; + +import java.util.ArrayList; +import static cs.cube555.Util.*; + +class SolvingCube extends CubieCube { + + private ArrayList solution = new ArrayList(60); + private int conjIdx = 0; + private int moveCost = 0; + + SolvingCube() {} + + SolvingCube(CubieCube cc) { + copy(cc); + } + + @Override + void copy(CubieCube cc) { + super.copy(cc); + if (cc instanceof SolvingCube) { + SolvingCube sc = (SolvingCube) cc; + this.conjIdx = sc.conjIdx; + this.moveCost = sc.moveCost; + this.solution.clear(); + this.solution.addAll(sc.solution); + } else { + this.conjIdx = 0; + this.moveCost = 0; + this.solution.clear(); + } + } + + @Override + void doMove(int ... moves) { + super.doMove(moves); + for (int i = 0; i < moves.length; i++) { + solution.add(CubieCube.SymMove[conjIdx][moves[i]]); + } + moveCost += moves.length; + } + + @Override + void doConj(int idx) { + super.doConj(idx); + conjIdx = CubieCube.SymMult[conjIdx][idx]; + } + + int[] getSolution() { + int[] ret = new int[moveCost]; + int i = 0; + for (int m : solution) { + if (m != -1) { + ret[i++] = m; + } + } + return ret; + } + + void addCheckPoint() { + solution.add(-1); + } + + int length() { + return moveCost; + } + + String toSolutionString(int verbose) { + StringBuffer sb = new StringBuffer(); + for (int move : solution) { + if (move == -1) { + if ((verbose & Search.USE_SEPARATOR) != 0) { + sb.append(". "); + } + continue; + } + sb.append(move2str[move]).append(' '); + } + return sb.toString(); + } + + @Override + public String toString() { + StringBuffer sb = new StringBuffer(); + int cnt = 0; + int cumcnt = 0; + for (int move : solution) { + if (move == -1) { + cumcnt += cnt; + sb.append(String.format("//(%df,cum=%df)\n", cnt, cumcnt)); + cnt = 0; + continue; + } + cnt++; + sb.append(move2str[move]).append(' '); + } + sb.append(String.format("//conjIdx=%d\n", conjIdx)); + sb.append(super.toString()); + return sb.toString(); + } +} \ No newline at end of file diff --git a/cube555/src/main/java/cs/cube555/Tools.java b/cube555/src/main/java/cs/cube555/Tools.java new file mode 100755 index 00000000..e757d741 --- /dev/null +++ b/cube555/src/main/java/cs/cube555/Tools.java @@ -0,0 +1,80 @@ +package cs.cube555; + +import static cs.cube555.Util.*; +import java.io.ObjectOutputStream; +import java.io.ObjectInputStream; +import java.io.BufferedOutputStream; +import java.io.BufferedInputStream; +import java.io.FileOutputStream; +import java.io.FileInputStream; +import java.util.Random; + +public class Tools { + + static boolean SaveToFile(String filename, Object obj) { + try { + ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(filename))); + oos.writeObject(obj); + oos.close(); + } catch (Exception e) { + System.out.println(e); + return false; + } + return true; + } + + static Object LoadFromFile(String filename) { + Object ret; + try { + ObjectInputStream oos = new ObjectInputStream(new BufferedInputStream(new FileInputStream(filename))); + ret = oos.readObject(); + oos.close(); + } catch (Exception e) { + System.out.println(e); + return null; + } + return ret; + } + + static Random gen = new Random(); + + static CubieCube randomCubieCube(Random gen) { + CubieCube cc = new CubieCube(); + for (int i = 0; i < 23; i++) { + swap(cc.xCenter, i, i + gen.nextInt(24 - i)); + swap(cc.tCenter, i, i + gen.nextInt(24 - i)); + swap(cc.wEdge, i, i + gen.nextInt(24 - i)); + } + int eoSum = 0; + int eParity = 0; + for (int i = 0; i < 11; i++) { + int swap = gen.nextInt(12 - i); + if (swap != 0) { + swap(cc.mEdge, i, i + swap); + eParity ^= 1; + } + int flip = gen.nextInt(2); + cc.mEdge[i] ^= flip; + eoSum ^= flip; + } + cc.mEdge[11] ^= eoSum; + int cp = 0; + do { + cp = gen.nextInt(40320); + } while (eParity != getParity(cp, 8)); + cc.corner.copy(new CubieCube.CornerCube(cp, gen.nextInt(2187))); + return cc; + } + + static CubieCube randomCubieCube() { + return randomCubieCube(gen); + } + + public static String randomCube(Random gen) { + return randomCubieCube(gen).toFacelet(); + } + + public static String randomCube() { + return randomCube(gen); + } +} \ No newline at end of file diff --git a/cube555/src/main/java/cs/cube555/Util.java b/cube555/src/main/java/cs/cube555/Util.java new file mode 100644 index 00000000..d526d793 --- /dev/null +++ b/cube555/src/main/java/cs/cube555/Util.java @@ -0,0 +1,861 @@ +package cs.cube555; + +class Util { + static final int U1 = 0; + static final int U2 = 1; + static final int U3 = 2; + static final int U4 = 3; + static final int U5 = 4; + static final int U6 = 5; + static final int U7 = 6; + static final int U8 = 7; + static final int U9 = 8; + static final int U10 = 9; + static final int U11 = 10; + static final int U12 = 11; + static final int U13 = 12; + static final int U14 = 13; + static final int U15 = 14; + static final int U16 = 15; + static final int U17 = 16; + static final int U18 = 17; + static final int U19 = 18; + static final int U20 = 19; + static final int U21 = 20; + static final int U22 = 21; + static final int U23 = 22; + static final int U24 = 23; + static final int U25 = 24; + static final int R1 = 25; + static final int R2 = 26; + static final int R3 = 27; + static final int R4 = 28; + static final int R5 = 29; + static final int R6 = 30; + static final int R7 = 31; + static final int R8 = 32; + static final int R9 = 33; + static final int R10 = 34; + static final int R11 = 35; + static final int R12 = 36; + static final int R13 = 37; + static final int R14 = 38; + static final int R15 = 39; + static final int R16 = 40; + static final int R17 = 41; + static final int R18 = 42; + static final int R19 = 43; + static final int R20 = 44; + static final int R21 = 45; + static final int R22 = 46; + static final int R23 = 47; + static final int R24 = 48; + static final int R25 = 49; + static final int F1 = 50; + static final int F2 = 51; + static final int F3 = 52; + static final int F4 = 53; + static final int F5 = 54; + static final int F6 = 55; + static final int F7 = 56; + static final int F8 = 57; + static final int F9 = 58; + static final int F10 = 59; + static final int F11 = 60; + static final int F12 = 61; + static final int F13 = 62; + static final int F14 = 63; + static final int F15 = 64; + static final int F16 = 65; + static final int F17 = 66; + static final int F18 = 67; + static final int F19 = 68; + static final int F20 = 69; + static final int F21 = 70; + static final int F22 = 71; + static final int F23 = 72; + static final int F24 = 73; + static final int F25 = 74; + static final int D1 = 75; + static final int D2 = 76; + static final int D3 = 77; + static final int D4 = 78; + static final int D5 = 79; + static final int D6 = 80; + static final int D7 = 81; + static final int D8 = 82; + static final int D9 = 83; + static final int D10 = 84; + static final int D11 = 85; + static final int D12 = 86; + static final int D13 = 87; + static final int D14 = 88; + static final int D15 = 89; + static final int D16 = 90; + static final int D17 = 91; + static final int D18 = 92; + static final int D19 = 93; + static final int D20 = 94; + static final int D21 = 95; + static final int D22 = 96; + static final int D23 = 97; + static final int D24 = 98; + static final int D25 = 99; + static final int L1 = 100; + static final int L2 = 101; + static final int L3 = 102; + static final int L4 = 103; + static final int L5 = 104; + static final int L6 = 105; + static final int L7 = 106; + static final int L8 = 107; + static final int L9 = 108; + static final int L10 = 109; + static final int L11 = 110; + static final int L12 = 111; + static final int L13 = 112; + static final int L14 = 113; + static final int L15 = 114; + static final int L16 = 115; + static final int L17 = 116; + static final int L18 = 117; + static final int L19 = 118; + static final int L20 = 119; + static final int L21 = 120; + static final int L22 = 121; + static final int L23 = 122; + static final int L24 = 123; + static final int L25 = 124; + static final int B1 = 125; + static final int B2 = 126; + static final int B3 = 127; + static final int B4 = 128; + static final int B5 = 129; + static final int B6 = 130; + static final int B7 = 131; + static final int B8 = 132; + static final int B9 = 133; + static final int B10 = 134; + static final int B11 = 135; + static final int B12 = 136; + static final int B13 = 137; + static final int B14 = 138; + static final int B15 = 139; + static final int B16 = 140; + static final int B17 = 141; + static final int B18 = 142; + static final int B19 = 143; + static final int B20 = 144; + static final int B21 = 145; + static final int B22 = 146; + static final int B23 = 147; + static final int B24 = 148; + static final int B25 = 149; + + 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; + static final byte ux1 = 18; + static final byte ux2 = 19; + static final byte ux3 = 20; + static final byte rx1 = 21; + static final byte rx2 = 22; + static final byte rx3 = 23; + static final byte fx1 = 24; + static final byte fx2 = 25; + static final byte fx3 = 26; + static final byte dx1 = 27; + static final byte dx2 = 28; + static final byte dx3 = 29; + static final byte lx1 = 30; + static final byte lx2 = 31; + static final byte lx3 = 32; + static final byte bx1 = 33; + static final byte bx2 = 34; + static final byte bx3 = 35; + + static final String[] move2str = new String[] { + "U ", "U2", "U'", "R ", "R2", "R'", "F ", "F2", "F'", + "D ", "D2", "D'", "L ", "L2", "L'", "B ", "B2", "B'", + "u ", "u2", "u'", "r ", "r2", "r'", "f ", "f2", "f'", + "d ", "d2", "d'", "l ", "l2", "l'", "b ", "b2", "b'" + }; + + static int[][] Cnk = new int[25][25]; + static int[] fact = new int[13]; + + static { + for (int i = 0; i < 25; i++) { + Cnk[i][i] = 1; + Cnk[i][0] = 1; + } + for (int i = 1; i < 25; i++) { + for (int j = 1; j <= i; j++) { + Cnk[i][j] = Cnk[i - 1][j] + Cnk[i - 1][j - 1]; + } + } + fact[0] = 1; + for (int i = 1; i < 13; i++) { + fact[i] = fact[i - 1] * i; + } + } + + static long[] genSkipMoves(int[] VALID_MOVES) { + long[] ret = new long[VALID_MOVES.length + 1]; + for (int last = 0; last < VALID_MOVES.length; last++) { + ret[last] = 0; + int la = VALID_MOVES[last] / 3; + for (int move = 0; move < VALID_MOVES.length; move++) { + int axis = VALID_MOVES[move] / 3; + if (axis == la || axis % 3 == la % 3 && axis >= la) { + ret[last] |= 1 << move; + } + } + } + return ret; + } + + static long genNextAxis(int[] VALID_MOVES) { + long ret = 0; + for (int i = 0; i < VALID_MOVES.length; i++) { + if (VALID_MOVES[i] % 3 == 0) { + //if Mx1 makes state farther, Mx2 and Mx3 should be skipped + // (next_axis >> i & 3) == 2 for Mx1, 1 for Mx2, 0 for Mx3 + ret |= 1L << (i + 1); + } + } + return ret; + } + + static int[] setPerm(int[] arr, int idx, int n, boolean even) { + long val = 0xFEDCBA9876543210L; + int parity = 0; + if (even) { + idx <<= 1; + } + n--; + for (int i = 0; i < n; ++i) { + int p = fact[n - i]; + int v = ~~(idx / p); + parity ^= v; + idx %= p; + v <<= 2; + arr[i] = (int) (val >> v & 0xf); + long m = (1L << v) - 1; + val = (val & m) + (val >> 4 & ~m); + } + if (even && (parity & 1) != 0) { + arr[n] = arr[n - 1]; + arr[n - 1] = (int) (val & 0xf); + } else { + arr[n] = (int) (val & 0xf); + } + return arr; + } + + static int[] setPerm(int[] arr, int idx, int n) { + return setPerm(arr, idx, n, false); + } + + static int[] setPerm(int[] arr, int idx) { + return setPerm(arr, idx, arr.length, false); + } + + static int getPerm(int[] arr, int n, boolean even) { + int idx = 0; + long val = 0xFEDCBA9876543210L; + for (int i = 0; i < n - 1; ++i) { + int v = arr[i] << 2; + idx = (n - i) * idx + (int) (val >> v & 0xf); + val -= 0x1111111111111110L << v; + } + return even ? (idx >> 1) : idx; + } + + static int getPerm(int[] arr, int n) { + return getPerm(arr, n, false); + } + + static int getPerm(int[] arr) { + return getPerm(arr, arr.length, false); + } + + static int[] setComb(int[] arr, int idx, int r, int n) { + for (int i = n - 1; i >= 0; i--) { + if (idx >= Cnk[i][r]) { + idx -= Cnk[i][r--]; + arr[i] = 0; + } else { + arr[i] = -1; + } + } + return arr; + } + + static int[] setComb(int[] arr, int idx, int r) { + return setComb(arr, idx, r, arr.length); + } + + static int getComb(int[] arr, int r, int n) { + int idx = 0; + for (int i = n - 1; i >= 0; i--) { + if (arr[i] != -1) { + idx += Cnk[i][r--]; + } + } + return idx; + } + + static int getComb(int[] arr, int r) { + return getComb(arr, r, arr.length); + } + + static int getSComb(int[] arr, int n) { + int idx = 0; + int r = n / 2; + for (int i = n - 1; i >= 0; i--) { + if (arr[i] != arr[n - 1]) { + idx += Cnk[i][r--]; + } + } + return idx; + } + + static int getSComb(int[] arr) { + return getSComb(arr, arr.length); + } + + static void copyFromComb(int[] src, int[] dst) { + int r = 0; + for (int i = 0; i < src.length; i++) { + if (src[i] != -1) { + dst[r++] = src[i]; + } + } + } + + static void copyToComb(int[] src, int[] dst) { + int r = 0; + for (int i = 0; i < dst.length; i++) { + if (dst[i] != -1) { + dst[i] = src[r++]; + } + } + } + + static int getParity(int idx, int n) { + int parity = 0; + for (int i = n - 2; i >= 0; --i) { + parity ^= idx % (n - i); + idx /= n - i; + } + return parity & 1; + } + + static int getParity(int[] arr) { + int parity = 0; + for (int i = 0; i < arr.length - 1; i++) { + for (int j = i + 1; j < arr.length; j++) { + if (arr[i] > arr[j]) { + parity ^= 1; + } + } + } + return parity; + } + + static void swap(int[] arr, int a, int b) { + int temp = arr[a]; + arr[a] = arr[b]; + arr[b] = temp; + } + + static void swapCorner(int[] arr, int a, int b, int c, int d, int pow) { + int temp; + switch (pow) { + case 0: + temp = (arr[d] + 8) % 24; + arr[d] = (arr[c] + 16) % 24; + arr[c] = (arr[b] + 8) % 24; + arr[b] = (arr[a] + 16) % 24; + arr[a] = temp; + return; + case 1: + temp = arr[a]; + arr[a] = arr[c]; + arr[c] = temp; + temp = arr[b]; + arr[b] = arr[d]; + arr[d] = temp; + return; + case 2: + temp = (arr[a] + 8) % 24; + arr[a] = (arr[b] + 16) % 24; + arr[b] = (arr[c] + 8) % 24; + arr[c] = (arr[d] + 16) % 24; + arr[d] = temp; + return; + } + } + + static void swap(int[] arr, int a, int b, int c, int d, int pow, boolean flip) { + int xor = flip ? 1 : 0; + int temp; + switch (pow) { + case 0: + temp = arr[d] ^ xor; + arr[d] = arr[c] ^ xor; + arr[c] = arr[b] ^ xor; + arr[b] = arr[a] ^ xor; + arr[a] = temp; + return; + case 1: + temp = arr[a]; + arr[a] = arr[c]; + arr[c] = temp; + temp = arr[b]; + arr[b] = arr[d]; + arr[d] = temp; + return; + case 2: + temp = arr[a] ^ xor; + arr[a] = arr[b] ^ xor; + arr[b] = arr[c] ^ xor; + arr[c] = arr[d] ^ xor; + arr[d] = temp; + return; + } + } + + static void swap(int[] arr, int a, int b, int c, int d, int pow) { + swap(arr, a, b, c, d, pow, false); + } + + static int indexOf(int[] arr, int value) { + for (int i = 0; i < arr.length; i++) { + if (arr[i] == value) { + return i; + } + } + return -1; + } + + static abstract class Coord { + int N_IDX = 1; + int N_MOVES = 0; + int idx; + void set(int idx) { + this.idx = idx; + } + abstract int getMoved(int move); + } + + static abstract class SymCoord extends Coord { + int N_SYM; + int[] SelfSym; + } + + static abstract class RawCoord extends Coord { + int getConj(int idx, int conj) { + return idx; + } + } + + static class TableSymCoord extends SymCoord { + int[][] moveTable; + TableSymCoord(int[][] moveTable, int[] SelfSym, int N_SYM) { + this.moveTable = moveTable; + this.SelfSym = SelfSym; + this.N_SYM = N_SYM; + this.N_IDX = moveTable.length; + this.N_MOVES = moveTable[0].length; + } + int getMoved(int move) { + return moveTable[idx][move]; + } + } + + static class TableRawCoord extends RawCoord { + int[][] moveTable; + int[][] conjTable; + TableRawCoord(int[][] moveTable, int[][] conjTable) { + this.moveTable = moveTable; + this.conjTable = conjTable; + this.N_IDX = moveTable.length; + this.N_MOVES = moveTable[0].length; + } + int getMoved(int move) { + return moveTable[idx][move]; + } + int getConj(int idx, int conj) { + return conjTable[idx][conj]; + } + } + + static int[][] packSolved(int[] Solved1, int[] Solved2) { + if (Solved1 == null) { + Solved1 = new int[] {0}; + } + if (Solved2 == null) { + Solved2 = new int[] {0}; + } + int[][] Solved = new int[Solved1.length * Solved2.length][]; + int idx = 0; + for (int idx1 : Solved1) { + for (int idx2 : Solved2) { + Solved[idx++] = new int[] {idx1, idx2}; + } + } + return Solved; + } + + static class PruningTable { + int N_STATE; + int N_STATE2; + int[] Prun; + int TABLE_MASK = 0x7fffffff; + + private static void setPrun(int[] Prun, int idx, int xorval) { + Prun[idx >> 3] ^= xorval << (idx << 2); + } + + private static int getPrun(int[] Prun, int idx) { + return Prun[idx >> 3] >> (idx << 2) & 0xf; + } + + PruningTable(Coord coord, int[] Solved, String filename) { + initPrunTable(coord, Solved, filename); + } + + PruningTable(SymCoord coord, int[] Solved, String filename) { + if (Solved == null) { + Solved = new int[] {0}; + } + int[][] Solved2 = new int[Solved.length][2]; + for (int i = 0; i < Solved.length; i++) { + Solved2[i][0] = Solved[i]; + } + initPrunTable(coord, new RawCoord() { + int getMoved(int move) { + return 0; + } + }, Solved2, filename); + } + + PruningTable(SymCoord symCoord, RawCoord rawCoord, int[][] Solved, String filename) { + initPrunTable(symCoord, rawCoord, Solved, filename); + } + + PruningTable(SymCoord symCoord, RawCoord rawCoord, int[][] Solved, int maxl, int TABLE_SIZE, String filename) { + initPrunTablePartial(symCoord, rawCoord, Solved, maxl, TABLE_SIZE, filename); + } + + PruningTable(int[][] Move, int[] Solved, String filename) { + initPrunTable(new TableRawCoord(Move, null), Solved, filename); + } + + PruningTable(final int[][] Move1, final int[][] Move2, int[] Solved1, int[] Solved2, String filename) { + N_STATE2 = Move2.length; + N_STATE = Move1.length * Move2.length; + if (Solved1 == null) { + Solved1 = new int[] {0}; + } + if (Solved2 == null) { + Solved2 = new int[] {0}; + } + int[] Solved = new int[Solved1.length * Solved2.length]; + int idx = 0; + for (int idx1 : Solved1) { + for (int idx2 : Solved2) { + Solved[idx++] = idx1 * N_STATE2 + idx2; + } + } + initPrunTable(new Coord() { + { + N_IDX = Move1.length * Move2.length; + N_MOVES = Move1[0].length; + } + int state2 = 0; + void set(int i) { + idx = i / N_STATE2; + state2 = i % N_STATE2; + } + int getMoved(int move) { + return Move1[idx][move] * N_STATE2 + Move2[state2][move]; + } + }, Solved, filename); + } + + private void initPrunTablePartial(SymCoord symCoord, RawCoord rawCoord, int[][] Solved, int maxl, int TABLE_SIZE, String filename) { + N_STATE = symCoord.N_IDX * rawCoord.N_IDX; + N_STATE2 = rawCoord.N_IDX; + int N_SYM = symCoord.N_SYM; + int N_MOVES = symCoord.N_MOVES; + TABLE_MASK = TABLE_SIZE - 1; + Prun = (int[]) Tools.LoadFromFile(filename + "Prun.jpdata"); + if (Prun != null) { + return; + } + if (Solved == null) { + Solved = new int[][] {{0, 0}}; + } + java.util.HashMap PrunP = new java.util.HashMap(); + int done = 0; + long realDone = 0; + int depth = 0; + for (int[] val : Solved) { + long idx = val[0] * (long) N_STATE2 + val[1]; + PrunP.put(idx, (byte) 0); + done++; + realDone += N_SYM / Integer.bitCount(symCoord.SelfSym[val[0]]); + } + int cumDone = done; + long cumRealDone = cumDone; + long startTime = System.nanoTime(); + do { + System.out.println(String.format("%s:%2d%,14d%,14d%,16d%,16d%10dms", filename, + depth, done, cumDone, realDone, cumRealDone, + (System.nanoTime() - startTime) / 1000000)); + done = 0; + realDone = 0; + byte fill = (byte) (depth + 1); + java.util.HashMap PrunPClone = (java.util.HashMap) PrunP.clone(); + for (java.util.Map.Entry entry : PrunPClone.entrySet()) { + if (entry.getValue() != depth) { + continue; + } + long i = entry.getKey(); + symCoord.set((int) (i / N_STATE2)); + rawCoord.set((int) (i % N_STATE2)); + for (int m = 0; m < N_MOVES; m++) { + int newSym = symCoord.getMoved(m); + int newRaw = rawCoord.getConj(rawCoord.getMoved(m), newSym % N_SYM); + newSym /= N_SYM; + long newIdx = newSym * (long) N_STATE2 + newRaw; + if (PrunP.putIfAbsent(newIdx, fill) != null) { + continue; + } + done++; + realDone += N_SYM / Integer.bitCount(symCoord.SelfSym[newSym]); + for (int j = 1, symState = symCoord.SelfSym[newSym]; (symState >>= 1) != 0; j++) { + if ((symState & 1) != 1) { + continue; + } + long newIdx2 = newSym * (long) N_STATE2 + rawCoord.getConj(newRaw, j); + if (PrunP.putIfAbsent(newIdx2, fill) != null) { + continue; + } + done++; + realDone += N_SYM / Integer.bitCount(symCoord.SelfSym[newSym]); + } + } + } + cumDone += done; + cumRealDone += realDone; + depth++; + } while (done > 0 && depth < maxl); + System.out.println(String.format("%s:%2d%,14d%,14d%,16d%,16d%10dms", filename, + depth, done, cumDone, realDone, cumRealDone, + (System.nanoTime() - startTime) / 1000000)); + + Prun = new int[TABLE_SIZE >> 3]; + for (int i = 0; i < Prun.length; i++) { + Prun[i] = 0x11111111 * (maxl + 1); + } + for (java.util.Map.Entry entry : PrunP.entrySet()) { + int idx = (int) (entry.getKey() & TABLE_MASK); + int val = entry.getValue(); + int prun = getPrun(Prun, idx); + if (val < prun) { + setPrun(Prun, idx, val ^ prun); + } + } + int[] depthCnt = new int[16]; + for (int i = 0; i < TABLE_SIZE; i++) { + depthCnt[getPrun(Prun, i)]++; + } + for (int i = 0; i < 16; i++) { + if (depthCnt[i] != 0) { + System.out.println(String.format("%s-%2d%,14d", filename, i, depthCnt[i])); + } + } + Tools.SaveToFile(filename + "Prun.jpdata", Prun); + } + + private void initPrunTable(SymCoord symCoord, RawCoord rawCoord, int[][] Solved, String filename) { + N_STATE = symCoord.N_IDX * rawCoord.N_IDX; + N_STATE2 = rawCoord.N_IDX; + int N_SYM = symCoord.N_SYM; + int N_MOVES = symCoord.N_MOVES; + Prun = (int[]) Tools.LoadFromFile(filename + "Prun.jhdata"); + if (Prun != null) { + return; + } + if (Solved == null) { + Solved = new int[][] {{0, 0}}; + } + Prun = new int[(N_STATE + 7) / 8]; + for (int i = 0; i < Prun.length; i++) { + Prun[i] = -1; + } + int done = 0; + long realDone = 0; + int depth = 0; + for (int[] val : Solved) { + int idx = val[0] * N_STATE2 + val[1]; + setPrun(Prun, idx, 0xf); + done++; + realDone += N_SYM / Integer.bitCount(symCoord.SelfSym[val[0]]); + } + int cumDone = done; + long cumRealDone = cumDone; + long startTime = System.nanoTime(); + do { + System.out.println(String.format("%s:%2d%,14d%,14d%,16d%,16d%10dms", filename, + depth, done, cumDone, realDone, cumRealDone, + (System.nanoTime() - startTime) / 1000000)); + done = 0; + realDone = 0; + boolean inv = cumDone > N_STATE / 2; + // boolean inv = true; + int select = inv ? 0xf : depth; + int check = inv ? depth : 0xf; + int fill = depth + 1; + depth++; + int val = 0; + for (int i = 0; i < N_STATE; i++, val >>= 4) { + if ((i & 7) == 0) { + val = Prun[i >> 3]; + if (!inv && val == -1) { + i += 7; + continue; + } + } + if ((val & 0xf) != select) { + continue; + } + symCoord.set(i / N_STATE2); + rawCoord.set(i % N_STATE2); + for (int m = 0; m < N_MOVES; m++) { + int newSym = symCoord.getMoved(m); + int newRaw = rawCoord.getConj(rawCoord.getMoved(m), newSym % N_SYM); + newSym /= N_SYM; + int newIdx = newSym * N_STATE2 + newRaw; + if (getPrun(Prun, newIdx) != check) { + continue; + } + done++; + if (inv) { + setPrun(Prun, i, fill ^ 0xf); + realDone += N_SYM / Integer.bitCount(symCoord.SelfSym[i / N_STATE2]); + break; + } + setPrun(Prun, newIdx, fill ^ 0xf); + realDone += N_SYM / Integer.bitCount(symCoord.SelfSym[newSym]); + + for (int j = 1, symState = symCoord.SelfSym[newSym]; (symState >>= 1) != 0; j++) { + if ((symState & 1) != 1) { + continue; + } + int newIdx2 = newSym * N_STATE2 + rawCoord.getConj(newRaw, j); + if (getPrun(Prun, newIdx2) != check) { + continue; + } + setPrun(Prun, newIdx2, fill ^ 0xf); + done++; + realDone += N_SYM / Integer.bitCount(symCoord.SelfSym[newSym]); + } + } + } + cumDone += done; + cumRealDone += realDone; + } while (done > 0 && depth < 15); + Tools.SaveToFile(filename + "Prun.jhdata", Prun); + } + + private void initPrunTable(Coord coord, int[] Solved, String filename) { + N_STATE = coord.N_IDX; + Prun = (int[]) Tools.LoadFromFile(filename + "Prun.jhdata"); + if (Prun != null) { + return; + } + if (Solved == null) { + Solved = new int[] {0}; + } + Prun = new int[(N_STATE + 7) / 8]; + for (int i = 0; i < Prun.length; i++) { + Prun[i] = -1; + } + int done = 0; + int depth = 0; + for (int idx : Solved) { + setPrun(Prun, idx, 0xf); + done++; + } + long startTime = System.nanoTime(); + int cumDone = done; + do { + System.out.println(String.format("%s:%2d%,14d%,14d%10dms", filename, + depth, done, cumDone, + (System.nanoTime() - startTime) / 1000000)); + done = 0; + boolean inv = cumDone > N_STATE / 2; + int select = inv ? 0xf : depth; + int check = inv ? depth : 0xf; + int fill = depth + 1; + depth++; + int val = 0; + for (int i = 0; i < N_STATE; i++, val >>= 4) { + if ((i & 7) == 0) { + val = Prun[i >> 3]; + if (!inv && val == -1) { + i += 7; + continue; + } + } + if ((val & 0xf) != select) { + continue; + } + coord.set(i); + for (int m = 0; m < coord.N_MOVES; m++) { + int newIdx = coord.getMoved(m); + if (getPrun(Prun, newIdx) != check) { + continue; + } + done++; + if (inv) { + setPrun(Prun, i, fill ^ 0xf); + break; + } + setPrun(Prun, newIdx, fill ^ 0xf); + } + } + cumDone += done; + } while (done > 0 && depth <= 15); + Tools.SaveToFile(filename + "Prun.jhdata", Prun); + } + + int getPrun(int state1, int state2) { + return getPrun(Prun, (state1 * N_STATE2 + state2) & TABLE_MASK); + } + + int getPrun(int state) { + return getPrun(Prun, state & TABLE_MASK); + } + } +} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 3b20607f..f64db78a 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -6,3 +6,4 @@ include("scrambleanalysis") include("sq12phase") include("svglite") include("threephase") +include("cube555") From 3a5159f4fdb01ca19a4c922d6861b7846dfcef0b Mon Sep 17 00:00:00 2001 From: Gregor Billing Date: Thu, 24 Nov 2022 20:40:52 +0900 Subject: [PATCH 2/4] Integrate cube555 with existing Puzzle infrastructure --- cube555/src/main/java/cs/cube555/Search.java | 360 +++++++++--------- .../src/main/java/cs/cube555/SolvingCube.java | 37 +- cube555/src/main/java/cs/cube555/Util.java | 14 +- scrambles/build.gradle.kts | 1 + .../tnoodle/puzzle/FiveByFiveCubePuzzle.java | 77 ++++ .../puzzle/ThreeByThreeCubePuzzle.java | 6 +- .../tnoodle/scrambles/PuzzleRegistry.java | 1 + 7 files changed, 305 insertions(+), 191 deletions(-) create mode 100644 scrambles/src/main/java/org/worldcubeassociation/tnoodle/puzzle/FiveByFiveCubePuzzle.java diff --git a/cube555/src/main/java/cs/cube555/Search.java b/cube555/src/main/java/cs/cube555/Search.java index 44075c92..789c8936 100755 --- a/cube555/src/main/java/cs/cube555/Search.java +++ b/cube555/src/main/java/cs/cube555/Search.java @@ -1,179 +1,181 @@ -package cs.cube555; - -import java.util.ArrayList; -import static cs.cube555.Util.*; - -public class Search { - - public static final int USE_SEPARATOR = 0x1; - - static int phase1SolsSize = 200; - static int phase2SolsSize = 500; - static int phase3SolsSize = 500; - static int phase4SolsSize = 500; - static int phase5SolsSize = 1; - - public static class Logger { - final static boolean DEBUG = true; - static long startTime; - static long cumSolLen = 0; - static long[] cumPhaseT = new long[5]; - static void start() { - startTime = System.nanoTime(); - } - static void logTime(int phase) { - cumPhaseT[phase] += System.nanoTime() - startTime; - System.out.println(String.format("Phase%d Finished in %d ms", phase + 1, (System.nanoTime() - startTime) / 1000000)); - startTime = System.nanoTime(); - } - public static void print(int div) { - System.out.println( - String.format( - "AvgLen=%.2f P1T=%4dms P2T=%4dms P3T=%4dms P4T=%4dms P5T=%4dms TOT=%4dms", - cumSolLen * 1.0 / div, - cumPhaseT[0] / div / 1000000, - cumPhaseT[1] / div / 1000000, - cumPhaseT[2] / div / 1000000, - cumPhaseT[3] / div / 1000000, - cumPhaseT[4] / div / 1000000, - (cumPhaseT[0] + cumPhaseT[1] + cumPhaseT[2] + cumPhaseT[3] + cumPhaseT[4]) / div / 1000000 - )); - } - } - - static boolean isInited = false; - - public static synchronized void init() { - if (isInited) { - return; - } - CubieCube.init(); - Phase1Search.init(); - Phase2Search.init(); - Phase3Search.init(); - Phase4Search.init(); - Phase5Search.init(); - isInited = true; - } - - Phase1Search p1search = new Phase1Search(); - Phase2Search p2search = new Phase2Search(); - Phase3Search p3search = new Phase3Search(); - Phase4Search p4search = new Phase4Search(); - Phase5Search p5search = new Phase5Search(); - ArrayList p1sols = new ArrayList(); - ArrayList p2sols = new ArrayList(); - ArrayList p3sols = new ArrayList(); - ArrayList p4sols = new ArrayList(); - ArrayList p5sols = new ArrayList(); - SolvingCube[] p1cc; - SolvingCube[] p2cc; - SolvingCube[] p3cc; - SolvingCube[] p4cc; - SolvingCube[] p5cc; - - public synchronized String[] solveReduction(String facelet, int verbose) { - CubieCube cc = new CubieCube(); - int verifyReduction = cc.fromFacelet(facelet); - if (verifyReduction != 0) { - System.out.println(verifyReduction); - return new String[] {"Error " + verifyReduction, null}; - } - p1sols.clear(); - p2sols.clear(); - p3sols.clear(); - p4sols.clear(); - p5sols.clear(); - - Logger.start(); - System.out.println(cc); - - SolvingCube sc = new SolvingCube(cc); - - SolvingCube[] p1cc = new SolvingCube[3]; - for (int i = 0; i < 3; i++) { - p1cc[i] = new SolvingCube(sc); - sc.doConj(16); - } - p1search.solve(p1cc, new SolutionChecker(p1cc) { - @Override - int check(SolvingCube sc) { - p1sols.add(sc); - return p1sols.size() >= phase1SolsSize ? 0 : 1; - } - }); - Logger.logTime(0); - - p2cc = p1sols.toArray(new SolvingCube[0]); - p2search.solve(p2cc, new SolutionChecker(p2cc) { - @Override - int check(SolvingCube sc) { - for (int i = 0; i < 3; i++) { - p2sols.add(new SolvingCube(sc)); - sc.doConj(16); - } - return p2sols.size() >= phase2SolsSize ? 0 : 1; - } - }); - Logger.logTime(1); - - p3cc = p2sols.toArray(new SolvingCube[0]); - p3search.solve(p3cc, new SolutionChecker(p3cc) { - @Override - int check(SolvingCube sc) { - int maskY = 0; - int maskZ = 0; - for (int i = 0; i < 4; i++) { - maskY |= 1 << (sc.wEdge[8 + i] % 12); - maskY |= 1 << (sc.wEdge[8 + i + 12] % 12); - maskY |= 1 << (sc.mEdge[8 + i] >> 1); - maskZ |= 1 << (sc.wEdge[4 + i] % 12); - maskZ |= 1 << (sc.wEdge[4 + i + 12] % 12); - maskZ |= 1 << (sc.mEdge[4 + i] >> 1); - } - if (Integer.bitCount(maskY) <= 8) { - p3sols.add(sc); - } - if (Integer.bitCount(maskZ) <= 8) { - sc.doConj(1); - p3sols.add(new SolvingCube(sc)); - } - return p3sols.size() >= phase3SolsSize ? 0 : 1; - } - }); - Logger.logTime(2); - - p4cc = p3sols.toArray(new SolvingCube[0]); - p4search.solve(p4cc, new SolutionChecker(p4cc) { - @Override - int check(SolvingCube sc) { - sc.doConj(1); - p4sols.add(sc); - return p4sols.size() >= phase4SolsSize ? 0 : 1; - } - }); - Logger.logTime(3); - - p5cc = p4sols.toArray(new SolvingCube[0]); - p5search.solve(p5cc, new SolutionChecker(p5cc) { - @Override - int check(SolvingCube sc) { - p5sols.add(sc); - return p5sols.size() >= phase5SolsSize ? 0 : 1; - } - }); - Logger.logTime(4); - - sc = p5sols.get(0); - System.out.println(sc); - System.out.println("Reduction: " + sc.length()); - Logger.cumSolLen += sc.length(); - - cc.doMove(sc.getSolution()); - cc.doCornerMove(sc.getSolution()); - String[] ret = new String[2]; - ret[0] = sc.toSolutionString(verbose); - ret[1] = CubieCube.to333Facelet(cc.toFacelet()); - return ret; - } -} \ No newline at end of file +package cs.cube555; + +import java.util.ArrayList; +import static cs.cube555.Util.*; + +public class Search { + + public static final int USE_SEPARATOR = 0x1; + public static final int INVERT_SOLUTION = 0x2; + + static int phase1SolsSize = 200; + static int phase2SolsSize = 500; + static int phase3SolsSize = 500; + static int phase4SolsSize = 500; + static int phase5SolsSize = 1; + + public static class Logger { + final static boolean DEBUG = true; + static long startTime; + static long cumSolLen = 0; + static long[] cumPhaseT = new long[5]; + static void start() { + startTime = System.nanoTime(); + } + static void logTime(int phase) { + cumPhaseT[phase] += System.nanoTime() - startTime; + System.out.println(String.format("Phase%d Finished in %d ms", phase + 1, (System.nanoTime() - startTime) / 1000000)); + startTime = System.nanoTime(); + } + public static void print(int div) { + System.out.println( + String.format( + "AvgLen=%.2f P1T=%4dms P2T=%4dms P3T=%4dms P4T=%4dms P5T=%4dms TOT=%4dms", + cumSolLen * 1.0 / div, + cumPhaseT[0] / div / 1000000, + cumPhaseT[1] / div / 1000000, + cumPhaseT[2] / div / 1000000, + cumPhaseT[3] / div / 1000000, + cumPhaseT[4] / div / 1000000, + (cumPhaseT[0] + cumPhaseT[1] + cumPhaseT[2] + cumPhaseT[3] + cumPhaseT[4]) / div / 1000000 + )); + } + } + + static boolean isInited = false; + + public static synchronized void init() { + if (isInited) { + return; + } + CubieCube.init(); + Phase1Search.init(); + Phase2Search.init(); + Phase3Search.init(); + Phase4Search.init(); + Phase5Search.init(); + isInited = true; + } + + Phase1Search p1search = new Phase1Search(); + Phase2Search p2search = new Phase2Search(); + Phase3Search p3search = new Phase3Search(); + Phase4Search p4search = new Phase4Search(); + Phase5Search p5search = new Phase5Search(); + ArrayList p1sols = new ArrayList(); + ArrayList p2sols = new ArrayList(); + ArrayList p3sols = new ArrayList(); + ArrayList p4sols = new ArrayList(); + ArrayList p5sols = new ArrayList(); + SolvingCube[] p1cc; + SolvingCube[] p2cc; + SolvingCube[] p3cc; + SolvingCube[] p4cc; + SolvingCube[] p5cc; + + public synchronized String[] solveReduction(String facelet, int verbose) { + init(); + CubieCube cc = new CubieCube(); + int verifyReduction = cc.fromFacelet(facelet); + if (verifyReduction != 0) { + System.out.println(verifyReduction); + return new String[] {"Error " + verifyReduction, null}; + } + p1sols.clear(); + p2sols.clear(); + p3sols.clear(); + p4sols.clear(); + p5sols.clear(); + + Logger.start(); + System.out.println(cc); + + SolvingCube sc = new SolvingCube(cc); + + SolvingCube[] p1cc = new SolvingCube[3]; + for (int i = 0; i < 3; i++) { + p1cc[i] = new SolvingCube(sc); + sc.doConj(16); + } + p1search.solve(p1cc, new SolutionChecker(p1cc) { + @Override + int check(SolvingCube sc) { + p1sols.add(sc); + return p1sols.size() >= phase1SolsSize ? 0 : 1; + } + }); + Logger.logTime(0); + + p2cc = p1sols.toArray(new SolvingCube[0]); + p2search.solve(p2cc, new SolutionChecker(p2cc) { + @Override + int check(SolvingCube sc) { + for (int i = 0; i < 3; i++) { + p2sols.add(new SolvingCube(sc)); + sc.doConj(16); + } + return p2sols.size() >= phase2SolsSize ? 0 : 1; + } + }); + Logger.logTime(1); + + p3cc = p2sols.toArray(new SolvingCube[0]); + p3search.solve(p3cc, new SolutionChecker(p3cc) { + @Override + int check(SolvingCube sc) { + int maskY = 0; + int maskZ = 0; + for (int i = 0; i < 4; i++) { + maskY |= 1 << (sc.wEdge[8 + i] % 12); + maskY |= 1 << (sc.wEdge[8 + i + 12] % 12); + maskY |= 1 << (sc.mEdge[8 + i] >> 1); + maskZ |= 1 << (sc.wEdge[4 + i] % 12); + maskZ |= 1 << (sc.wEdge[4 + i + 12] % 12); + maskZ |= 1 << (sc.mEdge[4 + i] >> 1); + } + if (Integer.bitCount(maskY) <= 8) { + p3sols.add(sc); + } + if (Integer.bitCount(maskZ) <= 8) { + sc.doConj(1); + p3sols.add(new SolvingCube(sc)); + } + return p3sols.size() >= phase3SolsSize ? 0 : 1; + } + }); + Logger.logTime(2); + + p4cc = p3sols.toArray(new SolvingCube[0]); + p4search.solve(p4cc, new SolutionChecker(p4cc) { + @Override + int check(SolvingCube sc) { + sc.doConj(1); + p4sols.add(sc); + return p4sols.size() >= phase4SolsSize ? 0 : 1; + } + }); + Logger.logTime(3); + + p5cc = p4sols.toArray(new SolvingCube[0]); + p5search.solve(p5cc, new SolutionChecker(p5cc) { + @Override + int check(SolvingCube sc) { + p5sols.add(sc); + return p5sols.size() >= phase5SolsSize ? 0 : 1; + } + }); + Logger.logTime(4); + + sc = p5sols.get(0); + System.out.println(sc); + System.out.println("Reduction: " + sc.length()); + Logger.cumSolLen += sc.length(); + + cc.doMove(sc.getSolution()); + cc.doCornerMove(sc.getSolution()); + String[] ret = new String[2]; + ret[0] = sc.toSolutionString(verbose); + ret[1] = CubieCube.to333Facelet(cc.toFacelet()); + return ret; + } +} diff --git a/cube555/src/main/java/cs/cube555/SolvingCube.java b/cube555/src/main/java/cs/cube555/SolvingCube.java index 3cce2837..4a5383a2 100755 --- a/cube555/src/main/java/cs/cube555/SolvingCube.java +++ b/cube555/src/main/java/cs/cube555/SolvingCube.java @@ -1,6 +1,9 @@ package cs.cube555; import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + import static cs.cube555.Util.*; class SolvingCube extends CubieCube { @@ -65,8 +68,35 @@ int length() { return moveCost; } + List getOrderedSolution(boolean reverse) { + List tempSolution = new ArrayList<>(solution); + + if (reverse) { + Collections.reverse(tempSolution); + + for (int i = 0; i < tempSolution.size(); i++) { + int solMove = tempSolution.get(i); + + if (solMove >= 0) { + int moveBase = solMove / 3; + int movePow = solMove % 3; + + int invBase = 3 * moveBase; + int invPow = 2 - movePow; + + tempSolution.set(i, invBase + invPow); + } + } + } + + return tempSolution; + } + String toSolutionString(int verbose) { - StringBuffer sb = new StringBuffer(); + boolean invertSolution = (verbose & Search.INVERT_SOLUTION) != 0; + List solution = getOrderedSolution(invertSolution); + + StringBuilder sb = new StringBuilder(); for (int move : solution) { if (move == -1) { if ((verbose & Search.USE_SEPARATOR) != 0) { @@ -81,7 +111,8 @@ String toSolutionString(int verbose) { @Override public String toString() { - StringBuffer sb = new StringBuffer(); + List solution = getOrderedSolution(false); + StringBuilder sb = new StringBuilder(); int cnt = 0; int cumcnt = 0; for (int move : solution) { @@ -98,4 +129,4 @@ public String toString() { sb.append(super.toString()); return sb.toString(); } -} \ No newline at end of file +} diff --git a/cube555/src/main/java/cs/cube555/Util.java b/cube555/src/main/java/cs/cube555/Util.java index d526d793..4d6dc884 100644 --- a/cube555/src/main/java/cs/cube555/Util.java +++ b/cube555/src/main/java/cs/cube555/Util.java @@ -1,5 +1,7 @@ package cs.cube555; +import java.util.HashMap; + class Util { static final int U1 = 0; static final int U2 = 1; @@ -190,10 +192,10 @@ class Util { static final byte bx3 = 35; static final String[] move2str = new String[] { - "U ", "U2", "U'", "R ", "R2", "R'", "F ", "F2", "F'", - "D ", "D2", "D'", "L ", "L2", "L'", "B ", "B2", "B'", - "u ", "u2", "u'", "r ", "r2", "r'", "f ", "f2", "f'", - "d ", "d2", "d'", "l ", "l2", "l'", "b ", "b2", "b'" + "U", "U2", "U'", "R", "R2", "R'", "F", "F2", "F'", + "D", "D2", "D'", "L", "L2", "L'", "B", "B2", "B'", + "Uw", "Uw2", "Uw'", "Rw", "Rw2", "Rw'", "Fw", "Fw2", "Fw'", + "Dw", "Dw2", "Dw'", "Lw", "Lw2", "Lw'", "Bw", "Bw2", "Bw'" }; static int[][] Cnk = new int[25][25]; @@ -634,7 +636,7 @@ private void initPrunTablePartial(SymCoord symCoord, RawCoord rawCoord, int[][] done = 0; realDone = 0; byte fill = (byte) (depth + 1); - java.util.HashMap PrunPClone = (java.util.HashMap) PrunP.clone(); + java.util.HashMap PrunPClone = new HashMap<>(PrunP); for (java.util.Map.Entry entry : PrunPClone.entrySet()) { if (entry.getValue() != depth) { continue; @@ -858,4 +860,4 @@ int getPrun(int state) { return getPrun(Prun, state & TABLE_MASK); } } -} \ No newline at end of file +} diff --git a/scrambles/build.gradle.kts b/scrambles/build.gradle.kts index 230c8b13..fa6a9032 100644 --- a/scrambles/build.gradle.kts +++ b/scrambles/build.gradle.kts @@ -28,6 +28,7 @@ dependencies { implementation(project(":min2phase")) implementation(project(":threephase")) implementation(project(":sq12phase")) + implementation(project(":cube555")) api(libs.gwt.exporter) } diff --git a/scrambles/src/main/java/org/worldcubeassociation/tnoodle/puzzle/FiveByFiveCubePuzzle.java b/scrambles/src/main/java/org/worldcubeassociation/tnoodle/puzzle/FiveByFiveCubePuzzle.java new file mode 100644 index 00000000..7c24ed21 --- /dev/null +++ b/scrambles/src/main/java/org/worldcubeassociation/tnoodle/puzzle/FiveByFiveCubePuzzle.java @@ -0,0 +1,77 @@ +package org.worldcubeassociation.tnoodle.puzzle; + +import cs.cube555.Search; +import cs.cube555.Tools; +import cs.min2phase.SearchWCA; +import org.timepedia.exporter.client.Export; +import org.worldcubeassociation.tnoodle.scrambles.*; +import org.worldcubeassociation.tnoodle.scrambles.AlgorithmBuilder.MergingMode; + +import java.util.Random; +import java.util.logging.Logger; + +@Export +public class FiveByFiveCubePuzzle extends CubePuzzle { + private static final Logger l = Logger.getLogger(FiveByFiveCubePuzzle.class.getName()); + + private final ThreadLocal threePhaseSearcher; + private final ThreadLocal twoPhaseSearcher; + + public FiveByFiveCubePuzzle() { + super(5); + + threePhaseSearcher = ThreadLocal.withInitial(Search::new); + twoPhaseSearcher = ThreadLocal.withInitial(SearchWCA::new); + } + + @Override + public String getShortName() { + return "555rs"; + } + + @Override + public String getLongName() { + return "5x5x5 (random state, unofficial)"; + } + + @Override + public PuzzleStateAndGenerator generateRandomMoves(Random r) { + String randomState = Tools.randomCube(r); + String[] scrambleState = threePhaseSearcher.get().solveReduction(randomState, Search.INVERT_SOLUTION); + + String reductionSolution = scrambleState[0]; + String reducedState = scrambleState[1]; + + if (reducedState == null) { + // TODO - Not really sure what to do here. + l.severe(reductionSolution + " while searching for solution to " + randomState); + assert false; + return null; + } + + String reducedSolution = twoPhaseSearcher.get().solution(reducedState, ThreeByThreeCubePuzzle.THREE_BY_THREE_MAX_SCRAMBLE_LENGTH, ThreeByThreeCubePuzzle.THREE_BY_THREE_TIMEOUT, ThreeByThreeCubePuzzle.THREE_BY_THREE_TIMEMIN, SearchWCA.INVERSE_SOLUTION).trim(); + + if(reducedSolution.startsWith("Error")) { + // TODO - Not really sure what to do here. + l.severe(reducedSolution + " while searching for solution to " + reducedState); + assert false; + return null; + } + + AlgorithmBuilder ab = new AlgorithmBuilder(this, MergingMode.CANONICALIZE_MOVES); + + try { + ab.appendAlgorithm(reducedSolution); + } catch (InvalidMoveException e) { + throw new RuntimeException(new InvalidScrambleException(reducedSolution, e)); + } + + try { + ab.appendAlgorithm(reductionSolution); + } catch (InvalidMoveException e) { + throw new RuntimeException(new InvalidScrambleException(reductionSolution, e)); + } + + return ab.getStateAndGenerator(); + } +} diff --git a/scrambles/src/main/java/org/worldcubeassociation/tnoodle/puzzle/ThreeByThreeCubePuzzle.java b/scrambles/src/main/java/org/worldcubeassociation/tnoodle/puzzle/ThreeByThreeCubePuzzle.java index 6f77692f..6e53e313 100644 --- a/scrambles/src/main/java/org/worldcubeassociation/tnoodle/puzzle/ThreeByThreeCubePuzzle.java +++ b/scrambles/src/main/java/org/worldcubeassociation/tnoodle/puzzle/ThreeByThreeCubePuzzle.java @@ -15,9 +15,9 @@ @Export public class ThreeByThreeCubePuzzle extends CubePuzzle { private static final Logger l = Logger.getLogger(ThreeByThreeCubePuzzle.class.getName()); - private static final int THREE_BY_THREE_MAX_SCRAMBLE_LENGTH = 21; - private static final int THREE_BY_THREE_TIMEMIN = 200; //milliseconds - private static final int THREE_BY_THREE_TIMEOUT = 60*1000; //milliseconds + public static final int THREE_BY_THREE_MAX_SCRAMBLE_LENGTH = 21; + public static final int THREE_BY_THREE_TIMEMIN = 200; //milliseconds + public static final int THREE_BY_THREE_TIMEOUT = 60*1000; //milliseconds private final ThreadLocal twoPhaseSearcher; public ThreeByThreeCubePuzzle() { diff --git a/scrambles/src/main/java/org/worldcubeassociation/tnoodle/scrambles/PuzzleRegistry.java b/scrambles/src/main/java/org/worldcubeassociation/tnoodle/scrambles/PuzzleRegistry.java index 8c2bdb08..e8882acf 100644 --- a/scrambles/src/main/java/org/worldcubeassociation/tnoodle/scrambles/PuzzleRegistry.java +++ b/scrambles/src/main/java/org/worldcubeassociation/tnoodle/scrambles/PuzzleRegistry.java @@ -8,6 +8,7 @@ public enum PuzzleRegistry { FOUR(FourByFourCubePuzzle.class), FOUR_FAST(FourByFourRandomTurnsCubePuzzle.class), FIVE(CubePuzzle.class, 5), + FIVE_RS(FiveByFiveCubePuzzle.class), SIX(CubePuzzle.class, 6), SEVEN(CubePuzzle.class, 7), THREE_NI(NoInspectionThreeByThreeCubePuzzle.class), From 31cb92cebeb68821442cc42ab82ac31d3d73969e Mon Sep 17 00:00:00 2001 From: Gregor Billing Date: Thu, 24 Nov 2022 21:34:01 +0900 Subject: [PATCH 3/4] Redirect raw sysout calls to logger --- cube555/src/main/java/cs/cube555/Search.java | 16 +++++----- cube555/src/main/java/cs/cube555/Tools.java | 10 +++++-- cube555/src/main/java/cs/cube555/Util.java | 31 ++++++++++++-------- 3 files changed, 34 insertions(+), 23 deletions(-) diff --git a/cube555/src/main/java/cs/cube555/Search.java b/cube555/src/main/java/cs/cube555/Search.java index 789c8936..436f3fb7 100755 --- a/cube555/src/main/java/cs/cube555/Search.java +++ b/cube555/src/main/java/cs/cube555/Search.java @@ -1,9 +1,11 @@ package cs.cube555; +import org.slf4j.LoggerFactory; + import java.util.ArrayList; -import static cs.cube555.Util.*; public class Search { + private static org.slf4j.Logger logger = LoggerFactory.getLogger(Search.class); public static final int USE_SEPARATOR = 0x1; public static final int INVERT_SOLUTION = 0x2; @@ -24,11 +26,11 @@ static void start() { } static void logTime(int phase) { cumPhaseT[phase] += System.nanoTime() - startTime; - System.out.println(String.format("Phase%d Finished in %d ms", phase + 1, (System.nanoTime() - startTime) / 1000000)); + logger.info(String.format("Phase%d Finished in %d ms", phase + 1, (System.nanoTime() - startTime) / 1000000)); startTime = System.nanoTime(); } public static void print(int div) { - System.out.println( + logger.debug( String.format( "AvgLen=%.2f P1T=%4dms P2T=%4dms P3T=%4dms P4T=%4dms P5T=%4dms TOT=%4dms", cumSolLen * 1.0 / div, @@ -78,7 +80,7 @@ public synchronized String[] solveReduction(String facelet, int verbose) { CubieCube cc = new CubieCube(); int verifyReduction = cc.fromFacelet(facelet); if (verifyReduction != 0) { - System.out.println(verifyReduction); + logger.error("Reduction error " + verifyReduction); return new String[] {"Error " + verifyReduction, null}; } p1sols.clear(); @@ -88,7 +90,7 @@ public synchronized String[] solveReduction(String facelet, int verbose) { p5sols.clear(); Logger.start(); - System.out.println(cc); + logger.info(cc.toString()); SolvingCube sc = new SolvingCube(cc); @@ -167,8 +169,8 @@ int check(SolvingCube sc) { Logger.logTime(4); sc = p5sols.get(0); - System.out.println(sc); - System.out.println("Reduction: " + sc.length()); + logger.info(sc.toString()); + logger.debug("Reduction: " + sc.length()); Logger.cumSolLen += sc.length(); cc.doMove(sc.getSolution()); diff --git a/cube555/src/main/java/cs/cube555/Tools.java b/cube555/src/main/java/cs/cube555/Tools.java index e757d741..cfa96782 100755 --- a/cube555/src/main/java/cs/cube555/Tools.java +++ b/cube555/src/main/java/cs/cube555/Tools.java @@ -1,5 +1,8 @@ package cs.cube555; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import static cs.cube555.Util.*; import java.io.ObjectOutputStream; import java.io.ObjectInputStream; @@ -10,6 +13,7 @@ import java.util.Random; public class Tools { + private static Logger logger = LoggerFactory.getLogger(Tools.class); static boolean SaveToFile(String filename, Object obj) { try { @@ -17,7 +21,7 @@ static boolean SaveToFile(String filename, Object obj) { oos.writeObject(obj); oos.close(); } catch (Exception e) { - System.out.println(e); + logger.error("unable to save file", e); return false; } return true; @@ -30,7 +34,7 @@ static Object LoadFromFile(String filename) { ret = oos.readObject(); oos.close(); } catch (Exception e) { - System.out.println(e); + logger.error("unable to load file", e); return null; } return ret; @@ -77,4 +81,4 @@ public static String randomCube(Random gen) { public static String randomCube() { return randomCube(gen); } -} \ No newline at end of file +} diff --git a/cube555/src/main/java/cs/cube555/Util.java b/cube555/src/main/java/cs/cube555/Util.java index 4d6dc884..d2334ec3 100644 --- a/cube555/src/main/java/cs/cube555/Util.java +++ b/cube555/src/main/java/cs/cube555/Util.java @@ -1,8 +1,13 @@ package cs.cube555; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.util.HashMap; class Util { + private static Logger logger = LoggerFactory.getLogger(Tools.class); + static final int U1 = 0; static final int U2 = 1; static final int U3 = 2; @@ -630,9 +635,9 @@ private void initPrunTablePartial(SymCoord symCoord, RawCoord rawCoord, int[][] long cumRealDone = cumDone; long startTime = System.nanoTime(); do { - System.out.println(String.format("%s:%2d%,14d%,14d%,16d%,16d%10dms", filename, - depth, done, cumDone, realDone, cumRealDone, - (System.nanoTime() - startTime) / 1000000)); + logger.debug(String.format("%s:%2d%,14d%,14d%,16d%,16d%10dms", filename, + depth, done, cumDone, realDone, cumRealDone, + (System.nanoTime() - startTime) / 1000000)); done = 0; realDone = 0; byte fill = (byte) (depth + 1); @@ -671,9 +676,9 @@ private void initPrunTablePartial(SymCoord symCoord, RawCoord rawCoord, int[][] cumRealDone += realDone; depth++; } while (done > 0 && depth < maxl); - System.out.println(String.format("%s:%2d%,14d%,14d%,16d%,16d%10dms", filename, - depth, done, cumDone, realDone, cumRealDone, - (System.nanoTime() - startTime) / 1000000)); + logger.debug(String.format("%s:%2d%,14d%,14d%,16d%,16d%10dms", filename, + depth, done, cumDone, realDone, cumRealDone, + (System.nanoTime() - startTime) / 1000000)); Prun = new int[TABLE_SIZE >> 3]; for (int i = 0; i < Prun.length; i++) { @@ -693,7 +698,7 @@ private void initPrunTablePartial(SymCoord symCoord, RawCoord rawCoord, int[][] } for (int i = 0; i < 16; i++) { if (depthCnt[i] != 0) { - System.out.println(String.format("%s-%2d%,14d", filename, i, depthCnt[i])); + logger.debug(String.format("%s-%2d%,14d", filename, i, depthCnt[i])); } } Tools.SaveToFile(filename + "Prun.jpdata", Prun); @@ -728,9 +733,9 @@ private void initPrunTable(SymCoord symCoord, RawCoord rawCoord, int[][] Solved, long cumRealDone = cumDone; long startTime = System.nanoTime(); do { - System.out.println(String.format("%s:%2d%,14d%,14d%,16d%,16d%10dms", filename, - depth, done, cumDone, realDone, cumRealDone, - (System.nanoTime() - startTime) / 1000000)); + logger.debug(String.format("%s:%2d%,14d%,14d%,16d%,16d%10dms", filename, + depth, done, cumDone, realDone, cumRealDone, + (System.nanoTime() - startTime) / 1000000)); done = 0; realDone = 0; boolean inv = cumDone > N_STATE / 2; @@ -812,9 +817,9 @@ private void initPrunTable(Coord coord, int[] Solved, String filename) { long startTime = System.nanoTime(); int cumDone = done; do { - System.out.println(String.format("%s:%2d%,14d%,14d%10dms", filename, - depth, done, cumDone, - (System.nanoTime() - startTime) / 1000000)); + logger.debug(String.format("%s:%2d%,14d%,14d%10dms", filename, + depth, done, cumDone, + (System.nanoTime() - startTime) / 1000000)); done = 0; boolean inv = cumDone > N_STATE / 2; int select = inv ? 0xf : depth; From 65dae245267cee93a2fa58edba110c2f61b01ad0 Mon Sep 17 00:00:00 2001 From: Gregor Billing Date: Thu, 24 Nov 2022 21:41:16 +0900 Subject: [PATCH 4/4] Expose pruning table folder config --- cube555/src/main/java/cs/cube555/Tools.java | 46 ++++++++++++------- .../tnoodle/puzzle/FiveByFiveCubePuzzle.java | 6 +++ 2 files changed, 36 insertions(+), 16 deletions(-) diff --git a/cube555/src/main/java/cs/cube555/Tools.java b/cube555/src/main/java/cs/cube555/Tools.java index cfa96782..1e9ea3d2 100755 --- a/cube555/src/main/java/cs/cube555/Tools.java +++ b/cube555/src/main/java/cs/cube555/Tools.java @@ -4,40 +4,54 @@ import org.slf4j.LoggerFactory; import static cs.cube555.Util.*; -import java.io.ObjectOutputStream; -import java.io.ObjectInputStream; -import java.io.BufferedOutputStream; -import java.io.BufferedInputStream; -import java.io.FileOutputStream; -import java.io.FileInputStream; + +import java.io.*; import java.util.Random; public class Tools { private static Logger logger = LoggerFactory.getLogger(Tools.class); + public static File pruningTableFolder = null; + static boolean SaveToFile(String filename, Object obj) { - try { - ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(filename))); + if (pruningTableFolder == null) { + return false; + } + + if (!pruningTableFolder.exists() && !pruningTableFolder.mkdirs()) { + return false; + } + + File pruningTable = new File(pruningTableFolder, filename); + + try(ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(pruningTable)))) { oos.writeObject(obj); - oos.close(); } catch (Exception e) { logger.error("unable to save file", e); return false; } + return true; } static Object LoadFromFile(String filename) { - Object ret; - try { - ObjectInputStream oos = new ObjectInputStream(new BufferedInputStream(new FileInputStream(filename))); - ret = oos.readObject(); - oos.close(); + if (pruningTableFolder == null) { + return null; + } + + File pruningTable = new File(pruningTableFolder, filename); + + if (!pruningTable.exists()) { + return null; + } + + try(ObjectInputStream oos = new ObjectInputStream(new BufferedInputStream(new FileInputStream(pruningTable)))) { + return oos.readObject(); } catch (Exception e) { logger.error("unable to load file", e); - return null; } - return ret; + + return null; } static Random gen = new Random(); diff --git a/scrambles/src/main/java/org/worldcubeassociation/tnoodle/puzzle/FiveByFiveCubePuzzle.java b/scrambles/src/main/java/org/worldcubeassociation/tnoodle/puzzle/FiveByFiveCubePuzzle.java index 7c24ed21..a0effb01 100644 --- a/scrambles/src/main/java/org/worldcubeassociation/tnoodle/puzzle/FiveByFiveCubePuzzle.java +++ b/scrambles/src/main/java/org/worldcubeassociation/tnoodle/puzzle/FiveByFiveCubePuzzle.java @@ -7,6 +7,7 @@ import org.worldcubeassociation.tnoodle.scrambles.*; import org.worldcubeassociation.tnoodle.scrambles.AlgorithmBuilder.MergingMode; +import java.io.File; import java.util.Random; import java.util.logging.Logger; @@ -74,4 +75,9 @@ public PuzzleStateAndGenerator generateRandomMoves(Random r) { return ab.getStateAndGenerator(); } + + public static void initPruningTables(File baseFolder) { + Tools.pruningTableFolder = baseFolder; + Search.init(); + } }