Project

General

Profile

Download (17 KB) Statistics
| Branch: | Tag: | Revision:

magiccube / src / main / java / org / distorted / solvers / cube3 / SolverCubieCube.java @ 68191e7d

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2008 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Magic Cube.                                                              //
5
//                                                                                               //
6
// Magic Cube is free software: you can redistribute it and/or modify                            //
7
// it under the terms of the GNU General Public License as published by                          //
8
// the Free Software Foundation, either version 2 of the License, or                             //
9
// (at your option) any later version.                                                           //
10
//                                                                                               //
11
// Magic Cube is distributed in the hope that it will be useful,                                 //
12
// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
14
// GNU General Public License for more details.                                                  //
15
//                                                                                               //
16
// You should have received a copy of the GNU General Public License                             //
17
// along with Magic Cube.  If not, see <http://www.gnu.org/licenses/>.                           //
18
///////////////////////////////////////////////////////////////////////////////////////////////////
19

    
20
package org.distorted.solvers.cube3;
21

    
22
///////////////////////////////////////////////////////////////////////////////////////////////////
23

    
24
class SolverCubieCube
25
  {
26
  private static final int[][] cnk     = new int[12][7];
27
  private static final int[] tmpEdge6  = new int[6];
28
  private static final int[] tmpEdge4  = new int[4];
29
  private static final int[] tmpEdge3  = new int[3];
30
  private static final int[] tmpCorner6= new int[6];
31

    
32
  // corner permutation
33
  int[] cp = { SolverCorner.URF, SolverCorner.UFL, SolverCorner.ULB, SolverCorner.UBR, SolverCorner.DFR, SolverCorner.DLF, SolverCorner.DBL, SolverCorner.DRB };
34

    
35
  // corner orientation
36
  byte[] co = { 0, 0, 0, 0, 0, 0, 0, 0 };
37

    
38
  // edge permutation
39
  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 };
40

    
41
  // edge orientation
42
  byte[] eo = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
43

    
44
  // Moves on the cubie level
45
  private static final int[]  cpU = { SolverCorner.UBR, SolverCorner.URF, SolverCorner.UFL, SolverCorner.ULB, SolverCorner.DFR, SolverCorner.DLF, SolverCorner.DBL, SolverCorner.DRB };
46
  private static final byte[] coU = { 0, 0, 0, 0, 0, 0, 0, 0 };
47
  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 };
48
  private static final byte[] eoU = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
49

    
50
  private static final int[]  cpR = { SolverCorner.DFR, SolverCorner.UFL, SolverCorner.ULB, SolverCorner.URF, SolverCorner.DRB, SolverCorner.DLF, SolverCorner.DBL, SolverCorner.UBR };
51
  private static final byte[] coR = { 2, 0, 0, 1, 1, 0, 0, 2 };
52
  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 };
53
  private static final byte[] eoR = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
54

    
55
  private static final int[]  cpF = { SolverCorner.UFL, SolverCorner.DLF, SolverCorner.ULB, SolverCorner.UBR, SolverCorner.URF, SolverCorner.DFR, SolverCorner.DBL, SolverCorner.DRB };
56
  private static final byte[] coF = { 1, 2, 0, 0, 2, 1, 0, 0 };
57
  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 };
58
  private static final byte[] eoF = { 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0 };
59

    
60
  private static final int[]  cpD = { SolverCorner.URF, SolverCorner.UFL, SolverCorner.ULB, SolverCorner.UBR, SolverCorner.DLF, SolverCorner.DBL, SolverCorner.DRB, SolverCorner.DFR };
61
  private static final byte[] coD = { 0, 0, 0, 0, 0, 0, 0, 0 };
62
  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 };
63
  private static final byte[] eoD = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
64

    
65
  private static final int[]  cpL = { SolverCorner.URF, SolverCorner.ULB, SolverCorner.DBL, SolverCorner.UBR, SolverCorner.DFR, SolverCorner.UFL, SolverCorner.DLF, SolverCorner.DRB };
66
  private static final byte[] coL = { 0, 1, 2, 0, 0, 2, 1, 0 };
67
  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 };
68
  private static final byte[] eoL = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
69

    
70
  private static final int[]  cpB = { SolverCorner.URF, SolverCorner.UFL, SolverCorner.UBR, SolverCorner.DRB, SolverCorner.DFR, SolverCorner.DLF, SolverCorner.ULB, SolverCorner.DBL };
71
  private static final byte[] coB = { 0, 0, 1, 2, 0, 0, 2, 1 };
72
  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 };
73
  private static final byte[] eoB = { 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1 };
74

    
75
  // this CubieCube array represents the 6 basic cube moves
76
  static SolverCubieCube[] moveCube = new SolverCubieCube[6];
77

    
78
  static
79
    {
80
    moveCube[0] = new SolverCubieCube();
81
    moveCube[0].cp = cpU;
82
    moveCube[0].co = coU;
83
    moveCube[0].ep = epU;
84
    moveCube[0].eo = eoU;
85

    
86
    moveCube[1] = new SolverCubieCube();
87
    moveCube[1].cp = cpR;
88
    moveCube[1].co = coR;
89
    moveCube[1].ep = epR;
90
    moveCube[1].eo = eoR;
91

    
92
    moveCube[2] = new SolverCubieCube();
93
    moveCube[2].cp = cpF;
94
    moveCube[2].co = coF;
95
    moveCube[2].ep = epF;
96
    moveCube[2].eo = eoF;
97

    
98
    moveCube[3] = new SolverCubieCube();
99
    moveCube[3].cp = cpD;
100
    moveCube[3].co = coD;
101
    moveCube[3].ep = epD;
102
    moveCube[3].eo = eoD;
103

    
104
    moveCube[4] = new SolverCubieCube();
105
    moveCube[4].cp = cpL;
106
    moveCube[4].co = coL;
107
    moveCube[4].ep = epL;
108
    moveCube[4].eo = eoL;
109

    
110
    moveCube[5] = new SolverCubieCube();
111
    moveCube[5].cp = cpB;
112
    moveCube[5].co = coB;
113
    moveCube[5].ep = epB;
114
    moveCube[5].eo = eoB;
115
    }
116

    
117
  static
118
    {
119
    for(int n=0; n<12; n++)
120
      for(int k=0; k<7; k++)
121
	      cnk[n][k] = -1;
122
    }
123

    
124
///////////////////////////////////////////////////////////////////////////////////////////////////
125

    
126
  SolverCubieCube()
127
    {
128
    }
129

    
130
///////////////////////////////////////////////////////////////////////////////////////////////////
131
// n choose k
132

    
133
  static int Cnk(int n, int k)
134
    {
135
    if( cnk[n][k]<0 )
136
      {
137
      int i, j, s;
138

    
139
      if (k > n  ) { cnk[n][k]=0; return 0; }
140
      if (k > n/2) k = n-k;
141
		  
142
      for(s=1, i=n, j=1; i!=n-k; i--, j++)
143
        {
144
	      s *= i;
145
	      s /= j;
146
        }
147
      cnk[n][k]= s;
148
      }
149
		
150
    return cnk[n][k];
151
    }
152

    
153
///////////////////////////////////////////////////////////////////////////////////////////////////
154
// Left rotation of all array elements between 0 and r
155

    
156
  static void rotateLeft(int[] arr, int r)
157
    {
158
    int tmp = arr[0];
159
    for (int i=0; i<r; i++) arr[i] = arr[i + 1];
160
    arr[r] = tmp;
161
    }
162

    
163
///////////////////////////////////////////////////////////////////////////////////////////////////
164
// Right rotation of all array elements between l and r
165

    
166
  static void rotateRight(int[] arr, int r)
167
    {
168
    int tmp = arr[r];
169
    for (int i = r; i > 0; i--) arr[i] = arr[i - 1];
170
    arr[0] = tmp;
171
    }
