Project

General

Profile

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

magiccube / src / main / java / org / distorted / solvers / SolverPyraminx.java @ a2dd09be

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.ObjectType;
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.TablebasesPyraminx;
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_CORNER_TWISTED   = -17;
46
  private static final int ERROR_EDGE_TWISTED     = -18;
47
  private static final int ERROR_C_V_DONT_MATCH   = -19;
48
  private static final int ERROR_TWO_EDGES        = -20;
49

    
50
  private static final int[][] edgeColors = new int[][]
51
      {
52
          {3,2},{1,3},{0,3},{2,1},{2,0},{1,0}  // order of those pairs determines edge twist
53
      };
54

    
55
  TablebasesAbstract mSolver;
56

    
57
///////////////////////////////////////////////////////////////////////////////////////////////////
58

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

    
69
///////////////////////////////////////////////////////////////////////////////////////////////////
70

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

    
77
///////////////////////////////////////////////////////////////////////////////////////////////////
78

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

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

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

    
99
    return 0;
100
    }
101

    
102
///////////////////////////////////////////////////////////////////////////////////////////////////
103

    
104
  private int checkAllVerticesPresent(int[][] vertex)
105
    {
106
    boolean ybr = false;
107
    boolean gbr = false;
108
    boolean gyr = false;
109
    boolean gyb = false;
110

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

    
119
    if( !ybr ) return ERROR_VERTEX_YBR_MISSING;
120
    if( !gbr ) return ERROR_VERTEX_GBR_MISSING;
121
    if( !gyr ) return ERROR_VERTEX_GYR_MISSING;
122
    if( !gyb ) return ERROR_VERTEX_GYB_MISSING;
123

    
124
    return 0;
125
    }
126

    
127
///////////////////////////////////////////////////////////////////////////////////////////////////
128

    
129
  private int checkAllEdgesPresent(int[][] edges)
130
    {
131
    boolean[] present = new boolean[6];
132
    for(int i=0; i<6; i++) present[i] = false;
133

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

    
142
    if( !present[0] ) return ERROR_EDGE_RB_MISSING;
143
    if( !present[1] ) return ERROR_EDGE_RY_MISSING;
144
    if( !present[2] ) return ERROR_EDGE_RG_MISSING;
145
    if( !present[3] ) return ERROR_EDGE_YB_MISSING;
146
    if( !present[4] ) return ERROR_EDGE_GB_MISSING;
147
    if( !present[5] ) return ERROR_EDGE_GY_MISSING;
148

    
149
    return 0;
150
    }
151

    
152
///////////////////////////////////////////////////////////////////////////////////////////////////
153

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

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

    
162
    return ret;
163
    }
164

    
165
///////////////////////////////////////////////////////////////////////////////////////////////////
166

    
167
  private int checkAgreement(int[] faces1, int[] faces2)
168
    {
169
    for(int i=0; i<4; i++)
170
      if( faces1[i]!=faces2[i] ) return ERROR_C_V_DONT_MATCH;
171

    
172
    return 0;
173
    }
174

    
175
///////////////////////////////////////////////////////////////////////////////////////////////////
176

    
177
  private int computePieceTwist(int index, int[] corner, int[] faceColor)
178
    {
179
    int twist1=0, twist2=0, twist3=0;
180

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

    
213
    return ( twist1!=twist2 || twist1!=twist3 ) ? ERROR_CORNERS_CANNOT : twist1;
214
    }
215

    
216
///////////////////////////////////////////////////////////////////////////////////////////////////
217

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

    
224
    return -1;
225
    }
226

    
227
///////////////////////////////////////////////////////////////////////////////////////////////////
228

    
229
  private int edgeTwist(int[] edge, int[] colors)
230
    {
231
    return edge[0]==colors[0] ? 0:1;
232
    }
233

    
234
///////////////////////////////////////////////////////////////////////////////////////////////////
235

    
236
  private int[] computeEdgeQuats(int[][] edges)
237
    {
238
    int[] quats = new int[6];
239

    
240
    for(int i=0; i<6; i++)
241
      {
242
      int pos   = locateEdge(edges,edgeColors[i]);
243
      int twist = edgeTwist(edges[pos],edgeColors[i]);
244
      quats[i]  = TablebasesPyraminx.EDGE_QUATS[pos][twist];
245
      }
246

    
247
    return quats;
248
    }
249

    
250
///////////////////////////////////////////////////////////////////////////////////////////////////
251

    
252
  public SolverPyraminx(Resources res, TwistyObject object)
