Revision b95ceafc
Added by Leszek Koltunski over 5 years ago
| src/main/java/org/distorted/solvers/cube3/Color.java | ||
|---|---|---|
| 1 | package org.distorted.solvers.cube3; | |
| 2 |  | |
| 3 | //++++++++++++++++++++++++++++++ Names the colors of the cube facelets ++++++++++++++++++++++++++++++++++++++++++++++++ | |
| 4 |  | |
| 5 | class Color | |
| 6 |   {
 | |
| 7 | public static final int U=0; | |
| 8 | public static final int R=1; | |
| 9 | public static final int F=2; | |
| 10 | public static final int D=3; | |
| 11 | public static final int L=4; | |
| 12 | public static final int B=5; | |
| 13 |  | |
| 14 | public static String toString(int i) | |
| 15 |     {
 | |
| 16 | switch(i) | |
| 17 |       {
 | |
| 18 | case U: return "U"; | |
| 19 | case R: return "R"; | |
| 20 | case F: return "F"; | |
| 21 | case D: return "D"; | |
| 22 | case L: return "L"; | |
| 23 | case B: return "B"; | |
| 24 | default: return "?"; | |
| 25 | } | |
| 26 | } | |
| 27 |  | |
| 28 | public static int toInt(String s) | |
| 29 |     {
 | |
| 30 | switch(s.charAt(0)) | |
| 31 |       {
 | |
| 32 | case 'U': return U; | |
| 33 | case 'R': return R; | |
| 34 | case 'F': return F; | |
| 35 | case 'D': return D; | |
| 36 | case 'L': return L; | |
| 37 | case 'B': return B; | |
| 38 | default: return -1; | |
| 39 | } | |
| 40 | } | |
| 41 | } | |
| src/main/java/org/distorted/solvers/cube3/CoordCube.java | ||
|---|---|---|
| 1 | package org.distorted.solvers.cube3; | |
| 2 |  | |
| 3 | import android.content.res.Resources; | |
| 4 | import java.io.InputStream; | |
| 5 |  | |
| 6 | //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| 7 | // Representation of the cube on the coordinate level | |
| 8 | class CoordCube {
 | |
| 9 |  | |
| 10 | static final short N_TWIST = 2187;// 3^7 possible corner orientations | |
| 11 | static final short N_FLIP = 2048;// 2^11 possible edge flips | |
| 12 | static final short N_SLICE1 = 495;// 12 choose 4 possible positions of FR,FL,BL,BR edges | |
| 13 | static final short N_SLICE2 = 24;// 4! permutations of FR,FL,BL,BR edges in phase2 | |
| 14 | static final short N_PARITY = 2; // 2 possible corner parities | |
| 15 | static final short N_URFtoDLF = 20160;// 8!/(8-6)! permutation of URF,UFL,ULB,UBR,DFR,DLF corners | |
| 16 | static final short N_FRtoBR = 11880; // 12!/(12-4)! permutation of FR,FL,BL,BR edges | |
| 17 | static final short N_URtoUL = 1320; // 12!/(12-3)! permutation of UR,UF,UL edges | |
| 18 | static final short N_UBtoDF = 1320; // 12!/(12-3)! permutation of UB,DR,DF edges | |
| 19 | static final short N_URtoDF = 20160; // 8!/(8-6)! permutation of UR,UF,UL,UB,DR,DF edges in phase2 | |
| 20 |  | |
| 21 | static final int N_URFtoDLB = 40320;// 8! permutations of the corners | |
| 22 | static final int N_URtoBR = 479001600;// 8! permutations of the corners | |
| 23 |  | |
| 24 | static final short N_MOVE = 18; | |
| 25 |  | |
| 26 | // All coordinates are 0 for a solved cube except for UBtoDF, which is 114 | |
| 27 | short twist; | |
| 28 | short flip; | |
| 29 | short parity; | |
| 30 | short FRtoBR; | |
| 31 | short URFtoDLF; | |
| 32 | short URtoUL; | |
| 33 | short UBtoDF; | |
| 34 | int URtoDF; | |
| 35 |  | |
| 36 | private static boolean[] init = new boolean[12]; | |
| 37 |  | |
| 38 | static | |
| 39 | 	  {
 | |
| 40 | for(int i=0; i<12; i++ ) init[i] = false; | |
| 41 | } | |
| 42 |  | |
| 43 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| 44 | // Generate a CoordCube from a CubieCube | |
| 45 | 	CoordCube(CubieCube c) {
 | |
| 46 | twist = c.getTwist(); | |
| 47 | flip = c.getFlip(); | |
| 48 | parity = c.cornerParity(); | |
| 49 | FRtoBR = c.getFRtoBR(); | |
| 50 | URFtoDLF = c.getURFtoDLF(); | |
| 51 | URtoUL = c.getURtoUL(); | |
| 52 | UBtoDF = c.getUBtoDF(); | |
| 53 | URtoDF = c.getURtoDF();// only needed in phase2 | |
| 54 | } | |
| 55 |  | |
| 56 | // A move on the coordinate level | |
| 57 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| 58 | 	void move(int m) {
 | |
| 59 | twist = getTwistMove(twist,m); | |
| 60 | flip = getFlipMove(flip,m); | |
| 61 | parity = parityMove[parity][m]; | |
| 62 | FRtoBR = getFRtoBR_Move(FRtoBR,m); | |
| 63 | URFtoDLF = getURFtoDLF_Move(URFtoDLF,m); | |
| 64 | URtoUL = getURtoUL_Move(URtoUL,m); | |
| 65 | UBtoDF = getUBtoDF_Move(UBtoDF,m); | |
| 66 | if (URtoUL < 336 && UBtoDF < 336)// updated only if UR,UF,UL,UB,DR,DF | |
| 67 | // are not in UD-slice | |
| 68 | URtoDF = getMergeURtoULandUBtoDF(URtoUL,UBtoDF); | |
| 69 | } | |
| 70 |  | |
| 71 | // ******************************************Phase 1 move tables***************************************************** | |
| 72 |  | |
| 73 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| 74 | // Move table for the twists of the corners | |
| 75 | // twist < 2187 in phase 2. | |
| 76 | // twist = 0 in phase 2. | |
| 77 | private static byte[] twistMove = new byte[2*N_TWIST*N_MOVE]; | |
| 78 |  | |
| 79 | public static boolean initialize1(Resources res) | |
| 80 | 	{/*
 | |
| 81 | if( init[0]==true ) return; | |
| 82 |  | |
| 83 | CubieCube a = new CubieCube(); | |
| 84 | 		for (short i = 0; i < N_TWIST; i++) {
 | |
| 85 | a.setTwist(i); | |
| 86 | 			for (int j = 0; j < 6; j++) {
 | |
| 87 | 				for (int k = 0; k < 3; k++) {
 | |
| 88 | a.cornerMultiply(CubieCube.moveCube[j]); | |
| 89 | twistMove[i][3 * j + k] = a.getTwist(); | |
| 90 | } | |
| 91 | a.cornerMultiply(CubieCube.moveCube[j]);// 4. faceturn restores | |
| 92 | // a | |
| 93 | } | |
| 94 | } | |
| 95 |  | |
| 96 | init[0]=true; | |
| 97 | */ | |
| 98 | if( init[0]==false ) | |
| 99 | 		  {
 | |
| 100 | try | |
| 101 | 		    {
 | |
| 102 | InputStream is = res.openRawResource(com.threedcell.rubik.R.raw.table1); | |
| 103 | is.read( twistMove, 0, 2*N_TWIST*N_MOVE); | |
| 104 | } | |
| 105 | catch(Exception ioe) | |
| 106 | 		    {
 | |
| 107 | 		    System.out.println("error reading table1");
 | |
| 108 | return false; | |
| 109 | } | |
| 110 |  | |
| 111 | init[0]=true; | |
| 112 | } | |
| 113 |  | |
| 114 | return true; | |
| 115 | } | |
| 116 |  | |
| 117 | public static short getTwistMove(int a,int b) | |
| 118 | 	{
 | |
| 119 | short upperS = twistMove[2*(a*N_MOVE+b)]; | |
| 120 | short lowerS = twistMove[2*(a*N_MOVE+b)+1]; | |
| 121 |  | |
| 122 | if( upperS<0 ) upperS+=256; | |
| 123 | if( lowerS<0 ) lowerS+=256; | |
| 124 |  | |
| 125 | return (short)( (upperS<<8) + lowerS ); | |
| 126 | } | |
| 127 |  | |
| 128 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| 129 | // Move table for the flips of the edges | |
| 130 | // flip < 2048 in phase 1 | |
| 131 | // flip = 0 in phase 2. | |
| 132 | private static byte[] flipMove = new byte[2*N_FLIP*N_MOVE]; | |
| 133 |  | |
| 134 | public static boolean initialize2(Resources res) | |
| 135 | 	{/*
 | |
| 136 | if( init[1]==true ) return; | |
| 137 |  | |
| 138 | CubieCube a = new CubieCube(); | |
| 139 | 		for (short i = 0; i < N_FLIP; i++) {
 | |
| 140 | a.setFlip(i); | |
| 141 | 			for (int j = 0; j < 6; j++) {
 | |
| 142 | 				for (int k = 0; k < 3; k++) {
 | |
| 143 | a.edgeMultiply(CubieCube.moveCube[j]); | |
| 144 | flipMove[i][3 * j + k] = a.getFlip(); | |
| 145 | } | |
| 146 | a.edgeMultiply(CubieCube.moveCube[j]); | |
| 147 | // a | |
| 148 | } | |
| 149 | } | |
| 150 |  | |
| 151 | init[1]=true; | |
| 152 | */ | |
| 153 | if( init[1]==false ) | |
| 154 | 		  {
 | |
| 155 | try | |
| 156 | 		    {
 | |
| 157 | InputStream is = res.openRawResource(com.threedcell.rubik.R.raw.table2); | |
| 158 | is.read( flipMove, 0, 2*N_FLIP*N_MOVE); | |
| 159 | } | |
| 160 | catch(Exception ioe) | |
| 161 | 		    {
 | |
| 162 | 		    System.out.println("error reading table2");
 | |
| 163 | return false; | |
| 164 | } | |
| 165 |  | |
| 166 | init[1]=true; | |
| 167 | } | |
| 168 |  | |
| 169 | return true; | |
| 170 | } | |
| 171 |  | |
| 172 | public static short getFlipMove(int a,int b) | |
| 173 | 	{
 | |
| 174 | short upperS = flipMove[2*(a*N_MOVE+b)]; | |
| 175 | short lowerS = flipMove[2*(a*N_MOVE+b)+1]; | |
| 176 |  | |
| 177 | if( upperS<0 ) upperS+=256; | |
| 178 | if( lowerS<0 ) lowerS+=256; | |
| 179 |  | |
| 180 | return (short)( (upperS<<8) + lowerS ); | |
| 181 | } | |
| 182 |  | |
| 183 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| 184 | // Parity of the corner permutation. This is the same as the parity for the edge permutation of a valid cube. | |
| 185 | // parity has values 0 and 1 | |
| 186 | 	static short[][] parityMove = { { 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1 },
 | |
| 187 | 			{ 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0 } };
 | |
| 188 |  | |
| 189 | // ***********************************Phase 1 and 2 movetable******************************************************** | |
| 190 |  | |
| 191 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| 192 | // Move table for the four UD-slice edges FR, FL, Bl and BR | |
| 193 | // FRtoBRMove < 11880 in phase 1 | |
| 194 | // FRtoBRMove < 24 in phase 2 | |
| 195 | // FRtoBRMove = 0 for solved cube | |
| 196 | private static byte[] FRtoBR_Move = new byte[2*N_FRtoBR*N_MOVE]; | |
| 197 |  | |
| 198 | public static boolean initialize3(Resources res) | |
| 199 | 	{/*
 | |
| 200 | if( init[2]==true ) return; | |
| 201 |  | |
| 202 | CubieCube a = new CubieCube(); | |
| 203 | 		for (short i = 0; i < N_FRtoBR; i++) {
 | |
| 204 | a.setFRtoBR(i); | |
| 205 | 			for (int j = 0; j < 6; j++) {
 | |
| 206 | 				for (int k = 0; k < 3; k++) {
 | |
| 207 | a.edgeMultiply(CubieCube.moveCube[j]); | |
| 208 | FRtoBR_Move[i][3 * j + k] = a.getFRtoBR(); | |
| 209 | } | |
| 210 | a.edgeMultiply(CubieCube.moveCube[j]); | |
| 211 | } | |
| 212 | } | |
| 213 |  | |
| 214 | init[2]=true; | |
| 215 | */ | |
| 216 |  | |
| 217 | if( init[2]==false ) | |
| 218 | 		  {
 | |
| 219 | try | |
| 220 | 		    {
 | |
| 221 | InputStream is = res.openRawResource(com.threedcell.rubik.R.raw.table3); | |
| 222 | is.read( FRtoBR_Move, 0, 2*N_FRtoBR*N_MOVE); | |
| 223 | } | |
| 224 | catch(Exception ioe) | |
| 225 | 		    {
 | |
| 226 | 		    System.out.println("error reading table3");
 | |
| 227 | return true; | |
| 228 | } | |
| 229 |  | |
| 230 | init[2]=true; | |
| 231 | } | |
| 232 |  | |
| 233 | return false; | |
| 234 | } | |
| 235 |  | |
| 236 | public static short getFRtoBR_Move(int a,int b) | |
| 237 | 	{
 | |
| 238 | short upperS = FRtoBR_Move[2*(a*N_MOVE+b)]; | |
| 239 | short lowerS = FRtoBR_Move[2*(a*N_MOVE+b)+1]; | |
| 240 |  | |
| 241 | if( upperS<0 ) upperS+=256; | |
| 242 | if( lowerS<0 ) lowerS+=256; | |
| 243 |  | |
| 244 | return (short)( (upperS<<8) + lowerS ); | |
| 245 | } | |
| 246 |  | |
| 247 | // *******************************************Phase 1 and 2 movetable************************************************ | |
| 248 |  | |
| 249 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| 250 | // Move table for permutation of six corners. The positions of the DBL and DRB corners are determined by the parity. | |
| 251 | // URFtoDLF < 20160 in phase 1 | |
| 252 | // URFtoDLF < 20160 in phase 2 | |
| 253 | // URFtoDLF = 0 for solved cube. | |
| 254 | private static byte[] URFtoDLF_Move = new byte[2*N_URFtoDLF*N_MOVE]; | |
| 255 |  | |
| 256 | public static boolean initialize4(Resources res) | |
| 257 | 	{/*
 | |
| 258 | if( init[3]==true ) return; | |
| 259 |  | |
| 260 | CubieCube a = new CubieCube(); | |
| 261 | 		for (short i = 0; i < N_URFtoDLF; i++) {
 | |
| 262 | a.setURFtoDLF(i); | |
| 263 | 			for (int j = 0; j < 6; j++) {
 | |
| 264 | 				for (int k = 0; k < 3; k++) {
 | |
| 265 | a.cornerMultiply(CubieCube.moveCube[j]); | |
| 266 | URFtoDLF_Move[i][3 * j + k] = a.getURFtoDLF(); | |
| 267 | } | |
| 268 | a.cornerMultiply(CubieCube.moveCube[j]); | |
| 269 | } | |
| 270 | } | |
| 271 |  | |
| 272 | init[3]=true; | |
| 273 | */ | |
| 274 | if( init[3]==false ) | |
| 275 | 		  {
 | |
| 276 | try | |
| 277 | 		    {
 | |
| 278 | InputStream is = res.openRawResource(com.threedcell.rubik.R.raw.table4); | |
| 279 | is.read( URFtoDLF_Move, 0, 2*N_URFtoDLF*N_MOVE); | |
| 280 | } | |
| 281 | catch(Exception ioe) | |
| 282 | 		    {
 | |
| 283 | 		    System.out.println("error reading table4");
 | |
| 284 | return false; | |
| 285 | } | |
| 286 |  | |
| 287 | init[3]=true; | |
| 288 | } | |
| 289 |  | |
| 290 | return true; | |
| 291 | } | |
| 292 |  | |
| 293 | public static short getURFtoDLF_Move(int a,int b) | |
| 294 | 	{
 | |
| 295 | short upperS = URFtoDLF_Move[2*(a*N_MOVE+b)]; | |
| 296 | short lowerS = URFtoDLF_Move[2*(a*N_MOVE+b)+1]; | |
| 297 |  | |
| 298 | if( upperS<0 ) upperS+=256; | |
| 299 | if( lowerS<0 ) lowerS+=256; | |
| 300 |  | |
| 301 | return (short)( (upperS<<8) + lowerS ); | |
| 302 | } | |
| 303 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| 304 | // Move table for the permutation of six U-face and D-face edges in phase2. The positions of the DL and DB edges are | |
| 305 | // determined by the parity. | |
| 306 | // URtoDF < 665280 in phase 1 | |
| 307 | // URtoDF < 20160 in phase 2 | |
| 308 | // URtoDF = 0 for solved cube. | |
| 309 | private static byte[] URtoDF_Move = new byte[2*N_URtoDF*N_MOVE]; | |
| 310 |  | |
| 311 | public static boolean initialize5(Resources res) | |
| 312 | 	{/*
 | |
| 313 | if( init[4]==true ) return; | |
| 314 |  | |
| 315 | CubieCube a = new CubieCube(); | |
| 316 | 		for (short i = 0; i < N_URtoDF; i++) {
 | |
| 317 | a.setURtoDF(i); | |
| 318 | 			for (int j = 0; j < 6; j++) {
 | |
| 319 | 				for (int k = 0; k < 3; k++) {
 | |
| 320 | a.edgeMultiply(CubieCube.moveCube[j]); | |
| 321 | URtoDF_Move[i][3 * j + k] = (short) a.getURtoDF(); | |
| 322 | // Table values are only valid for phase 2 moves! | |
| 323 | // For phase 1 moves, casting to short is not possible. | |
| 324 | } | |
| 325 | a.edgeMultiply(CubieCube.moveCube[j]); | |
| 326 | } | |
| 327 | } | |
| 328 |  | |
| 329 | init[4]=true; | |
| 330 | */ | |
| 331 | if( init[4]==false ) | |
| 332 | 		  {
 | |
| 333 | try | |
| 334 | 		    {
 | |
| 335 | InputStream is = res.openRawResource(com.threedcell.rubik.R.raw.table5); | |
| 336 | is.read( URtoDF_Move, 0, 2*N_URtoDF*N_MOVE); | |
| 337 | } | |
| 338 | catch(Exception ioe) | |
| 339 | 		    {
 | |
| 340 | 		    System.out.println("error reading table5");
 | |
| 341 | return false; | |
| 342 | } | |
| 343 |  | |
| 344 | init[4]=true; | |
| 345 | } | |
| 346 |  | |
| 347 | return true; | |
| 348 | } | |
| 349 |  | |
| 350 | public static short getURtoDF_Move(int a,int b) | |
| 351 | 	{
 | |
| 352 | short upperS = URtoDF_Move[2*(a*N_MOVE+b)]; | |
| 353 | short lowerS = URtoDF_Move[2*(a*N_MOVE+b)+1]; | |
| 354 |  | |
| 355 | if( upperS<0 ) upperS+=256; | |
| 356 | if( lowerS<0 ) lowerS+=256; | |
| 357 |  | |
| 358 | return (short)( (upperS<<8) + lowerS ); | |
| 359 | } | |
| 360 | // **************************helper move tables to compute URtoDF for the beginning of phase2************************ | |
| 361 |  | |
| 362 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| 363 | // Move table for the three edges UR,UF and UL in phase1. | |
| 364 | private static byte[] URtoUL_Move = new byte[2*N_URtoUL*N_MOVE]; | |
| 365 |  | |
| 366 | public static boolean initialize6(Resources res) | |
| 367 | 	{/*
 | |
| 368 | if( init[5]==true ) return; | |
| 369 |  | |
| 370 | CubieCube a = new CubieCube(); | |
| 371 | 		for (short i = 0; i < N_URtoUL; i++) {
 | |
| 372 | a.setURtoUL(i); | |
| 373 | 			for (int j = 0; j < 6; j++) {
 | |
| 374 | 				for (int k = 0; k < 3; k++) {
 | |
| 375 | a.edgeMultiply(CubieCube.moveCube[j]); | |
| 376 | URtoUL_Move[i][3 * j + k] = a.getURtoUL(); | |
| 377 | } | |
| 378 | a.edgeMultiply(CubieCube.moveCube[j]); | |
| 379 | } | |
| 380 | } | |
| 381 |  | |
| 382 | init[5]=true; | |
| 383 | */ | |
| 384 | if( init[5]==false ) | |
| 385 | 		  {
 | |
| 386 | try | |
| 387 | 		    {
 | |
| 388 | InputStream is = res.openRawResource(com.threedcell.rubik.R.raw.table6); | |
| 389 | is.read( URtoUL_Move, 0, 2*N_URtoUL*N_MOVE); | |
| 390 | } | |
| 391 | catch(Exception ioe) | |
| 392 | 		    {
 | |
| 393 | 		    System.out.println("error reading table6");
 | |
| 394 | return false; | |
| 395 | } | |
| 396 |  | |
| 397 | init[5]=true; | |
| 398 | } | |
| 399 |  | |
| 400 | return true; | |
| 401 | } | |
| 402 |  | |
| 403 | public static short getURtoUL_Move(int a,int b) | |
| 404 | 	{
 | |
| 405 | short upperS = URtoUL_Move[2*(a*N_MOVE+b)]; | |
| 406 | short lowerS = URtoUL_Move[2*(a*N_MOVE+b)+1]; | |
| 407 |  | |
| 408 | if( upperS<0 ) upperS+=256; | |
| 409 | if( lowerS<0 ) lowerS+=256; | |
| 410 |  | |
| 411 | return (short)( (upperS<<8) + lowerS ); | |
| 412 | } | |
| 413 |  | |
| 414 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| 415 | // Move table for the three edges UB,DR and DF in phase1. | |
| 416 | private static byte[] UBtoDF_Move = new byte[2*N_UBtoDF*N_MOVE]; | |
| 417 |  | |
| 418 | public static boolean initialize7(Resources res) | |
| 419 | 	{/*
 | |
| 420 | if( init[6]==true ) return; | |
| 421 |  | |
| 422 | CubieCube a = new CubieCube(); | |
| 423 | 		for (short i = 0; i < N_UBtoDF; i++) {
 | |
| 424 | a.setUBtoDF(i); | |
| 425 | 			for (int j = 0; j < 6; j++) {
 | |
| 426 | 				for (int k = 0; k < 3; k++) {
 | |
| 427 | a.edgeMultiply(CubieCube.moveCube[j]); | |
| 428 | UBtoDF_Move[i][3 * j + k] = a.getUBtoDF(); | |
| 429 | } | |
| 430 | a.edgeMultiply(CubieCube.moveCube[j]); | |
| 431 | } | |
| 432 | } | |
| 433 |  | |
| 434 | init[6]=true; | |
| 435 | */ | |
| 436 | if( init[6]==false ) | |
| 437 | 		  {
 | |
| 438 | try | |
| 439 | 		    {
 | |
| 440 | InputStream is = res.openRawResource(com.threedcell.rubik.R.raw.table7); | |
| 441 | is.read( UBtoDF_Move, 0, 2*N_UBtoDF*N_MOVE); | |
| 442 | } | |
| 443 | catch(Exception ioe) | |
| 444 | 		    {
 | |
| 445 | 		    System.out.println("error reading table7");
 | |
| 446 | return false; | |
| 447 | } | |
| 448 |  | |
| 449 | init[6]=true; | |
| 450 | } | |
| 451 |  | |
| 452 | return true; | |
| 453 | } | |
| 454 |  | |
| 455 | public static short getUBtoDF_Move(int a,int b) | |
| 456 | 	{
 | |
| 457 | short upperS = UBtoDF_Move[2*(a*N_MOVE+b)]; | |
| 458 | short lowerS = UBtoDF_Move[2*(a*N_MOVE+b)+1]; | |
| 459 |  | |
| 460 | if( upperS<0 ) upperS+=256; | |
| 461 | if( lowerS<0 ) lowerS+=256; | |
| 462 |  | |
| 463 | return (short)( (upperS<<8) + lowerS ); | |
| 464 | } | |
| 465 |  | |
| 466 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| 467 | // Table to merge the coordinates of the UR,UF,UL and UB,DR,DF edges at the beginning of phase2 | |
| 468 | private static byte[] MergeURtoULandUBtoDF = new byte[2*336*336]; | |
| 469 |  | |
| 470 | public static boolean initialize8(Resources res) | |
| 471 | 	{/*
 | |
| 472 | if( init[7]==true ) return; | |
| 473 |  | |
| 474 | // for i, j <336 the six edges UR,UF,UL,UB,DR,DF are not in the | |
| 475 | // UD-slice and the index is <20160 | |
| 476 | 		for (short uRtoUL = 0; uRtoUL < 336; uRtoUL++) {
 | |
| 477 | 			for (short uBtoDF = 0; uBtoDF < 336; uBtoDF++) {
 | |
| 478 | MergeURtoULandUBtoDF[uRtoUL][uBtoDF] = (short) CubieCube.getURtoDF(uRtoUL, uBtoDF); | |
| 479 | } | |
| 480 | } | |
| 481 |  | |
| 482 | init[7]=true; | |
| 483 | */ | |
| 484 | if( init[7]==false ) | |
| 485 | 		  {
 | |
| 486 | try | |
| 487 | 		    {
 | |
| 488 | InputStream is = res.openRawResource(com.threedcell.rubik.R.raw.table8); | |
| 489 | is.read( MergeURtoULandUBtoDF, 0, 2*336*336); | |
| 490 | } | |
| 491 | catch(Exception ioe) | |
| 492 | 		    {
 | |
| 493 | 		    System.out.println("error reading table8");
 | |
| 494 | return false; | |
| 495 | } | |
| 496 |  | |
| 497 | init[7]=true; | |
| 498 | } | |
| 499 |  | |
| 500 | return true; | |
| 501 | } | |
| 502 |  | |
| 503 | public static short getMergeURtoULandUBtoDF(int a,int b) | |
| 504 | 	{
 | |
| 505 | short upperS = MergeURtoULandUBtoDF[2*(a*336+b)]; | |
| 506 | short lowerS = MergeURtoULandUBtoDF[2*(a*336+b)+1]; | |
| 507 |  | |
| 508 | if( upperS<0 ) upperS+=256; | |
| 509 | if( lowerS<0 ) lowerS+=256; | |
| 510 |  | |
| 511 | return (short)( (upperS<<8) + lowerS ); | |
| 512 | } | |
| 513 | // ****************************************Pruning tables for the search********************************************* | |
| 514 |  | |
| 515 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| 516 | // Pruning table for the permutation of the corners and the UD-slice edges in phase2. | |
| 517 | // The pruning table entries give a lower estimation for the number of moves to reach the solved cube. | |
| 518 | public static byte[] Slice_URFtoDLF_Parity_Prun = new byte[N_SLICE2 * N_URFtoDLF * N_PARITY / 2]; | |
| 519 |  | |
| 520 | public static boolean initialize9(Resources res) | |
| 521 | 	{
 | |
| 522 |  | |
| 523 | /* | |
| 524 | for (int i = 0; i < N_SLICE2 * N_URFtoDLF * N_PARITY / 2; i++) | |
| 525 | Slice_URFtoDLF_Parity_Prun[i] = -1; | |
| 526 | int depth = 0; | |
| 527 | setPruning(Slice_URFtoDLF_Parity_Prun, 0, (byte) 0); | |
| 528 | int done = 1; | |
| 529 | 		while (done != N_SLICE2 * N_URFtoDLF * N_PARITY) {
 | |
| 530 | 			for (int i = 0; i < N_SLICE2 * N_URFtoDLF * N_PARITY; i++) {
 | |
| 531 | int parity = i % 2; | |
| 532 | int URFtoDLF = (i / 2) / N_SLICE2; | |
| 533 | int slice = (i / 2) % N_SLICE2; | |
| 534 | 				if (getPruning(Slice_URFtoDLF_Parity_Prun, i) == depth) {
 | |
| 535 | 					for (int j = 0; j < 18; j++) {
 | |
| 536 | 						switch (j) {
 | |
| 537 | case 3: | |
| 538 | case 5: | |
| 539 | case 6: | |
| 540 | case 8: | |
| 541 | case 12: | |
| 542 | case 14: | |
| 543 | case 15: | |
| 544 | case 17: | |
| 545 | continue; | |
| 546 | default: | |
| 547 | int newSlice = FRtoBR_Move[slice][j]; | |
| 548 | int newURFtoDLF = URFtoDLF_Move[URFtoDLF][j]; | |
| 549 | int newParity = parityMove[parity][j]; | |
| 550 | 							if (getPruning(Slice_URFtoDLF_Parity_Prun, (N_SLICE2 * newURFtoDLF + newSlice) * 2 + newParity) == 0x0f) {
 | |
| 551 | setPruning(Slice_URFtoDLF_Parity_Prun, (N_SLICE2 * newURFtoDLF + newSlice) * 2 + newParity, | |
| 552 | (byte) (depth + 1)); | |
| 553 | done++; | |
| 554 | } | |
| 555 | } | |
| 556 | } | |
| 557 | } | |
| 558 | } | |
| 559 | depth++; | |
| 560 | } | |
| 561 | */ | |
| 562 |  | |
| 563 | if( init[8]==false ) | |
| 564 | 		  {
 | |
| 565 | try | |
| 566 | 		    {
 | |
| 567 | InputStream is = res.openRawResource(com.threedcell.rubik.R.raw.table9); | |
| 568 | is.read( Slice_URFtoDLF_Parity_Prun, 0, N_SLICE2 * N_URFtoDLF * N_PARITY / 2); | |
| 569 | } | |
| 570 | catch(Exception ioe) | |
| 571 | 		    {
 | |
| 572 | 		    System.out.println("error reading table9");
 | |
| 573 | return false; | |
| 574 | } | |
| 575 |  | |
| 576 | init[8]=true; | |
| 577 | } | |
| 578 |  | |
| 579 | return true; | |
| 580 | } | |
| 581 |  | |
| 582 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| 583 | // Pruning table for the permutation of the edges in phase2. | |
| 584 | // The pruning table entries give a lower estimation for the number of moves to reach the solved cube. | |
| 585 | public static byte[] Slice_URtoDF_Parity_Prun = new byte[N_SLICE2 * N_URtoDF * N_PARITY / 2]; | |
| 586 |  | |
| 587 | public static boolean initialize10(Resources res) | |
| 588 | 	{/*
 | |
| 589 | if( init[9]==true ) return; | |
| 590 |  | |
| 591 | for (int i = 0; i < N_SLICE2 * N_URtoDF * N_PARITY / 2; i++) | |
| 592 | Slice_URtoDF_Parity_Prun[i] = -1; | |
| 593 | int depth = 0; | |
| 594 | setPruning(Slice_URtoDF_Parity_Prun, 0, (byte) 0); | |
| 595 | int done = 1; | |
| 596 | 		while (done != N_SLICE2 * N_URtoDF * N_PARITY) {
 | |
| 597 | 			for (int i = 0; i < N_SLICE2 * N_URtoDF * N_PARITY; i++) {
 | |
| 598 | int parity = i % 2; | |
| 599 | int URtoDF = (i / 2) / N_SLICE2; | |
| 600 | int slice = (i / 2) % N_SLICE2; | |
| 601 | 				if (getPruning(Slice_URtoDF_Parity_Prun, i) == depth) {
 | |
| 602 | 					for (int j = 0; j < 18; j++) {
 | |
| 603 | 						switch (j) {
 | |
| 604 | case 3: | |
| 605 | case 5: | |
| 606 | case 6: | |
| 607 | case 8: | |
| 608 | case 12: | |
| 609 | case 14: | |
| 610 | case 15: | |
| 611 | case 17: | |
| 612 | continue; | |
| 613 | default: | |
| 614 | int newSlice = FRtoBR_Move[slice][j]; | |
| 615 | int newURtoDF = URtoDF_Move[URtoDF][j]; | |
| 616 | int newParity = parityMove[parity][j]; | |
| 617 | 							if (getPruning(Slice_URtoDF_Parity_Prun, (N_SLICE2 * newURtoDF + newSlice) * 2 + newParity) == 0x0f) {
 | |
| 618 | setPruning(Slice_URtoDF_Parity_Prun, (N_SLICE2 * newURtoDF + newSlice) * 2 + newParity, | |
| 619 | (byte) (depth + 1)); | |
| 620 | done++; | |
| 621 | } | |
| 622 | } | |
| 623 | } | |
| 624 | } | |
| 625 | } | |
| 626 | depth++; | |
| 627 | } | |
| 628 |  | |
| 629 | init[9]=true; | |
| 630 | */ | |
| 631 |  | |
| 632 | if( init[9]==false ) | |
| 633 | 		  {
 | |
| 634 | try | |
| 635 | 		    {
 | |
| 636 | InputStream is = res.openRawResource(com.threedcell.rubik.R.raw.table10); | |
| 637 | is.read( Slice_URtoDF_Parity_Prun, 0, N_SLICE2 * N_URtoDF * N_PARITY / 2); | |
| 638 | } | |
| 639 | catch(Exception ioe) | |
| 640 | 		    {
 | |
| 641 | 		    System.out.println("error reading table10");
 | |
| 642 | return false; | |
| 643 | } | |
| 644 |  | |
| 645 | init[9]=true; | |
| 646 | } | |
| 647 |  | |
| 648 | return true; | |
| 649 | } | |
| 650 |  | |
| 651 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| 652 | // Pruning table for the twist of the corners and the position (not permutation) of the UD-slice edges in phase1 | |
| 653 | // The pruning table entries give a lower estimation for the number of moves to reach the H-subgroup. | |
| 654 | public static byte[] Slice_Twist_Prun = new byte[N_SLICE1 * N_TWIST / 2 + 1]; | |
| 655 |  | |
| 656 | public static boolean initialize11(Resources res) | |
| 657 | 	{/*
 | |
| 658 | if( init[10]==true ) return; | |
| 659 |  | |
| 660 | for (int i = 0; i < N_SLICE1 * N_TWIST / 2 + 1; i++) | |
| 661 | Slice_Twist_Prun[i] = -1; | |
| 662 | int depth = 0; | |
| 663 | setPruning(Slice_Twist_Prun, 0, (byte) 0); | |
| 664 | int done = 1; | |
| 665 | 		while (done != N_SLICE1 * N_TWIST) {
 | |
| 666 | 			for (int i = 0; i < N_SLICE1 * N_TWIST; i++) {
 | |
| 667 | int twist = i / N_SLICE1, slice = i % N_SLICE1; | |
| 668 | 				if (getPruning(Slice_Twist_Prun, i) == depth) {
 | |
| 669 | 					for (int j = 0; j < 18; j++) {
 | |
| 670 | int newSlice = FRtoBR_Move[slice * 24][j] / 24; | |
| 671 | int newTwist = twistMove[twist][j]; | |
| 672 | 						if (getPruning(Slice_Twist_Prun, N_SLICE1 * newTwist + newSlice) == 0x0f) {
 | |
| 673 | setPruning(Slice_Twist_Prun, N_SLICE1 * newTwist + newSlice, (byte) (depth + 1)); | |
| 674 | done++; | |
| 675 | } | |
| 676 | } | |
| 677 | } | |
| 678 | } | |
| 679 | depth++; | |
| 680 | } | |
| 681 |  | |
| 682 | init[10]=true; | |
| 683 | */ | |
| 684 | if( init[10]==false ) | |
| 685 | 		  {
 | |
| 686 | try | |
| 687 | 		    {
 | |
| 688 | InputStream is = res.openRawResource(com.threedcell.rubik.R.raw.table11); | |
| 689 | is.read( Slice_Twist_Prun, 0, N_SLICE1 * N_TWIST / 2 + 1); | |
| 690 | } | |
| 691 | catch(Exception ioe) | |
| 692 | 		    {
 | |
| 693 | 		    System.out.println("error reading table11");
 | |
| 694 | return false; | |
| 695 | } | |
| 696 |  | |
| 697 | init[10]=true; | |
| 698 | } | |
| 699 |  | |
| 700 | return true; | |
| 701 | } | |
| 702 |  | |
| 703 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| 704 | // Pruning table for the flip of the edges and the position (not permutation) of the UD-slice edges in phase1 | |
| 705 | // The pruning table entries give a lower estimation for the number of moves to reach the H-subgroup. | |
| 706 | public static byte[] Slice_Flip_Prun = new byte[N_SLICE1 * N_FLIP / 2]; | |
| 707 |  | |
| 708 | public static boolean initialize12(Resources res) | |
| 709 | 	{/*
 | |
| 710 | if( init[11]==true ) return; | |
| 711 |  | |
| 712 | for (int i = 0; i < N_SLICE1 * N_FLIP / 2; i++) | |
| 713 | Slice_Flip_Prun[i] = -1; | |
| 714 | int depth = 0; | |
| 715 | setPruning(Slice_Flip_Prun, 0, (byte) 0); | |
| 716 | int done = 1; | |
| 717 | 		while (done != N_SLICE1 * N_FLIP) {
 | |
| 718 | 			for (int i = 0; i < N_SLICE1 * N_FLIP; i++) {
 | |
| 719 | int flip = i / N_SLICE1, slice = i % N_SLICE1; | |
| 720 | 				if (getPruning(Slice_Flip_Prun, i) == depth) {
 | |
| 721 | 					for (int j = 0; j < 18; j++) {
 | |
| 722 | int newSlice = FRtoBR_Move[slice * 24][j] / 24; | |
| 723 | int newFlip = flipMove[flip][j]; | |
| 724 | 						if (getPruning(Slice_Flip_Prun, N_SLICE1 * newFlip + newSlice) == 0x0f) {
 | |
| 725 | setPruning(Slice_Flip_Prun, N_SLICE1 * newFlip + newSlice, (byte) (depth + 1)); | |
| 726 | done++; | |
| 727 | } | |
| 728 | } | |
| 729 | } | |
| 730 | } | |
| 731 | depth++; | |
| 732 | } | |
| 733 |  | |
| 734 | init[11]=true; | |
| 735 | */ | |
| 736 | if( init[11]==false ) | |
| 737 | 		  {
 | |
| 738 | try | |
| 739 | 		    {
 | |
| 740 | InputStream is = res.openRawResource(com.threedcell.rubik.R.raw.table12); | |
| 741 | is.read( Slice_Flip_Prun, 0, N_SLICE1 * N_FLIP / 2); | |
| 742 | } | |
| 743 | catch(Exception ioe) | |
| 744 | 		    {
 | |
| 745 | 		    System.out.println("error reading table12");
 | |
| 746 | return false; | |
| 747 | } | |
| 748 |  | |
| 749 | init[11]=true; | |
| 750 | } | |
| 751 |  | |
| 752 | return true; | |
| 753 | } | |
| 754 |  | |
| 755 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| 756 | // Set pruning value in table. Two values are stored in one byte. | |
| 757 | 	static void setPruning(byte[] table, int index, byte value) {
 | |
| 758 | if ((index & 1) == 0) | |
| 759 | table[index / 2] &= 0xf0 | value; | |
| 760 | else | |
| 761 | table[index / 2] &= 0x0f | (value << 4); | |
| 762 | } | |
| 763 |  | |
| 764 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| 765 | // Extract pruning value | |
| 766 | 	static byte getPruning(byte[] table, int index) {
 | |
| 767 | if ((index & 1) == 0) | |
| 768 | return (byte) (table[index / 2] & 0x0f); | |
| 769 | else | |
| 770 | return (byte) ((table[index / 2] & 0xf0) >>> 4); | |
| 771 | } | |
| 772 | } | |
| src/main/java/org/distorted/solvers/cube3/Corner.java | ||
|---|---|---|
| 1 | package org.distorted.solvers.cube3; | |
| 2 |  | |
| 3 | //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| 4 | //The names of the corner positions of the cube. Corner URF e.g., has an U(p), a R(ight) and a F(ront) facelet | |
| 5 |  | |
| 6 | class Corner | |
| 7 |   {
 | |
| 8 | public static final int URF =0; | |
| 9 | public static final int UFL =1; | |
| 10 | public static final int ULB =2; | |
| 11 | public static final int UBR =3; | |
| 12 | public static final int DFR =4; | |
| 13 | public static final int DLF =5; | |
| 14 | public static final int DBL =6; | |
| 15 | public static final int DRB =7; | |
| 16 | } | |
| src/main/java/org/distorted/solvers/cube3/CubieCube.java | ||
|---|---|---|
| 1 | package org.distorted.solvers.cube3; | |
| 2 |  | |
| 3 | //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| 4 | //Cube on the cubie level | |
| 5 | class CubieCube | |
| 6 |   {
 | |
| 7 | private static int[][] cnk = new int[12][7]; | |
| 8 |  | |
| 9 | private static byte[] tmpByte12 = new byte[12]; | |
| 10 | private static byte[] tmpByte8 = new byte[8]; | |
| 11 |  | |
| 12 | private static int[] tmpEdge12 = new int[12]; | |
| 13 | private static int[] tmpEdge6 = new int[6]; | |
| 14 | private static int[] tmpEdge4 = new int[4]; | |
| 15 | private static int[] tmpEdge3 = new int[3]; | |
| 16 |  | |
| 17 | private static int[] tmpCorner6 = new int[6]; | |
| 18 | private static int[] tmpCorner8 = new int[8]; | |
| 19 |  | |
| 20 | // initialize to Id-Cube | |
| 21 |  | |
| 22 | // corner permutation | |
| 23 |   int[] cp = { Corner.URF, Corner.UFL, Corner.ULB, Corner.UBR, Corner.DFR, Corner.DLF, Corner.DBL, Corner.DRB };
 | |
| 24 |  | |
| 25 | // corner orientation | |
| 26 |   byte[] co = { 0, 0, 0, 0, 0, 0, 0, 0 };
 | |
| 27 |  | |
| 28 | // edge permutation | |
| 29 |   int[] ep = { Edge.UR, Edge.UF, Edge.UL, Edge.UB, Edge.DR, Edge.DF, Edge.DL, Edge.DB, Edge.FR, Edge.FL, Edge.BL, Edge.BR };
 | |
| 30 |  | |
| 31 | // edge orientation | |
| 32 |   byte[] eo = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
 | |
| 33 |  | |
| 34 | // ************************************** Moves on the cubie level *************************************************** | |
| 35 |  | |
| 36 |   private static int[]  cpU = { Corner.UBR, Corner.URF, Corner.UFL, Corner.ULB, Corner.DFR, Corner.DLF, Corner.DBL, Corner.DRB };
 | |
| 37 |   private static byte[] coU = { 0, 0, 0, 0, 0, 0, 0, 0 };
 | |
| 38 |   private static int[]  epU = { Edge.UB, Edge.UR, Edge.UF, Edge.UL, Edge.DR, Edge.DF, Edge.DL, Edge.DB, Edge.FR, Edge.FL, Edge.BL, Edge.BR };
 | |
| 39 |   private static byte[] eoU = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
 | |
| 40 |  | |
| 41 |   private static int[]  cpR = { Corner.DFR, Corner.UFL, Corner.ULB, Corner.URF, Corner.DRB, Corner.DLF, Corner.DBL, Corner.UBR };
 | |
| 42 |   private static byte[] coR = { 2, 0, 0, 1, 1, 0, 0, 2 };
 | |
| 43 |   private static int[]  epR = { Edge.FR, Edge.UF, Edge.UL, Edge.UB, Edge.BR, Edge.DF, Edge.DL, Edge.DB, Edge.DR, Edge.FL, Edge.BL, Edge.UR };
 | |
| 44 |   private static byte[] eoR = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
 | |
| 45 |  | |
| 46 |   private static int[]  cpF = { Corner.UFL, Corner.DLF, Corner.ULB, Corner.UBR, Corner.URF, Corner.DFR, Corner.DBL, Corner.DRB };
 | |
| 47 |   private static byte[] coF = { 1, 2, 0, 0, 2, 1, 0, 0 };
 | |
| 48 |   private static int[]  epF = { Edge.UR, Edge.FL, Edge.UL, Edge.UB, Edge.DR, Edge.FR, Edge.DL, Edge.DB, Edge.UF, Edge.DF, Edge.BL, Edge.BR };
 | |
| 49 |   private static byte[] eoF = { 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0 };
 | |
| 50 |  | |
| 51 |   private static int[]  cpD = { Corner.URF, Corner.UFL, Corner.ULB, Corner.UBR, Corner.DLF, Corner.DBL, Corner.DRB, Corner.DFR };
 | |
| 52 |   private static byte[] coD = { 0, 0, 0, 0, 0, 0, 0, 0 };
 | |
| 53 |   private static int[]  epD = { Edge.UR, Edge.UF, Edge.UL, Edge.UB, Edge.DF, Edge.DL, Edge.DB, Edge.DR, Edge.FR, Edge.FL, Edge.BL, Edge.BR };
 | |
| 54 |   private static byte[] eoD = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
 | |
| 55 |  | |
| 56 |   private static int[]  cpL = { Corner.URF, Corner.ULB, Corner.DBL, Corner.UBR, Corner.DFR, Corner.UFL, Corner.DLF, Corner.DRB };
 | |
| 57 |   private static byte[] coL = { 0, 1, 2, 0, 0, 2, 1, 0 };
 | |
| 58 |   private static int[]  epL = { Edge.UR, Edge.UF, Edge.BL, Edge.UB, Edge.DR, Edge.DF, Edge.FL, Edge.DB, Edge.FR, Edge.UL, Edge.DL, Edge.BR };
 | |
| 59 |   private static byte[] eoL = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
 | |
| 60 |  | |
| 61 |   private static int[]  cpB = { Corner.URF, Corner.UFL, Corner.UBR, Corner.DRB, Corner.DFR, Corner.DLF, Corner.ULB, Corner.DBL };
 | |
| 62 |   private static byte[] coB = { 0, 0, 1, 2, 0, 0, 2, 1 };
 | |
| 63 |   private static int[]  epB = { Edge.UR, Edge.UF, Edge.UL, Edge.BR, Edge.DR, Edge.DF, Edge.DL, Edge.BL, Edge.FR, Edge.FL, Edge.UB, Edge.DB };
 | |
| 64 |   private static byte[] eoB = { 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1 };
 | |
| 65 |  | |
| 66 | // this CubieCube array represents the 6 basic cube moves | |
| 67 | static CubieCube[] moveCube = new CubieCube[6]; | |
| 68 |  | |
| 69 | static | |
| 70 |     {
 | |
| 71 | moveCube[0] = new CubieCube(); | |
| 72 | moveCube[0].cp = cpU; | |
| 73 | moveCube[0].co = coU; | |
| 74 | moveCube[0].ep = epU; | |
| 75 | moveCube[0].eo = eoU; | |
| 76 |  | |
| 77 | moveCube[1] = new CubieCube(); | |
| 78 | moveCube[1].cp = cpR; | |
| 79 | moveCube[1].co = coR; | |
| 80 | moveCube[1].ep = epR; | |
| 81 | moveCube[1].eo = eoR; | |
| 82 |  | |
| 83 | moveCube[2] = new CubieCube(); | |
| 84 | moveCube[2].cp = cpF; | |
| 85 | moveCube[2].co = coF; | |
| 86 | moveCube[2].ep = epF; | |
| 87 | moveCube[2].eo = eoF; | |
| 88 |  | |
| 89 | moveCube[3] = new CubieCube(); | |
| 90 | moveCube[3].cp = cpD; | |
| 91 | moveCube[3].co = coD; | |
| 92 | moveCube[3].ep = epD; | |
| 93 | moveCube[3].eo = eoD; | |
| 94 |  | |
| 95 | moveCube[4] = new CubieCube(); | |
| 96 | moveCube[4].cp = cpL; | |
| 97 | moveCube[4].co = coL; | |
| 98 | moveCube[4].ep = epL; | |
| 99 | moveCube[4].eo = eoL; | |
| 100 |  | |
| 101 | moveCube[5] = new CubieCube(); | |
| 102 | moveCube[5].cp = cpB; | |
| 103 | moveCube[5].co = coB; | |
| 104 | moveCube[5].ep = epB; | |
| 105 | moveCube[5].eo = eoB; | |
| 106 | } | |
| 107 |  | |
| 108 | static | |
| 109 |     {
 | |
| 110 | for(int n=0; n<12; n++) | |
| 111 | for(int k=0; k<7; k++) | |
| 112 | cnk[n][k] = -1; | |
| 113 | } | |
| 114 |  | |
| 115 |   CubieCube() { };
 | |
| 116 |  | |
| 117 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| 118 | CubieCube(int[] cp, byte[] co, int[] ep, byte[] eo) | |
| 119 |     {
 | |
| 120 | this(); | |
| 121 |  | |
| 122 | for (int i = 0; i < 8; i++) | |
| 123 |       {
 | |
| 124 | this.cp[i] = cp[i]; | |
| 125 | this.co[i] = co[i]; | |
| 126 | } | |
| 127 | for (int i = 0; i < 12; i++) | |
| 128 |       {
 | |
| 129 | this.ep[i] = ep[i]; | |
| 130 | this.eo[i] = eo[i]; | |
| 131 | } | |
| 132 | } | |
| 133 |  | |
| 134 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| 135 | // n choose k | |
| 136 | static int Cnk(int n, int k) | |
| 137 |     {
 | |
| 138 | if( cnk[n][k]<0 ) | |
| 139 |       {
 | |
| 140 | int i, j, s; | |
| 141 |  | |
| 142 |       if (n < k) { cnk[n][k]=0; return 0; }
 | |
| 143 | if (k > n / 2) k = n - k; | |
| 144 |  | |
| 145 | for (s = 1, i = n, j = 1; i != n - k; i--, j++) | |
| 146 |         {
 | |
| 147 | s *= i; | |
| 148 | s /= j; | |
| 149 | } | |
| 150 | cnk[n][k]= s; | |
| 151 | } | |
| 152 |  | |
| 153 | return cnk[n][k]; | |
| 154 | } | |
| 155 |  | |
| 156 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| 157 | static void rotateLeft(int[] arr, int l, int r) | |
| 158 | // Left rotation of all array elements between l and r | |
| 159 |     {
 | |
| 160 | int tmp = arr[l]; | |
| 161 | for (int i = l; i < r; i++) arr[i] = arr[i + 1]; | |
| 162 | arr[r] = tmp; | |
| 163 | } | |
| 164 |  | |
| 165 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| 166 | static void rotateRight(int[] arr, int l, int r) | |
| 167 | // Right rotation of all array elements between l and r | |
| 168 |     {
 | |
| 169 | int tmp = arr[r]; | |
| 170 | for (int i = r; i > l; i--) arr[i] = arr[i - 1]; | |
| 171 | arr[l] = tmp; | |
| 172 | } | |
| 173 |  | |
| 174 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| 175 | // return cube in facelet representation | |
| 176 | FaceCube toFaceCube() | |
| 177 |     {
 | |
| 178 | FaceCube fcRet = new FaceCube(); | |
| 179 |  | |
| 180 | for ( int c=Corner.URF; c<=Corner.DRB; c++) | |
| 181 |       {
 | |
| 182 | int j = cp[c]; // cornercubie with index j is at cornerposition with index i | |
| 183 | byte ori = co[c];// Orientation of this cubie | |
| 184 |  | |
| 185 | for (int n = 0; n < 3; n++) | |
| 186 | fcRet.f[FaceCube.cornerFacelet[c][(n + ori) % 3]] = FaceCube.cornerColor[j][n]; | |
| 187 | } | |
| 188 |  | |
| 189 | for ( int e=Edge.UR; e<=Edge.BR; e++) | |
| 190 |       {
 | |
| 191 | int j = ep[e]; // edgecubie with index j is at edgeposition with index i | |
| 192 | byte ori = eo[e];// Orientation of this cubie | |
| 193 |  | |
| 194 | for (int n = 0; n < 2; n++) | |
| 195 | fcRet.f[FaceCube.edgeFacelet[e][(n + ori) % 2]] = FaceCube.edgeColor[j][n]; | |
| 196 | } | |
| 197 |  | |
| 198 | return fcRet; | |
| 199 | } | |
| 200 |  | |
| 201 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| 202 | // Multiply this CubieCube with another cubiecube b, restricted to the corners.<br> | |
| 203 | // Because we also describe reflections of the whole cube by permutations, we get a complication with the corners. The | |
| 204 | // orientations of mirrored corners are described by the numbers 3, 4 and 5. The composition of the orientations | |
| 205 | // cannot | |
| 206 | // be computed by addition modulo three in the cyclic group C3 any more. Instead the rules below give an addition in | |
| 207 | // the dihedral group D3 with 6 elements.<br> | |
| 208 | // | |
| 209 | // NOTE: Because we do not use symmetry reductions and hence no mirrored cubes in this simple implementation of the | |
| 210 | // Two-Phase-Algorithm, some code is not necessary here. | |
| 211 | // | |
| 212 | void cornerMultiply(CubieCube b) | |
| 213 |     {
 | |
| 214 | for ( int corn=Corner.URF; corn<=Corner.DRB; corn++) | |
| 215 |       {
 | |
| 216 | tmpCorner8[corn] = cp[b.cp[corn]]; | |
| 217 | byte oriA = co[b.cp[corn]]; | |
| 218 | byte oriB = b.co[corn]; | |
| 219 | byte ori = 0; | |
| 220 |  | |
| 221 | if (oriA < 3 && oriB < 3) // if both cubes are regular cubes... | |
| 222 |         {
 | |
| 223 | ori = (byte) (oriA + oriB); // just do an addition modulo 3 here | |
| 224 | if (ori >= 3) ori -= 3; // the composition is a regular cube | |
| 225 |  | |
| 226 | // +++++++++++++++++++++not used in this implementation +++++++++++++++++++++++++++++++++++ | |
| 227 | } | |
| 228 | else if (oriA < 3 && oriB >= 3) // if cube b is in a mirrored state... | |
| 229 |         {
 | |
| 230 | ori = (byte) (oriA + oriB); | |
| 231 | if (ori >= 6) ori -= 3; // the composition is a mirrored cube | |
| 232 | } | |
| 233 | else if (oriA >= 3 && oriB < 3) // if cube a is an a mirrored state... | |
| 234 | 	{
 | |
| 235 | ori = (byte) (oriA - oriB); | |
| 236 | if (ori < 3) ori += 3; // the composition is a mirrored cube | |
| 237 | } | |
| 238 | else if (oriA >= 3 && oriB >= 3) // if both cubes are in mirrored states... | |
| 239 | 	{
 | |
| 240 | ori = (byte) (oriA - oriB); | |
| 241 | if (ori < 0) ori += 3; // the composition is a regular cube | |
| 242 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| 243 | } | |
| 244 |  | |
| 245 | tmpByte8[corn] = ori; | |
| 246 | } | |
| 247 |  | |
| 248 | for ( int c=Corner.URF; c<=Corner.DRB; c++) | |
| 249 |       {
 | |
| 250 | cp[c] = tmpCorner8[c]; | |
| 251 | co[c] = tmpByte8[c]; | |
| 252 | } | |
| 253 | } | |
| 254 |  | |
| 255 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| 256 | // Multiply this CubieCube with another cubiecube b, restricted to the edges. | |
| 257 | void edgeMultiply(CubieCube b) | |
| 258 |     {
 | |
| 259 | for ( int edge=Edge.UR; edge<=Edge.BR; edge++) | |
| 260 |       {
 | |
| 261 | tmpEdge12[edge] = ep[b.ep[edge]]; | |
| 262 | tmpByte12[edge] = (byte) ((b.eo[edge] + eo[b.ep[edge]]) % 2); | |
| 263 | } | |
| 264 |  | |
| 265 | for ( int e=Edge.UR; e<=Edge.BR; e++) | |
| 266 |       {
 | |
| 267 | ep[e] = tmpEdge12[e]; | |
| 268 | eo[e] = tmpByte12[e]; | |
| 269 | } | |
| 270 | } | |
| 271 |  | |
| 272 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| 273 | // Multiply this CubieCube with another CubieCube b. | |
| 274 | void multiply(CubieCube b) | |
| 275 |     {
 | |
| 276 | cornerMultiply(b); | |
| 277 | //edgeMultiply(b); | |
| 278 | } | |
| 279 |  | |
| 280 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| 281 | // Compute the inverse CubieCube | |
| 282 | void invCubieCube(CubieCube c) | |
| 283 |     {
 | |
| 284 | for ( int edge=Edge.UR; edge<=Edge.BR; edge++) c.ep[ep[edge]] = edge; | |
| 285 | for ( int edge=Edge.UR; edge<=Edge.BR; edge++) c.eo[edge] = eo[c.ep[edge]]; | |
| 286 |  | |
| 287 | for ( int corn=Corner.URF; corn<=Corner.DRB; corn++) c.cp[cp[corn]] = corn; | |
| 288 | for ( int corn=Corner.URF; corn<=Corner.DRB; corn++) | |
| 289 |       {
 | |
| 290 | byte ori = co[c.cp[corn]]; | |
| 291 | if (ori >= 3)// Just for completeness. We do not invert mirrored cubes in the program. | |
| 292 | c.co[corn] = ori; | |
| 293 | else | |
| 294 |         {// the standard case
 | |
| 295 | c.co[corn] = (byte) -ori; | |
| 296 | if (c.co[corn] < 0) c.co[corn] += 3; | |
| 297 | } | |
| 298 | } | |
| 299 | } | |
| 300 |  | |
| 301 | // ********************************************* Get and set coordinates ********************************************* | |
| 302 |  | |
| 303 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| 304 | // return the twist of the 8 corners. 0 <= twist < 3^7 | |
| 305 | short getTwist() | |
| 306 |     {
 | |
| 307 | short ret = 0; | |
| 308 |  | |
| 309 | for ( int i=Corner.URF; i<Corner.DRB; i++) | |
| 310 | ret = (short) (3 * ret + co[i]); | |
| 311 |  | |
| 312 | return ret; | |
| 313 | } | |
| 314 |  | |
| 315 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| 316 | void setTwist(short twist) | |
| 317 |     {
 | |
| 318 | int twistParity = 0; | |
| 319 |  | |
| 320 | for ( int i=Corner.DRB-1; i>=Corner.URF; i--) | |
| 321 |       {
 | |
| 322 | twistParity += co[i] = (byte) (twist % 3); | |
| 323 | twist /= 3; | |
| 324 | } | |
| 325 | co[Corner.DRB] = (byte) ((3 - twistParity % 3) % 3); | |
| 326 | } | |
| 327 |  | |
| 328 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| 329 | // return the flip of the 12 edges. 0<= flip < 2^11 | |
| 330 | short getFlip() | |
| 331 |     {
 | |
| 332 | short ret = 0; | |
| 333 |  | |
| 334 | for ( int i=Edge.UR; i<Edge.BR; i++) | |
| 335 | ret = (short) (2 * ret + eo[i]); | |
| 336 |  | |
| 337 | return ret; | |
| 338 | } | |
| 339 |  | |
| 340 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| 341 | void setFlip(short flip) | |
| 342 |     {
 | |
| 343 | int flipParity = 0; | |
| 344 |  | |
| 345 | for (int i=Edge.BR-1; i>=Edge.UR; i--) | |
| 346 |       {
 | |
| 347 | flipParity += eo[i] = (byte) (flip % 2); | |
| 348 | flip /= 2; | |
| 349 | } | |
| 350 | eo[Edge.BR] = (byte) ((2 - flipParity % 2) % 2); | |
| 351 | } | |
| 352 |  | |
| 353 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| 354 | // Parity of the corner permutation | |
| 355 | short cornerParity() | |
| 356 |     {
 | |
| 357 | int s = 0; | |
| 358 |  | |
| 359 | for (int i=Corner.DRB; i>=Corner.URF+1; i--) | |
| 360 | for (int j = i - 1; j >= Corner.URF; j--) | |
| 361 | if (cp[j] > cp[i]) s++; | |
| 362 |  | |
| 363 | return (short) (s % 2); | |
| 364 | } | |
| 365 |  | |
| 366 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| 367 | // Parity of the edges permutation. Parity of corners and edges are the same if the cube is solvable. | |
| 368 | short edgeParity() | |
| 369 |     {
 | |
| 370 | int s = 0; | |
| 371 |  | |
| 372 | for (int i = Edge.BR; i >= Edge.UR+1; i--) | |
| 373 | for (int j = i - 1; j >= Edge.UR; j--) | |
| 374 | if (ep[j] > ep[i]) s++; | |
| 375 |  | |
| 376 | return (short) (s % 2); | |
| 377 | } | |
| 378 |  | |
| 379 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| 380 | // permutation of the UD-slice edges FR,FL,BL and BR | |
| 381 | short getFRtoBR() | |
| 382 |     {
 | |
| 383 | int a = 0, x = 0; | |
| 384 |  | |
| 385 | // compute the index a < (12 choose 4) and the permutation array perm. | |
| 386 | for (int j = Edge.BR; j >= Edge.UR; j--) | |
| 387 | if (Edge.FR <= ep[j] && ep[j] <= Edge.BR) | |
| 388 |         {
 | |
| 389 | a += Cnk(11 - j, x + 1); | |
| 390 | tmpEdge4[3 - x++] = ep[j]; | |
| 391 | } | |
| 392 |  | |
| 393 | int b = 0; | |
| 394 | for (int j = 3; j > 0; j--)// compute the index b < 4! for the permutation in perm | |
| 395 |       {
 | |
| 396 | int k = 0; | |
| 397 | while (tmpEdge4[j] != j + 8) | |
| 398 |         {
 | |
| 399 | rotateLeft(tmpEdge4, 0, j); | |
| 400 | k++; | |
| 401 | } | |
| 402 | b = (j + 1) * b + k; | |
| 403 | } | |
| 404 |  | |
| 405 | return (short) (24 * a + b); | |
| 406 | } | |
| 407 |  | |
| 408 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| 409 | void setFRtoBR(short idx) | |
| 410 |     {
 | |
| 411 | int x; | |
| 412 |     int[] sliceEdge = { Edge.FR, Edge.FL, Edge.BL, Edge.BR };
 | |
| 413 |     int[] otherEdge = { Edge.UR, Edge.UF, Edge.UL, Edge.UB, Edge.DR, Edge.DF, Edge.DL, Edge.DB };
 | |
| 414 | int b = idx % 24; // Permutation | |
| 415 | int a = idx / 24; // Combination | |
| 416 |  | |
| 417 | for ( int e=Edge.UR; e<=Edge.BR; e++) ep[e] = Edge.DB;// Use UR to invalidate all edges | |
| 418 |  | |
| 419 | for (int j = 1, k; j < 4; j++)// generate permutation from index b | |
| 420 |       {
 | |
| 421 | k = b % (j + 1); | |
| 422 | b /= j + 1; | |
| 423 | while (k-- > 0) rotateRight(sliceEdge, 0, j); | |
| 424 | } | |
| 425 |  | |
| 426 | x = 3;// generate combination and set slice edges | |
| 427 |  | |
| 428 | for (int j = Edge.UR; j <= Edge.BR; j++) | |
| 429 | if (a - Cnk(11 - j, x + 1) >= 0) | |
| 430 |         {
 | |
| 431 | ep[j] = sliceEdge[3 - x]; | |
| 432 | a -= Cnk(11 - j, x-- + 1); | |
| 433 | } | |
| 434 |  | |
| 435 | x = 0; // set the remaining edges UR..DB | |
| 436 |  | |
| 437 | for (int j = Edge.UR; j <= Edge.BR; j++) | |
| 438 | if (ep[j] == Edge.DB) | |
| 439 | ep[j] = otherEdge[x++]; | |
| 440 |  | |
| 441 | } | |
| 442 |  | |
| 443 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| 444 | // Permutation of all corners except DBL and DRB | |
| 445 | short getURFtoDLF() | |
| 446 |     {
 | |
| 447 | int a = 0, x = 0; | |
| 448 |  | |
| 449 | // compute the index a < (8 choose 6) and the corner permutation. | |
| 450 | for (int j = Corner.URF; j <= Corner.DRB; j++) | |
| 451 | if (cp[j] <= Corner.DLF) | |
| 452 |         {
 | |
| 453 | a += Cnk(j, x + 1); | |
| 454 | tmpCorner6[x++] = cp[j]; | |
| 455 | } | |
| 456 |  | |
| 457 | int b = 0; | |
| 458 |  | |
| 459 | for (int j = 5; j > 0; j--)// compute the index b < 6! for the permutation in corner6 | |
| 460 |       {
 | |
| 461 | int k = 0; | |
| 462 |  | |
| 463 | while (tmpCorner6[j] != j) | |
| 464 |         {
 | |
| 465 | rotateLeft(tmpCorner6, 0, j); | |
| 466 | k++; | |
| 467 | } | |
| 468 | b = (j + 1) * b + k; | |
| 469 | } | |
| 470 |  | |
| 471 | return (short) (720 * a + b); | |
| 472 | } | |
| 473 |  | |
| 474 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| 475 | void setURFtoDLF(short idx) | |
| 476 |     {
 | |
| 477 | int x; | |
| 478 |  | |
| 479 |     int[] corner6 = { Corner.URF, Corner.UFL, Corner.ULB, Corner.UBR, Corner.DFR, Corner.DLF };
 | |
| 480 |     int[] otherCorner = { Corner.DBL, Corner.DRB };
 | |
| 481 | int b = idx % 720; // Permutation | |
| 482 | int a = idx / 720; // Combination | |
| 483 |  | |
| 484 | for ( int c=Corner.URF; c<=Corner.DRB; c++) cp[c] = Corner.DRB;// Use DRB to invalidate all corners | |
| 485 |  | |
| 486 | for (int j = 1, k; j < 6; j++)// generate permutation from index b | |
| 487 |       {
 | |
| 488 | k = b % (j + 1); | |
| 489 | b /= j + 1; | |
| 490 | while (k-- > 0) rotateRight(corner6, 0, j); | |
| 491 | } | |
| 492 |  | |
| 493 | x = 5;// generate combination and set corners | |
| 494 |  | |
| 495 | for (int j = Corner.DRB; j >= 0; j--) | |
| 496 | if (a - Cnk(j, x + 1) >= 0) | |
| 497 |         {
 | |
| 498 | cp[j] = corner6[x]; | |
| 499 | a -= Cnk(j, x-- + 1); | |
| 500 | } | |
| 501 |  | |
| 502 | x = 0; | |
| 503 |  | |
| 504 | for (int j = Corner.URF; j <= Corner.DRB; j++) | |
| 505 | if (cp[j] == Corner.DRB) | |
| 506 | cp[j] = otherCorner[x++]; | |
| 507 | } | |
| 508 |  | |
| 509 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| 510 | // Permutation of the six edges UR,UF,UL,UB,DR,DF. | |
| 511 | int getURtoDF() | |
| 512 |     {
 | |
| 513 | int a = 0, x = 0; | |
| 514 | // compute the index a < (12 choose 6) and the edge permutation. | |
| 515 |  | |
| 516 | for (int j = Edge.UR; j <= Edge.BR; j++) | |
| 517 | if (ep[j] <= Edge.DF) | |
| 518 |         {
 | |
| 519 | a += Cnk(j, x + 1); | |
| 520 | tmpEdge6[x++] = ep[j]; | |
| 521 | } | |
| 522 |  | |
| 523 | int b = 0; | |
| 524 |  | |
| 525 | for (int j = 5; j > 0; j--)// compute the index b < 6! for the permutation in edge6 | |
| 526 |       {
 | |
| 527 | int k = 0; | |
| 528 |  | |
| 529 | while (tmpEdge6[j] != j) | |
| 530 |         {
 | |
| 531 | rotateLeft(tmpEdge6, 0, j); | |
| 532 | k++; | |
| 533 | } | |
| 534 | b = (j + 1) * b + k; | |
| 535 | } | |
| 536 | return 720 * a + b; | |
| 537 | } | |
| 538 |  | |
| 539 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| 540 | void setURtoDF(int idx) | |
| 541 |     {
 | |
| 542 | int x; | |
| 543 |     int[] edge6 = { Edge.UR, Edge.UF, Edge.UL, Edge.UB, Edge.DR, Edge.DF };
 | |
| 544 |     int[] otherEdge = { Edge.DL, Edge.DB, Edge.FR, Edge.FL, Edge.BL, Edge.BR };
 | |
| 545 | int b = idx % 720; // Permutation | |
| 546 | int a = idx / 720; // Combination | |
| 547 |  | |
| 548 | for ( int e=Edge.UR; e<=Edge.BR; e++) ep[e] = Edge.BR;// Use BR to invalidate all edges | |
| 549 |  | |
| 550 | for (int j = 1, k; j < 6; j++)// generate permutation from index b | |
| 551 |       {
 | |
| 552 | k = b % (j + 1); | |
| 553 | b /= j + 1; | |
| 554 | while (k-- > 0) rotateRight(edge6, 0, j); | |
| 555 | } | |
| 556 |  | |
| 557 | x = 5;// generate combination and set edges | |
| 558 |  | |
| 559 | for (int j = Edge.BR; j >= 0; j--) | |
| 560 | if (a - Cnk(j, x + 1) >= 0) | |
| 561 |         {
 | |
| 562 | ep[j] = edge6[x]; | |
| 563 | a -= Cnk(j, x-- + 1); | |
| 564 | } | |
| 565 |  | |
| 566 | x = 0; // set the remaining edges DL..BR | |
| 567 |  | |
| 568 | for (int j = Edge.UR; j <= Edge.BR; j++) | |
| 569 | if (ep[j] == Edge.BR) | |
| 570 | ep[j] = otherEdge[x++]; | |
| 571 | } | |
| 572 |  | |
| 573 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| 574 | // Permutation of the six edges UR,UF,UL,UB,DR,DF | |
| 575 | public static int getURtoDF(short idx1, short idx2) | |
| 576 |     {
 | |
| 577 | CubieCube a = new CubieCube(); | |
| 578 | CubieCube b = new CubieCube(); | |
| 579 | a.setURtoUL(idx1); | |
| 580 | b.setUBtoDF(idx2); | |
| 581 |  | |
| 582 | for (int i = 0; i < 8; i++) | |
| 583 |       {
 | |
| 584 | if (a.ep[i] != Edge.BR) | |
| 585 | if (b.ep[i] != Edge.BR)// collision | |
| 586 | return -1; | |
| 587 | else | |
| 588 | b.ep[i] = a.ep[i]; | |
| 589 | } | |
| 590 |  | |
| 591 | return b.getURtoDF(); | |
| 592 | } | |
| 593 |  | |
| 594 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| 595 | // Permutation of the three edges UR,UF,UL | |
| 596 | short getURtoUL() | |
| 597 |     {
 | |
| 598 | int a = 0, x = 0; | |
| 599 | // compute the index a < (12 choose 3) and the edge permutation. | |
| 600 | for (int j = Edge.UR; j <= Edge.BR; j++) | |
| 601 | if (ep[j] <= Edge.UL) | |
| 602 |         {
 | |
| 603 | a += Cnk(j, x + 1); | |
| 604 | tmpEdge3[x++] = ep[j]; | |
| 605 | } | |
| 606 |  | |
| 607 | int b = 0; | |
| 608 |  | |
| 609 | for (int j = 2; j > 0; j--)// compute the index b < 3! for the permutation in edge3 | |
| 610 |       {
 | |
| 611 | int k = 0; | |
| 612 | while (tmpEdge3[j] != j) | |
| 613 |         {
 | |
| 614 | rotateLeft(tmpEdge3, 0, j); | |
| 615 | k++; | |
| 616 | } | |
| 617 | b = (j + 1) * b + k; | |
| 618 | } | |
| 619 |  | |
| 620 | return (short) (6 * a + b); | |
| 621 | } | |
| 622 |  | |
| 623 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| 624 | void setURtoUL(short idx) | |
| 625 |     {
 | |
| 626 | int x; | |
| 627 |     int[] edge3 = { Edge.UR, Edge.UF, Edge.UL };
 | |
| 628 | int b = idx % 6; // Permutation | |
| 629 | int a = idx / 6; // Combination | |
| 630 |  | |
| 631 | for (int e = Edge.UR; e <= Edge.BR; e++) ep[e] = Edge.BR;// Use BR to invalidate all edges | |
| 632 |  | |
| 633 | for (int j = 1, k; j < 3; j++)// generate permutation from index b | |
| 634 |       {
 | |
| 635 | k = b % (j + 1); | |
| 636 | b /= j + 1; | |
| 637 |  | |
| 638 | while (k-- > 0) rotateRight(edge3, 0, j); | |
| 639 | } | |
| 640 |  | |
Also available in: Unified diff
More support for the 3x3x3 Solver: add the actual 3x3x3 solver mechanism.