Project

General

Profile

« Previous | Next » 

Revision b95ceafc

Added by Leszek Koltunski about 4 years ago

More support for the 3x3x3 Solver: add the actual 3x3x3 solver mechanism.

View differences:

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

  
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff