Project

General

Profile

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

magiccube / src / main / java / org / distorted / solvers / SolverPyraminx.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.TablebaseHelpers;
19
import org.distorted.objectlib.tablebases.TablebasesAbstract;
20
import org.distorted.objectlib.tablebases.TBPyraminx;
21

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

    
24
public class SolverPyraminx 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_VERTEX_GYB_MISSING = -5;
32
  private static final int ERROR_VERTEX_GYR_MISSING = -6;
33
  private static final int ERROR_VERTEX_GBR_MISSING = -7;
34
  private static final int ERROR_VERTEX_YBR_MISSING = -8;
35

    
36
  private static final int ERROR_EDGE_RB_MISSING = -9;
37
  private static final int ERROR_EDGE_RY_MISSING = -10;
38
  private static final int ERROR_EDGE_RG_MISSING = -11;
39
  private static final int ERROR_EDGE_YB_MISSING = -12;
40
  private static final int ERROR_EDGE_GB_MISSING = -13;
41
  private static final int ERROR_EDGE_GY_MISSING = -14;
42

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

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

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

    
55
  private boolean pieceEqual3(int[] piece, int c1, int c2, int c3)
56
    {
57
    return ( (piece[0]==c1 && piece[1]==c2 && piece[2]==c3) ||
58
             (piece[0]==c1 && piece[2]==c2 && piece[1]==c3) ||
59
             (piece[1]==c1 && piece[0]==c2 && piece[2]==c3) ||
60
             (piece[1]==c1 && piece[2]==c2 && piece[0]==c3) ||
61
             (piece[2]==c1 && piece[1]==c2 && piece[0]==c3) ||
62
             (piece[2]==c1 && piece[0]==c2 && piece[1]==c3)  );
63
    }
64

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

    
67
  private boolean pieceEqual2(int[] piece, int[] colors)
68
    {
69
    return ( (piece[0]==colors[0] && piece[1]==colors[1]) ||
70
             (piece[0]==colors[1] && piece[1]==colors[0])  );
71
    }
72

    
73
///////////////////////////////////////////////////////////////////////////////////////////////////
74

    
75
  private int checkAllCornersPresent(int[][] corners)
76
    {
77
    boolean ybr = false;
78
    boolean gbr = false;
79
    boolean gyr = false;
80
    boolean gyb = false;
81

    
82
    for(int i=0; i<4; i++)
83
      {
84
      if( pieceEqual3(corners[i],0,1,2) ) gyb = true;
85
      if( pieceEqual3(corners[i],0,1,3) ) gyr = true;
86
      if( pieceEqual3(corners[i],0,2,3) ) gbr = true;
87
      if( pieceEqual3(corners[i],1,2,3) ) ybr = true;
88
      }
89

    
90
    if( !ybr ) return ERROR_CORNER_YBR_MISSING;
91
    if( !gbr ) return ERROR_CORNER_GBR_MISSING;
92
    if( !gyr ) return ERROR_CORNER_GYR_MISSING;
93
    if( !gyb ) return ERROR_CORNER_GYB_MISSING;
94

    
95
    return 0;
96
    }
97

    
98
///////////////////////////////////////////////////////////////////////////////////////////////////
99

    
100
  private int checkAllVerticesPresent(int[][] vertex)
101
    {
102
    boolean ybr = false;
103
    boolean gbr = false;
104
    boolean gyr = false;
105
    boolean gyb = false;
106

    
107
    for(int i=0; i<4; i++)
108
      {
109
      if( pieceEqual3(vertex[i],0,1,2) ) gyb = true;
110
      if( pieceEqual3(vertex[i],0,1,3) ) gyr = true;
111
      if( pieceEqual3(vertex[i],0,2,3) ) gbr = true;
112
      if( pieceEqual3(vertex[i],1,2,3) ) ybr = true;
113
      }
114

    
115
    if( !ybr ) return ERROR_VERTEX_YBR_MISSING;
116
    if( !gbr ) return ERROR_VERTEX_GBR_MISSING;
117
    if( !gyr ) return ERROR_VERTEX_GYR_MISSING;
118
    if( !gyb ) return ERROR_VERTEX_GYB_MISSING;
119

    
120
    return 0;
121
    }