172

    
173
///////////////////////////////////////////////////////////////////////////////////////////////////
174
// return cube in facelet representation
175

    
176
  SolverFaceCube toFaceCube()
177
    {
178
    SolverFaceCube fcRet = new SolverFaceCube();
179

    
180
    for(int c = SolverCorner.URF; c<= SolverCorner.DRB; c++)
181
      {
182
      int j = cp[c];   // corner cubie with index j is at corner position with index i
183
      byte ori = co[c];// orientation of this cubie
184

    
185
      for( int n=0; n<3; n++)
186
        fcRet.f[SolverFaceCube.cornerFacelet[c][(n + ori) % 3]] = SolverFaceCube.cornerColor[j][n];
187
      }
188

    
189
    for(int e = SolverEdge.UR; e<= SolverEdge.BR; e++)
190
      {
191
      int j = ep[e];   // edge cubie with index j is at edge position with index i
192
      byte ori = eo[e];// orientation of this cubie
193

    
194
      for( int n=0; n<2; n++)
195
	      fcRet.f[SolverFaceCube.edgeFacelet[e][(n + ori) % 2]] = SolverFaceCube.edgeColor[j][n];
196
      }
197

    
198
    return fcRet;
199
    }
200

    
201
///////////////////////////////////////////////////////////////////////////////////////////////////
202
// return the twist of the 8 corners. 0 <= twist < 3^7
203

    
204
  short getTwist()
205
    {
206
    short ret = 0;
207

    
208
    for(int i = SolverCorner.URF; i< SolverCorner.DRB; i++)
209
      ret = (short) (3*ret+co[i]);
210

    
211
    return ret;
212
    }
213

    
214
///////////////////////////////////////////////////////////////////////////////////////////////////
215

    
216
  void setTwist(short twist)
217
    {
218
    int twistParity = 0;
219

    
220
    for (int i = SolverCorner.DRB-1; i>= SolverCorner.URF; i--)
221
      {
222
      twistParity += co[i] = (byte) (twist%3);
223
      twist /= 3;
224
      }
225
    co[SolverCorner.DRB] = (byte) ((3 - twistParity % 3) % 3);
226
    }
227

    
228
///////////////////////////////////////////////////////////////////////////////////////////////////
229
// return the flip of the 12 edges. 0<= flip < 2^11
230

    
231
  short getFlip()
232
    {
233
    short ret = 0;
234

    
235
    for (int i = SolverEdge.UR; i< SolverEdge.BR; i++)
236
      ret = (short) (2 * ret + eo[i]);
237

    
238
    return ret;
239
    }
240

    
241
///////////////////////////////////////////////////////////////////////////////////////////////////
242

    
243
  void setFlip(short flip)
244
    {
245
    int flipParity = 0;
246

    
247
    for (int i = SolverEdge.BR-1; i>= SolverEdge.UR; i--)
248
      {
249
      flipParity += eo[i] = (byte) (flip % 2);
250
      flip /= 2;
251
      }
252
    eo[SolverEdge.BR] = (byte) ((2 - flipParity % 2) % 2);
253
    }
254

    
255
///////////////////////////////////////////////////////////////////////////////////////////////////
256
// Parity of the corner permutation
257

    
258
  short cornerParity()
