Project

General

Profile

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

magiccube / src / main / java / org / distorted / solvers / SolverPyraminx.java @ 55b2d967

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
  TablebasesAbstract mSolver;
51

    
52
///////////////////////////////////////////////////////////////////////////////////////////////////
53

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

    
64
///////////////////////////////////////////////////////////////////////////////////////////////////
65

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

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

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

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

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

    
94
    return 0;
95
    }
96

    
97
///////////////////////////////////////////////////////////////////////////////////////////////////
98

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

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

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

    
119
    return 0;
120
    }
121

    
122
///////////////////////////////////////////////////////////////////////////////////////////////////
123

    
124
  private int checkAllEdgesPresent(int[][] edges)
125
    {
126
    boolean rb = false;
127
    boolean ry = false;
128
    boolean rg = false;
129
    boolean yb = false;
130
    boolean gb = false;
131
    boolean gy = false;
132

    
133
    for(int i=0; i<6; i++)
134
      {
135
      if( pieceEqual2(edges[i],3,2) ) rb = true;
136
      if( pieceEqual2(edges[i],3,1) ) ry = true;
137
      if( pieceEqual2(edges[i],3,0) ) rg = true;
138
      if( pieceEqual2(edges[i],2,1) ) yb = true;
139
      if( pieceEqual2(edges[i],2,0) ) gb = true;
140
      if( pieceEqual2(edges[i],1,0) ) gy = true;
141
      }
142

    
143
    if( !rb ) return ERROR_EDGE_RB_MISSING;
144
    if( !ry ) return ERROR_EDGE_RY_MISSING;
145
    if( !rg ) return ERROR_EDGE_RG_MISSING;
146
    if( !yb ) return ERROR_EDGE_YB_MISSING;
147
    if( !gb ) return ERROR_EDGE_GB_MISSING;
148
    if( !gy ) return ERROR_EDGE_GY_MISSING;
149

    
150
    return 0;
151
    }
152

    
153
///////////////////////////////////////////////////////////////////////////////////////////////////
154

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

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

    
163
    return ret;
164
    }
165

    
166
///////////////////////////////////////////////////////////////////////////////////////////////////
167

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

    
173
    return 0;
174
    }
175

    
176
///////////////////////////////////////////////////////////////////////////////////////////////////
177

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

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

    
214
    return ( twist1!=twist2 || twist1!=twist3 ) ? -1 : twist1;
215
    }
216

    
217
///////////////////////////////////////////////////////////////////////////////////////////////////
218

    
219
  private int[] computeEdgeQuats(int[][] edges)
220
    {
221
    return null;
222
    }
223

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

    
226
  public SolverPyraminx(Resources res, TwistyObject object)
227
    {
228
    super(res,object);
229
    }
230

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

    
233
  private void getCorners(TwistyObject object, int[][] corners)
234
    {
235
    corners[0][0] = object.getCubitFaceStickerIndex(6,3);  // R
236
    corners[0][1] = object.getCubitFaceStickerIndex(6,2);  // B
237
    corners[0][2] = object.getCubitFaceStickerIndex(6,1);  // Y
238

    
239
    corners[1][0] = object.getCubitFaceStickerIndex(4,3);  // R
240
    corners[1][1] = object.getCubitFaceStickerIndex(4,0);  // G
241
    corners[1][2] = object.getCubitFaceStickerIndex(4,2);  // B
242

    
243
    corners[2][0] = object.getCubitFaceStickerIndex(13,3);  // R
244
    corners[2][1] = object.getCubitFaceStickerIndex(13,1);  // Y
245
    corners[2][2] = object.getCubitFaceStickerIndex(13,0);  // G
246

    
247
    corners[3][0] = object.getCubitFaceStickerIndex(11,0);  // G
248
    corners[3][1] = object.getCubitFaceStickerIndex(11,1);  // Y
249
    corners[3][2] = object.getCubitFaceStickerIndex(11,2);  // B
250
    }
251

    
252
///////////////////////////////////////////////////////////////////////////////////////////////////
253

    
254
  private void getVertices(TwistyObject object, int[][] vertex)
255
    {
256
    vertex[0][0] = object.getCubitFaceStickerIndex(1,5);  // R
257
    vertex[0][1] = object.getCubitFaceStickerIndex(1,7);  // B
258
    vertex[0][2] = object.getCubitFaceStickerIndex(1,2);  // Y
259

    
260
    vertex[1][0] = object.getCubitFaceStickerIndex(0,5);  // R
261
    vertex[1][1] = object.getCubitFaceStickerIndex(0,0);  // G
262
    vertex[1][2] = object.getCubitFaceStickerIndex(0,7);  // B
263

    
264
    vertex[2][0] = object.getCubitFaceStickerIndex(3,5);  // R
265
    vertex[2][1] = object.getCubitFaceStickerIndex(3,2);  // Y
266
    vertex[2][2] = object.getCubitFaceStickerIndex(3,0);  // G
267

    
268
    vertex[3][0] = object.getCubitFaceStickerIndex(2,0);  // G
269
    vertex[3][1] = object.getCubitFaceStickerIndex(2,2);  // Y
270
    vertex[3][2] = object.getCubitFaceStickerIndex(2,7);  // B
271
    }