122

    
123
///////////////////////////////////////////////////////////////////////////////////////////////////
124

    
125
  private int checkAllEdgesPresent(int[][] edges, int[][] edgeColors)
126
    {
127
    boolean[] present = new boolean[6];
128
    for(int i=0; i<6; i++) present[i] = false;
129

    
130
    for(int i=0; i<6; i++)
131
      for(int j=0; j<6; j++)
132
        if (pieceEqual2(edges[i], edgeColors[j]))
133
          {
134
          present[j] = true;
135
          break;
136
          }
137

    
138
    if( !present[0] ) return ERROR_EDGE_RB_MISSING;
139
    if( !present[1] ) return ERROR_EDGE_RY_MISSING;
140
    if( !present[2] ) return ERROR_EDGE_RG_MISSING;
141
    if( !present[3] ) return ERROR_EDGE_YB_MISSING;
142
    if( !present[4] ) return ERROR_EDGE_GB_MISSING;
143
    if( !present[5] ) return ERROR_EDGE_GY_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 checkAgreement(int[] faces1, int[] faces2)
164
    {
165
    for(int i=0; i<4; i++)
166
      if( faces1[i]!=faces2[i] ) return ERROR_C_V_DONT_MATCH;
167

    
168
    return 0;
169
    }
170

    
171
///////////////////////////////////////////////////////////////////////////////////////////////////
172

    
173
  private int computePieceTwist(int index, int[] corner, int[] faceColor)
174
    {
175
    int twist1=0, twist2=0, twist3=0;
176

    
177
    switch(index)
178
      {
179
      case 0: if( corner[1]==faceColor[1] ) twist1=1;
180
              if( corner[2]==faceColor[1] ) twist1=2;
181
              if( corner[0]==faceColor[2] ) twist2=2;
182
              if( corner[2]==faceColor[2] ) twist2=1;
183
              if( corner[0]==faceColor[3] ) twist3=1;
184
              if( corner[1]==faceColor[3] ) twist3=2;
185
              break;
186
      case 1: if( corner[1]==faceColor[0] ) twist1=1;
187
              if( corner[2]==faceColor[0] ) twist1=2;
188
              if( corner[0]==faceColor[2] ) twist2=1;
189
              if( corner[1]==faceColor[2] ) twist2=2;
190
              if( corner[0]==faceColor[3] ) twist3=2;
191
              if( corner[2]==faceColor[3] ) twist3=1;
192
              break;
193
      case 2: if( corner[1]==faceColor[0] ) twist1=1;
194
              if( corner[2]==faceColor[0] ) twist1=2;
195
              if( corner[0]==faceColor[1] ) twist2=2;
196
              if( corner[2]==faceColor[1] ) twist2=1;
197
              if( corner[0]==faceColor[3] ) twist3=1;
198
              if( corner[1]==faceColor[3] ) twist3=2;
199
              break;
200
      case 3: if( corner[1]==faceColor[0] ) twist1=1;
201
              if( corner[2]==faceColor[0] ) twist1=2;
202
              if( corner[0]==faceColor[1] ) twist2=1;
203
              if( corner[1]==faceColor[1] ) twist2=2;
204
              if( corner[0]==faceColor[2] ) twist3=2;
205
              if( corner[2]==faceColor[2] ) twist3=1;
206
              break;
207
      }
208

    
209
    return ( twist1!=twist2 || twist1!=twist3 ) ? ERROR_CORNERS_CANNOT : twist1;
210
    }
211

    
212
///////////////////////////////////////////////////////////////////////////////////////////////////
213

    
214
  private int locateEdge(int[][] edges, int[] colors)
215
    {
216
    for(int i=0; i<6; i++)
217
      if( edges[i][0]==colors[0] && edges[i][1]==colors[1] ||
218
          edges[i][0]==colors[1] && edges[i][1]==colors[0]  ) return i;
219

    
220
    return -1;
221
    }
222

    
223
///////////////////////////////////////////////////////////////////////////////////////////////////
224

    
225
  private int edgeTwist(int[] edge, int[] colors)
226
    {
227
    return edge[0]==colors[0] ? 0:1;
228
    }
229

    
230
///////////////////////////////////////////////////////////////////////////////////////////////////
231

    
232
  private int[] computeEdgeQuats(int[][] edges, int[][] edgeColors)
233
    {
234
    int[] quats = new int[6];
235

    
236
    for(int i=0; i<6; i++)
237
      {
238
      int pos   = locateEdge(edges,edgeColors[i]);
239
      int twist = edgeTwist(edges[pos],edgeColors[i]);
240
      quats[i]  = TBPyraminx.EDGE_QUATS[pos][twist];
241
      }
242

    
243
    return quats;
244
    }
245

    
246
///////////////////////////////////////////////////////////////////////////////////////////////////
247

    
248
  public SolverPyraminx(Resources res, TwistyObject object)
249
    {
250
    super(res,object);
251
    }
252

    
253
///////////////////////////////////////////////////////////////////////////////////////////////////
254

    
255
  private void getCorners(TwistyObject object, int[][] corners)
256
    {
257
    corners[0][0] = object.getCubitFaceStickerIndex(4,0);  // G
258
    corners[0][1] = object.getCubitFaceStickerIndex(4,3);  // R
259
    corners[0][2] = object.getCubitFaceStickerIndex(4,2);  // B
260

    
261
    corners[1][0] = object.getCubitFaceStickerIndex(6,1);  // Y
262
    corners[1][1] = object.getCubitFaceStickerIndex(6,2);  // B
263
    corners[1][2] = object.getCubitFaceStickerIndex(6,3);  // R
264

    
265
    corners[2][0] = object.getCubitFaceStickerIndex(11,1);  // Y
266
    corners[2][1] = object.getCubitFaceStickerIndex(11,0);  // G
267
    corners[2][2] = object.getCubitFaceStickerIndex(11,2);  // B
268

    
269
    corners[3][0] = object.getCubitFaceStickerIndex(13,1);  // Y
270
    corners[3][1] = object.getCubitFaceStickerIndex(13,3);  // R
271
    corners[3][2] = object.getCubitFaceStickerIndex(13,0);  // G
272
    }
273

    
274
///////////////////////////////////////////////////////////////////////////////////////////////////
275

    
276
  private void getVertices(TwistyObject object, int[][] vertex)
277
    {
278
    vertex[0][0] = object.getCubitFaceStickerIndex(0,0);  // G
279
    vertex[0][1] = object.getCubitFaceStickerIndex(0,5);  // R
280
    vertex[0][2] = object.getCubitFaceStickerIndex(0,7);  // B
281

    
282
    vertex[1][0] = object.getCubitFaceStickerIndex(1,2);  // Y
283
    vertex[1][1] = object.getCubitFaceStickerIndex(1,7);  // B
284
    vertex[1][2] = object.getCubitFaceStickerIndex(1,5);  // R
285

    
286
    vertex[2][0] = object.getCubitFaceStickerIndex(2,2);  // Y
287
    vertex[2][1] = object.getCubitFaceStickerIndex(2,0);  // G
288
    vertex[2][2] = object.getCubitFaceStickerIndex(2,7);  // B
289

    
290
    vertex[3][0] = object.getCubitFaceStickerIndex(3,2);  // Y
291
    vertex[3][1] = object.getCubitFaceStickerIndex(3,5);  // R
292
    vertex[3][2] = object.getCubitFaceStickerIndex(3,0);  // G
293
    }
294

    
295
///////////////////////////////////////////////////////////////////////////////////////////////////
296

    
297
  private void getEdges(TwistyObject object, int[][] edges)
298
    {
299
    edges[0][0] = object.getCubitFaceStickerIndex(5,3);  // R
300
    edges[0][1] = object.getCubitFaceStickerIndex(5,2);  // B
301

    
302
    edges[1][0] = object.getCubitFaceStickerIndex(10,1); // Y
303
    edges[1][1] = object.getCubitFaceStickerIndex(10,3); // R
304

    
305
    edges[2][0] = object.getCubitFaceStickerIndex(9,0);  // G
306
    edges[2][1] = object.getCubitFaceStickerIndex(9,3);  // R
307

    
308
    edges[3][0] = object.getCubitFaceStickerIndex(8,2);  // B
309
    edges[3][1] = object.getCubitFaceStickerIndex(8,1);  // Y
310

    
311
    edges[4][0] = object.getCubitFaceStickerIndex(7,2);  // B
312
    edges[4][1] = object.getCubitFaceStickerIndex(7,0);  // G
313

    
314
    edges[5][0] = object.getCubitFaceStickerIndex(12,1); // Y
315
    edges[5][1] = object.getCubitFaceStickerIndex(12,0); // G
316
    }
317

    
318
///////////////////////////////////////////////////////////////////////////////////////////////////
319

    
320
  private int[][] computeEdgeColors(int[] faceColor)
321
    {
322
    // The first pair being (2,3) means 'the first edge's first face is on the tetrahedron
323
    // face which oppeses corner number 2, and its second face on tetra face which opposes
324
    // corner number 3'
325
    // Order of those pairs determines edge twist.
326

    
327
    final int[][] edgeColorIndices = new int[][] { {2,3},{0,2},{1,2},{3,0},{3,1},{0,1}  };
328
    int[][] ret = new int[6][2];
329

    
330
    for(int i=0; i<6; i++)
331
      {
332
      ret[i][0] = faceColor[edgeColorIndices[i][0]];
333
      ret[i][1] = faceColor[edgeColorIndices[i][1]];
334
      }
335

    
336
    return ret;
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[][] vertices= new int[4][3];
346
    int[] vertex_twist = new int[4];
347
    mCornerTwist = new int[4];
348

    
349
    getCorners(object,corners);
350
    getVertices(object,vertices);
351

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

    
355
    int result2 = checkAllVerticesPresent(vertices);
356
    if( result2<0 ) return result2;
357

    
358
    int[] facesC = computeFaceColors(corners);
359
    int[] facesV = computeFaceColors(vertices);
360

    
361
    int result3 = checkAgreement(facesC,facesV);
362
    if( result3<0 ) return result3;
363

    
364
    mFaceColors = facesC;
365

    
366
    int[][] edgeColors = computeEdgeColors(mFaceColors);
367

    
368
    getEdges(object,edges);
369
    int result4 = checkAllEdgesPresent(edges,edgeColors);
370
    if( result4<0 ) return result4;
371

    
372
    for(int i=0; i<4; i++)
373
      {
374
      mCornerTwist[i] = computePieceTwist(i,corners[i],mFaceColors);
375
      if( mCornerTwist[i]<0 ) return ERROR_CORNERS_CANNOT;
376
      }
377

    
378
    for(int i=0; i<4; i++)
379
      {
380
      vertex_twist[i] = computePieceTwist(i,vertices[i],mFaceColors);
381
      if( vertex_twist[i]<0 ) return ERROR_VERTICES_CANNOT;
382
      }
383

    
384
    int[] quats = computeEdgeQuats(edges,edgeColors);
385
    int[] permutation = new int[6];
386
    TBPyraminx.getEdgePermutation(permutation,quats,0);
387
    boolean even = TablebaseHelpers.permutationIsEven(permutation);
388
    if( !even ) return ERROR_TWO_EDGES;
389
    int[] edge_twist = new int[6];
390
    TBPyraminx.getEdgeTwist(edge_twist,quats,0);
391

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

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

    
400
    return vertexTwist + 81*(edgeTwist + 32*perm_num);
401
    }
402

    
403
///////////////////////////////////////////////////////////////////////////////////////////////////
404

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

    
415
    return -1;
416
    }
