Project

General

Profile

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

magiccube / src / main / java / org / distorted / solvers / SolverJing.java @ db4775f7

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.TBPyraminx;
19
import org.distorted.objectlib.tablebases.TablebaseHelpers;
20
import org.distorted.objectlib.tablebases.TablebasesAbstract;
21

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

    
24
public class SolverJing extends SolverTablebase
25
{
26
  private static final int ERROR_CORNER_GYB_MISSING = -1;
27
  private static final int ERROR_CORNER_GYR_MISSING = -2;
28
  private static final int ERROR_CORNER_GBR_MISSING = -3;
29
  private static final int ERROR_CORNER_YBR_MISSING = -4;
30

    
31
  private static final int ERROR_EDGE_RB_MISSING    = -5;
32
  private static final int ERROR_EDGE_RY_MISSING    = -6;
33
  private static final int ERROR_EDGE_RG_MISSING    = -7;
34
  private static final int ERROR_EDGE_YB_MISSING    = -8;
35
  private static final int ERROR_EDGE_GB_MISSING    = -9;
36
  private static final int ERROR_EDGE_GY_MISSING    = -10;
37

    
38
  private static final int ERROR_CENTER_G_MISSING   = -11;
39
  private static final int ERROR_CENTER_Y_MISSING   = -12;
40
  private static final int ERROR_CENTER_B_MISSING   = -13;
41
  private static final int ERROR_CENTER_R_MISSING   = -14;
42

    
43
  private static final int ERROR_CORNERS_CANNOT     = -15;
44
  private static final int ERROR_EDGE_TWISTED       = -16;
45
  private static final int ERROR_CORNER_TWISTED     = -17;
46
  private static final int ERROR_TWO_EDGES          = -18;
47
  private static final int ERROR_TWO_CENTERS        = -19;
48

    
49
  private TablebasesAbstract mSolver;
50
  private int[] mFaceColors;
51

    
52
///////////////////////////////////////////////////////////////////////////////////////////////////
53

    
54
  public SolverJing(Resources res, TwistyObject object)
55
    {
56
    super(res,object);
57
    }
58

    
59
///////////////////////////////////////////////////////////////////////////////////////////////////
60

    
61
  private boolean pieceEqual3(int[] piece, int c1, int c2, int c3)
62
    {
63
    return ( (piece[0]==c1 && piece[1]==c2 && piece[2]==c3) ||
64
             (piece[0]==c1 && piece[2]==c2 && piece[1]==c3) ||
65
             (piece[1]==c1 && piece[0]==c2 && piece[2]==c3) ||
66
             (piece[1]==c1 && piece[2]==c2 && piece[0]==c3) ||
67
             (piece[2]==c1 && piece[1]==c2 && piece[0]==c3) ||
68
             (piece[2]==c1 && piece[0]==c2 && piece[1]==c3)  );
69
    }
70

    
71
///////////////////////////////////////////////////////////////////////////////////////////////////
72

    
73
  private boolean pieceEqual2(int[] piece, int[] colors)
74
    {
75
    return ( (piece[0]==colors[0] && piece[1]==colors[1]) ||
76
             (piece[0]==colors[1] && piece[1]==colors[0])  );
77
    }
78

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

    
81
  private int checkAllCornersPresent(int[][] corners)
82
    {
83
    boolean ybr = false;
84
    boolean gbr = false;
85
    boolean gyr = false;
86
    boolean gyb = false;
87

    
88
    for(int i=0; i<4; i++)
89
      {
90
      if( pieceEqual3(corners[i],0,1,2) ) gyb = true;
91
      if( pieceEqual3(corners[i],0,1,3) ) gyr = true;
92
      if( pieceEqual3(corners[i],0,2,3) ) gbr = true;
93
      if( pieceEqual3(corners[i],1,2,3) ) ybr = true;
94
      }
95

    
96
    if( !ybr ) return ERROR_CORNER_YBR_MISSING;
97
    if( !gbr ) return ERROR_CORNER_GBR_MISSING;
98
    if( !gyr ) return ERROR_CORNER_GYR_MISSING;
99
    if( !gyb ) return ERROR_CORNER_GYB_MISSING;
100

    
101
    return 0;
102
    }
103

    
104
///////////////////////////////////////////////////////////////////////////////////////////////////
105

    
106
  private int checkAllEdgesPresent(int[][] edges, int[][] edgeColors)
107
    {
108
    boolean[] present = new boolean[6];
109
    for(int i=0; i<6; i++) present[i] = false;
110

    
111
    for(int i=0; i<6; i++)
112
      for(int j=0; j<6; j++)
113
        if (pieceEqual2(edges[i], edgeColors[j]))
114
          {
115
          present[j] = true;
116
          break;
117
          }
118

    
119
    if( !present[0] ) return ERROR_EDGE_RB_MISSING;
120
    if( !present[1] ) return ERROR_EDGE_GB_MISSING;
121
    if( !present[2] ) return ERROR_EDGE_RG_MISSING;
122
    if( !present[3] ) return ERROR_EDGE_YB_MISSING;
123
    if( !present[4] ) return ERROR_EDGE_RY_MISSING;
124
    if( !present[5] ) return ERROR_EDGE_GY_MISSING;
125

    
126
    return 0;
127
    }
128

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

    
131
  private int checkAllCentersPresent(int[] centers)
132
    {
133
    boolean[] present = new boolean[4];
134
    for(int i=0; i<4; i++) present[i] = false;
135

    
136
    for(int i=0; i<4; i++)
137
      {
138
      present[centers[i]]= true;
139
      }
140

    
141
    if( !present[0] ) return ERROR_CENTER_G_MISSING;
142
    if( !present[1] ) return ERROR_CENTER_Y_MISSING;
143
    if( !present[2] ) return ERROR_CENTER_B_MISSING;
144
    if( !present[3] ) return ERROR_CENTER_R_MISSING;
145

    
146
    return 0;
147
    }
148

    
149
///////////////////////////////////////////////////////////////////////////////////////////////////
150

    
151
  private int[] computeFaceColors(int[][] corners)
152
    {
153
    int[] ret = new int[4];
154

    
155
    for(int i=0; i<4; i++)
156
      for(int j=0; j<4; j++)
157
        if( corners[i][0]!=j && corners[i][1]!=j && corners[i][2]!=j ) ret[i]=j;
158

    
159
    return ret;
160
    }
161

    
162
///////////////////////////////////////////////////////////////////////////////////////////////////
163

    
164
  private int computePieceTwist(int index, int[] corner, int[] faceColor)
165
    {
166
    int twist1=0, twist2=0, twist3=0;
167

    
168
    switch(index)
169
      {
170
      case 0: if( corner[1]==faceColor[1] ) twist1=1;
171
              if( corner[2]==faceColor[1] ) twist1=2;
172
              if( corner[0]==faceColor[2] ) twist2=2;
173
              if( corner[2]==faceColor[2] ) twist2=1;
174
              if( corner[0]==faceColor[3] ) twist3=1;
175
              if( corner[1]==faceColor[3] ) twist3=2;
176
              break;
177
      case 1: if( corner[1]==faceColor[0] ) twist1=1;
178
              if( corner[2]==faceColor[0] ) twist1=2;
179
              if( corner[0]==faceColor[2] ) twist2=1;
180
              if( corner[1]==faceColor[2] ) twist2=2;
181
              if( corner[0]==faceColor[3] ) twist3=2;
182
              if( corner[2]==faceColor[3] ) twist3=1;
183
              break;
184
      case 2: if( corner[1]==faceColor[0] ) twist1=1;
185
              if( corner[2]==faceColor[0] ) twist1=2;
186
              if( corner[0]==faceColor[1] ) twist2=2;
187
              if( corner[2]==faceColor[1] ) twist2=1;
188
              if( corner[0]==faceColor[3] ) twist3=1;
189
              if( corner[1]==faceColor[3] ) twist3=2;
190
              break;
191
      case 3: if( corner[1]==faceColor[0] ) twist1=1;
192
              if( corner[2]==faceColor[0] ) twist1=2;
193
              if( corner[0]==faceColor[1] ) twist2=1;
194
              if( corner[1]==faceColor[1] ) twist2=2;
195
              if( corner[0]==faceColor[2] ) twist3=2;
196
              if( corner[2]==faceColor[2] ) twist3=1;
197
              break;
198
      }
199

    
200
    return ( twist1!=twist2 || twist1!=twist3 ) ? ERROR_CORNERS_CANNOT : twist1;
201
    }
202

    
203
///////////////////////////////////////////////////////////////////////////////////////////////////
204

    
205
  private int locateEdge(int[][] edges, int[] colors)
206
    {
207
    for(int i=0; i<6; i++)
208
      if( edges[i][0]==colors[0] && edges[i][1]==colors[1] ||
209
          edges[i][0]==colors[1] && edges[i][1]==colors[0]  ) return i;
210

    
211
    return -1;
212
    }
213

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

    
216
  private int edgeTwist(int[] edge, int[] colors)
217
    {
218
    return edge[0]==colors[0] ? 0:1;
219
    }
220

    
221
///////////////////////////////////////////////////////////////////////////////////////////////////
222

    
223
  private int[] computeEdgeQuats(int[][] edges, int[][] edgeColors)
224
    {
225
    int[] quats = new int[6];
226

    
227
    for(int i=0; i<6; i++)
228
      {
229
      int pos   = locateEdge(edges,edgeColors[i]);
230
      int twist = edgeTwist(edges[pos],edgeColors[i]);
231
      quats[i]  = TBPyraminx.EDGE_QUATS[pos][twist];
232
      }
233

    
234
    return quats;
235
    }
236

    
237
///////////////////////////////////////////////////////////////////////////////////////////////////
238
// GRB YBR YGB YRG
239

    
240
  private void getCorners(TwistyObject object, int[][] corners)
241
    {
242
    for(int i=0; i<4; i++)
243
      for(int j=0; j<3; j++)
244
        corners[i][j] = object.getCubitFaceStickerIndex(i,j);
245
    }
246

    
247
///////////////////////////////////////////////////////////////////////////////////////////////////
248
// RB GB RG YB RY GY
249

    
250
  private void getEdges(TwistyObject object, int[][] edges)
251
    {
252
    for(int i=0; i<6; i++)
253
      for(int j=0; j<2; j++)
254
        edges[i][j] = object.getCubitFaceStickerIndex(i+4,j) -4;
255
    }
256

    
257
///////////////////////////////////////////////////////////////////////////////////////////////////
258
// G Y B R
259

    
260
  private void getCenters(TwistyObject object, int[] centers)
261
    {
262
    for(int i=0; i<4; i++)
263
      centers[i] = object.getCubitFaceStickerIndex(i+10,0) - 8;
264
    }
265

    
266
///////////////////////////////////////////////////////////////////////////////////////////////////
267

    
268
  private int[][] computeEdgeColors(int[] faceColor)
269
    {
270
    // The first pair being (2,3) means 'the first edge's first face is on the tetrahedron
271
    // face which opposes corner number 2, and its second face on tetra face which opposes
272
    // corner number 3'
273
    // Order of those pairs determines edge twist.
274

    
275
    final int[][] edgeColorIndices = new int[][] { {2,3},{1,3},{2,1},{0,3},{2,0},{1,0}  };
276
    int[][] ret = new int[6][2];
277

    
278
    for(int i=0; i<6; i++)
279
      {
280
      ret[i][0] = faceColor[edgeColorIndices[i][0]];
281
      ret[i][1] = faceColor[edgeColorIndices[i][1]];
282
      }
283

    
284
    return ret;
285
    }
286

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

    
289
  private int computeCenterTwist(int[] centers, int color1, int color2)
290
    {
291
    if( centers[0]==color1 )
292
      {
293
      if( centers[1]==color2 ) return 1;
294
      if( centers[2]==color2 ) return 2;
295
      if( centers[3]==color2 ) return 0;
296

    
297
      return -1;
298
      }
299
    if( centers[1]==color1 )
300
      {
301
      if( centers[0]==color2 ) return 1;
302
      if( centers[2]==color2 ) return 0;
303
      if( centers[3]==color2 ) return 2;
304

    
305
      return -1;
306
      }
307
    if( centers[2]==color1 )
308
      {
309
      if( centers[0]==color2 ) return 2;
310
      if( centers[1]==color2 ) return 0;
311
      if( centers[3]==color2 ) return 1;
312

    
313
      return -1;
314
      }
315
    if( centers[3]==color1 )
316
      {
317
      if( centers[0]==color2 ) return 0;
318
      if( centers[1]==color2 ) return 2;
319
      if( centers[2]==color2 ) return 1;
320

    
321
      return -1;
322
      }
323

    
324
    return -2;
325
    }
326

    
327
///////////////////////////////////////////////////////////////////////////////////////////////////
328

    
329
  private int getFaceOfCenter(int color, int[] centers)
330
    {
331
    if( centers[0]==color ) return 0;
332
    if( centers[1]==color ) return 1;
333
    if( centers[2]==color ) return 2;
334
    if( centers[3]==color ) return 3;
335

    
336
    return -1;
337
    }
338

    
339
///////////////////////////////////////////////////////////////////////////////////////////////////
340

    
341
  public int tablebaseIndex(TwistyObject object)
342
    {
343
    int[][] corners   = new int[4][3];
344
    int[][] edges     = new int[6][2];
345
    int[] centers     = new int[4];
346
    int[] corner_twist= new int[4];
347

    
348
    getCorners(object,corners);
349

    
350
    int result1 = checkAllCornersPresent(corners);
351
    if( result1<0 ) return result1;
352

    
353
    mFaceColors = computeFaceColors(corners);
354
    int[][] edgeColors = computeEdgeColors(mFaceColors);
355

    
356
    getEdges(object,edges);
357
    int result2 = checkAllEdgesPresent(edges,edgeColors);
358
    if( result2<0 ) return result2;
359

    
360
    getCenters(object,centers);
361
    int result3 = checkAllCentersPresent(centers);
362
    if( result3<0 ) return result3;
363

    
364
    for(int i=0; i<4; i++)
365
      {
366
      corner_twist[i] = computePieceTwist(i,corners[i],mFaceColors);
367
      if( corner_twist[i]<0 ) return ERROR_CORNERS_CANNOT;
368
      }
369

    
370
    int[] quats = computeEdgeQuats(edges,edgeColors);
371
    int[] permutation = new int[6];
372
    TBPyraminx.getEdgePermutation(permutation,quats,0);
373
    boolean even = TablebaseHelpers.permutationIsEven(permutation);
374
    if( !even ) return ERROR_TWO_EDGES;
375
    int[] edge_twist = new int[6];
376
    TBPyraminx.getEdgeTwist(edge_twist,quats,0);
377

    
378
    int twist_gr = computeCenterTwist(centers,mFaceColors[1],mFaceColors[2]);
379
    int twist_ry = computeCenterTwist(centers,mFaceColors[2],mFaceColors[0]);
380

    
381
    if( (twist_ry-twist_gr+1)%3 != 0 ) return ERROR_TWO_CENTERS;
382

    
383
    int total_twist=0;
384
    for(int i=0; i<4; i++) total_twist += corner_twist[i];
385

    
386
    if( (total_twist-twist_gr)%3 !=0 ) return ERROR_CORNER_TWISTED;
387

    
388
    int green_face = getFaceOfCenter(mFaceColors[1],centers);
389

    
390
    int totalEdgeTwist=0;
391
    for(int i=0; i<6; i++) totalEdgeTwist += edge_twist[i];
392
    if( (totalEdgeTwist%2)!=0 ) return ERROR_EDGE_TWISTED;
393

    
394
    int vertexTwist = corner_twist[0]+ 3*(corner_twist[1]+ 3*(corner_twist[2]+ 3*corner_twist[3]));
395
    int edgeTwist = edge_twist[0]+ 2*(edge_twist[1]+ 2*(edge_twist[2]+ 2*(edge_twist[3]+ 2*edge_twist[4])));
396
    int perm_num = TablebaseHelpers.computeEvenPermutationNum(permutation);
397

    
398
    return green_face + 4*(vertexTwist + 81*(edgeTwist + 32*perm_num));
399
    }
400

    
401
///////////////////////////////////////////////////////////////////////////////////////////////////
402

    
403
  private int getColorIndex3(int color)
404
    {
405
    switch(color)
406
      {
407
      case 0: return R.string.color_green3;
408
      case 1: return R.string.color_yellow3;
409
      case 2: return R.string.color_blue3;
410
      case 3: return R.string.color_red3;
411
      }
412

    
413
    return -1;
414
    }
415

    
416
///////////////////////////////////////////////////////////////////////////////////////////////////
417

    
418
  private int getColorIndex4(int color)
419
    {
420
    switch(color)
421
      {
422
      case 0: return R.string.color_green4;
423
      case 1: return R.string.color_yellow4;
424
      case 2: return R.string.color_blue4;
425
      case 3: return R.string.color_red4;
426
      }
427

    
428
    return -1;
429
    }
430

    
431
///////////////////////////////////////////////////////////////////////////////////////////////////
432

    
433
  private int getFaceIndex3(int face)
434
    {
435
    switch(mFaceColors[face])
436
      {
437
      case 0: return R.string.color_green3;
438
      case 1: return R.string.color_yellow3;
439
      case 2: return R.string.color_blue3;
440
      case 3: return R.string.color_red3;
441
      }
442

    
443
    return -1;
444
    }
445

    
446
///////////////////////////////////////////////////////////////////////////////////////////////////
447

    
448
  private int getFaceIndex6(int face)
449
    {
450
    switch(mFaceColors[face])
451
      {
452
      case 0: return R.string.color_green6;
453
      case 1: return R.string.color_yellow6;
454
      case 2: return R.string.color_blue6;
455
      case 3: return R.string.color_red6;
456
      }
457

    
458
    return -1;
459
    }
460

    
461
///////////////////////////////////////////////////////////////////////////////////////////////////
462

    
463
  private String cornerError(Resources res, int color0, int color1, int color2)
464
    {
465
    int j0 = getColorIndex3(color0);
466
    int j1 = getColorIndex3(color1);
467
    int j2 = getColorIndex4(color2);
468

    
469
    String c0 = res.getString(j0);
470
    String c1 = res.getString(j1);
471
    String c2 = res.getString(j2);
472

    
473
    return res.getString(R.string.solver_generic_missing_corner,c0,c1,c2);
474
    }
475

    
476
///////////////////////////////////////////////////////////////////////////////////////////////////
477

    
478
  private String edgeError(Resources res, int face0, int face1)
479
    {
480
    int j0 = getFaceIndex3(face0);
481
    int j1 = getFaceIndex6(face1);
482

    
483
    String c0 = res.getString(j0);
484
    String c1 = res.getString(j1);
485

    
486
    return res.getString(R.string.solver_generic_missing_edge,c0,c1);
487
    }
488

    
489
///////////////////////////////////////////////////////////////////////////////////////////////////
490

    
491
  public String error(int index, Resources res)
492
    {
493
    switch(index)
494
      {
495
      case ERROR_CORNER_YBR_MISSING: return cornerError(res,3,2,1);
496
      case ERROR_CORNER_GBR_MISSING: return cornerError(res,3,2,0);
497
      case ERROR_CORNER_GYR_MISSING: return cornerError(res,3,1,0);
498
      case ERROR_CORNER_GYB_MISSING: return cornerError(res,2,1,0);
499
      case ERROR_EDGE_RB_MISSING   : return edgeError(res,3,2);
500
      case ERROR_EDGE_RY_MISSING   : return edgeError(res,2,0);
501
      case ERROR_EDGE_RG_MISSING   : return edgeError(res,2,1);
502
      case ERROR_EDGE_YB_MISSING   : return edgeError(res,3,0);
503
      case ERROR_EDGE_GB_MISSING   : return edgeError(res,3,1);
504
      case ERROR_EDGE_GY_MISSING   : return edgeError(res,1,0);
505
      case ERROR_CENTER_G_MISSING  : String colorG = res.getString(R.string.color_green2);
506
                                     return res.getString(R.string.solver_generic_missing_center,colorG);
507
      case ERROR_CENTER_Y_MISSING  : String colorY = res.getString(R.string.color_yellow2);
508
                                     return res.getString(R.string.solver_generic_missing_center,colorY);
509
      case ERROR_CENTER_B_MISSING  : String colorB = res.getString(R.string.color_blue2);
510
                                     return res.getString(R.string.solver_generic_missing_center,colorB);
511
      case ERROR_CENTER_R_MISSING  : String colorR = res.getString(R.string.color_red2);
512
                                     return res.getString(R.string.solver_generic_missing_center,colorR);
513
      case ERROR_CORNER_TWISTED    : return res.getString(R.string.solver_generic_corner_twist);
514
      case ERROR_EDGE_TWISTED      : return res.getString(R.string.solver_generic_edge_twist);
515
      case ERROR_CORNERS_CANNOT    : return res.getString(R.string.solver_generic_corners_cannot);
516
      case ERROR_TWO_EDGES         : return res.getString(R.string.solver_generic_two_edges);
517
      case ERROR_TWO_CENTERS       : return res.getString(R.string.solver_generic_two_centers);
518
      }
519

    
520
    return null;
521
    }
522

    
523
///////////////////////////////////////////////////////////////////////////////////////////////////
524

    
525
  public int[][] solution(int index, Resources res)
526
    {
527
    if( mSolver==null )
528
      {
529
      mSolver = ImplementedTablebasesList.createPacked(res,ObjectSignatures.JING_2);
530
      }
531

    
532
    return mSolver!=null ? mSolver.solution(index,null) : null;
533
    }
534
}  
535

    
(7-7/13)