Project

General

Profile

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

magiccube / src / main / java / org / distorted / solvers / SolverJing.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 android.content.res.Resources;
13

    
14
import org.distorted.main.R;
15
import org.distorted.objectlib.helpers.OperatingSystemInterface;
16
import org.distorted.objectlib.metadata.ListObjects;
17
import org.distorted.objectlib.main.TwistyObject;
18
import org.distorted.objectlib.tablebases.ImplementedTablebasesList;
19
import org.distorted.objectlib.tablebases.TBPyraminx;
20
import org.distorted.objectlib.tablebases.TablebaseHelpers;
21
import org.distorted.objectlib.tablebases.TablebasesAbstract;
22

    
23
///////////////////////////////////////////////////////////////////////////////////////////////////
24

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

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

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

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

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

    
53
///////////////////////////////////////////////////////////////////////////////////////////////////
54

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

    
60
///////////////////////////////////////////////////////////////////////////////////////////////////
61

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

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

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

    
80
///////////////////////////////////////////////////////////////////////////////////////////////////
81

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

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

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

    
102
    return 0;
103
    }
104

    
105
///////////////////////////////////////////////////////////////////////////////////////////////////
106

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

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

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

    
127
    return 0;
128
    }
129

    
130
///////////////////////////////////////////////////////////////////////////////////////////////////
131

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

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

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

    
147
    return 0;
148
    }
149

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

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

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

    
160
    return ret;
161
    }
162

    
163
///////////////////////////////////////////////////////////////////////////////////////////////////
164

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

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

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

    
204
///////////////////////////////////////////////////////////////////////////////////////////////////
205

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

    
212
    return -1;
213
    }
214

    
215
///////////////////////////////////////////////////////////////////////////////////////////////////
216

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

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

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

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

    
235
    return quats;
236
    }
237

    
238
///////////////////////////////////////////////////////////////////////////////////////////////////
239
// GRB YBR YGB YRG
240

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

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

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

    
258
///////////////////////////////////////////////////////////////////////////////////////////////////
259
// G Y B R
260

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

    
267
///////////////////////////////////////////////////////////////////////////////////////////////////
268

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

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

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

    
285
    return ret;
286
    }
287

    
288
///////////////////////////////////////////////////////////////////////////////////////////////////
289

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

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

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

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

    
322
      return -1;
323
      }
324

    
325
    return -2;
326
    }
327

    
328
///////////////////////////////////////////////////////////////////////////////////////////////////
329

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

    
337
    return -1;
338
    }
339

    
340
///////////////////////////////////////////////////////////////////////////////////////////////////
341

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

    
349
    getCorners(object,corners);
350

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
402
///////////////////////////////////////////////////////////////////////////////////////////////////
403

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

    
414
    return -1;
415
    }
416

    
417
///////////////////////////////////////////////////////////////////////////////////////////////////
418

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

    
429
    return -1;
430
    }
431

    
432
///////////////////////////////////////////////////////////////////////////////////////////////////
433

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

    
444
    return -1;
445
    }
446

    
447
///////////////////////////////////////////////////////////////////////////////////////////////////
448

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

    
459
    return -1;
460
    }
461

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

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

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

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

    
477
///////////////////////////////////////////////////////////////////////////////////////////////////
478

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

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

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

    
490
///////////////////////////////////////////////////////////////////////////////////////////////////
491

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

    
521
    return null;
522
    }
523

    
524
///////////////////////////////////////////////////////////////////////////////////////////////////
525

    
526
  public int[][] solution(int index, OperatingSystemInterface os)
527
    {
528
    if( mSolver==null )
529
      {
530
      mSolver = ImplementedTablebasesList.createPacked(os, ListObjects.JING_2.name());
531
      }
532

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

    
(9-9/16)