Project

General

Profile

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

magiccube / src / main / java / org / distorted / solvers / SolverSkewb.java @ 14cf0761

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.solvers;
11

    
12
import android.content.res.Resources;
13

    
14
import org.distorted.main.R;
15
import org.distorted.objectlib.main.ObjectSignatures;
16
import org.distorted.objectlib.main.TwistyObject;
17
import org.distorted.objectlib.tablebases.ImplementedTablebasesList;
18
import org.distorted.objectlib.tablebases.TablebaseHelpers;
19
import org.distorted.objectlib.tablebases.TablebasesAbstract;
20

    
21
///////////////////////////////////////////////////////////////////////////////////////////////////
22

    
23
public class SolverSkewb extends SolverTablebase
24
{
25
  private static final int ERROR_CORNER_135_MISSING = -1;
26
  private static final int ERROR_CORNER_134_MISSING = -2;
27
  private static final int ERROR_CORNER_125_MISSING = -3;
28
  private static final int ERROR_CORNER_124_MISSING = -4;
29
  private static final int ERROR_CORNER_035_MISSING = -5;
30
  private static final int ERROR_CORNER_034_MISSING = -6;
31
  private static final int ERROR_CORNER_025_MISSING = -7;
32
  private static final int ERROR_CORNER_024_MISSING = -8;
33

    
34
  private static final int ERROR_CENTER_0_MISSING   = -9;
35
  private static final int ERROR_CENTER_1_MISSING   = -10;
36
  private static final int ERROR_CENTER_2_MISSING   = -11;
37
  private static final int ERROR_CENTER_3_MISSING   = -12;
38
  private static final int ERROR_CENTER_4_MISSING   = -13;
39
  private static final int ERROR_CENTER_5_MISSING   = -14;
40

    
41
  private static final int ERROR_CORNERS_CANNOT     = -15;
42
  private static final int ERROR_CORNER_TWISTED     = -16;
43
  private static final int ERROR_TWO_CENTERS        = -17;
44
  private static final int ERROR_TWO_CORNERS        = -18;
45

    
46
  private TablebasesAbstract mSolver;
47
  private final int[] mFaceColors;
48

    
49
///////////////////////////////////////////////////////////////////////////////////////////////////
50

    
51
  public SolverSkewb(Resources res, TwistyObject object)
52
    {
53
    super(res,object);
54
    mFaceColors = new int[6];
55
    }
56

    
57
///////////////////////////////////////////////////////////////////////////////////////////////////
58

    
59
  private void getCorners(TwistyObject object, int[][] corners)
60
    {
61
    for(int i=0; i<8; i++)
62
      for(int j=0; j<3; j++)
63
        corners[i][j] = object.getCubitFaceStickerIndex(i,j);
64
    }
65

    
66
///////////////////////////////////////////////////////////////////////////////////////////////////
67

    
68
  private void getCenters(TwistyObject object, int[] centers)
69
    {
70
    int[] map = {12,13,10,11,8,9};
71

    
72
    for(int i=0; i<6; i++)
73
      centers[i] = object.getCubitFaceStickerIndex(map[i],0) - 6;
74
    }
75

    
76
///////////////////////////////////////////////////////////////////////////////////////////////////
77

    
78
  private int commonCornerColor(int[] c1, int[] c2)
79
    {
80
    int theSame = 0;
81
    int index   = 0;
82

    
83
    for(int i=0; i<3; i++)
84
      for(int j=0; j<3; j++)
85
        if( c1[i]==c2[j] )
86
          {
87
          index = i;
88
          theSame++;
89
          }
90

    
91
    return theSame==1 ? c1[index] : ERROR_CORNERS_CANNOT;
92
    }
93

    
94
///////////////////////////////////////////////////////////////////////////////////////////////////
95

    
96
  private int computeFaceColors(int[][] corners, int[] output)
97
    {
98
    final int[][] map = { {0,3},{5,6},{0,5},{6,3},{0,6},{3,5} };
99

    
100
    for(int i=0; i<6; i++)
101
      {
102
      int c1 = map[i][0];
103
      int c2 = map[i][1];
104
      output[i] = commonCornerColor(corners[c1],corners[c2]);
105
      if( output[i]<0 ) return ERROR_CORNERS_CANNOT;
106
      }
107

    
108
    return 0;
109
    }
110

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

    
113
  private boolean cornerIs(int[] corner, int c0, int c1, int c2)
114
    {
115
    return ( (corner[0]==c0 && corner[1]==c1 && corner[2]==c2 ) ||
116
             (corner[1]==c0 && corner[2]==c1 && corner[0]==c2 ) ||
117
             (corner[2]==c0 && corner[0]==c1 && corner[1]==c2 )  );
118
    }
119

    
120
///////////////////////////////////////////////////////////////////////////////////////////////////
121

    
122
  private int checkAllCornersPresent(int[][] corners)
123
    {
124
    boolean[] present = new boolean[8];
125

    
126
    for(int i=0; i<8; i++)
127
      {
128
      if( cornerIs(corners[i],4,2,0) ) present[0]=true;
129
      if( cornerIs(corners[i],2,5,0) ) present[1]=true;
130
      if( cornerIs(corners[i],3,4,0) ) present[2]=true;
131
      if( cornerIs(corners[i],5,3,0) ) present[3]=true;
132
      if( cornerIs(corners[i],1,2,4) ) present[4]=true;
133
      if( cornerIs(corners[i],5,2,1) ) present[5]=true;
134
      if( cornerIs(corners[i],4,3,1) ) present[6]=true;
135
      if( cornerIs(corners[i],1,3,5) ) present[7]=true;
136
      }
137

    
138
    if( !present[0] ) return ERROR_CORNER_024_MISSING;
139
    if( !present[1] ) return ERROR_CORNER_025_MISSING;
140
    if( !present[2] ) return ERROR_CORNER_034_MISSING;
141
    if( !present[3] ) return ERROR_CORNER_035_MISSING;
142
    if( !present[4] ) return ERROR_CORNER_124_MISSING;
143
    if( !present[5] ) return ERROR_CORNER_125_MISSING;
144
    if( !present[6] ) return ERROR_CORNER_134_MISSING;
145
    if( !present[7] ) return ERROR_CORNER_135_MISSING;
146

    
147
    return 0;
148
    }
149

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

    
152
  private int checkAllCentersPresent(int[] centers)
153
    {
154
    boolean[] present = new boolean[6];
155
    for(int i=0; i<6; i++) present[centers[i]]= true;
156

    
157
    if( !present[0] ) return ERROR_CENTER_4_MISSING;
158
    if( !present[1] ) return ERROR_CENTER_5_MISSING;
159
    if( !present[2] ) return ERROR_CENTER_2_MISSING;
160
    if( !present[3] ) return ERROR_CENTER_3_MISSING;
161
    if( !present[4] ) return ERROR_CENTER_0_MISSING;
162
    if( !present[5] ) return ERROR_CENTER_1_MISSING;
163

    
164
    return 0;
165
    }
166

    
167
///////////////////////////////////////////////////////////////////////////////////////////////////
168
// free corners: 1,2,4,7
169

    
170
  private int retFreeCornerPermutation(int[] perm, int[][] corners)
171
    {
172
    int[] map = {1,2,4,7};
173

    
174
    perm[0] = -1;
175
    perm[1] = -1;
176
    perm[2] = -1;
177
    perm[3] = -1;
178

    
179
    for(int i=0; i<4; i++)
180
      {
181
      int[] cor = corners[map[i]];
182

    
183
      if( cornerIs(cor,2,5,0) ) perm[0] = i;
184
      if( cornerIs(cor,3,4,0) ) perm[1] = i;
185
      if( cornerIs(cor,1,2,4) ) perm[2] = i;
186
      if( cornerIs(cor,1,3,5) ) perm[3] = i;
187
      }
188

    
189
    if( perm[0]==-1 ) return ERROR_CORNER_025_MISSING;
190
    if( perm[1]==-1 ) return ERROR_CORNER_034_MISSING;
191
    if( perm[2]==-1 ) return ERROR_CORNER_124_MISSING;
192
    if( perm[3]==-1 ) return ERROR_CORNER_135_MISSING;
193

    
194
    return 0;
195
    }
196

    
197
///////////////////////////////////////////////////////////////////////////////////////////////////
198

    
199
  // [1][] are the 3 quats the 1st 'fixed' corner will have when 'fakeTwisted' (which in case of
200
  // the fixed corners is the same as the final twist) with respectively twist 0,1,2.
201

    
202
  private final int[][] fixedQuats = { {0,1,2},{0,7,8},{0,6,5},{0,4,3} };
203

    
204
  // [1][2][] are the 3 quats the 1st free corner, when permuted to the location of the 2nd corner,
205
  // will have when it is 'fakeTwisted' with fakeTwist 0,1,2.
206
  // fakeTwist is an intermediate twist which needs yet to be translated to the final twist of the
207
  // corners (which needs to sum up to something divisible by 3).
208

    
209
  private final int[][][] freeQuats=
210
    {
211
        { {0,3,4},{9,8,1},{6,11,2},{7,10,5} },
212
        { {9,2,7},{0,5,6},{1,10,3},{4,11,8} },
213
        { {5,1,11},{2,4,10},{0,8,7},{9,3,6} },
214
        { {8,6,10},{3,7,11},{9,5,4},{0,2,1} }
215
    };
216

    
217
  private void fillInQuats(int[] output, int[] perm, int[] twist)
218
    {
219
    output[0] = fixedQuats[0][twist[0]];
220
    output[1] = freeQuats[0][perm[0]][twist[1]];
221
    output[2] = freeQuats[1][perm[1]][twist[2]];
222
    output[3] = fixedQuats[1][twist[3]];
223
    output[4] = freeQuats[2][perm[2]][twist[3]];
224
    output[5] = fixedQuats[2][twist[5]];
225
    output[6] = fixedQuats[3][twist[6]];
226
    output[7] = freeQuats[3][perm[3]][twist[7]];
227
    }
228

    
229
///////////////////////////////////////////////////////////////////////////////////////////////////
230

    
231
  private int computeLocation(int quat)
232
    {
233
    for(int i=0; i<4; i++)
234
      {
235
      int[] q = freeQuats[0][i];
236
      if( quat==q[0] || quat==q[1] || quat==q[2] ) return i;
237
      }
238

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

    
243
///////////////////////////////////////////////////////////////////////////////////////////////////
244

    
245
  private int retFixed(int index, int quat)
246
    {
247
    int[] qs = fixedQuats[index];
248

    
249
    if( quat==qs[0]) return 0;
250
    if( quat==qs[1]) return 1;
251
    if( quat==qs[2]) return 2;
252

    
253
    android.util.Log.e("D", "error in retFixed, index="+index+" quat="+quat);
254
    return -1;
255
    }
256

    
257
///////////////////////////////////////////////////////////////////////////////////////////////////
258

    
259
  private int retFree(int index, int quat)
260
    {
261
    int[][] qs = freeQuats[index];
262

    
263
    for(int i=0; i<4; i++)
264
      {
265
      if( quat==qs[i][0]) return 0;
266
      if( quat==qs[i][1]) return 1;
267
      if( quat==qs[i][2]) return 2;
268
      }
269

    
270
    android.util.Log.e("D", "error in retFree, index="+index+" quat="+quat);
271
    return -1;
272
    }
273

    
274
///////////////////////////////////////////////////////////////////////////////////////////////////
275
// In case of the four 'fixed' corners (0,3,5,6) which do not change their location,
276
// the twist is natural: 0 in the init positions and increasing 1 mod 3 on each CW turn.
277
//
278
// In case of the four 'free' corners their twist is relative to the position of the 'free'
279
// tetrahedron. And so, for example the twist of free corner 1 (whose 0th face is orange) is equal
280
// to 0 if free corner 7 is on the same face like 0th face of corner 1 (which is the case in init
281
// position); then once free corners 2,4,7 permute CW, twist of corner 1 increases by 1 mod 3.
282

    
283
  private void computeCornerTwists(int[] twists, int[] quats)
284
    {
285
    twists[0] = retFixed(0,quats[0]);
286
    twists[3] = retFixed(1,quats[3]);
287
    twists[5] = retFixed(2,quats[5]);
288
    twists[6] = retFixed(3,quats[6]);
289

    
290
    twists[1] = retFree(0,quats[1]);
291
    twists[2] = retFree(1,quats[2]);
292
    twists[4] = retFree(2,quats[4]);
293
    twists[7] = retFree(3,quats[7]);
294
    }
295

    
296
///////////////////////////////////////////////////////////////////////////////////////////////////
297

    
298
  private int retCornerPerm(int index, int[] perm)
299
    {
300
    int[] free = {1,2,4,7};
301

    
302
    switch(index)
303
      {
304
      case 0: return 0;
305
      case 1: return free[perm[0]];
306
      case 2: return free[perm[1]];
307
      case 3: return 3;
308
      case 4: return free[perm[2]];
309
      case 5: return 5;
310
      case 6: return 6;
311
      case 7: return free[perm[3]];
312
      }
313

    
314
    return -1;
315
    }
316

    
317
///////////////////////////////////////////////////////////////////////////////////////////////////
318

    
319
  private void computeCornerQuats(int[] quats, int[][] corners, int[] perm)
320
    {
321
    final int[] map = { 4,2,3,5,1,5,4,1 };
322
    int[] twists = new int[8];
323

    
324
    for(int i=0; i<8; i++)
325
      {
326
      int color = mFaceColors[map[i]];
327
      int[] c = corners[retCornerPerm(i,perm)];
328

    
329
           if( c[0]==color ) twists[i] = 0;
330
      else if( c[1]==color ) twists[i] = 1;
331
      else                   twists[i] = 2;
332
      }
333

    
334
    fillInQuats(quats,perm,twists);
335
    }
336

    
337
///////////////////////////////////////////////////////////////////////////////////////////////////
338

    
339
  public int tablebaseIndex(TwistyObject object)
340
    {
341
    int[][] corners= new int[8][3];
342
    int[] centers  = new int[6];
343
    int[] twist    = new int[8];
344
    int[] freePerm = new int[4];
345
    int[] quats    = new int[8];
346

    
347
    getCorners(object,corners);
348

    
349
    int result1 = computeFaceColors(corners,mFaceColors);
350
    if( result1<0 ) return result1;
351

    
352
    int result2 = checkAllCornersPresent(corners);
353
    if( result2<0 ) return result2;
354

    
355
    getCenters(object,centers);
356
    int result3 = checkAllCentersPresent(centers);
357
    if( result3<0 ) return result3;
358
/*
359
for(int i=0; i<8; i++)
360
  for(int j=0; j<3; j++) android.util.Log.e("D", "corner "+i+" face "+j+" : "+corners[i][j]);
361

    
362
for(int i=0; i<6; i++) android.util.Log.e("D", "center "+i+" : "+centers[i]);
363
for(int i=0; i<6; i++) android.util.Log.e("D", "face "+i+" : "+mFaceColors[i]);
364
*/
365
    if( !TablebaseHelpers.permutationIsEven(centers) ) return ERROR_TWO_CENTERS;
366
    int center_perm_num = TablebaseHelpers.computeEvenPermutationNum(centers);
367

    
368
    int result4 = retFreeCornerPermutation(freePerm,corners);
369
    if( result4<0 ) return result4;
370

    
371
    computeCornerQuats(quats,corners,freePerm);
372
    computeCornerTwists(twist,quats);
373
/*
374
for(int i=0; i<4; i++) android.util.Log.e("D", "perm "+i+" : "+freePerm[i]);
375
for(int i=0; i<8; i++) android.util.Log.e("D", "quat "+i+" : "+quats[i]);
376
for(int i=0; i<8; i++) android.util.Log.e("D", "twist "+i+" : "+twist[i]);
377
*/
378
    int total = twist[1]+twist[2]+twist[4]+twist[7];
379
    if( (total%3)!=0 ) return ERROR_CORNER_TWISTED;
380
    int totalTwist = twist[0]+ 3*(twist[1]+ 3*(twist[2]+ 3*(twist[3]+ 3*(twist[4]+ 3*(twist[5]+ 3*twist[6])))));
381

    
382
    int locationOfFree0 = computeLocation(quats[1]);
383

    
384
    return center_perm_num+ 360*(totalTwist + 2187*locationOfFree0);
385
    }
386

    
387
///////////////////////////////////////////////////////////////////////////////////////////////////
388

    
389
  private int getColorIndex2(int face)
390
    {
391
    switch(mFaceColors[face])
392
      {
393
      case 0: return R.string.color_yellow2;
394
      case 1: return R.string.color_white2;
395
      case 2: return R.string.color_blue2;
396
      case 3: return R.string.color_green2;
397
      case 4: return R.string.color_red2;
398
      case 5: return R.string.color_orange2;
399
      }
400

    
401
    return -1;
402
    }
403

    
404
///////////////////////////////////////////////////////////////////////////////////////////////////
405

    
406
  private int getColorIndex3(int face)
407
    {
408
    switch(mFaceColors[face])
409
      {
410
      case 0: return R.string.color_yellow3;
411
      case 1: return R.string.color_white3;
412
      case 2: return R.string.color_blue3;
413
      case 3: return R.string.color_green3;
414
      case 4: return R.string.color_red3;
415
      case 5: return R.string.color_orange3;
416
      }
417

    
418
    return -1;
419
    }
420

    
421
///////////////////////////////////////////////////////////////////////////////////////////////////
422

    
423
  private int getColorIndex4(int face)
424
    {
425
    switch(mFaceColors[face])
426
      {
427
      case 0: return R.string.color_yellow4;
428
      case 1: return R.string.color_white4;
429
      case 2: return R.string.color_blue4;
430
      case 3: return R.string.color_green4;
431
      case 4: return R.string.color_red4;
432
      case 5: return R.string.color_orange4;
433
      }
434

    
435
    return -1;
436
    }
437

    
438
///////////////////////////////////////////////////////////////////////////////////////////////////
439

    
440
  private String cornerError(Resources res, int face0, int face1, int face2)
441
    {
442
    int j0 = getColorIndex3(face0);
443
    int j1 = getColorIndex3(face1);
444
    int j2 = getColorIndex4(face2);
445

    
446
    String c0 = res.getString(j0);
447
    String c1 = res.getString(j1);
448
    String c2 = res.getString(j2);
449

    
450
    return res.getString(R.string.solver_generic_missing_corner,c0,c1,c2);
451
    }
452

    
453
///////////////////////////////////////////////////////////////////////////////////////////////////
454

    
455
  private String centerError(Resources res, int face)
456
    {
457
    int color = getColorIndex2(face);
458
    String clr= res.getString(color);
459
    return res.getString(R.string.solver_generic_missing_center,clr);
460
    }
461

    
462
///////////////////////////////////////////////////////////////////////////////////////////////////
463

    
464
  public String error(int index, Resources res)
465
    {
466
    switch(index)
467
      {
468
      case ERROR_CORNER_135_MISSING: return cornerError(res,1,3,5);
469
      case ERROR_CORNER_134_MISSING: return cornerError(res,1,3,4);
470
      case ERROR_CORNER_125_MISSING: return cornerError(res,1,2,5);
471
      case ERROR_CORNER_124_MISSING: return cornerError(res,1,2,4);
472
      case ERROR_CORNER_035_MISSING: return cornerError(res,0,3,5);
473
      case ERROR_CORNER_034_MISSING: return cornerError(res,0,3,4);
474
      case ERROR_CORNER_025_MISSING: return cornerError(res,0,2,5);
475
      case ERROR_CORNER_024_MISSING: return cornerError(res,0,2,4);
476

    
477
      case ERROR_CENTER_0_MISSING  : return centerError(res,0);
478
      case ERROR_CENTER_1_MISSING  : return centerError(res,1);
479
      case ERROR_CENTER_2_MISSING  : return centerError(res,2);
480
      case ERROR_CENTER_3_MISSING  : return centerError(res,3);
481
      case ERROR_CENTER_4_MISSING  : return centerError(res,4);
482
      case ERROR_CENTER_5_MISSING  : return centerError(res,5);
483

    
484
      case ERROR_CORNERS_CANNOT    : return res.getString(R.string.solver_generic_corners_cannot);
485
      case ERROR_CORNER_TWISTED    : return res.getString(R.string.solver_generic_corner_twist);
486
      case ERROR_TWO_CENTERS       : return res.getString(R.string.solver_generic_two_centers);
487
      case ERROR_TWO_CORNERS       : return res.getString(R.string.solver_generic_two_corners);
488
      }
489

    
490
    return null;
491
    }
492

    
493
///////////////////////////////////////////////////////////////////////////////////////////////////
494

    
495
  public int[][] solution(int index, Resources res)
496
    {
497
    if( mSolver==null )
498
      {
499
      mSolver = ImplementedTablebasesList.createUnpacked(ObjectSignatures.SKEW_2);
500

    
501
      if( mSolver!=null )
502
        {
503
        mSolver.createTablebase(-1);
504
        mSolver.pack();
505
        }
506
      }
507

    
508
    return mSolver!=null ? mSolver.solution(index,null) : null;
509
    }
510
}  
511

    
(10-10/12)