Project

General

Profile

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

magiccube / src / main / java / org / distorted / solvers / SolverSkewb.java @ master

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 static org.distorted.objectlib.tablebases.TBSkewb.FIXED;
13
import static org.distorted.objectlib.tablebases.TBSkewb.FREE;
14

    
15
import android.content.res.Resources;
16

    
17
import org.distorted.main.R;
18
import org.distorted.objectlib.helpers.OperatingSystemInterface;
19
import org.distorted.objectlib.metadata.ListObjects;
20
import org.distorted.objectlib.main.TwistyObject;
21
import org.distorted.objectlib.tablebases.ImplementedTablebasesList;
22
import org.distorted.objectlib.tablebases.TBSkewb;
23
import org.distorted.objectlib.tablebases.TablebaseHelpers;
24
import org.distorted.objectlib.tablebases.TablebasesAbstract;
25

    
26
///////////////////////////////////////////////////////////////////////////////////////////////////
27

    
28
public class SolverSkewb extends SolverTablebase
29
{
30
  private static final int ERROR_CORNER_135_MISSING = -1;
31
  private static final int ERROR_CORNER_134_MISSING = -2;
32
  private static final int ERROR_CORNER_125_MISSING = -3;
33
  private static final int ERROR_CORNER_124_MISSING = -4;
34
  private static final int ERROR_CORNER_035_MISSING = -5;
35
  private static final int ERROR_CORNER_034_MISSING = -6;
36
  private static final int ERROR_CORNER_025_MISSING = -7;
37
  private static final int ERROR_CORNER_024_MISSING = -8;
38

    
39
  private static final int ERROR_CENTER_0_MISSING   = -9;
40
  private static final int ERROR_CENTER_1_MISSING   = -10;
41
  private static final int ERROR_CENTER_2_MISSING   = -11;
42
  private static final int ERROR_CENTER_3_MISSING   = -12;
43
  private static final int ERROR_CENTER_4_MISSING   = -13;
44
  private static final int ERROR_CENTER_5_MISSING   = -14;
45

    
46
  private static final int ERROR_CORNERS_CANNOT     = -15;
47
  private static final int ERROR_CORNER_TWISTED     = -16;
48
  private static final int ERROR_TWO_CENTERS        = -17;
49
  private static final int ERROR_TWO_CORNERS        = -18;
50

    
51
  private static final int ERROR_FREE_CORNERS_NOT_EVEN    = -19;
52
  private static final int ERROR_FREE_CORNERS_ROTATED     = -20;
53

    
54
  private TablebasesAbstract mSolver;
55
  private final int[] mFaceColors;
56

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

    
59
  public SolverSkewb(OperatingSystemInterface os, Resources res, TwistyObject object)
60
    {
61
    super(os,res,object);
62
    mFaceColors = new int[6];
63
    }
64

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

    
67
  private void getCorners(TwistyObject object, int[][] corners)
68
    {
69
    for(int i=0; i<8; i++)
70
      for(int j=0; j<3; j++)
71
        corners[i][j] = object.getCubitFaceStickerIndex(i,j);
72
    }
73

    
74
///////////////////////////////////////////////////////////////////////////////////////////////////
75

    
76
  private void createCenterPermutation(int[] output, int[] symbols, int[] perm)
77
    {
78
    for(int s=0; s<6; s++)
79
      {
80
      int symbol = symbols[s];
81

    
82
      for(int p=0; p<6; p++)
83
        if( perm[p]==symbol )
84
          {
85
          output[s] = p;
86
          break;
87
          }
88
      }
89
    }
90

    
91
///////////////////////////////////////////////////////////////////////////////////////////////////
92

    
93
  private int getCenters(TwistyObject object, int[] out)
94
    {
95
    final int[] map = {4,5,2,3,0,1};
96
    int[] tmp = new int[6];
97
    int[] mcl = new int[6];
98
    boolean[] present = new boolean[6];
99

    
100
    for(int i=0; i<6; i++)
101
      {
102
      int color = object.getCubitFaceStickerIndex(i+8,0) - 6;
103
      present[color] = true;
104
      tmp[i] = color;
105
      }
106

    
107
    if( !present[0] ) return ERROR_CENTER_0_MISSING;
108
    if( !present[1] ) return ERROR_CENTER_1_MISSING;
109
    if( !present[2] ) return ERROR_CENTER_2_MISSING;
110
    if( !present[3] ) return ERROR_CENTER_3_MISSING;
111
    if( !present[4] ) return ERROR_CENTER_4_MISSING;
112
    if( !present[5] ) return ERROR_CENTER_5_MISSING;
113

    
114
    for(int i=0; i<6; i++) mcl[i] = map[mFaceColors[i]];
115
    createCenterPermutation(out,mcl,tmp);
116

    
117
    return 0;
118
    }
119

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

    
122
  private int commonCornerColor(int[] c1, int[] c2)
123
    {
124
    int theSame = 0;
125
    int index   = 0;
126

    
127
    for(int i=0; i<3; i++)
128
      for(int j=0; j<3; j++)
129
        if( c1[i]==c2[j] )
130
          {
131
          index = i;
132
          theSame++;
133
          }
134

    
135
    return theSame==1 ? c1[index] : ERROR_CORNERS_CANNOT;
136
    }
137

    
138
///////////////////////////////////////////////////////////////////////////////////////////////////
139

    
140
  private int computeFaceColors(int[][] corners, int[] output)
141
    {
142
    final int[][] corner_indices = { {0,3},{5,6},{0,5},{6,3},{0,6},{3,5} };
143

    
144
    for(int i=0; i<6; i++)
145
      {
146
      int c1 = corner_indices[i][0];
147
      int c2 = corner_indices[i][1];
148
      output[i] = commonCornerColor(corners[c1],corners[c2]);
149
      if( output[i]<0 ) return ERROR_CORNERS_CANNOT;
150
      }
151

    
152
    return 0;
153
    }
154

    
155
///////////////////////////////////////////////////////////////////////////////////////////////////
156

    
157
  private boolean cornerIs(int[] corner, int f0, int f1, int f2)
158
    {
159
    int c0 = mFaceColors[f0];
160
    int c1 = mFaceColors[f1];
161
    int c2 = mFaceColors[f2];
162

    
163
    return ( (corner[0]==c0 && corner[1]==c1 && corner[2]==c2 ) ||
164
             (corner[1]==c0 && corner[2]==c1 && corner[0]==c2 ) ||
165
             (corner[2]==c0 && corner[0]==c1 && corner[1]==c2 )  );
166
    }
167

    
168
///////////////////////////////////////////////////////////////////////////////////////////////////
169

    
170
  private int checkAllCornersPresent(int[][] corners)
171
    {
172
    boolean[] present = new boolean[8];
173

    
174
    for(int i=0; i<8; i++)
175
      {
176
      if( cornerIs(corners[i],4,2,0) ) present[0]=true;
177
      if( cornerIs(corners[i],2,5,0) ) present[1]=true;
178
      if( cornerIs(corners[i],3,4,0) ) present[2]=true;
179
      if( cornerIs(corners[i],5,3,0) ) present[3]=true;
180
      if( cornerIs(corners[i],1,2,4) ) present[4]=true;
181
      if( cornerIs(corners[i],5,2,1) ) present[5]=true;
182
      if( cornerIs(corners[i],4,3,1) ) present[6]=true;
183
      if( cornerIs(corners[i],1,3,5) ) present[7]=true;
184
      }
185

    
186
    if( !present[0] ) return ERROR_CORNER_024_MISSING;
187
    if( !present[1] ) return ERROR_CORNER_025_MISSING;
188
    if( !present[2] ) return ERROR_CORNER_034_MISSING;
189
    if( !present[3] ) return ERROR_CORNER_035_MISSING;
190
    if( !present[4] ) return ERROR_CORNER_124_MISSING;
191
    if( !present[5] ) return ERROR_CORNER_125_MISSING;
192
    if( !present[6] ) return ERROR_CORNER_134_MISSING;
193
    if( !present[7] ) return ERROR_CORNER_135_MISSING;
194

    
195
    return 0;
196
    }
197

    
198
///////////////////////////////////////////////////////////////////////////////////////////////////
199

    
200
  private int retFreeCornerPermutation(int[] perm, int[][] corners)
201
    {
202
    perm[0] = -1;
203
    perm[1] = -1;
204
    perm[2] = -1;
205
    perm[3] = -1;
206

    
207
    for(int i=0; i<4; i++)
208
      {
209
      int[] cor = corners[FREE[i]];
210

    
211
      if( cornerIs(cor,2,5,0) ) perm[0] = i;
212
      if( cornerIs(cor,3,4,0) ) perm[1] = i;
213
      if( cornerIs(cor,1,2,4) ) perm[2] = i;
214
      if( cornerIs(cor,1,3,5) ) perm[3] = i;
215
      }
216

    
217
    if( perm[0]==-1 ) return ERROR_CORNER_025_MISSING;
218
    if( perm[1]==-1 ) return ERROR_CORNER_034_MISSING;
219
    if( perm[2]==-1 ) return ERROR_CORNER_124_MISSING;
220
    if( perm[3]==-1 ) return ERROR_CORNER_135_MISSING;
221

    
222
    return 0;
223
    }
224

    
225
///////////////////////////////////////////////////////////////////////////////////////////////////
226

    
227
  private void computeCornerQuats(int[] quats, int[][] corners, int[] perm)
228
    {
229
    final int[] zeroeth_face_map = { 4,2,3,5,1,5,4,1 };
230
    int[] twist = new int[8];
231

    
232
    for(int i=0; i<4; i++)
233
      {
234
      int fi = FIXED[i];
235
      int colorFi = mFaceColors[zeroeth_face_map[fi]];
236
      int[] cFi = corners[fi];
237

    
238
           if( cFi[0]==colorFi ) twist[fi] = 0;
239
      else if( cFi[1]==colorFi ) twist[fi] = 1;
240
      else                       twist[fi] = 2;
241
      }
242

    
243
    int[] inv_perm = new int[4];
244
    TablebaseHelpers.invertPermutation(perm,inv_perm);
245

    
246
    int common14 = commonCornerColor(corners[1], corners[4]);
247
    int common27 = commonCornerColor(corners[2], corners[7]);
248
    int common47 = commonCornerColor(corners[4], corners[7]);
249
    int index;
250
    int[] c;
251

    
252
    index = FREE[inv_perm[0]];
253
    c = corners[FREE[0]];
254

    
255
         if(c[0]==common14) twist[index] = 0;
256
    else if(c[1]==common14) twist[index] = 2;
257
    else                    twist[index] = 1;
258

    
259
    index = FREE[inv_perm[1]];
260
    c = corners[FREE[1]];
261

    
262
         if(c[0]==common27) twist[index] = 0;
263
    else if(c[1]==common27) twist[index] = 2;
264
    else                    twist[index] = 1;
265

    
266
    index = FREE[inv_perm[2]];
267
    c = corners[FREE[2]];
268

    
269
         if(c[0]==common47) twist[index] = 0;
270
    else if(c[1]==common47) twist[index] = 2;
271
    else                    twist[index] = 1;
272

    
273
    index = FREE[inv_perm[3]];
274
    c = corners[FREE[3]];
275

    
276
         if(c[0]==common47) twist[index] = 0;
277
    else if(c[1]==common47) twist[index] = 2;
278
    else                    twist[index] = 1;
279

    
280
    TBSkewb.fillInQuats(quats,perm,twist);
281
    }
282

    
283
///////////////////////////////////////////////////////////////////////////////////////////////////
284

    
285
  public int tablebaseIndex(TwistyObject object)
286
    {
287
    int[][] corners= new int[8][3];
288
    int[] centers  = new int[6];
289
    int[] twist    = new int[8];
290
    int[] freePerm = new int[4];
291
    int[] quats    = new int[8];
292

    
293
    getCorners(object,corners);
294

    
295
    int result1 = computeFaceColors(corners,mFaceColors);
296
    if( result1<0 ) return result1;
297

    
298
    int result2 = checkAllCornersPresent(corners);
299
    if( result2<0 ) return result2;
300

    
301
    int result3 = getCenters(object,centers);
302
    if( result3<0 ) return result3;
303

    
304
    if( !TablebaseHelpers.permutationIsEven(centers) ) return ERROR_TWO_CENTERS;
305
    int center_perm_num = TablebaseHelpers.computeEvenPermutationNum(centers);
306

    
307
    int result4 = retFreeCornerPermutation(freePerm,corners);
308
    if( result4<0 ) return result4;
309

    
310
    computeCornerQuats(quats,corners,freePerm);
311

    
312
    int[] freeLoc = new int[4];
313
    for(int f=0; f<4; f++) freeLoc[f] = TBSkewb.computeLocation(f,quats[FREE[f]]);
314
    if( !TablebaseHelpers.permutationIsEven(freeLoc) ) return ERROR_FREE_CORNERS_NOT_EVEN;
315

    
316
    TBSkewb.computeCornerTwists(twist,quats);
317

    
318
    int total = 0;
319
    for(int i=0; i<8; i++) total += twist[i];
320
    if( (total%3)!=0 ) return ERROR_CORNER_TWISTED;
321
    int totalTwist = twist[0]+ 3*(twist[1]+ 3*(twist[2]+ 3*(twist[3]+ 3*(twist[4]+ 3*(twist[5]+ 3*twist[6])))));
322

    
323
    int sumFixedTwists = twist[FIXED[0]]+twist[FIXED[1]]+twist[FIXED[2]]+twist[FIXED[3]];
324
    int freeLoc1 = TBSkewb.permFree1(freeLoc[0],sumFixedTwists);
325
    if( freeLoc[1] != freeLoc1 ) return ERROR_FREE_CORNERS_ROTATED;
326

    
327
    return center_perm_num+ 360*(totalTwist + 2187*freeLoc[0]);
328
    }
329

    
330
///////////////////////////////////////////////////////////////////////////////////////////////////
331

    
332
  private int getColorIndex2(int face)
333
    {
334
    switch(mFaceColors[face])
335
      {
336
      case 0: return R.string.color_yellow2;
337
      case 1: return R.string.color_white2;
338
      case 2: return R.string.color_blue2;
339
      case 3: return R.string.color_green2;
340
      case 4: return R.string.color_red2;
341
      case 5: return R.string.color_orange2;
342
      }
343

    
344
    return -1;
345
    }
346

    
347
///////////////////////////////////////////////////////////////////////////////////////////////////
348

    
349
  private int getColorIndex3(int face)
350
    {
351
    switch(mFaceColors[face])
352
      {
353
      case 0: return R.string.color_yellow3;
354
      case 1: return R.string.color_white3;
355
      case 2: return R.string.color_blue3;
356
      case 3: return R.string.color_green3;
357
      case 4: return R.string.color_red3;
358
      case 5: return R.string.color_orange3;
359
      }
360

    
361
    return -1;
362
    }
363

    
364
///////////////////////////////////////////////////////////////////////////////////////////////////
365

    
366
  private int getColorIndex4(int face)
367
    {
368
    switch(mFaceColors[face])
369
      {
370
      case 0: return R.string.color_yellow4;
371
      case 1: return R.string.color_white4;
372
      case 2: return R.string.color_blue4;
373
      case 3: return R.string.color_green4;
374
      case 4: return R.string.color_red4;
375
      case 5: return R.string.color_orange4;
376
      }
377

    
378
    return -1;
379
    }
380

    
381
///////////////////////////////////////////////////////////////////////////////////////////////////
382

    
383
  private String cornerError(Resources res, int face0, int face1, int face2)
384
    {
385
    int j0 = getColorIndex3(face0);
386
    int j1 = getColorIndex3(face1);
387
    int j2 = getColorIndex4(face2);
388

    
389
    String c0 = res.getString(j0);
390
    String c1 = res.getString(j1);
391
    String c2 = res.getString(j2);
392

    
393
    return res.getString(R.string.solver_generic_missing_corner,c0,c1,c2);
394
    }
395

    
396
///////////////////////////////////////////////////////////////////////////////////////////////////
397

    
398
  private String centerError(Resources res, int face)
399
    {
400
    int color = getColorIndex2(face);
401
    String clr= res.getString(color);
402
    return res.getString(R.string.solver_generic_missing_center,clr);
403
    }
404

    
405
///////////////////////////////////////////////////////////////////////////////////////////////////
406

    
407
  public String error(int index, Resources res)
408
    {
409
    switch(index)
410
      {
411
      case ERROR_CORNER_135_MISSING   : return cornerError(res,1,3,5);
412
      case ERROR_CORNER_134_MISSING   : return cornerError(res,1,3,4);
413
      case ERROR_CORNER_125_MISSING   : return cornerError(res,1,2,5);
414
      case ERROR_CORNER_124_MISSING   : return cornerError(res,1,2,4);
415
      case ERROR_CORNER_035_MISSING   : return cornerError(res,0,3,5);
416
      case ERROR_CORNER_034_MISSING   : return cornerError(res,0,3,4);
417
      case ERROR_CORNER_025_MISSING   : return cornerError(res,0,2,5);
418
      case ERROR_CORNER_024_MISSING   : return cornerError(res,0,2,4);
419

    
420
      case ERROR_CENTER_0_MISSING     : return centerError(res,0);
421
      case ERROR_CENTER_1_MISSING     : return centerError(res,1);
422
      case ERROR_CENTER_2_MISSING     : return centerError(res,2);
423
      case ERROR_CENTER_3_MISSING     : return centerError(res,3);
424
      case ERROR_CENTER_4_MISSING     : return centerError(res,4);
425
      case ERROR_CENTER_5_MISSING     : return centerError(res,5);
426

    
427
      case ERROR_CORNERS_CANNOT       : return res.getString(R.string.solver_generic_corners_cannot);
428
      case ERROR_CORNER_TWISTED       : return res.getString(R.string.solver_generic_corner_twist);
429
      case ERROR_TWO_CENTERS          : return res.getString(R.string.solver_generic_two_centers);
430
      case ERROR_TWO_CORNERS          : return res.getString(R.string.solver_generic_two_corners);
431

    
432
      case ERROR_FREE_CORNERS_NOT_EVEN: return res.getString(R.string.solver_generic_free_corners_odd);
433
      case ERROR_FREE_CORNERS_ROTATED : return res.getString(R.string.solver_generic_free_corners_rotated);
434
      }
435

    
436
    return null;
437
    }
438

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

    
441
  public int[][] solution(int index, OperatingSystemInterface os)
442
    {
443
    if( mSolver==null )
444
      {
445
      mSolver = ImplementedTablebasesList.createPacked(os, ListObjects.SKEW_2.name() );
446
      }
447

    
448
    return mSolver!=null ? mSolver.solution(index,null,os) : null;
449
    }
450
}  
451

    
(14-14/16)