Project

General

Profile

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

magiccube / src / main / java / org / distorted / solvers / SolverTablebasePYRA3.java @ f4b24b79

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.main.TwistyObject;
17
import org.distorted.objectlib.tablebases.TablebaseHelpers;
18
import org.distorted.objectlib.tablebases.TBPyraminx;
19

    
20
///////////////////////////////////////////////////////////////////////////////////////////////////
21

    
22
public class SolverTablebasePYRA3 extends SolverTablebase
23
{
24
  private static final int ERROR_CORNER_GYB_MISSING = -1;
25
  private static final int ERROR_CORNER_GYR_MISSING = -2;
26
  private static final int ERROR_CORNER_GBR_MISSING = -3;
27
  private static final int ERROR_CORNER_YBR_MISSING = -4;
28

    
29
  private static final int ERROR_VERTEX_GYB_MISSING = -5;
30
  private static final int ERROR_VERTEX_GYR_MISSING = -6;
31
  private static final int ERROR_VERTEX_GBR_MISSING = -7;
32
  private static final int ERROR_VERTEX_YBR_MISSING = -8;
33

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

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

    
47
  private int[] mCornerTwist;
48
  private int[] mFaceColors;
49

    
50
///////////////////////////////////////////////////////////////////////////////////////////////////
51

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

    
62
///////////////////////////////////////////////////////////////////////////////////////////////////
63

    
64
  private boolean pieceEqual2(int[] piece, int[] colors)
65
    {
66
    return ( (piece[0]==colors[0] && piece[1]==colors[1]) ||
67
             (piece[0]==colors[1] && piece[1]==colors[0])  );
68
    }
69

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

    
72
  private int checkAllCornersPresent(int[][] corners)
73
    {
74
    boolean ybr = false;
75
    boolean gbr = false;
76
    boolean gyr = false;
77
    boolean gyb = false;
78

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

    
87
    if( !ybr ) return ERROR_CORNER_YBR_MISSING;
88
    if( !gbr ) return ERROR_CORNER_GBR_MISSING;
89
    if( !gyr ) return ERROR_CORNER_GYR_MISSING;
90
    if( !gyb ) return ERROR_CORNER_GYB_MISSING;
91

    
92
    return 0;
93
    }
94

    
95
///////////////////////////////////////////////////////////////////////////////////////////////////
96

    
97
  private int checkAllVerticesPresent(int[][] vertex)
98
    {
99
    boolean ybr = false;
100
    boolean gbr = false;
101
    boolean gyr = false;
102
    boolean gyb = false;
103

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

    
112
    if( !ybr ) return ERROR_VERTEX_YBR_MISSING;
113
    if( !gbr ) return ERROR_VERTEX_GBR_MISSING;
114
    if( !gyr ) return ERROR_VERTEX_GYR_MISSING;
115
    if( !gyb ) return ERROR_VERTEX_GYB_MISSING;
116

    
117
    return 0;
118
    }
119

    
120
///////////////////////////////////////////////////////////////////////////////////////////////////
121

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

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

    
135
    if( !present[0] ) return ERROR_EDGE_RB_MISSING;
136
    if( !present[1] ) return ERROR_EDGE_RY_MISSING;
137
    if( !present[2] ) return ERROR_EDGE_RG_MISSING;
138
    if( !present[3] ) return ERROR_EDGE_YB_MISSING;
139
    if( !present[4] ) return ERROR_EDGE_GB_MISSING;
140
    if( !present[5] ) return ERROR_EDGE_GY_MISSING;
141

    
142
    return 0;
143
    }
144

    
145
///////////////////////////////////////////////////////////////////////////////////////////////////
146

    
147
  private int[] computeFaceColors(int[][] corners)
148
    {
149
    int[] ret = new int[4];
150

    
151
    for(int i=0; i<4; i++)
152
      for(int j=0; j<4; j++)
153
        if( corners[i][0]!=j && corners[i][1]!=j && corners[i][2]!=j ) ret[i]=j;
154

    
155
    return ret;
156
    }
157

    
158
///////////////////////////////////////////////////////////////////////////////////////////////////
159

    
160
  private int checkAgreement(int[] faces1, int[] faces2)
161
    {
162
    for(int i=0; i<4; i++)
163
      if( faces1[i]!=faces2[i] ) return ERROR_C_V_DONT_MATCH;
164

    
165
    return 0;
166
    }
167

    
168
///////////////////////////////////////////////////////////////////////////////////////////////////
169

    
170
  private int computePieceTwist(int index, int[] corner, int[] faceColor)
171
    {
172
    int twist1=0, twist2=0, twist3=0;
173

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

    
206
    return ( twist1!=twist2 || twist1!=twist3 ) ? ERROR_CORNERS_CANNOT : twist1;
207
    }
208

    
209
///////////////////////////////////////////////////////////////////////////////////////////////////
210

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

    
217
    return -1;
218
    }
219

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

    
222
  private int edgeTwist(int[] edge, int[] colors)
223
    {
224
    return edge[0]==colors[0] ? 0:1;
225
    }
226

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

    
229
  private int[] computeEdgeQuats(int[][] edges, int[][] edgeColors)
230
    {
231
    int[] quats = new int[6];
232

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

    
240
    return quats;
241
    }
242

    
243
///////////////////////////////////////////////////////////////////////////////////////////////////
244

    
245
  public SolverTablebasePYRA3(OperatingSystemInterface os, Resources res, TwistyObject object)
246
    {
247
    super(os,res,object);
248
    }
249

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

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

    
258
    corners[1][0] = object.getCubitFaceStickerIndex(6,1);  // Y