272

    
273
///////////////////////////////////////////////////////////////////////////////////////////////////
274

    
275
  private void getEdges(TwistyObject object, int[][] edges)
276
    {
277
    edges[0][0] = object.getCubitFaceStickerIndex(5,3);  // R
278
    edges[0][1] = object.getCubitFaceStickerIndex(5,2);  // B
279

    
280
    edges[1][0] = object.getCubitFaceStickerIndex(10,3); // R
281
    edges[1][1] = object.getCubitFaceStickerIndex(10,1); // Y
282

    
283
    edges[2][0] = object.getCubitFaceStickerIndex(9,3);  // R
284
    edges[2][1] = object.getCubitFaceStickerIndex(9,0);  // G
285

    
286
    edges[3][0] = object.getCubitFaceStickerIndex(8,1);  // Y
287
    edges[3][1] = object.getCubitFaceStickerIndex(8,2);  // B
288

    
289
    edges[4][0] = object.getCubitFaceStickerIndex(7,0);  // G
290
    edges[4][1] = object.getCubitFaceStickerIndex(7,2);  // B
291

    
292
    edges[5][0] = object.getCubitFaceStickerIndex(12,0); // G
293
    edges[5][1] = object.getCubitFaceStickerIndex(12,1); // Y
294
    }
295

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

    
298
  public int tablebaseIndex(TwistyObject object)
299
    {
300
    int[][] corners = new int[4][3];
301
    int[][] edges   = new int[6][2];
302
    int[][] vertices= new int[4][3];
303
    int[] corner_twist = new int[4];
304
    int[] vertex_twist = new int[4];
305

    
306
    getCorners(object,corners);
307
    getVertices(object,vertices);
308
    getEdges(object,edges);
309

    
310
    int result1 = checkAllCornersPresent(corners);
311
    if( result1<0 ) return result1;
312

    
313
    int result2 = checkAllVerticesPresent(vertices);
314
    if( result2<0 ) return result2;
315

    
316
    int result3 = checkAllEdgesPresent(edges);
317
    if( result3<0 ) return result3;
318

    
319
    int[] faces1 = computeFaceColors(corners);
320
    int[] faces2 = computeFaceColors(vertices);
321

    
322
    int result4 = checkAgreement(faces1,faces2);
323
    if( result4<0 ) return result4;
324

    
325
    for(int i=0; i<4; i++)
326
      {
327
      corner_twist[i] = computePieceTwist(i,corners[i],faces1);
328
      if( corner_twist[i]<0 ) return ERROR_CORNERS_CANNOT;
329
      }
330

    
331
    for(int i=0; i<4; i++)
332
      {
333
      vertex_twist[i] = computePieceTwist(i,vertices[i],faces1);
334
      if( vertex_twist[i]<0 ) return ERROR_VERTICES_CANNOT;
335
      }
336

    
337
    int[] quats = computeEdgeQuats(edges);
338
    int[] permutation = new int[6];
339
    TablebasesPyraminx.getEdgePermutation(permutation,quats);
340
    boolean even = TablebaseHelpers.permutationIsEven(permutation);
341
    if( !even ) return ERROR_TWO_EDGES;
342

    
343
    return 0;
344
    }
345

    
346
///////////////////////////////////////////////////////////////////////////////////////////////////
347

    
348
  private int getColorIndex3(int color)
349
    {
350
    switch(color)
351
      {
352
      case 0: return R.string.color_green3;
353
      case 1: return R.string.color_yellow3;
354
      case 2: return R.string.color_blue3;
355
      case 3: return R.string.color_red3;
356
      }
357

    
358
    return -1;
359
    }
360

    
361
///////////////////////////////////////////////////////////////////////////////////////////////////
362

    
363
  private int getColorIndex4(int color)
364
    {
365
    switch(color)
366
      {
367
      case 0: return R.string.color_green4;
368
      case 1: return R.string.color_yellow4;
369
      case 2: return R.string.color_blue4;
370
      case 3: return R.string.color_red4;
371
      }
372

    
373
    return -1;
374
    }