253
    {
254
    super(res,object);
255
    }
256

    
257
///////////////////////////////////////////////////////////////////////////////////////////////////
258

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

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

    
269
    corners[2][0] = object.getCubitFaceStickerIndex(11,1);  // Y
270
    corners[2][1] = object.getCubitFaceStickerIndex(11,0);  // G
271
    corners[2][2] = object.getCubitFaceStickerIndex(11,2);  // B
272

    
273
    corners[3][0] = object.getCubitFaceStickerIndex(13,1);  // Y
274
    corners[3][1] = object.getCubitFaceStickerIndex(13,3);  // R
275
    corners[3][2] = object.getCubitFaceStickerIndex(13,0);  // G
276
    }
277

    
278
///////////////////////////////////////////////////////////////////////////////////////////////////
279

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

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

    
290
    vertex[2][0] = object.getCubitFaceStickerIndex(2,2);  // Y
291
    vertex[2][1] = object.getCubitFaceStickerIndex(2,0);  // G
292
    vertex[2][2] = object.getCubitFaceStickerIndex(2,7);  // B
293

    
294
    vertex[3][0] = object.getCubitFaceStickerIndex(3,2);  // Y
295
    vertex[3][1] = object.getCubitFaceStickerIndex(3,5);  // R
296
    vertex[3][2] = object.getCubitFaceStickerIndex(3,0);  // G
297
    }
298

    
299
///////////////////////////////////////////////////////////////////////////////////////////////////
300

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

    
306
    edges[1][0] = object.getCubitFaceStickerIndex(10,1); // Y
307
    edges[1][1] = object.getCubitFaceStickerIndex(10,3); // R
308

    
309
    edges[2][0] = object.getCubitFaceStickerIndex(9,0);  // G
310
    edges[2][1] = object.getCubitFaceStickerIndex(9,3);  // R
311

    
312
    edges[3][0] = object.getCubitFaceStickerIndex(8,2);  // B
313
    edges[3][1] = object.getCubitFaceStickerIndex(8,1);  // Y
314

    
315
    edges[4][0] = object.getCubitFaceStickerIndex(7,2);  // B
316
    edges[4][1] = object.getCubitFaceStickerIndex(7,0);  // G
317

    
318
    edges[5][0] = object.getCubitFaceStickerIndex(12,1); // Y
319
    edges[5][1] = object.getCubitFaceStickerIndex(12,0); // G
320
    }
321

    
322
///////////////////////////////////////////////////////////////////////////////////////////////////
323

    
324
  public int tablebaseIndex(TwistyObject object)