259
    {
260
    int s = 0;
261

    
262
    for (int i = SolverCorner.DRB; i>= SolverCorner.URF+1; i--)
263
      for (int j = i - 1; j >= SolverCorner.URF; j--)
264
        if (cp[j] > cp[i]) s++;
265

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

    
269
///////////////////////////////////////////////////////////////////////////////////////////////////
270
// Parity of the edges permutation. Parity of corners and edges are the same if the cube is solvable.
271

    
272
  short edgeParity()
273
    {
274
    int s = 0;
275

    
276
    for (int i = SolverEdge.BR; i >= SolverEdge.UR+1; i--)
277
      for (int j = i - 1; j >= SolverEdge.UR; j--)
278
        if (ep[j] > ep[i]) s++;
279

    
280
    return (short) (s%2);
281
    }
282

    
283
///////////////////////////////////////////////////////////////////////////////////////////////////
284
// permutation of the UD-slice edges FR,FL,BL and BR
285

    
286
  short getFRtoBR()
287
    {
288
    int a = 0, x = 0;
289

    
290
    // compute the index a < (12 choose 4) and the permutation array perm.
291
    for(int j = SolverEdge.BR; j >= SolverEdge.UR; j--)
292
      if (SolverEdge.FR <= ep[j] && ep[j] <= SolverEdge.BR)
293
        {
294
        a += Cnk(11-j, x+1);
295
	      tmpEdge4[3-x++] = ep[j];
296
	      }
297

    
298
    int b = 0;
299
    for( int j=3; j>0; j--) // compute the index b < 4! for the permutation in perm
300
      {
301
      int k = 0;
302
      while (tmpEdge4[j] != j+8)
303
        {
304
	      rotateLeft(tmpEdge4,j);
305
	      k++;
306
        }
307
      b = (j+1)*b + k;
308
      }
309

    
310
    return (short) (24*a+b);
311
    }
312

    
313
///////////////////////////////////////////////////////////////////////////////////////////////////
314
// Permutation of all corners except DBL and DRB
315

    
316
  short getURFtoDLF()
317
    {
318
    int a = 0, x = 0;
319

    
320
    // compute the index a < (8 choose 6) and the corner permutation.
321
    for(int j = SolverCorner.URF; j<= SolverCorner.DRB; j++)
322
      if( cp[j] <= SolverCorner.DLF )
323
        {
324
	      a += Cnk(j, x+1);
325
	      tmpCorner6[x++] = cp[j];
326
	      }
327

    
328
    int b = 0;
329

    
330
    for( int j=5; j>0; j--) // compute the index b < 6! for the permutation in corner6
331
      {
332
      int k = 0;
333

    
334
      while (tmpCorner6[j] != j)
335
        {
336
	      rotateLeft(tmpCorner6,j);
337
	      k++;
338
	      }
339
      b = (j+1)*b + k;
340
      }
341

    
342
    return (short) (720*a+b);
343
    }
344

    
345
///////////////////////////////////////////////////////////////////////////////////////////////////
346
// Permutation of the six edges UR,UF,UL,UB,DR,DF.
347

    
348
  int getURtoDF()
349
    {
350
    int a = 0, x = 0;
351
    // compute the index a < (12 choose 6) and the edge permutation.
352

    
353
    for(int j = SolverEdge.UR; j<= SolverEdge.BR; j++)
354
      if (ep[j] <= SolverEdge.DF)
355
        {
356
	      a += Cnk(j, x+1);
357
	      tmpEdge6[x++] = ep[j];
358
	      }
359

    
360
    int b = 0;
361

    
362
    for (int j=5; j>0; j--)// compute the index b < 6! for the permutation in edge6
363
      {
364
      int k = 0;
365

    
366
      while (tmpEdge6[j] != j)
367
        {
368
	      rotateLeft(tmpEdge6,j);
369
	      k++;
370
	      }
371
      b = (j+1)*b + k;
372
      }
373
    return 720*a+b;
374
    }
375

    
376
///////////////////////////////////////////////////////////////////////////////////////////////////
377
// Permutation of the three edges UR,UF,UL
378

    
379
  short getURtoUL()
380
    {
381
    int a=0, x=0;
382

    
383
    // compute the index a < (12 choose 3) and the edge permutation.
384
    for(int j = SolverEdge.UR; j<= SolverEdge.BR; j++)
385
      if (ep[j] <= SolverEdge.UL)
386
        {
387
	      a += Cnk(j, x + 1);
388
	      tmpEdge3[x++] = ep[j];
389
	      }
390

    
391
    int b=0;
392

    
393
    for( int j=2; j>0; j--)// compute the index b < 3! for the permutation in edge3
394
      {
395
      int k = 0;
396
      while (tmpEdge3[j] != j)
397
        {
398
	      rotateLeft(tmpEdge3,j);
399
	      k++;
400
	      }
401
      b = (j+1)*b+k;
402
      }
403
	
404
    return (short) (6*a+b);
405
    }
406

    
407
///////////////////////////////////////////////////////////////////////////////////////////////////
408
// Permutation of the three edges UB,DR,DF
409

    
410
  short getUBtoDF()
411
    {
412
    int a=0, x=0;
413
    // compute the index a < (12 choose 3) and the edge permutation.
414

    
415
    for(int j = SolverEdge.UR; j<= SolverEdge.BR; j++)
416
      if (SolverEdge.UB <= ep[j] && ep[j] <= SolverEdge.DF)
417
        {
418
	      a += Cnk(j, x+1);
419
	      tmpEdge3[x++] = ep[j];
420
	      }
421

    
422
    int b=0;
423

    
424
    for (int j=2; j>0; j--) // compute the index b < 3! for the permutation in edge3
425
      {
426
      int k=0;
427

    
428
      while (tmpEdge3[j] != SolverEdge.UB + j)
429
        {
430
	      rotateLeft(tmpEdge3,j);
431
	      k++;
432
	      }
433
      b = (j+1)*b+k;
434
      }
435

    
436
    return (short) (6*a+b);
437
    }
438

    
439
///////////////////////////////////////////////////////////////////////////////////////////////////
440

    
441
  void setURFtoDLB(int idx)
442
    {
443
    int[] perm = { SolverCorner.URF, SolverCorner.UFL, SolverCorner.ULB, SolverCorner.UBR, SolverCorner.DFR, SolverCorner.DLF, SolverCorner.DBL, SolverCorner.DRB };
444
    int k;
445

    
446
    for( int j=1; j<8; j++)
447
      {
448
      k = idx % (j+1);
449
      idx /= j+1;
450
      while (k-- > 0) rotateRight(perm,j);
451
      }
452

    
453
    int x=7;// set corners
454

    
455
    for( int j=7; j>=0; j--) cp[j] = perm[x--];
456
    }
457

    
458
///////////////////////////////////////////////////////////////////////////////////////////////////
459

    
460
  void setURtoBR(int idx)
461
    {
462
    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 };
463
    int k;
464

    
465
    for( int j=1; j<12; j++)
466
      {
467
      k = idx % (j+1);
468
      idx /= j+1;
469

    
470
      while (k-- > 0) rotateRight(perm,j);
471
      }
472

    
473
    int x=11;// set edges
474

    
475
    for( int j=11; j>=0; j--) ep[j] = perm[x--];
476
    }
477

    
478
///////////////////////////////////////////////////////////////////////////////////////////////////
479
// Check a cubie cube for solvability. Return the error code.
480
// 0: Cube is solvable
481
// -2: Not all 12 edges exist exactly once
482
// -3: Flip error: One edge has to be flipped
483
// -4: Not all corners exist exactly once
484
// -5: Twist error: One corner has to be twisted
485
// -6: Parity error: Two corners ore two edges have to be exchanged
486

    
487
  int verify()
488
    {
489
    int sum = 0;
490
    int[] edgeCount = new int[12];
491

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

    
494
    for( int i=0; i<12; i++)
495
      if (edgeCount[i] != 1) return -2;
496

    
497
    for( int i=0; i<12; i++) sum += eo[i];
498

    
499
    if( (sum%2) != 0) return -3;
500

    
501
    int[] cornerCount = new int[8];
502

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

    
505
    for (int i = 0; i < 8; i++)
506
      if (cornerCount[i] != 1) return -4;// missing corners
507

    
508
    sum = 0;
509

    
510
    for( int i=0; i<8; i++) sum += co[i];
511

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

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

    
516
    return 0;// cube ok
517
    }
518
}
(4-4/8)