375

    
376
///////////////////////////////////////////////////////////////////////////////////////////////////
377

    
378
  private int getColorIndex6(int color)
379
    {
380
    switch(color)
381
      {
382
      case 0: return R.string.color_green6;
383
      case 1: return R.string.color_yellow6;
384
      case 2: return R.string.color_blue6;
385
      case 3: return R.string.color_red6;
386
      }
387

    
388
    return -1;
389
    }
390

    
391
///////////////////////////////////////////////////////////////////////////////////////////////////
392

    
393
  private String cornerError(Resources res, int color0, int color1, int color2)
394
    {
395
    int j0 = getColorIndex3(color0);
396
    int j1 = getColorIndex3(color1);
397
    int j2 = getColorIndex4(color2);
398

    
399
    String c0 = res.getString(j0);
400
    String c1 = res.getString(j1);
401
    String c2 = res.getString(j2);
402

    
403
    return res.getString(R.string.solver_generic_missing_corner,c0,c1,c2);
404
    }
405

    
406
///////////////////////////////////////////////////////////////////////////////////////////////////
407

    
408
  private String vertexError(Resources res, int color0, int color1, int color2)
409
    {
410
    int j0 = getColorIndex3(color0);
411
    int j1 = getColorIndex3(color1);
412
    int j2 = getColorIndex4(color2);
413

    
414
    String c0 = res.getString(j0);
415
    String c1 = res.getString(j1);
416
    String c2 = res.getString(j2);
417

    
418
    return res.getString(R.string.solver_generic_missing_vertex,c0,c1,c2);
419
    }
420

    
421
///////////////////////////////////////////////////////////////////////////////////////////////////
422

    
423
  private String edgeError(Resources res, int color0, int color1)
424
    {
425
    int j0 = getColorIndex3(color0);
426
    int j1 = getColorIndex6(color1);
427

    
428
    String c0 = res.getString(j0);
429
    String c1 = res.getString(j1);
430

    
431
    return res.getString(R.string.solver_generic_missing_edge,c0,c1);
432
    }
433

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

    
436
  public String error(int index, Resources res)
437
    {
438
    switch(index)
439
      {
440
      case ERROR_CORNER_YBR_MISSING: return cornerError(res,3,2,1);
441
      case ERROR_CORNER_GBR_MISSING: return cornerError(res,3,2,0);
442
      case ERROR_CORNER_GYR_MISSING: return cornerError(res,3,1,0);
443
      case ERROR_CORNER_GYB_MISSING: return cornerError(res,2,1,0);
444
      case ERROR_VERTEX_YBR_MISSING: return vertexError(res,3,2,1);
445
      case ERROR_VERTEX_GBR_MISSING: return vertexError(res,3,2,0);
446
      case ERROR_VERTEX_GYR_MISSING: return vertexError(res,3,1,0);
447
      case ERROR_VERTEX_GYB_MISSING: return vertexError(res,2,1,0);
448
      case ERROR_EDGE_RB_MISSING   : return edgeError(res,3,2);
449
      case ERROR_EDGE_RY_MISSING   : return edgeError(res,3,1);
450
      case ERROR_EDGE_RG_MISSING   : return edgeError(res,3,0);
451
      case ERROR_EDGE_YB_MISSING   : return edgeError(res,2,1);
452
      case ERROR_EDGE_GB_MISSING   : return edgeError(res,2,0);
453
      case ERROR_EDGE_GY_MISSING   : return edgeError(res,1,0);
454
      case ERROR_CORNER_TWISTED    : return res.getString(R.string.solver_generic_corner_twist);
455
      case ERROR_EDGE_TWISTED      : return res.getString(R.string.solver_generic_edge_twist);
456
      case ERROR_CORNERS_CANNOT    : return res.getString(R.string.solver_generic_corners_cannot);
457
      case ERROR_VERTICES_CANNOT   : return res.getString(R.string.solver_generic_vertices_cannot);
458
      case ERROR_C_V_DONT_MATCH    : return res.getString(R.string.solver_generic_c_v_dont_match);
459
      case ERROR_TWO_EDGES         : return res.getString(R.string.solver_generic_two_edges);
460
      }
461

    
462
    return null;
463
    }
464

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

    
467
  public int[][] solution(int index, Resources res)
468
    {
469
    if( mSolver==null )
470
      {
471
      //mSolver = ImplementedTablebasesList.createPacked(res,ObjectType.PYRA_3);
472
      mSolver = ImplementedTablebasesList.createUnpacked(ObjectType.PYRA_3);
473
      if( mSolver!=null ) mSolver.createTablebase();
474
      }
475

    
476
    return mSolver!=null ? mSolver.solution(index) : null;
477
    }
478
}  
479

    
(6-6/8)