325
    {
326
    int[][] corners = new int[4][3];
327
    int[][] edges   = new int[6][2];
328
    int[][] vertices= new int[4][3];
329
    int[] corner_twist = new int[4];
330
    int[] vertex_twist = new int[4];
331

    
332
    getCorners(object,corners);
333
    getVertices(object,vertices);
334
    getEdges(object,edges);
335

    
336
    int result1 = checkAllCornersPresent(corners);
337
    if( result1<0 ) return result1;
338

    
339
    int result2 = checkAllVerticesPresent(vertices);
340
    if( result2<0 ) return result2;
341

    
342
    int result3 = checkAllEdgesPresent(edges);
343
    if( result3<0 ) return result3;
344

    
345
    int[] faces1 = computeFaceColors(corners);
346
    int[] faces2 = computeFaceColors(vertices);
347

    
348
    int result4 = checkAgreement(faces1,faces2);
349
    if( result4<0 ) return result4;
350
/*
351
for(int i=0; i<4; i++)
352
  android.util.Log.e("D", "face "+i+" : "+faces1[i]);
353
*/
354
    for(int i=0; i<4; i++)
355
      {
356
      corner_twist[i] = computePieceTwist(i,corners[i],faces1);
357

    
358
      //android.util.Log.e("D", "corner twist "+i+" : "+corner_twist[i]);
359

    
360
      if( corner_twist[i]<0 ) return ERROR_CORNERS_CANNOT;
361
      }
362

    
363
    for(int i=0; i<4; i++)
364
      {
365
      vertex_twist[i] = computePieceTwist(i,vertices[i],faces1);
366
      if( vertex_twist[i]<0 ) return ERROR_VERTICES_CANNOT;
367
      }
368
/*
369
for(int i=0; i<6; i++)
370
  android.util.Log.e("D", "edge "+i+" : "+edges[i][0]+" "+edges[i][1]);
371
*/
372

    
373
    int[] quats = computeEdgeQuats(edges);
374
    int[] permutation = new int[6];
375
    TablebasesPyraminx.getEdgePermutation(permutation,quats,0);
376
    boolean even = TablebaseHelpers.permutationIsEven(permutation);
377
    if( !even ) return ERROR_TWO_EDGES;
378
    int[] edge_twist = new int[6];
379
    TablebasesPyraminx.getEdgeTwist(edge_twist,quats,0);
380
/*
381
for(int i=0; i<6; i++)
382
  android.util.Log.e("D", "q edge "+i+" : "+quats[i]);
383

    
384
for(int i=0; i<6; i++)
385
  android.util.Log.e("D", "p edge "+i+" : "+permutation[i]);
386
*/
387

    
388
/*
389
for(int i=0; i<6; i++)
390
  android.util.Log.e("D", "edge twist "+i+" : "+edge_twist[i]);
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
//android.util.Log.e("D", "vertexTwist: : "+vertexTwist+" edgeTwist: "+edgeTwist+" perm_num: "+perm_num );
401

    
402
    return vertexTwist + 81*(edgeTwist + 32*perm_num);
403
    }
404

    
405
///////////////////////////////////////////////////////////////////////////////////////////////////
406

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

    
417
    return -1;
418
    }
419

    
420
///////////////////////////////////////////////////////////////////////////////////////////////////
421

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

    
432
    return -1;
433
    }
434

    
435
///////////////////////////////////////////////////////////////////////////////////////////////////
436

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

    
447
    return -1;
448
    }
449

    
450
///////////////////////////////////////////////////////////////////////////////////////////////////
451

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

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

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

    
465
///////////////////////////////////////////////////////////////////////////////////////////////////
466

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

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

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

    
480
///////////////////////////////////////////////////////////////////////////////////////////////////
481

    
482
  private String edgeError(Resources res, int color0, int color1)
483
    {
484
    int j0 = getColorIndex3(color0);
485
    int j1 = getColorIndex6(color1);
486

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

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

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

    
495
  public String error(int index, Resources res)
496
    {
497
    switch(index)
498
      {
499
      case ERROR_CORNER_YBR_MISSING: return cornerError(res,3,2,1);
500
      case ERROR_CORNER_GBR_MISSING: return cornerError(res,3,2,0);
501
      case ERROR_CORNER_GYR_MISSING: return cornerError(res,3,1,0);
502
      case ERROR_CORNER_GYB_MISSING: return cornerError(res,2,1,0);
503
      case ERROR_VERTEX_YBR_MISSING: return vertexError(res,3,2,1);
504
      case ERROR_VERTEX_GBR_MISSING: return vertexError(res,3,2,0);
505
      case ERROR_VERTEX_GYR_MISSING: return vertexError(res,3,1,0);
506
      case ERROR_VERTEX_GYB_MISSING: return vertexError(res,2,1,0);
507
      case ERROR_EDGE_RB_MISSING   : return edgeError(res,3,2);
508
      case ERROR_EDGE_RY_MISSING   : return edgeError(res,3,1);
509
      case ERROR_EDGE_RG_MISSING   : return edgeError(res,3,0);
510
      case ERROR_EDGE_YB_MISSING   : return edgeError(res,2,1);
511
      case ERROR_EDGE_GB_MISSING   : return edgeError(res,2,0);
512
      case ERROR_EDGE_GY_MISSING   : return edgeError(res,1,0);
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_VERTICES_CANNOT   : return res.getString(R.string.solver_generic_vertices_cannot);
517
      case ERROR_C_V_DONT_MATCH    : return res.getString(R.string.solver_generic_c_v_dont_match);
518
      case ERROR_TWO_EDGES         : return res.getString(R.string.solver_generic_two_edges);
519
      }
520

    
521
    return null;
522
    }
523

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

    
526
  public int[][] solution(int index, Resources res)
527
    {
528
    if( mSolver==null )
529
      {
530
      //mSolver = ImplementedTablebasesList.createPacked(res,ObjectType.PYRA_3);
531
      mSolver = ImplementedTablebasesList.createUnpacked(ObjectType.PYRA_3);
532
      if( mSolver!=null ) mSolver.createTablebase();
533
      }
534

    
535
    return mSolver!=null ? mSolver.solution(index) : null;
536
    }
537
}  
538

    
(6-6/8)