417

    
418
///////////////////////////////////////////////////////////////////////////////////////////////////
419

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

    
430
    return -1;
431
    }
432

    
433
///////////////////////////////////////////////////////////////////////////////////////////////////
434

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

    
445
    return -1;
446
    }
447

    
448
///////////////////////////////////////////////////////////////////////////////////////////////////
449

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

    
460
    return -1;
461
    }
462

    
463
///////////////////////////////////////////////////////////////////////////////////////////////////
464

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

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

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

    
478
///////////////////////////////////////////////////////////////////////////////////////////////////
479

    
480
  private String vertexError(Resources res, int color0, int color1, int color2)
481
    {
482
    int j0 = getColorIndex3(color0);
483
    int j1 = getColorIndex3(color1);
484
    int j2 = getColorIndex4(color2);
485

    
486
    String c0 = res.getString(j0);
487
    String c1 = res.getString(j1);
488
    String c2 = res.getString(j2);
489

    
490
    return res.getString(R.string.solver_generic_missing_vertex,c0,c1,c2);
491
    }
492

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

    
495
  private String edgeError(Resources res, int color0, int color1)
496
    {
497
    int j0 = getFaceIndex3(color0);
498
    int j1 = getFaceIndex6(color1);
499

    
500
    String c0 = res.getString(j0);
501
    String c1 = res.getString(j1);
502

    
503
    return res.getString(R.string.solver_generic_missing_edge,c0,c1);
504
    }
