Project

General

Profile

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

magiccube / src / main / java / org / distorted / solvers / SolverJing.java @ 841f82f0

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

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

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

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

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

    
70
///////////////////////////////////////////////////////////////////////////////////////////////////
71

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

    
78
///////////////////////////////////////////////////////////////////////////////////////////////////
79

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

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

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

    
100
    return 0;
101
    }
102

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

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

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

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

    
125
    return 0;
126
    }
127

    
128
///////////////////////////////////////////////////////////////////////////////////////////////////
129

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

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

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

    
145
    return 0;
146
    }
147

    
148
///////////////////////////////////////////////////////////////////////////////////////////////////
149

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

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

    
158
    return ret;
159
    }
160

    
161
///////////////////////////////////////////////////////////////////////////////////////////////////
162

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

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

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

    
202
///////////////////////////////////////////////////////////////////////////////////////////////////
203

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

    
210
    return -1;
211
    }
212

    
213
///////////////////////////////////////////////////////////////////////////////////////////////////
214

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

    
220
///////////////////////////////////////////////////////////////////////////////////////////////////
221

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

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

    
233
    return quats;
234
    }
235

    
236
///////////////////////////////////////////////////////////////////////////////////////////////////
237
// GRB YBR YGB YRG
238

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

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

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

    
256
///////////////////////////////////////////////////////////////////////////////////////////////////
257
// G Y B R
258

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

    
265
///////////////////////////////////////////////////////////////////////////////////////////////////
266

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

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

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

    
283
    return ret;
284
    }
285

    
286
///////////////////////////////////////////////////////////////////////////////////////////////////
287

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

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

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

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

    
320
      return -1;
321
      }
322

    
323
    return -2;
324
    }
325

    
326
///////////////////////////////////////////////////////////////////////////////////////////////////
327

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

    
335
    return -1;
336
    }
337

    
338
///////////////////////////////////////////////////////////////////////////////////////////////////
339

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

    
347
    getCorners(object,corners);
348

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

    
352
    int[] faces = computeFaceColors(corners);
353
    int[][] edgeColors = computeEdgeColors(faces);
354

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

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

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

    
369
    int[] quats = computeEdgeQuats(edges,edgeColors);
370
    int[] permutation = new int[6];
371
    TBPyraminx.getEdgePermutation(permutation,quats,0);
372
    boolean even = TablebaseHelpers.permutationIsEven(permutation);
373
    if( !even ) return ERROR_TWO_EDGES;
374
    int[] edge_twist = new int[6];
375
    TBPyraminx.getEdgeTwist(edge_twist,quats,0);
376
/*
377
for(int i=0; i<4; i++) android.util.Log.e("D", "cornerTwist "+i+" : "+corner_twist[i]);
378
for(int i=0; i<6; i++) android.util.Log.e("D", "edgeTwist "+i+" : "+edge_twist[i]);
379
for(int i=0; i<6; i++) android.util.Log.e("D", "edge perm "+i+" : "+permutation[i]);
380
*/
381
    int twist_gr = computeCenterTwist(centers,faces[1],faces[2]);
382
    int twist_ry = computeCenterTwist(centers,faces[2],faces[0]);
383

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

    
386
    int total_twist=0;
387
    for(int i=0; i<4; i++) total_twist += corner_twist[i];
388

    
389
    if( (total_twist-twist_gr)%3 !=0 ) return ERROR_CORNER_TWISTED;
390

    
391
    int green_face = getFaceOfCenter(faces[1],centers);
392

    
393
    int totalEdgeTwist=0;
394
    for(int i=0; i<6; i++) totalEdgeTwist += edge_twist[i];
395
    if( (totalEdgeTwist%2)!=0 ) return ERROR_EDGE_TWISTED;
396

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

    
401
//android.util.Log.e("D", "ret: green_face="+green_face+" vertTwist="+vertexTwist+" edgeTwist="+edgeTwist+" perm: "+perm_num);
402

    
403
    return green_face + 4*(vertexTwist + 81*(edgeTwist + 32*perm_num));
404
    }
405

    
406
///////////////////////////////////////////////////////////////////////////////////////////////////
407

    
408
  private int getColorIndex3(int color)
409
    {
410
    switch(color)
411
      {
412
      case 0: return R.string.color_green3;
413
      case 1: return R.string.color_yellow3;
414
      case 2: return R.string.color_blue3;
415
      case 3: return R.string.color_red3;
416
      }
417

    
418
    return -1;
419
    }
420

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

    
423
  private int getColorIndex4(int color)
424
    {
425
    switch(color)
426
      {
427
      case 0: return R.string.color_green4;
428
      case 1: return R.string.color_yellow4;
429
      case 2: return R.string.color_blue4;
430
      case 3: return R.string.color_red4;
431
      }
432

    
433
    return -1;
434
    }
435

    
436
///////////////////////////////////////////////////////////////////////////////////////////////////
437

    
438
  private int getColorIndex6(int color)
439
    {
440
    switch(color)
441
      {
442
      case 0: return R.string.color_green6;
443
      case 1: return R.string.color_yellow6;
444
      case 2: return R.string.color_blue6;
445
      case 3: return R.string.color_red6;
446
      }
447

    
448
    return -1;
449
    }
450

    
451
///////////////////////////////////////////////////////////////////////////////////////////////////
452

    
453
  private String cornerError(Resources res, int color0, int color1, int color2)
454
    {
455
    int j0 = getColorIndex3(color0);
456
    int j1 = getColorIndex3(color1);
457
    int j2 = getColorIndex4(color2);
458

    
459
    String c0 = res.getString(j0);
460
    String c1 = res.getString(j1);
461
    String c2 = res.getString(j2);
462

    
463
    return res.getString(R.string.solver_generic_missing_corner,c0,c1,c2);
464
    }
465

    
466
///////////////////////////////////////////////////////////////////////////////////////////////////
467

    
468
  private String edgeError(Resources res, int color0, int color1)
469
    {
470
    int j0 = getColorIndex3(color0);
471
    int j1 = getColorIndex6(color1);
472

    
473
    String c0 = res.getString(j0);
474
    String c1 = res.getString(j1);
475

    
476
    return res.getString(R.string.solver_generic_missing_edge,c0,c1);
477
    }
478

    
479
///////////////////////////////////////////////////////////////////////////////////////////////////
480

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

    
510
    return null;
511
    }
512

    
513
///////////////////////////////////////////////////////////////////////////////////////////////////
514

    
515
  public int[][] solution(int index, Resources res)
516
    {
517
    if( mSolver==null )
518
      {
519
      mSolver = ImplementedTablebasesList.createUnpacked(ObjectSignatures.JING_2);
520
      if( mSolver!=null ) mSolver.createTablebase(-1);
521
      }
522
/*
523
int[] q= {0,0,0,0, 0,0,0,0,0,0, 0,0,0,0};
524
TBJing jing = new TBJing();
525
int in= jing.getIndex(q);
526
android.util.Log.e("D", "index = "+in);
527

    
528
int[] s = jing.getQuats(0);
529

    
530
for(int i=0; i<14; i++) android.util.Log.e("D", "quat = "+i+" : "+s[i]);
531
*/
532
    return mSolver!=null ? mSolver.solution(index,null) : null;
533
    }
534
}  
535

    
(6-6/11)