Project

General

Profile

Download (15.3 KB) Statistics
| Branch: | Revision:

distorted-objectlib / src / main / java / org / distorted / objectlib / kociemba / SolverCubieCube.java @ 6777e712

1
/*
2
 * Herbert Kociemba
3
 *
4
 * BSD-licensed. See https://opensource.org/licenses/BSD-3-Clause
5
 */
6

    
7
package org.distorted.objectlib.kociemba;
8

    
9
///////////////////////////////////////////////////////////////////////////////////////////////////
10

    
11
class SolverCubieCube
12
  {
13
  private static final int[][] cnk     = new int[12][7];
14
  private static final int[] tmpEdge6  = new int[6];
15
  private static final int[] tmpEdge4  = new int[4];
16
  private static final int[] tmpEdge3  = new int[3];
17
  private static final int[] tmpCorner6= new int[6];
18

    
19
  // corner permutation
20
  int[] cp = { SolverCorner.URF, SolverCorner.UFL, SolverCorner.ULB, SolverCorner.UBR, SolverCorner.DFR, SolverCorner.DLF, SolverCorner.DBL, SolverCorner.DRB };
21

    
22
  // corner orientation
23
  byte[] co = { 0, 0, 0, 0, 0, 0, 0, 0 };
24

    
25
  // edge permutation
26
  int[] ep = { SolverEdge.UR, SolverEdge.UF, SolverEdge.UL, SolverEdge.UB, SolverEdge.DR, SolverEdge.DF, SolverEdge.DL, SolverEdge.DB, SolverEdge.FR, SolverEdge.FL, SolverEdge.BL, SolverEdge.BR };
27

    
28
  // edge orientation
29
  byte[] eo = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
30

    
31
  // Moves on the cubie level
32
  private static final int[]  cpU = { SolverCorner.UBR, SolverCorner.URF, SolverCorner.UFL, SolverCorner.ULB, SolverCorner.DFR, SolverCorner.DLF, SolverCorner.DBL, SolverCorner.DRB };
33
  private static final byte[] coU = { 0, 0, 0, 0, 0, 0, 0, 0 };
34
  private static final int[]  epU = { SolverEdge.UB, SolverEdge.UR, SolverEdge.UF, SolverEdge.UL, SolverEdge.DR, SolverEdge.DF, SolverEdge.DL, SolverEdge.DB, SolverEdge.FR, SolverEdge.FL, SolverEdge.BL, SolverEdge.BR };
35
  private static final byte[] eoU = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
36

    
37
  private static final int[]  cpR = { SolverCorner.DFR, SolverCorner.UFL, SolverCorner.ULB, SolverCorner.URF, SolverCorner.DRB, SolverCorner.DLF, SolverCorner.DBL, SolverCorner.UBR };
38
  private static final byte[] coR = { 2, 0, 0, 1, 1, 0, 0, 2 };
39
  private static final int[]  epR = { SolverEdge.FR, SolverEdge.UF, SolverEdge.UL, SolverEdge.UB, SolverEdge.BR, SolverEdge.DF, SolverEdge.DL, SolverEdge.DB, SolverEdge.DR, SolverEdge.FL, SolverEdge.BL, SolverEdge.UR };
40
  private static final byte[] eoR = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
41

    
42
  private static final int[]  cpF = { SolverCorner.UFL, SolverCorner.DLF, SolverCorner.ULB, SolverCorner.UBR, SolverCorner.URF, SolverCorner.DFR, SolverCorner.DBL, SolverCorner.DRB };
43
  private static final byte[] coF = { 1, 2, 0, 0, 2, 1, 0, 0 };
44
  private static final int[]  epF = { SolverEdge.UR, SolverEdge.FL, SolverEdge.UL, SolverEdge.UB, SolverEdge.DR, SolverEdge.FR, SolverEdge.DL, SolverEdge.DB, SolverEdge.UF, SolverEdge.DF, SolverEdge.BL, SolverEdge.BR };
45
  private static final byte[] eoF = { 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0 };
46

    
47
  private static final int[]  cpD = { SolverCorner.URF, SolverCorner.UFL, SolverCorner.ULB, SolverCorner.UBR, SolverCorner.DLF, SolverCorner.DBL, SolverCorner.DRB, SolverCorner.DFR };
48
  private static final byte[] coD = { 0, 0, 0, 0, 0, 0, 0, 0 };
49
  private static final int[]  epD = { SolverEdge.UR, SolverEdge.UF, SolverEdge.UL, SolverEdge.UB, SolverEdge.DF, SolverEdge.DL, SolverEdge.DB, SolverEdge.DR, SolverEdge.FR, SolverEdge.FL, SolverEdge.BL, SolverEdge.BR };
50
  private static final byte[] eoD = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
51

    
52
  private static final int[]  cpL = { SolverCorner.URF, SolverCorner.ULB, SolverCorner.DBL, SolverCorner.UBR, SolverCorner.DFR, SolverCorner.UFL, SolverCorner.DLF, SolverCorner.DRB };
53
  private static final byte[] coL = { 0, 1, 2, 0, 0, 2, 1, 0 };
54
  private static final int[]  epL = { SolverEdge.UR, SolverEdge.UF, SolverEdge.BL, SolverEdge.UB, SolverEdge.DR, SolverEdge.DF, SolverEdge.FL, SolverEdge.DB, SolverEdge.FR, SolverEdge.UL, SolverEdge.DL, SolverEdge.BR };
55
  private static final byte[] eoL = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
56

    
57
  private static final int[]  cpB = { SolverCorner.URF, SolverCorner.UFL, SolverCorner.UBR, SolverCorner.DRB, SolverCorner.DFR, SolverCorner.DLF, SolverCorner.ULB, SolverCorner.DBL };
58
  private static final byte[] coB = { 0, 0, 1, 2, 0, 0, 2, 1 };
59
  private static final int[]  epB = { SolverEdge.UR, SolverEdge.UF, SolverEdge.UL, SolverEdge.BR, SolverEdge.DR, SolverEdge.DF, SolverEdge.DL, SolverEdge.BL, SolverEdge.FR, SolverEdge.FL, SolverEdge.UB, SolverEdge.DB };
60
  private static final byte[] eoB = { 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1 };
61

    
62
  // this CubieCube array represents the 6 basic cube moves
63
  static SolverCubieCube[] moveCube = new SolverCubieCube[6];
64

    
65
  static
66
    {
67
    moveCube[0] = new SolverCubieCube();
68
    moveCube[0].cp = cpU;
69
    moveCube[0].co = coU;
70
    moveCube[0].ep = epU;
71
    moveCube[0].eo = eoU;
72

    
73
    moveCube[1] = new SolverCubieCube();
74
    moveCube[1].cp = cpR;
75
    moveCube[1].co = coR;
76
    moveCube[1].ep = epR;
77
    moveCube[1].eo = eoR;
78

    
79
    moveCube[2] = new SolverCubieCube();
80
    moveCube[2].cp = cpF;
81
    moveCube[2].co = coF;
82
    moveCube[2].ep = epF;
83
    moveCube[2].eo = eoF;
84

    
85
    moveCube[3] = new SolverCubieCube();
86
    moveCube[3].cp = cpD;
87
    moveCube[3].co = coD;
88
    moveCube[3].ep = epD;
89
    moveCube[3].eo = eoD;
90

    
91
    moveCube[4] = new SolverCubieCube();
92
    moveCube[4].cp = cpL;
93
    moveCube[4].co = coL;
94
    moveCube[4].ep = epL;
95
    moveCube[4].eo = eoL;
96

    
97
    moveCube[5] = new SolverCubieCube();
98
    moveCube[5].cp = cpB;
99
    moveCube[5].co = coB;
100
    moveCube[5].ep = epB;
101
    moveCube[5].eo = eoB;
102
    }
103

    
104
  static
105
    {
106
    for(int n=0; n<12; n++)
107
      for(int k=0; k<7; k++)
108
	      cnk[n][k] = -1;
109
    }
110

    
111
///////////////////////////////////////////////////////////////////////////////////////////////////
112

    
113
  SolverCubieCube()
114
    {
115
    }
116

    
117
///////////////////////////////////////////////////////////////////////////////////////////////////
118
// n choose k
119

    
120
  static int Cnk(int n, int k)
121
    {
122
    if( cnk[n][k]<0 )
123
      {
124
      int i, j, s;
125

    
126
      if (k > n  ) { cnk[n][k]=0; return 0; }
127
      if (k > n/2) k = n-k;
128
		  
129
      for(s=1, i=n, j=1; i!=n-k; i--, j++)
130
        {
131
	      s *= i;
132
	      s /= j;
133
        }
134
      cnk[n][k]= s;
135
      }
136
		
137
    return cnk[n][k];
138
    }
139

    
140
///////////////////////////////////////////////////////////////////////////////////////////////////
141
// Left rotation of all array elements between 0 and r
142

    
143
  static void rotateLeft(int[] arr, int r)
144
    {
145
    int tmp = arr[0];
146
    for (int i=0; i<r; i++) arr[i] = arr[i + 1];
147
    arr[r] = tmp;
148
    }
149

    
150
///////////////////////////////////////////////////////////////////////////////////////////////////
151
// Right rotation of all array elements between l and r
152

    
153
  static void rotateRight(int[] arr, int r)
154
    {
155
    int tmp = arr[r];
156
    for (int i = r; i > 0; i--) arr[i] = arr[i - 1];
157
    arr[0] = tmp;
158
    }
159

    
160
///////////////////////////////////////////////////////////////////////////////////////////////////
161
// return cube in facelet representation
162

    
163
  SolverFaceCube toFaceCube()
164
    {
165
    SolverFaceCube fcRet = new SolverFaceCube();
166

    
167
    for(int c = SolverCorner.URF; c<= SolverCorner.DRB; c++)
168
      {
169
      int j = cp[c];   // corner cubie with index j is at corner position with index i
170
      byte ori = co[c];// orientation of this cubie
171

    
172
      for( int n=0; n<3; n++)
173
        fcRet.f[SolverFaceCube.cornerFacelet[c][(n + ori) % 3]] = SolverFaceCube.cornerColor[j][n];
174
      }
175

    
176
    for(int e = SolverEdge.UR; e<= SolverEdge.BR; e++)
177
      {
178
      int j = ep[e];   // edge cubie with index j is at edge position with index i
179
      byte ori = eo[e];// orientation of this cubie
180

    
181
      for( int n=0; n<2; n++)
182
	      fcRet.f[SolverFaceCube.edgeFacelet[e][(n + ori) % 2]] = SolverFaceCube.edgeColor[j][n];
183
      }
184

    
185
    return fcRet;
186
    }
187

    
188
///////////////////////////////////////////////////////////////////////////////////////////////////
189
// return the twist of the 8 corners. 0 <= twist < 3^7
190

    
191
  short getTwist()
192
    {
193
    short ret = 0;
194

    
195
    for(int i = SolverCorner.URF; i< SolverCorner.DRB; i++)
196
      ret = (short) (3*ret+co[i]);
197

    
198
    return ret;
199
    }
200

    
201
///////////////////////////////////////////////////////////////////////////////////////////////////
202

    
203
  void setTwist(short twist)
204
    {
205
    int twistParity = 0;
206

    
207
    for (int i = SolverCorner.DRB-1; i>= SolverCorner.URF; i--)
208
      {
209
      twistParity += co[i] = (byte) (twist%3);
210
      twist /= 3;
211
      }
212
    co[SolverCorner.DRB] = (byte) ((3 - twistParity % 3) % 3);
213
    }
214

    
215
///////////////////////////////////////////////////////////////////////////////////////////////////
216
// return the flip of the 12 edges. 0<= flip < 2^11
217

    
218
  short getFlip()
219
    {
220
    short ret = 0;
221

    
222
    for (int i = SolverEdge.UR; i< SolverEdge.BR; i++)
223
      ret = (short) (2 * ret + eo[i]);
224

    
225
    return ret;
226
    }
227

    
228
///////////////////////////////////////////////////////////////////////////////////////////////////
229

    
230
  void setFlip(short flip)
231
    {
232
    int flipParity = 0;
233

    
234
    for (int i = SolverEdge.BR-1; i>= SolverEdge.UR; i--)
235
      {
236
      flipParity += eo[i] = (byte) (flip % 2);
237
      flip /= 2;
238
      }
239
    eo[SolverEdge.BR] = (byte) ((2 - flipParity % 2) % 2);
240
    }
241

    
242
///////////////////////////////////////////////////////////////////////////////////////////////////
243
// Parity of the corner permutation
244

    
245
  short cornerParity()
246
    {
247
    int s = 0;
248

    
249
    for (int i = SolverCorner.DRB; i>= SolverCorner.URF+1; i--)
250
      for (int j = i - 1; j >= SolverCorner.URF; j--)
251
        if (cp[j] > cp[i]) s++;
252

    
253
    return (short) (s%2);
254
    }
255

    
256
///////////////////////////////////////////////////////////////////////////////////////////////////
257
// Parity of the edges permutation. Parity of corners and edges are the same if the cube is solvable.
258

    
259
  short edgeParity()
260
    {
261
    int s = 0;
262

    
263
    for (int i = SolverEdge.BR; i >= SolverEdge.UR+1; i--)
264
      for (int j = i - 1; j >= SolverEdge.UR; j--)
265
        if (ep[j] > ep[i]) s++;
266

    
267
    return (short) (s%2);
268
    }
269

    
270
///////////////////////////////////////////////////////////////////////////////////////////////////
271
// permutation of the UD-slice edges FR,FL,BL and BR
272

    
273
  short getFRtoBR()
274
    {
275
    int a = 0, x = 0;
276

    
277
    // compute the index a < (12 choose 4) and the permutation array perm.
278
    for(int j = SolverEdge.BR; j >= SolverEdge.UR; j--)
279
      if (SolverEdge.FR <= ep[j] && ep[j] <= SolverEdge.BR)
280
        {
281
        a += Cnk(11-j, x+1);
282
        tmpEdge4[3-x++] = ep[j];
283
        }
284

    
285
    int b = 0;
286
    for( int j=3; j>0; j--) // compute the index b < 4! for the permutation in perm
287
      {
288
      int k = 0;
289
      while (tmpEdge4[j] != j+8)
290
        {
291
	      rotateLeft(tmpEdge4,j);
292
	      k++;
293
        }
294
      b = (j+1)*b + k;
295
      }
296

    
297
    return (short) (24*a+b);
298
    }
299

    
300
///////////////////////////////////////////////////////////////////////////////////////////////////
301
// Permutation of all corners except DBL and DRB
302

    
303
  short getURFtoDLF()
304
    {
305
    int a = 0, x = 0;
306

    
307
    // compute the index a < (8 choose 6) and the corner permutation.
308
    for(int j = SolverCorner.URF; j<= SolverCorner.DRB; j++)
309
      if( cp[j] <= SolverCorner.DLF )
310
        {
311
	      a += Cnk(j, x+1);
312
	      tmpCorner6[x++] = cp[j];
313
	      }
314

    
315
    int b = 0;
316

    
317
    for( int j=5; j>0; j--) // compute the index b < 6! for the permutation in corner6
318
      {
319
      int k = 0;
320

    
321
      while (tmpCorner6[j] != j)
322
        {
323
	      rotateLeft(tmpCorner6,j);
324
	      k++;
325
	      }
326
      b = (j+1)*b + k;
327
      }
328

    
329
    return (short) (720*a+b);
330
    }
331

    
332
///////////////////////////////////////////////////////////////////////////////////////////////////
333
// Permutation of the six edges UR,UF,UL,UB,DR,DF.
334

    
335
  int getURtoDF()
336
    {
337
    int a = 0, x = 0;
338
    // compute the index a < (12 choose 6) and the edge permutation.
339

    
340
    for(int j = SolverEdge.UR; j<= SolverEdge.BR; j++)
341
      if (ep[j] <= SolverEdge.DF)
342
        {
343
	      a += Cnk(j, x+1);
344
	      tmpEdge6[x++] = ep[j];
345
	      }
346

    
347
    int b = 0;
348

    
349
    for (int j=5; j>0; j--)// compute the index b < 6! for the permutation in edge6
350
      {
351
      int k = 0;
352

    
353
      while (tmpEdge6[j] != j)
354
        {
355
	      rotateLeft(tmpEdge6,j);
356
	      k++;
357
	      }
358
      b = (j+1)*b + k;
359
      }
360
    return 720*a+b;
361
    }
362

    
363
///////////////////////////////////////////////////////////////////////////////////////////////////
364
// Permutation of the three edges UR,UF,UL
365

    
366
  short getURtoUL()
367
    {
368
    int a=0, x=0;
369

    
370
    // compute the index a < (12 choose 3) and the edge permutation.
371
    for(int j = SolverEdge.UR; j<= SolverEdge.BR; j++)
372
      if (ep[j] <= SolverEdge.UL)
373
        {
374
	      a += Cnk(j, x + 1);
375
	      tmpEdge3[x++] = ep[j];
376
	      }
377

    
378
    int b=0;
379

    
380
    for( int j=2; j>0; j--)// compute the index b < 3! for the permutation in edge3
381
      {
382
      int k = 0;
383
      while (tmpEdge3[j] != j)
384
        {
385
	      rotateLeft(tmpEdge3,j);
386
	      k++;
387
	      }
388
      b = (j+1)*b+k;
389
      }
390
	
391
    return (short) (6*a+b);
392
    }
393

    
394
///////////////////////////////////////////////////////////////////////////////////////////////////
395
// Permutation of the three edges UB,DR,DF
396

    
397
  short getUBtoDF()
398
    {
399
    int a=0, x=0;
400
    // compute the index a < (12 choose 3) and the edge permutation.
401

    
402
    for(int j = SolverEdge.UR; j<= SolverEdge.BR; j++)
403
      if (SolverEdge.UB <= ep[j] && ep[j] <= SolverEdge.DF)
404
        {
405
	      a += Cnk(j, x+1);
406
	      tmpEdge3[x++] = ep[j];
407
	      }
408

    
409
    int b=0;
410

    
411
    for (int j=2; j>0; j--) // compute the index b < 3! for the permutation in edge3
412
      {
413
      int k=0;
414

    
415
      while (tmpEdge3[j] != SolverEdge.UB + j)
416
        {
417
	      rotateLeft(tmpEdge3,j);
418
	      k++;
419
	      }
420
      b = (j+1)*b+k;
421
      }
422

    
423
    return (short) (6*a+b);
424
    }
425

    
426
///////////////////////////////////////////////////////////////////////////////////////////////////
427

    
428
  void setURFtoDLB(int idx)
429
    {
430
    int[] perm = { SolverCorner.URF, SolverCorner.UFL, SolverCorner.ULB, SolverCorner.UBR, SolverCorner.DFR, SolverCorner.DLF, SolverCorner.DBL, SolverCorner.DRB };
431
    int k;
432

    
433
    for( int j=1; j<8; j++)
434
      {
435
      k = idx % (j+1);
436
      idx /= j+1;
437
      while (k-- > 0) rotateRight(perm,j);
438
      }
439

    
440
    int x=7;// set corners
441

    
442
    for( int j=7; j>=0; j--) cp[j] = perm[x--];
443
    }
444

    
445
///////////////////////////////////////////////////////////////////////////////////////////////////
446

    
447
  void setURtoBR(int idx)
448
    {
449
    int[] perm = { SolverEdge.UR, SolverEdge.UF, SolverEdge.UL, SolverEdge.UB, SolverEdge.DR, SolverEdge.DF, SolverEdge.DL, SolverEdge.DB, SolverEdge.FR, SolverEdge.FL, SolverEdge.BL, SolverEdge.BR };
450
    int k;
451

    
452
    for( int j=1; j<12; j++)
453
      {
454
      k = idx % (j+1);
455
      idx /= j+1;
456

    
457
      while (k-- > 0) rotateRight(perm,j);
458
      }
459

    
460
    int x=11;// set edges
461

    
462
    for( int j=11; j>=0; j--) ep[j] = perm[x--];
463
    }
464

    
465
///////////////////////////////////////////////////////////////////////////////////////////////////
466
// Check a cubie cube for solvability. Return the error code.
467
// 0: Cube is solvable
468
// -2: Not all 12 edges exist exactly once
469
// -3: Flip error: One edge has to be flipped
470
// -4: Not all corners exist exactly once
471
// -5: Twist error: One corner has to be twisted
472
// -6: Parity error: Two corners ore two edges have to be exchanged
473

    
474
  int verify()
475
    {
476
    int sum = 0;
477
    int[] edgeCount = new int[12];
478

    
479
    for (int e = SolverEdge.UR; e <= SolverEdge.BR; e++) edgeCount[ep[e]]++;
480

    
481
    for( int i=0; i<12; i++)
482
      if (edgeCount[i] != 1) return -2;
483

    
484
    for( int i=0; i<12; i++) sum += eo[i];
485

    
486
    if( (sum%2) != 0) return -3;
487

    
488
    int[] cornerCount = new int[8];
489

    
490
    for(int c = SolverCorner.URF; c<= SolverCorner.DRB; c++) cornerCount[cp[c]]++;
491

    
492
    for (int i = 0; i < 8; i++)
493
      if (cornerCount[i] != 1) return -4;// missing corners
494

    
495
    sum = 0;
496

    
497
    for( int i=0; i<8; i++) sum += co[i];
498

    
499
    if( (sum%3) != 0) return -5;// twisted corner
500

    
501
    if( (edgeParity()^cornerParity()) != 0) return -6;// parity error
502

    
503
    return 0;// cube ok
504
    }
505
}
(4-4/8)