259
    corners[1][1] = object.getCubitFaceStickerIndex(6,2);  // B
260
    corners[1][2] = object.getCubitFaceStickerIndex(6,3);  // R
261

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

    
266
    corners[3][0] = object.getCubitFaceStickerIndex(13,1);  // Y
267
    corners[3][1] = object.getCubitFaceStickerIndex(13,3);  // R
268
    corners[3][2] = object.getCubitFaceStickerIndex(13,0);  // G
269
    }
270

    
271
///////////////////////////////////////////////////////////////////////////////////////////////////
272

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

    
279
    vertex[1][0] = object.getCubitFaceStickerIndex(1,2);  // Y
280
    vertex[1][1] = object.getCubitFaceStickerIndex(1,7);  // B
281
    vertex[1][2] = object.getCubitFaceStickerIndex(1,5);  // R
282

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

    
287
    vertex[3][0] = object.getCubitFaceStickerIndex(3,2);  // Y
288
    vertex[3][1] = object.getCubitFaceStickerIndex(3,5);  // R
289
    vertex[3][2] = object.getCubitFaceStickerIndex(3,0);  // G
290
    }
291

    
292
///////////////////////////////////////////////////////////////////////////////////////////////////
293

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

    
299
    edges[1][0] = object.getCubitFaceStickerIndex(10,1); // Y
300
    edges[1][1] = object.getCubitFaceStickerIndex(10,3); // R
301

    
302
    edges[2][0] = object.getCubitFaceStickerIndex(9,0);  // G
303
    edges[2][1] = object.getCubitFaceStickerIndex(9,3);  // R
304

    
305
    edges[3][0] = object.getCubitFaceStickerIndex(8,2);  // B
306
    edges[3][1] = object.getCubitFaceStickerIndex(8,1);  // Y
307

    
308
    edges[4][0] = object.getCubitFaceStickerIndex(7,2);  // B
309
    edges[4][1] = object.getCubitFaceStickerIndex(7,0);  // G
310

    
311
    edges[5][0] = object.getCubitFaceStickerIndex(12,1); // Y
312
    edges[5][1] = object.getCubitFaceStickerIndex(12,0); // G
313
    }
314

    
315
///////////////////////////////////////////////////////////////////////////////////////////////////
316

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

    
324
    final int[][] edgeColorIndices = new int[][] { {2,3},{0,2},{1,2},{3,0},{3,1},{0,1}  };
325
    int[][] ret = new int[6][2];
326

    
327
    for(int i=0; i<6; i++)
328
      {
329
      ret[i][0] = faceColor[edgeColorIndices[i][0]];
330
      ret[i][1] = faceColor[edgeColorIndices[i][1]];
331
      }
332

    
333
    return ret;
334
    }
335

    
336
///////////////////////////////////////////////////////////////////////////////////////////////////
337

    
338
  public int tablebaseIndex(TwistyObject object)
339
    {
340
    int[][] corners = new int[4][3];
341
    int[][] edges   = new int[6][2];
342
    int[][] vertices= new int[4][3];
343
    int[] vertex_twist = new int[4];
344
    mCornerTwist = new int[4];
345

    
346
    getCorners(object,corners);
347
    getVertices(object,vertices);
348

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

    
352
    int result2 = checkAllVerticesPresent(vertices);
353
    if( result2<0 ) return result2;
354

    
355
    int[] facesC = computeFaceColors(corners);
356
    int[] facesV = computeFaceColors(vertices);
357

    
358
    int result3 = checkAgreement(facesC,facesV);
359
    if( result3<0 ) return result3;
360

    
361
    mFaceColors = facesC;
362

    
363
    int[][] edgeColors = computeEdgeColors(mFaceColors);
364

    
365
    getEdges(object,edges);
366
    int result4 = checkAllEdgesPresent(edges,edgeColors);
367
    if( result4<0 ) return result4;
368

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

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

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

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

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

    
397
    return vertexTwist + 81*(edgeTwist + 32*perm_num);
398
    }
399

    
400
///////////////////////////////////////////////////////////////////////////////////////////////////
401

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

    
412
    return -1;
413
    }
414

    
415
///////////////////////////////////////////////////////////////////////////////////////////////////
416

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

    
427
    return -1;
428
    }
429

    
430
///////////////////////////////////////////////////////////////////////////////////////////////////
431

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

    
442
    return -1;
443
    }
444

    
445
///////////////////////////////////////////////////////////////////////////////////////////////////
446

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

    
457
    return -1;
458
    }
459

    
460
///////////////////////////////////////////////////////////////////////////////////////////////////
461

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

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

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

    
475
///////////////////////////////////////////////////////////////////////////////////////////////////
476

    
477
  private String vertexError(Resources res, int color0, int color1, int color2)
478
    {
479
    int j0 = getColorIndex3(color0);
480
    int j1 = getColorIndex3(color1);
481
    int j2 = getColorIndex4(color2);
482

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

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

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

    
492
  private String edgeError(Resources res, int color0, int color1)
493
    {
494
    int j0 = getFaceIndex3(color0);
495
    int j1 = getFaceIndex6(color1);
496

    
497
    String c0 = res.getString(j0);
498
    String c1 = res.getString(j1);
499

    
500
    return res.getString(R.string.solver_generic_missing_edge,c0,c1);
501
    }
502

    
503
///////////////////////////////////////////////////////////////////////////////////////////////////
504

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

    
530
    return null;
531
    }
532

    
533
///////////////////////////////////////////////////////////////////////////////////////////////////
534

    
535
  @Override int[] getExtra() { return mCornerTwist; }
536
}  
537

    
(13-13/17)