Project

General

Profile

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

distorted-objectlib / src / main / java / org / distorted / objectlib / tablebases / TBSkewb.java @ 6777e712

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2023 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Magic Cube.                                                              //
5
//                                                                                               //
6
// Magic Cube is proprietary software licensed under an EULA which you should have received      //
7
// along with the code. If not, check https://distorted.org/magic/License-Magic-Cube.html        //
8
///////////////////////////////////////////////////////////////////////////////////////////////////
9

    
10
package org.distorted.objectlib.tablebases;
11

    
12
import org.distorted.library.helpers.QuatHelper;
13
import org.distorted.library.type.Static3D;
14
import org.distorted.library.type.Static4D;
15
import org.distorted.objectlib.R;
16
import org.distorted.objectlib.helpers.OperatingSystemInterface;
17
import org.distorted.objectlib.helpers.QuatGroupGenerator;
18
import org.distorted.objectlib.objects.TwistySkewb;
19

    
20
///////////////////////////////////////////////////////////////////////////////////////////////////
21

    
22
public class TBSkewb extends TablebasesPruning
23
{
24
  public static final int[] FIXED= {0,3,5,6};
25
  public static final int[] FREE = {1,2,4,7};
26

    
27
  private static final int[][] freeIndex = { {1,3,2},{0,2,3},{3,1,0},{2,0,1} };
28

    
29
  // [1][] are the 3 quats the 1st 'fixed' corner will have when twisted with respectively twist 0,1,2.
30
  private static final int[][] fixedQuats = { {0,1,2},{0,7,8},{0,6,5},{0,4,3} };
31

    
32
  private static int[][] tetradPerm, divideTable, multiplyTable, locationTable;
33

    
34
  // centerQuats[0][1] are the two quats the 0th center might have when rotated to the position of
35
  // the 1st center.
36
  // Warning! Order of the centers follows the order from TwistySkewb, i.e. +z,-z,+y,-y,+x,-x
37
  private static final int[][][] centerQuats =
38
    {
39
        { {0,10},{9,11},{1,7},{4,6},{2,5},{3,8} },
40
        { {9,11},{0,10},{4,6},{1,7},{3,8},{2,5} },
41
        { {2,8},{3,5},{0,11},{9,10},{1,4},{6,7} },
42
        { {3,5},{2,8},{9,10},{0,11},{6,7},{1,4} },
43
        { {1,6},{4,7},{2,3},{5,8},{0,9},{10,11} },
44
        { {4,7},{1,6},{5,8},{2,3},{10,11},{0,9} }
45
    };
46

    
47
  private static Static4D[] mQuats;
48
  private static final Static3D[] ROT_AXIS = TwistySkewb.ROT_AXIS;
49
  private static final int[][] BASIC_ANGLES = { {3,3},{3,3},{3,3},{3,3} };
50

    
51
///////////////////////////////////////////////////////////////////////////////////////////////////
52

    
53
  public TBSkewb()
54
    {
55
    super();
56
    }
57

    
58
///////////////////////////////////////////////////////////////////////////////////////////////////
59

    
60
  public TBSkewb(OperatingSystemInterface os)
61
    {
62
    super(os,new int[] {R.raw.skew_2_pruning4,R.raw.skew_2_pruning5},new int[]{R.raw.skew_2_pruning11});
63
    }
64

    
65
///////////////////////////////////////////////////////////////////////////////////////////////////
66

    
67
  int[][] getBasicAngles()
68
    {
69
    return BASIC_ANGLES;
70
    }
71

    
72
///////////////////////////////////////////////////////////////////////////////////////////////////
73

    
74
  Static3D[] getRotationAxis()
75
    {
76
    return ROT_AXIS;
77
    }
78

    
79
///////////////////////////////////////////////////////////////////////////////////////////////////
80

    
81
  float[][] getPosition()
82
    {
83
    return new float[][]
84
         {
85
             { 1, 1, 1 },
86
             { 1, 1,-1 },
87
             { 1,-1, 1 },
88
             { 1,-1,-1 },
89
             {-1, 1, 1 },
90
             {-1, 1,-1 },
91
             {-1,-1, 1 },
92
             {-1,-1,-1 },
93

    
94
             { 0, 0, 1 },
95
             { 0, 0,-1 },
96
             { 0, 1, 0 },
97
             { 0,-1, 0 },
98
             { 1, 0, 0 },
99
             {-1, 0, 0 }
100
         };
101
    }
102

    
103
///////////////////////////////////////////////////////////////////////////////////////////////////
104

    
105
  float[][] getCuts()
106
    {
107
    float[] cut = {0};
108
    return new float[][] { cut,cut,cut,cut };
109
    }
110

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

    
113
  boolean[][] getRotatable()
114
    {
115
    boolean[] t1 = new boolean[] {false,true};
116
    boolean[] t2 = new boolean[] {true,false};
117
    return new boolean[][] { t1,t2,t2,t1 };
118
    }
119

    
120
///////////////////////////////////////////////////////////////////////////////////////////////////
121
// specifically for the tablebase
122
///////////////////////////////////////////////////////////////////////////////////////////////////
123

    
124
  int getSize()
125
    {
126
    return 3149280;  // see https://www.jaapsch.net/puzzles/skewb.htm
127
    }
128

    
129
///////////////////////////////////////////////////////////////////////////////////////////////////
130

    
131
  int getMinScramble()
132
    {
133
    return 9;
134
    }
135

    
136
///////////////////////////////////////////////////////////////////////////////////////////////////
137

    
138
  int[] getMidPruningLevels()
139
    {
140
    return new int[] {4,5};
141
    }
142

    
143
///////////////////////////////////////////////////////////////////////////////////////////////////
144

    
145
  int[] getHighPruningLevels()
146
    {
147
    return new int[] {11};
148
    }
149

    
150
///////////////////////////////////////////////////////////////////////////////////////////////////
151

    
152
  int getGodsNumber()
153
    {
154
    return 11;
155
    }
156

    
157
///////////////////////////////////////////////////////////////////////////////////////////////////
158

    
159
  boolean moveCanProceed(int lastA, int lastR, int currA, int currR)
160
    {
161
    return lastA!=currA;
162
    }
163

    
164
///////////////////////////////////////////////////////////////////////////////////////////////////
165

    
166
  private static int figureOutLocation(float[] loc, float[][] vectors)
167
    {
168
    float minDiff = Float.MAX_VALUE;
169
    int index = -1;
170

    
171
    for(int i=0; i<4; i++)
172
      {
173
      float[] v = vectors[i];
174
      float dx = v[0]-loc[0];
175
      float dy = v[1]-loc[1];
176
      float dz = v[2]-loc[2];
177
      float diff = dx*dx + dy*dy + dz*dz;
178

    
179
      if( diff<minDiff )
180
        {
181
        minDiff = diff;
182
        index = i;
183
        }
184
      }
185

    
186
    return index;
187
    }
188

    
189
///////////////////////////////////////////////////////////////////////////////////////////////////
190

    
191
  private static void generateLocation()
192
    {
193
    locationTable = new int[4][12];
194

    
195
    if( mQuats==null )
196
      mQuats = QuatGroupGenerator.computeGroup(ROT_AXIS,BASIC_ANGLES);
197

    
198
    float[][] vectors = new float[][]
199
      {
200
        { 1, 1,-1, 0},
201
        { 1,-1, 1, 0},
202
        {-1, 1, 1, 0},
203
        {-1,-1,-1, 0}
204
      };
205

    
206
    float[] output = new float[4];
207

    
208
    for(int i=0; i<4; i++)
209
      {
210
      float[] v = vectors[i];
211

    
212
      for(int q=0; q<12; q++)
213
        {
214
        Static4D quat = mQuats[q];
215
        QuatHelper.rotateVectorByQuat(output,v[0],v[1],v[2],v[3],quat);
216
        int loc = figureOutLocation(output,vectors);
217
        locationTable[i][q] = loc;
218
        }
219
      }
220
    }
221

    
222
///////////////////////////////////////////////////////////////////////////////////////////////////
223

    
224
  public static int computeLocation(int index, int quat)
225
    {
226
    if( locationTable==null ) generateLocation();
227
    return locationTable[index][quat];
228
    }
229

    
230
///////////////////////////////////////////////////////////////////////////////////////////////////
231

    
232
  private static int fixedQuatToTwist(int index, int quat)
233
    {
234
    int[] qs = fixedQuats[index];
235

    
236
    if( quat==qs[0]) return 0;
237
    if( quat==qs[1]) return 1;
238
    if( quat==qs[2]) return 2;
239

    
240
    android.util.Log.e("D", "error in fixedQuatToTwist, index="+index+" quat="+quat);
241
    return -1;
242
    }
243

    
244
///////////////////////////////////////////////////////////////////////////////////////////////////
245

    
246
  private static int fixedTwistToQuat(int index, int twist)
247
    {
248
    return fixedQuats[index][twist];
249
    }
250

    
251
///////////////////////////////////////////////////////////////////////////////////////////////////
252

    
253
  private static int figureOutTetrad(int q0, int q1, int q2, int q3)
254
    {
255
    int[] quats = fixedQuats[3];
256

    
257
    int s00 = divideFromRight(q0,quats[0]);
258
    int s01 = divideFromRight(q0,quats[1]);
259
    int s02 = divideFromRight(q0,quats[2]);
260

    
261
    quats = fixedQuats[1];
262

    
263
    int s10 = divideFromRight(q2,quats[0]);
264
    int s11 = divideFromRight(q2,quats[1]);
265
    int s12 = divideFromRight(q2,quats[2]);
266

    
267
    quats = fixedQuats[2];
268

    
269
    int s20 = divideFromRight(q1,quats[0]);
270

    
271
    if( s20==s00 || s20==s01 || s20==s02 )
272
      return ( s20==s10 || s20==s11 || s20==s12 ) ? s20 : -1;
273

    
274
    int s21 = divideFromRight(q1,quats[1]);
275

    
276
    if( s21==s00 || s21==s01 || s21==s02 )
277
      return ( s21==s10 || s21==s11 || s21==s12 ) ? s21 : -1;
278

    
279
    int s22 = divideFromRight(q1,quats[2]);
280

    
281
    if( s22==s00 || s22==s01 || s22==s02 )
282
      return ( s22==s10 || s22==s11 || s22==s12 ) ? s22 : -1;
283

    
284
    return -1;
285
    }
286

    
287
///////////////////////////////////////////////////////////////////////////////////////////////////
288

    
289
  private static void generateDivideTable()
290
    {
291
    divideTable = new int[12][12];
292

    
293
    for(int i=0; i<12; i++)
294
      for(int j=0; j<12; j++)
295
        {
296
        int res = multiplyQuat(i,j);
297
        divideTable[res][j] = i;
298
        }
299
    }
300

    
301
///////////////////////////////////////////////////////////////////////////////////////////////////
302
// double cover!
303

    
304
  private static int findQuat(Static4D quat)
305
    {
306
    float minDiff = Float.MAX_VALUE;
307
    int bestindex = -1;
308
    float dx,dy,dz,dw,diff;
309

    
310
    float x= quat.get0();
311
    float y= quat.get1();
312
    float z= quat.get2();
313
    float w= quat.get3();
314

    
315
    for(int i=0; i<12; i++)
316
      {
317
      Static4D q = mQuats[i];
318
      dx = x-q.get0();
319
      dy = y-q.get1();
320
      dz = z-q.get2();
321
      dw = w-q.get3();
322

    
323
      diff = dx*dx + dy*dy + dz*dz + dw*dw;
324

    
325
      if( diff<minDiff )
326
        {
327
        minDiff = diff;
328
        bestindex = i;
329
        }
330

    
331
      dx = x+q.get0();
332
      dy = y+q.get1();
333
      dz = z+q.get2();
334
      dw = w+q.get3();
335

    
336
      diff = dx*dx + dy*dy + dz*dz + dw*dw;
337

    
338
      if( diff<minDiff )
339
        {
340
        minDiff = diff;
341
        bestindex = i;
342
        }
343
      }
344

    
345
    return bestindex;
346
    }
347

    
348
///////////////////////////////////////////////////////////////////////////////////////////////////
349

    
350
  private static void generateMultiplyTable()
351
    {
352
    multiplyTable = new int[12][12];
353

    
354
    if( mQuats==null )
355
      mQuats = QuatGroupGenerator.computeGroup(ROT_AXIS,BASIC_ANGLES);
356

    
357
    for(int i=0; i<12; i++)
358
      {
359
      Static4D q0 = mQuats[i];
360

    
361
      for(int j=0; j<12; j++)
362
        {
363
        Static4D q1 = mQuats[j];
364
        Static4D res= QuatHelper.quatMultiply(q0,q1);
365
        int index   = findQuat(res);
366
        multiplyTable[i][j] = index;
367
        }
368
      }
369
    }
370

    
371
///////////////////////////////////////////////////////////////////////////////////////////////////
372

    
373
  private static void generateTetradPerm()
374
    {
375
    tetradPerm = new int[4][4];
376

    
377
    for(int i=0; i<4; i++)
378
      for(int j=0; j<4; j++) tetradPerm[i][j] = -1;
379

    
380
    for(int q=0; q<12; q++)
381
      {
382
      int loc0 = computeLocation(0,q);
383
      int loc1 = computeLocation(1,q);
384
      tetradPerm[loc0][loc1] = q;
385
      }
386
    }
387

    
388
///////////////////////////////////////////////////////////////////////////////////////////////////
389

    
390
  public static int figureOutTetrad(int[] perm)
391
    {
392
    if( tetradPerm==null ) generateTetradPerm();
393
    return tetradPerm[perm[0]][perm[1]];
394
    }
395

    
396
///////////////////////////////////////////////////////////////////////////////////////////////////
397
// return (r^-1) * q
398

    
399
  private static int divideFromLeft(int q, int r)
400
    {
401
    if( divideTable==null ) generateDivideTable();
402
    return multiplyTable[divideTable[0][r]][q];
403
    }
404

    
405
///////////////////////////////////////////////////////////////////////////////////////////////////
406
// return q * (r^-1)
407

    
408
  private static int divideFromRight(int q, int r)
409
    {
410
    if( divideTable==null ) generateDivideTable();
411
    return divideTable[q][r];
412
    }
413

    
414
///////////////////////////////////////////////////////////////////////////////////////////////////
415

    
416
  private static int multiplyQuat(int q, int r)
417
    {
418
    if( multiplyTable==null ) generateMultiplyTable();
419
    return multiplyTable[q][r];
420
    }
421

    
422
///////////////////////////////////////////////////////////////////////////////////////////////////
423
// In case of the four 'fixed' corners (0,3,5,6) which do not change their location,
424
// the twist is natural: 0 in the init positions and increasing 1 mod 3 on each CW turn.
425
//
426
// In case of the four 'free' corners their twist is relative to the position of the 'free'
427
// tetrahedron. And so, for example the twist of free corner 1 (whose 0th face is orange) is equal
428
// to 0 if free corner 7 is on the same face like 0th face of corner 1 (which is the case in init
429
// position); then once free corners 2,4,7 permute CW, twist of corner 1 increases by 1 mod 3.
430
//
431
// Way to figure out the 'free' twists: notice their final quat must be a product of initial
432
// 'in place' quat and a common quat which rotates the tetrad of all 4 'free' corners.
433
// Figure out the tetrad quat and divide free quats by it, then do the same like with fixed corners.
434

    
435
  public static void computeCornerTwists(int[] twists, int[] quats)
436
    {
437
    for(int i=0; i<4; i++) twists[FIXED[i]] = fixedQuatToTwist(i,quats[FIXED[i]]);
438

    
439
    int free0 = quats[FREE[0]];
440
    int free1 = quats[FREE[1]];
441
    int free2 = quats[FREE[2]];
442
    int free3 = quats[FREE[3]];
443

    
444
    int tetradQuat = figureOutTetrad(free0,free1,free2,free3);
445

    
446
    if( tetradQuat>=0 )
447
      {
448
      int quat0 = divideFromLeft(free0, tetradQuat);
449
      int quat1 = divideFromLeft(free1, tetradQuat);
450
      int quat2 = divideFromLeft(free2, tetradQuat);
451
      int quat3 = divideFromLeft(free3, tetradQuat);
452

    
453
      twists[FREE[0]] = fixedQuatToTwist(3, quat0);
454
      twists[FREE[1]] = fixedQuatToTwist(2, quat1);
455
      twists[FREE[2]] = fixedQuatToTwist(1, quat2);
456
      twists[FREE[3]] = fixedQuatToTwist(0, quat3);
457
      }
458
    else
459
      {
460
      android.util.Log.e("D", "ERROR in computeCornerTwists: "+free0+" "+free1+" "+free2+" "+free3);
461
      }
462
    }
463

    
464
///////////////////////////////////////////////////////////////////////////////////////////////////
465

    
466
  public static void fillInQuats(int[] quats, int[] perm, int[] twist)
467
    {
468
    for(int i=0; i<4; i++)
469
      {
470
      int fixed = FIXED[i];
471
      int twFi  = twist[fixed];
472
      quats[fixed] = fixedQuats[i][twFi];
473
      }
474

    
475
    int q0 = fixedTwistToQuat(3,twist[FREE[0]]);
476
    int q1 = fixedTwistToQuat(2,twist[FREE[1]]);
477
    int q2 = fixedTwistToQuat(1,twist[FREE[2]]);
478
    int q3 = fixedTwistToQuat(0,twist[FREE[3]]);
479

    
480
    int tetradQuat = figureOutTetrad(perm);
481

    
482
    quats[FREE[0]] = multiplyQuat(tetradQuat,q0);
483
    quats[FREE[1]] = multiplyQuat(tetradQuat,q1);
484
    quats[FREE[2]] = multiplyQuat(tetradQuat,q2);
485
    quats[FREE[3]] = multiplyQuat(tetradQuat,q3);
486
    }
487

    
488
///////////////////////////////////////////////////////////////////////////////////////////////////
489

    
490
  private int[] computeCenterPerm(int[] quats)
491
    {
492
    int[] output = new int[6];
493

    
494
    for(int i=0; i<6; i++)
495
      {
496
      output[i] = -1;
497
      int[][] c = centerQuats[i];
498
      int q = quats[8+i];
499

    
500
      for(int j=0; j<6; j++)
501
        if( c[j][0]==q || c[j][1]==q )
502
          {
503
          output[i] = j;
504
          break;
505
          }
506
      }
507

    
508
    return output;
509
    }
510

    
511
///////////////////////////////////////////////////////////////////////////////////////////////////
512

    
513
  private void fillCenterQuats(int[] quats, int[] perm)
514
    {
515
    for(int i=0; i<6; i++) quats[8+i] = centerQuats[i][perm[i]][0];
516
    }
517

    
518
///////////////////////////////////////////////////////////////////////////////////////////////////
519

    
520
  private void fillUpToEvenPerm(int[] perm)
521
    {
522
    int min, max;
523

    
524
         if( perm[0]!=0 && perm[1]!=0 ) min=0;
525
    else if( perm[0]!=1 && perm[1]!=1 ) min=1;
526
    else                                min=2;
527

    
528
         if( perm[0]!=3 && perm[1]!=3 ) max=3;
529
    else if( perm[0]!=2 && perm[1]!=2 ) max=2;
530
    else                                max=1;
531

    
532
    int diff = perm[1]-perm[0];
533

    
534
    if( diff==-2 || diff==1 || diff==3 ) { perm[2]=min; perm[3]=max; }
535
    else                                 { perm[2]=max; perm[3]=min; }
536
    }
537

    
538
///////////////////////////////////////////////////////////////////////////////////////////////////
539

    
540
  public static int permFree1(int permFree0, int sumFixedTwists)
541
    {
542
    return freeIndex[permFree0][sumFixedTwists%3];
543
    }
544

    
545
///////////////////////////////////////////////////////////////////////////////////////////////////
546

    
547
  int[] getQuats(int index)
548
    {
549
    int[] permFree = new int[4];
550
    int center_perm_num = (index%360);
551
    index /= 360;
552
    int totalTwist = (index%2187);
553
    permFree[0] = (index/2187);
554

    
555
    int[] quats = new int[14];
556
    int[] center_perm = new int[6];
557
    int[] twist = new int[8];
558

    
559
    TablebaseHelpers.getEvenPermutationFromNum(center_perm, center_perm_num);
560
    fillCenterQuats(quats,center_perm);
561

    
562
    int total = 0;
563

    
564
    for(int i=0; i<7; i++)
565
      {
566
      twist[i] = (totalTwist%3);
567
      totalTwist /= 3;
568
      total += twist[i];
569
      }
570

    
571
    twist[7] = ((24-total)%3);
572
    int sumFixedTwists = twist[FIXED[0]]+twist[FIXED[1]]+twist[FIXED[2]]+twist[FIXED[3]];
573

    
574
    permFree[1] = permFree1(permFree[0],sumFixedTwists);
575
    fillUpToEvenPerm(permFree);
576
    fillInQuats(quats,permFree,twist);
577

    
578
    return quats;
579
    }
580

    
581
///////////////////////////////////////////////////////////////////////////////////////////////////
582

    
583
  int getIndex(int[] quats)
584
    {
585
    int[] center_perm = computeCenterPerm(quats);
586
    int center_perm_num = TablebaseHelpers.computeEvenPermutationNum(center_perm);
587
    int[] twist = new int[8];
588
    computeCornerTwists(twist,quats);
589
    int totalTwist = twist[0]+ 3*(twist[1]+ 3*(twist[2]+ 3*(twist[3]+ 3*(twist[4]+ 3*(twist[5]+ 3*twist[6])))));
590
    int locationOfFree0 = computeLocation(0,quats[1]);
591

    
592
    return center_perm_num+ 360*(totalTwist + 2187*locationOfFree0);
593
    }
594
}  
595

    
(14-14/19)