Project

General

Profile

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

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

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

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

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

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

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

    
54
///////////////////////////////////////////////////////////////////////////////////////////////////
55

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

    
66
///////////////////////////////////////////////////////////////////////////////////////////////////
67

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

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

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

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

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

    
96
    return 0;
97
    }
98

    
99
///////////////////////////////////////////////////////////////////////////////////////////////////
100

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

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

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

    
121
    return 0;
122
    }
123

    
124
///////////////////////////////////////////////////////////////////////////////////////////////////
125

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

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

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

    
169
    return 0;
170
    }
171

    
172
///////////////////////////////////////////////////////////////////////////////////////////////////
173

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

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

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

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

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

    
221
    return -1;
222
    }
223

    
224
///////////////////////////////////////////////////////////////////////////////////////////////////
225

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

    
231
///////////////////////////////////////////////////////////////////////////////////////////////////
232

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

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

    
244
    return quats;
245
    }
246

    
247
///////////////////////////////////////////////////////////////////////////////////////////////////
248

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

    
254
///////////////////////////////////////////////////////////////////////////////////////////////////
255

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

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

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

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

    
275
///////////////////////////////////////////////////////////////////////////////////////////////////
276

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

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

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

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

    
296
///////////////////////////////////////////////////////////////////////////////////////////////////
297

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

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

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

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

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

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

    
319
///////////////////////////////////////////////////////////////////////////////////////////////////
320

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

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

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

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

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

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

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

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

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

    
365
    mFaceColors = facesC;
366

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

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

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

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

    
385
    int[] quats = computeEdgeQuats(edges,edgeColors);
386
    int[] permutation = new int[6];
387
    TBPyraminx.getEdgePermutation(permutation,quats,0);
388
    boolean even = TablebaseHelpers.permutationIsEven(permutation);
389
    if( !even ) return ERROR_TWO_EDGES;
390
    int[] edge_twist = new int[6];
391
    TBPyraminx.getEdgeTwist(edge_twist,quats,0);
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 = vertex_twist[0]+ 3*(vertex_twist[1]+ 3*(vertex_twist[2]+ 3*vertex_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
    return vertexTwist + 81*(edgeTwist + 32*perm_num);
402
    }
403

    
404
///////////////////////////////////////////////////////////////////////////////////////////////////
405

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

    
416
    return -1;
417
    }
418

    
419
///////////////////////////////////////////////////////////////////////////////////////////////////
420

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

    
431
    return -1;
432
    }
433

    
434
///////////////////////////////////////////////////////////////////////////////////////////////////
435

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

    
446
    return -1;
447
    }
448

    
449
///////////////////////////////////////////////////////////////////////////////////////////////////
450

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

    
461
    return -1;
462
    }
463

    
464
///////////////////////////////////////////////////////////////////////////////////////////////////
465

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

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

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

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

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

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

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

    
494
///////////////////////////////////////////////////////////////////////////////////////////////////
495

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

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

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

    
507
///////////////////////////////////////////////////////////////////////////////////////////////////
508

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

    
534
    return null;
535
    }
536

    
537
///////////////////////////////////////////////////////////////////////////////////////////////////
538

    
539
  public int[][] solution(int index, OperatingSystemInterface os)
540
    {
541
    if( mSolver==null )
542
      {
543
      mSolver = ImplementedTablebasesList.createPacked(os, ListObjects.PYRA_3.name());
544
      }
545

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

    
(11-11/16)