505

    
506
///////////////////////////////////////////////////////////////////////////////////////////////////
507

    
508
  public String error(int index, Resources res)
509
    {
510
    switch(index)
511
      {
512
      case ERROR_CORNER_YBR_MISSING: return cornerError(res,3,2,1);
513
      case ERROR_CORNER_GBR_MISSING: return cornerError(res,3,2,0);
514
      case ERROR_CORNER_GYR_MISSING: return cornerError(res,3,1,0);
515
      case ERROR_CORNER_GYB_MISSING: return cornerError(res,2,1,0);
516
      case ERROR_VERTEX_YBR_MISSING: return vertexError(res,3,2,1);
517
      case ERROR_VERTEX_GBR_MISSING: return vertexError(res,3,2,0);
518
      case ERROR_VERTEX_GYR_MISSING: return vertexError(res,3,1,0);
519
      case ERROR_VERTEX_GYB_MISSING: return vertexError(res,2,1,0);
520
      case ERROR_EDGE_RB_MISSING   : return edgeError(res,3,2);
521
      case ERROR_EDGE_RY_MISSING   : return edgeError(res,2,0);
522
      case ERROR_EDGE_RG_MISSING   : return edgeError(res,2,1);
523
      case ERROR_EDGE_YB_MISSING   : return edgeError(res,3,0);
524
      case ERROR_EDGE_GB_MISSING   : return edgeError(res,3,1);
525
      case ERROR_EDGE_GY_MISSING   : return edgeError(res,1,0);
526
      case ERROR_EDGE_TWISTED      : return res.getString(R.string.solver_generic_edge_twist);
527
      case ERROR_CORNERS_CANNOT    : return res.getString(R.string.solver_generic_corners_cannot);
528
      case ERROR_VERTICES_CANNOT   : return res.getString(R.string.solver_generic_vertices_cannot);
529
      case ERROR_C_V_DONT_MATCH    : return res.getString(R.string.solver_generic_c_v_dont_match);
530
      case ERROR_TWO_EDGES         : return res.getString(R.string.solver_generic_two_edges);
531
      }
532

    
533
    return null;
534
    }
535

    
536
///////////////////////////////////////////////////////////////////////////////////////////////////
537

    
538
  public int[][] solution(int index, Resources res)
539
    {
540
    if( mSolver==null )
541
      {
542
      mSolver = ImplementedTablebasesList.createPacked(res, ObjectSignatures.PYRA_3);
543
      }
544

    
545
    return mSolver!=null ? mSolver.solution(index,mCornerTwist) : null;
546
    }
547
}  
548

    
(9-9/13)