Project

General

Profile

« Previous | Next » 

Revision a480ee80

Added by Leszek Koltunski over 3 years ago

Standarize the 'isSolved()' method: now all objects, except one (Dino4) have a standard isSolved().
This incidentally also fixes detection of the solved state in case of Diamond4, i.e. a Master FTO.

View differences:

src/main/java/org/distorted/objects/MovementSquare.java
46 46

  
47 47
  int computeRowFromOffset(int face, int axisIndex, int numLayers, float offset)
48 48
    {
49
    //android.util.Log.e("D", "face="+face+" size="+numLayers+" offset="+offset);
50

  
51 49
    return offset>DIST2D? 2-axisIndex : 0;
52 50
    }
53 51

  
src/main/java/org/distorted/objects/TwistyBandagedAbstract.java
161 161
  abstract float[][] getPositions();
162 162
  abstract int[] getQuatIndices();
163 163

  
164
///////////////////////////////////////////////////////////////////////////////////////////////////
165

  
166
  int[] getSolvedQuats(int cubit, int numLayers)
167
    {
168
    int status = retCubitSolvedStatus(cubit,numLayers);
169
    return status<0 ? null : buildSolvedQuats(MovementCube.FACE_AXIS[status],QUATS);
170
    }
171

  
164 172
///////////////////////////////////////////////////////////////////////////////////////////////////
165 173

  
166 174
  int getNumCubits()
......
461 469
    {
462 470
    return BASIC_ANGLE;
463 471
    }
464

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

  
467
  public boolean isSolved()
468
    {
469
    int index = CUBITS[0].mQuatIndex;
470

  
471
    for(int i=1; i<NUM_CUBITS; i++)
472
      {
473
      if( thereIsVisibleDifference(CUBITS[i], index) ) return false;
474
      }
475

  
476
    return true;
477
    }
478 472
}
src/main/java/org/distorted/objects/TwistyCube.java
136 136
    super(size, size, quat, texture, mesh, effects, moves, ObjectList.CUBE, res, scrWidth);
137 137
    }
138 138

  
139
///////////////////////////////////////////////////////////////////////////////////////////////////
140

  
141
  int[] getSolvedQuats(int cubit, int numLayers)
142
    {
143
    int status = retCubitSolvedStatus(cubit,numLayers);
144
    return status<0 ? null : buildSolvedQuats(MovementCube.FACE_AXIS[status],QUATS);
145
    }
146

  
139 147
///////////////////////////////////////////////////////////////////////////////////////////////////
140 148

  
141 149
  ObjectShape getObjectShape(int cubit, int numLayers)
......
356 364
      }
357 365
    }
358 366

  
359
///////////////////////////////////////////////////////////////////////////////////////////////////
360

  
361
  public boolean isSolved()
362
    {
363
    int index = CUBITS[0].mQuatIndex;
364

  
365
    for(int i=1; i<NUM_CUBITS; i++)
366
      {
367
      if( thereIsVisibleDifference(CUBITS[i], index) ) return false;
368
      }
369

  
370
    return true;
371
    }
372

  
373 367
///////////////////////////////////////////////////////////////////////////////////////////////////
374 368

  
375 369
  public int getObjectName(int numLayers)
src/main/java/org/distorted/objects/TwistyDiamond.java
57 57
           COLOR_GREEN , COLOR_GREY
58 58
         };
59 59

  
60
  private static final int[] mFaceMap = new int[] {4,0,6,2,7,3,5,1};
61

  
60 62
  // All legal rotation quats of a Diamond: unit + three 180 deg turns + 8 generators
61 63
  private static final Static4D[] QUATS = new Static4D[]
62 64
         {
......
77 79

  
78 80
  private static final float DIST = 0.50f;
79 81

  
80
  private static final int[][] mFaceNeutralQuatIndex = new int[][]
81
         {
82
             {6,10},
83
             {4, 8},
84
             {7,11},
85
             {5, 9},
86
             {7,11},
87
             {5, 9},
88
             {6,10},
89
             {4, 8}
90
         };
91

  
92 82
  private static final int[] mTetraToFaceMap = new int[] {1,2,3,0,5,6,7,4};
93 83

  
94 84
  private static final double[][] VERTICES_TETRA = new double[][]
......
153 143
    super(size, size, quat, texture, mesh, effects, moves, ObjectList.DIAM, res, scrWidth);
154 144
    }
155 145

  
146
///////////////////////////////////////////////////////////////////////////////////////////////////
147

  
148
  int[] getSolvedQuats(int cubit, int numLayers)
149
    {
150
    int status = retCubitSolvedStatus(cubit,numLayers);
151
    return status<0 ? null : buildSolvedQuats(MovementDiamond.FACE_AXIS[mFaceMap[status]],QUATS);
152
    }
153

  
156 154
///////////////////////////////////////////////////////////////////////////////////////////////////
157 155

  
158 156
  float getScreenRatio()
......
541 539
      }
542 540
    }
543 541

  
544
///////////////////////////////////////////////////////////////////////////////////////////////////
545
// The Diamond is solved if and only if:
546
//
547
// - all cubits are rotated by the same quat
548
// - those which are internal to the side, i.e. those which have only one 'non-black' face, might
549
//   also be optionally rotated by one of the two quats whose axis is perpendicular to the face.
550
//   (including some octahedrons if numLayers>=4)
551

  
552
  public boolean isSolved()
553
    {
554
    int q = CUBITS[0].mQuatIndex;
555
    int layers = getNumLayers();
556
    int numO = getNumOctahedrons(layers);
557

  
558
    for(int i=1; i<numO; i++)
559
      {
560
      if( CUBITS[i].mQuatIndex != q ) return false;
561
      }
562

  
563
    int qI, q1Index, q2Index, face;
564

  
565
    for(int i=numO; i<NUM_CUBITS; i++)
566
      {
567
      face    = retFaceTetraBelongsTo(i-numO,layers);
568
      q1Index = mFaceNeutralQuatIndex[face][0];
569
      q2Index = mFaceNeutralQuatIndex[face][1];
570
      qI      = CUBITS[i].mQuatIndex;
571

  
572
      if( qI != q && qI != mulQuat(q,q1Index) && qI != mulQuat(q,q2Index) ) return false;
573
      }
574

  
575
    return true;
576
    }
577

  
578 542
///////////////////////////////////////////////////////////////////////////////////////////////////
579 543

  
580 544
  public int getObjectName(int numLayers)
src/main/java/org/distorted/objects/TwistyDino4.java
88 88
    super(size, quat, texture, mesh, effects, moves, ObjectList.DIN4, res, scrWidth);
89 89
    }
90 90

  
91
///////////////////////////////////////////////////////////////////////////////////////////////////
92

  
93
  int[] getSolvedQuats(int cubit, int numLayers)
94
    {
95
    return null;
96
    }
97

  
91 98
///////////////////////////////////////////////////////////////////////////////////////////////////
92 99

  
93 100
  int getFaceColor(int cubit, int cubitface, int size)
src/main/java/org/distorted/objects/TwistyDino6.java
45 45
    super(size, quat, texture, mesh, effects, moves, ObjectList.DINO, res, scrWidth);
46 46
    }
47 47

  
48
///////////////////////////////////////////////////////////////////////////////////////////////////
49
// Dino6 is solved if and only if:
50
//
51
// All four 'X' cubits (i.e. those whose longest edge goes along the X axis) are rotated
52
// by the same quaternion qX, similarly all four 'Y' cubits by the same qY and all four 'Z'
53
// by the same qZ, and then either:
54
//
55
// a) qX = qY = qZ
56
// b) qY = qX*Q2 and qZ = qX*Q8  (i.e. swap of WHITE and YELLOW faces)
57
// c) qX = qY*Q2 and qZ = qY*Q10 (i.e. swap of BLUE and GREEN faces)
58
// d) qX = qZ*Q8 and qY = qZ*Q10 (i.e. swap of RED and BROWN faces)
59
//
60
// BUT: cases b), c) and d) are really the same - it's all just a mirror image of the original.
61
//
62
// X cubits: 0, 2, 8, 10
63
// Y cubits: 1, 3, 9, 11
64
// Z cubits: 4, 5, 6, 7
65

  
66
  int[] getSolvedQuats(int cubit, int numLayers)
67
    {
68
    switch(cubit)
69
      {
70
      case 0: case 2: case 8: case 10: return null;
71
      case 1: case 3: case 9: case 11: return new int[] {2};
72
      case 4: case 5: case 6: case  7: return new int[] {8};
73
      }
74

  
75
    return null;
76
    }
77

  
48 78
///////////////////////////////////////////////////////////////////////////////////////////////////
49 79

  
50 80
  int getFaceColor(int cubit, int cubitface, int size)
......
87 117
      }
88 118
    }
89 119

  
90
///////////////////////////////////////////////////////////////////////////////////////////////////
91
// Dino6 is solved if and only if:
92
//
93
// All four 'X' cubits (i.e. those whose longest edge goes along the X axis) are rotated
94
// by the same quaternion qX, similarly all four 'Y' cubits by the same qY and all four 'Z'
95
// by the same qZ, and then either:
96
//
97
// a) qX = qY = qZ
98
// b) qY = qX*Q2 and qZ = qX*Q8  (i.e. swap of WHITE and YELLOW faces)
99
// c) qX = qY*Q2 and qZ = qY*Q10 (i.e. swap of BLUE and GREEN faces)
100
// d) qX = qZ*Q8 and qY = qZ*Q10 (i.e. swap of RED and BROWN faces)
101
//
102
// BUT: cases b), c) and d) are really the same - it's all just a mirror image of the original.
103
//
104
// X cubits: 0, 2, 8, 10
105
// Y cubits: 1, 3, 9, 11
106
// Z cubits: 4, 5, 6, 7
107

  
108
  public boolean isSolved()
109
    {
110
    int qX = CUBITS[0].mQuatIndex;
111
    int qY = CUBITS[1].mQuatIndex;
112
    int qZ = CUBITS[4].mQuatIndex;
113

  
114
    if( CUBITS[2].mQuatIndex != qX || CUBITS[8].mQuatIndex != qX || CUBITS[10].mQuatIndex != qX ||
115
        CUBITS[3].mQuatIndex != qY || CUBITS[9].mQuatIndex != qY || CUBITS[11].mQuatIndex != qY ||
116
        CUBITS[5].mQuatIndex != qZ || CUBITS[6].mQuatIndex != qZ || CUBITS[ 7].mQuatIndex != qZ  )
117
      {
118
      return false;
119
      }
120

  
121
    return ( qX==qY && qX==qZ ) || ( qY==mulQuat(qX,2) && qZ==mulQuat(qX,8) );
122
    }
123

  
124 120
///////////////////////////////////////////////////////////////////////////////////////////////////
125 121

  
126 122
  public int getObjectName(int numLayers)
src/main/java/org/distorted/objects/TwistyHelicopter.java
243 243
    super(size, size, quat, texture, mesh, effects, moves, ObjectList.HELI, res, scrWidth);
244 244
    }
245 245

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

  
248
  int[] getSolvedQuats(int cubit, int numLayers)
249
    {
250
    int status = retCubitSolvedStatus(cubit,numLayers);
251
    return status<0 ? null : buildSolvedQuats(MovementHelicopter.FACE_AXIS[status],QUATS);
252
    }
253

  
246 254
///////////////////////////////////////////////////////////////////////////////////////////////////
247 255

  
248 256
  float getScreenRatio()
......
426 434
      }
427 435
    }
428 436

  
429
///////////////////////////////////////////////////////////////////////////////////////////////////
430
// The Helicopter is solved if and only if:
431
//
432
// 1) all of its corner cubits are rotated with the same quat
433
// 2) all its face cubits are rotated with the same quat like the corner ones,
434
//    and optionally they also might be turned by a multiple of 90 degrees along
435
//    a vector perpendicular to the face they lie on.
436
//
437
// i.e.
438
// cubits  8, 9,10,11,12,13,14,15 - might be extra QUAT 1,8,9
439
// cubits 16,17,18,19,20,21,22,23 - might be extra QUAT 2,12,13
440
// cubits 24,25,26,27,28,29,30,31 - might be extra QUAT 3,14,15
441

  
442
  public boolean isSolved()
443
    {
444
    int q = CUBITS[0].mQuatIndex;
445

  
446
    if ( CUBITS[1].mQuatIndex == q &&
447
         CUBITS[2].mQuatIndex == q &&
448
         CUBITS[3].mQuatIndex == q &&
449
         CUBITS[4].mQuatIndex == q &&
450
         CUBITS[5].mQuatIndex == q &&
451
         CUBITS[6].mQuatIndex == q &&
452
         CUBITS[7].mQuatIndex == q  )
453
      {
454
      int q1 = mulQuat(q,1);
455
      int q2 = mulQuat(q,8);
456
      int q3 = mulQuat(q,9);
457

  
458
      for(int index=8; index<16; index++)
459
        {
460
        int qIndex = CUBITS[index].mQuatIndex;
461
        if( qIndex!=q && qIndex!=q1 && qIndex!=q2 && qIndex!=q3 ) return false;
462
        }
463

  
464
      q1 = mulQuat(q, 2);
465
      q2 = mulQuat(q,12);
466
      q3 = mulQuat(q,13);
467

  
468
      for(int index=16; index<24; index++)
469
        {
470
        int qIndex = CUBITS[index].mQuatIndex;
471
        if( qIndex!=q && qIndex!=q1 && qIndex!=q2 && qIndex!=q3 ) return false;
472
        }
473

  
474
      q1 = mulQuat(q, 3);
475
      q2 = mulQuat(q,14);
476
      q3 = mulQuat(q,15);
477

  
478
      for(int index=24; index<32; index++)
479
        {
480
        int qIndex = CUBITS[index].mQuatIndex;
481
        if( qIndex!=q && qIndex!=q1 && qIndex!=q2 && qIndex!=q3 ) return false;
482
        }
483

  
484
      return true;
485
      }
486

  
487
    return false;
488
    }
489

  
490 437
///////////////////////////////////////////////////////////////////////////////////////////////////
491 438

  
492 439
  public int getObjectName(int numLayers)
src/main/java/org/distorted/objects/TwistyIvy.java
124 124
    super(size, size, quat, texture, mesh, effects, moves, ObjectList.IVY, res, scrWidth);
125 125
    }
126 126

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

  
129
  int[] getSolvedQuats(int cubit, int numLayers)
130
    {
131
    int status = retCubitSolvedStatus(cubit,numLayers);
132
    return status<0 ? null : buildSolvedQuats(MovementIvy.FACE_AXIS[status],QUATS);
133
    }
134

  
127 135
///////////////////////////////////////////////////////////////////////////////////////////////////
128 136

  
129 137
  float getScreenRatio()
......
456 464
      }
457 465
    }
458 466

  
459
///////////////////////////////////////////////////////////////////////////////////////////////////
460
// The Ivy is solved if and only if:
461
//
462
// 1) all 4 of its corner cubits are rotated with the same quat
463
// 2) all its face cubits are rotated with the same quat like the corner ones,
464
//    and optionally they also might be upside down.
465
//
466
// i.e.
467
// cubits [4] and [5] - might be extra QUAT[1]
468
// cubits [6] and [7] - might be extra QUAT[2]
469
// cubits [8] and [9] - might be extra QUAT[3]
470

  
471
  public boolean isSolved()
472
    {
473
    int q1,q = CUBITS[0].mQuatIndex;
474

  
475
    if( CUBITS[1].mQuatIndex == q &&
476
        CUBITS[2].mQuatIndex == q &&
477
        CUBITS[3].mQuatIndex == q  )
478
      {
479
      q1 = mulQuat(q,1);
480
      if( CUBITS[4].mQuatIndex != q && CUBITS[4].mQuatIndex != q1 ) return false;
481
      if( CUBITS[5].mQuatIndex != q && CUBITS[5].mQuatIndex != q1 ) return false;
482

  
483
      q1 = mulQuat(q,2);
484
      if( CUBITS[6].mQuatIndex != q && CUBITS[6].mQuatIndex != q1 ) return false;
485
      if( CUBITS[7].mQuatIndex != q && CUBITS[7].mQuatIndex != q1 ) return false;
486

  
487
      q1 = mulQuat(q,3);
488
      if( CUBITS[8].mQuatIndex != q && CUBITS[8].mQuatIndex != q1 ) return false;
489
      if( CUBITS[9].mQuatIndex != q && CUBITS[9].mQuatIndex != q1 ) return false;
490

  
491
      return true;
492
      }
493

  
494
    return false;
495
    }
496

  
497 467
///////////////////////////////////////////////////////////////////////////////////////////////////
498 468

  
499 469
  public int getObjectName(int numLayers)
src/main/java/org/distorted/objects/TwistyJing.java
223 223
    super(size, size, quat, texture, mesh, effects, moves, ObjectList.JING, res, scrWidth);
224 224
    }
225 225

  
226
///////////////////////////////////////////////////////////////////////////////////////////////////
227

  
228
  int[] getSolvedQuats(int cubit, int numLayers)
229
    {
230
    int status = retCubitSolvedStatus(cubit,numLayers);
231
    return status<0 ? null : buildSolvedQuats(MovementJing.FACE_AXIS[status],QUATS);
232
    }
233

  
226 234
///////////////////////////////////////////////////////////////////////////////////////////////////
227 235

  
228 236
  float[][] getCubitPositions(int size)
......
406 414
      }
407 415
    }
408 416

  
409
///////////////////////////////////////////////////////////////////////////////////////////////////
410
// JingPyraminx is solved iff
411
// a) all of its corner and edge cubits are rotated with the same quat
412
// b) its 4 face cubits might also be rotated along the axis perpendicular to the face.
413
//
414
// So:
415
// [10] might be extra QUAT[4] or QUAT[8]
416
// [11] might be extra QUAT[5] or QUAT[9]
417
// [12] might be extra QUAT[2] or QUAT[6]
418
// [13] might be extra QUAT[3] or QUAT[7]
419

  
420
  public boolean isSolved()
421
    {
422
    int q1, q = CUBITS[0].mQuatIndex;
423

  
424
    if( CUBITS[1].mQuatIndex != q ) return false;
425
    if( CUBITS[2].mQuatIndex != q ) return false;
426
    if( CUBITS[3].mQuatIndex != q ) return false;
427
    if( CUBITS[4].mQuatIndex != q ) return false;
428
    if( CUBITS[5].mQuatIndex != q ) return false;
429
    if( CUBITS[6].mQuatIndex != q ) return false;
430
    if( CUBITS[7].mQuatIndex != q ) return false;
431
    if( CUBITS[8].mQuatIndex != q ) return false;
432
    if( CUBITS[9].mQuatIndex != q ) return false;
433

  
434
    q1 = CUBITS[10].mQuatIndex;
435
    if( q1!=q && q1!=mulQuat(q,4) && q1!=mulQuat(q,8) ) return false;
436
    q1 = CUBITS[11].mQuatIndex;
437
    if( q1!=q && q1!=mulQuat(q,5) && q1!=mulQuat(q,9) ) return false;
438
    q1 = CUBITS[12].mQuatIndex;
439
    if( q1!=q && q1!=mulQuat(q,2) && q1!=mulQuat(q,6) ) return false;
440
    q1 = CUBITS[13].mQuatIndex;
441
    if( q1!=q && q1!=mulQuat(q,3) && q1!=mulQuat(q,7) ) return false;
442

  
443
    return true;
444
    }
445

  
446 417
///////////////////////////////////////////////////////////////////////////////////////////////////
447 418

  
448 419
  public int getObjectName(int numLayers)
src/main/java/org/distorted/objects/TwistyKilominx.java
695 695
    return 2;
696 696
    }
697 697

  
698
///////////////////////////////////////////////////////////////////////////////////////////////////
699
// PUBLIC API
700

  
701
  public boolean isSolved()
702
    {
703
    int index = CUBITS[0].mQuatIndex;
704

  
705
    for(int i=1; i<NUM_CUBITS; i++)
706
      {
707
      if( thereIsVisibleDifference(CUBITS[i], index) ) return false;
708
      }
709

  
710
    return true;
711
    }
712

  
713 698
///////////////////////////////////////////////////////////////////////////////////////////////////
714 699

  
715 700
  public int getObjectName(int numLayers)
src/main/java/org/distorted/objects/TwistyMegaminx.java
608 608
    return 4;
609 609
    }
610 610

  
611
///////////////////////////////////////////////////////////////////////////////////////////////////
612
// PUBLIC API
613

  
614
  public boolean isSolved()
615
    {
616
    int index = CUBITS[0].mQuatIndex;
617

  
618
    for(int i=1; i<NUM_CUBITS; i++)
619
      {
620
      if( thereIsVisibleDifference(CUBITS[i], index) ) return false;
621
      }
622

  
623
    return true;
624
    }
625

  
626 611
///////////////////////////////////////////////////////////////////////////////////////////////////
627 612

  
628 613
  public int getObjectName(int numLayers)
src/main/java/org/distorted/objects/TwistyMinx.java
81 81
           MINX_DBLUE , MINX_DYELLOW, MINX_WHITE , MINX_GREY
82 82
         };
83 83

  
84
  private static final int[] mFaceMap = new int[] {8,10,3,7,1,11,9,2,4,0,5,6};
85

  
84 86
  // All 60 legal rotation quats of a Minx
85 87
  static final Static4D[] QUATS = new Static4D[]
86 88
         {
......
336 338
    super(numLayers, realSize, quat, texture, mesh, effects, moves, obj, res, scrWidth);
337 339
    }
338 340

  
341
///////////////////////////////////////////////////////////////////////////////////////////////////
342

  
343
  int[] getSolvedQuats(int cubit, int numLayers)
344
    {
345
    int status = retCubitSolvedStatus(cubit,numLayers);
346
    return status<0 ? null : buildSolvedQuats(MovementMinx.FACE_AXIS[mFaceMap[status]],QUATS);
347
    }
348

  
339 349
///////////////////////////////////////////////////////////////////////////////////////////////////
340 350

  
341 351
  Static4D[] getQuats()
src/main/java/org/distorted/objects/TwistyObject.java
95 95
  final int NUM_CUBITS;
96 96
  final int NUM_AXIS;
97 97

  
98
  private static final float[] mTmp1 = new float[4];
99
  private static final float[] mTmp2 = new float[4];
100

  
101 98
  private final int mNumCubitFaces;
102 99
  private final Static3D[] mAxis;
103 100
  private final float[][] mCuts;
......
119 116
  private final DistortedTexture mTexture;
120 117
  private final float mInitScreenRatio;
121 118
  private float mObjectScreenRatio;
119
  private int[][] mSolvedQuats;
120
  private int[][] mQuatMult;
121
  private int[] mTmpQuats;
122 122
  private int mNumTexRows, mNumTexCols;
123 123
  private int mRotRowBitmap;
124 124
  private int mRotAxis;
......
186 186

  
187 187
    CUBITS = new Cubit[NUM_CUBITS];
188 188
    createMeshAndCubits(list,res);
189
    createDataStructuresForSolved(numLayers);
189 190

  
190 191
    mTexture = new DistortedTexture();
191 192
    mEffects = new DistortedEffects();
......
316 317
    return mesh;
317 318
    }
318 319

  
320
///////////////////////////////////////////////////////////////////////////////////////////////////
321

  
322
  private void createDataStructuresForSolved(int numLayers)
323
    {
324
    mTmpQuats = new int[QUATS.length];
325
    mSolvedQuats = new int[NUM_CUBITS][];
326

  
327
    for(int c=0; c<NUM_CUBITS; c++)
328
      {
329
      mSolvedQuats[c] = getSolvedQuats(c,numLayers);
330
      }
331
    }
332

  
333
///////////////////////////////////////////////////////////////////////////////////////////////////
334
// This is used to build internal data structures for the generic 'isSolved()'
335
//
336
// if this is an internal cubit (all faces black): return -1
337
// if this is a face cubit (one non-black face): return the color index of the only non-black face.
338
// Color index, i.e. the index into the 'FACE_COLORS' table.
339
// else (edge or corner cubit, more than one non-black face): return -2.
340

  
341
  int retCubitSolvedStatus(int cubit, int numLayers)
342
    {
343
    int numNonBlack=0, nonBlackIndex=-1, color;
344

  
345
    for(int face=0; face<mNumCubitFaces; face++)
346
      {
347
      color = getFaceColor(cubit,face,numLayers);
348

  
349
      if( color<NUM_TEXTURES )
350
        {
351
        numNonBlack++;
352
        nonBlackIndex = color%NUM_FACES;
353
        }
354
      }
355

  
356
    if( numNonBlack==0 ) return -1;
357
    if( numNonBlack>=2 ) return -2;
358

  
359
    return nonBlackIndex;
360
    }
361

  
362
///////////////////////////////////////////////////////////////////////////////////////////////////
363

  
364
  int[] buildSolvedQuats(Static3D faceAx, Static4D[] quats)
365
    {
366
    final float MAXD = 0.0001f;
367
    float x = faceAx.get0();
368
    float y = faceAx.get1();
369
    float z = faceAx.get2();
370
    float a,dx,dy,dz,qx,qy,qz;
371
    Static4D quat;
372

  
373
    int len = quats.length;
374
    int place = 0;
375

  
376
    for(int q=1; q<len; q++)
377
      {
378
      quat = quats[q];
379
      qx = quat.get0();
380
      qy = quat.get1();
381
      qz = quat.get2();
382

  
383
           if( x!=0.0f ) { a = qx/x; }
384
      else if( y!=0.0f ) { a = qy/y; }
385
      else               { a = qz/z; }
386

  
387
      dx = a*x-qx;
388
      dy = a*y-qy;
389
      dz = a*z-qz;
390

  
391
      if( dx>-MAXD && dx<MAXD && dy>-MAXD && dy<MAXD && dz>-MAXD && dz<MAXD )
392
        {
393
        mTmpQuats[place++] = q;
394
        }
395
      }
396

  
397
    if( place!=0 )
398
      {
399
      int[] ret = new int[place];
400
      System.arraycopy(mTmpQuats,0,ret,0,place);
401
      return ret;
402
      }
403

  
404
    return null;
405
    }
406

  
407
///////////////////////////////////////////////////////////////////////////////////////////////////
408

  
409
  private int getMultQuat(int index1, int index2)
410
    {
411
    if( mQuatMult==null )
412
      {
413
      int len = QUATS.length;
414
      mQuatMult = new int[len][len];
415

  
416
      for(int i=0; i<len; i++)
417
        for(int j=0; j<len; j++) mQuatMult[i][j] = -1;
418
      }
419

  
420
    if( mQuatMult[index1][index2]==-1 )
421
      {
422
      mQuatMult[index1][index2] = mulQuat(index1,index2);
423
      }
424

  
425
    return mQuatMult[index1][index2];
426
    }
427

  
428
///////////////////////////////////////////////////////////////////////////////////////////////////
429

  
430
  public boolean isSolved()
431
    {
432
    int len, q1,q = CUBITS[0].mQuatIndex;
433
    int[] solved;
434
    boolean skip;
435

  
436
    for(int c=1; c<NUM_CUBITS; c++)
437
      {
438
      q1 = CUBITS[c].mQuatIndex;
439

  
440
      if( q1==q ) continue;
441

  
442
      skip = false;
443
      solved = mSolvedQuats[c];
444
      len = solved==null ? 0:solved.length;
445

  
446
      for(int i=0; i<len; i++)
447
        {
448
        if( q1==getMultQuat(q,solved[i]) )
449
          {
450
          skip = true;
451
          break;
452
          }
453
        }
454

  
455
      if( !skip ) return false;
456
      }
457

  
458
    return true;
459
    }
460

  
319 461
///////////////////////////////////////////////////////////////////////////////////////////////////
320 462

  
321 463
  public void setObjectRatio(float sizeChange)
......
523 665
    return -1;
524 666
    }
525 667

  
526
///////////////////////////////////////////////////////////////////////////////////////////////////
527
// return if the Cubit, when rotated with its own mQuatScramble, would have looked any different
528
// then if it were rotated by quaternion 'quat'.
529
// No it is not so simple as the quats need to be the same - imagine a 4x4x4 cube where the two
530
// middle squares get interchanged. No visible difference!
531
//
532
// So: this is true iff the cubit
533
// a) is a corner or edge and the quaternions are the same
534
// b) is inside one of the faces and after rotations by both quats it ends up on the same face.
535

  
536
  boolean thereIsVisibleDifference(Cubit cubit, int quatIndex)
537
    {
538
    if ( cubit.mQuatIndex == quatIndex ) return false;
539

  
540
    int belongsToHowManyFaces = 0;
541
    int bitmap = (1<<(getNumLayers()-1)) + 1;
542

  
543
    for(int i = 0; i< NUM_AXIS; i++)
544
      {
545
      if( (cubit.mRotationRow[i] & bitmap) != 0 ) belongsToHowManyFaces++;
546
      }
547

  
548
    switch(belongsToHowManyFaces)
549
      {
550
      case 0 : return false;  // 'inside' cubit that does not lie on any face
551
      case 1 :                // cubit that lies inside one of the faces
552
               float[] orig   = cubit.getOrigPosition();
553
               Static4D quat1 = QUATS[quatIndex];
554
               Static4D quat2 = QUATS[cubit.mQuatIndex];
555

  
556
               Static4D cubitCenter = new Static4D( orig[0], orig[1], orig[2], 0);              // not used for bandaged objects,
557
               Static4D rotated1 = QuatHelper.rotateVectorByQuat( cubitCenter, quat1 );   // only check the first position
558
               Static4D rotated2 = QuatHelper.rotateVectorByQuat( cubitCenter, quat2 );
559

  
560
               rotated1.get(mTmp1, 0, 0, 0);
561
               rotated2.get(mTmp2, 0, 0, 0);
562

  
563
               for(int i = 0; i< NUM_AXIS; i++)
564
                 {
565
                 if( (computeRow(mTmp1,i) & computeRow(mTmp2,i) & bitmap) != 0 ) return false;
566
                 }
567
               return true;
568

  
569
      default: return true;  // edge or corner
570
      }
571
    }
572

  
573
///////////////////////////////////////////////////////////////////////////////////////////////////
574
// create StickerCoord and FaceTransform data structures
575

  
576
  void createFaceDataStructures(double[][][] verts, int[][][] indices)
577
    {
578
    int numCubitTypes = verts.length;
579
    FactoryCubit factory = FactoryCubit.getInstance();
580
    factory.clear();
581

  
582
    for(int cubit=0; cubit<numCubitTypes; cubit++)
583
      {
584
      double[][] vertices = verts[cubit];
585
      int[][] vertIndices = indices[cubit];
586
      factory.createNewFaceTransform(vertices,vertIndices);
587
      }
588

  
589
    factory.printFaceTransform();
590
    factory.printStickerCoords();
591
    }
592

  
593 668
///////////////////////////////////////////////////////////////////////////////////////////////////
594 669

  
595 670
  public int getCubitFaceColorIndex(int cubit, int face)
......
1013 1088
  abstract int getNumCubitVariants(int numLayers);
1014 1089
  abstract Static4D getQuat(int cubit, int numLayers);
1015 1090
  abstract ObjectShape getObjectShape(int cubit, int numLayers);
1091
  abstract int[] getSolvedQuats(int cubit, int numLayers);
1016 1092

  
1017 1093
  public abstract Static3D[] getRotationAxis();
1018
  public abstract boolean isSolved();
1019 1094
  public abstract int[] getBasicAngle();
1020 1095
  public abstract void randomizeNewScramble(int[][] scramble, Random rnd, int curScramble, int totScrambles);
1021 1096
  public abstract int getObjectName(int numLayers);
src/main/java/org/distorted/objects/TwistyPyraminx.java
135 135
    super(size, size, quat, texture, mesh, effects, moves, ObjectList.PYRA, res, scrWidth);
136 136
    }
137 137

  
138
///////////////////////////////////////////////////////////////////////////////////////////////////
139

  
140
  int[] getSolvedQuats(int cubit, int numLayers)
141
    {
142
    int status = retCubitSolvedStatus(cubit,numLayers);
143
    return status<0 ? null : buildSolvedQuats(MovementPyraminx.FACE_AXIS[status],QUATS);
144
    }
145

  
138 146
///////////////////////////////////////////////////////////////////////////////////////////////////
139 147

  
140 148
  private float[] getRowChances(int numLayers)
......
441 449
      }
442 450
    }
443 451

  
444
///////////////////////////////////////////////////////////////////////////////////////////////////
445

  
446
  public boolean isSolved()
447
    {
448
    int index = CUBITS[0].mQuatIndex;
449

  
450
    for(int i=1; i<NUM_CUBITS; i++)
451
      {
452
      if( thereIsVisibleDifference(CUBITS[i], index) ) return false;
453
      }
454

  
455
    return true;
456
    }
457

  
458 452
///////////////////////////////////////////////////////////////////////////////////////////////////
459 453

  
460 454
  public int getObjectName(int numLayers)
src/main/java/org/distorted/objects/TwistyRedi.java
213 213
    super(size, size, quat, texture, mesh, effects, moves, ObjectList.REDI, res, scrWidth);
214 214
    }
215 215

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

  
218
  int[] getSolvedQuats(int cubit, int numLayers)
219
    {
220
    int status = retCubitSolvedStatus(cubit,numLayers);
221
    return status<0 ? null : buildSolvedQuats(MovementRedi.FACE_AXIS[status],QUATS);
222
    }
223

  
216 224
///////////////////////////////////////////////////////////////////////////////////////////////////
217 225

  
218 226
  float getScreenRatio()
......
478 486
      }
479 487
    }
480 488

  
481
///////////////////////////////////////////////////////////////////////////////////////////////////
482
// The Redi is solved if and only if all cubits are rotated with the same quat.
483

  
484
  public boolean isSolved()
485
    {
486
    int q = CUBITS[0].mQuatIndex;
487

  
488
    return ( CUBITS[ 1].mQuatIndex == q &&
489
             CUBITS[ 2].mQuatIndex == q &&
490
             CUBITS[ 3].mQuatIndex == q &&
491
             CUBITS[ 4].mQuatIndex == q &&
492
             CUBITS[ 5].mQuatIndex == q &&
493
             CUBITS[ 6].mQuatIndex == q &&
494
             CUBITS[ 7].mQuatIndex == q &&
495
             CUBITS[ 8].mQuatIndex == q &&
496
             CUBITS[ 9].mQuatIndex == q &&
497
             CUBITS[10].mQuatIndex == q &&
498
             CUBITS[11].mQuatIndex == q &&
499
             CUBITS[12].mQuatIndex == q &&
500
             CUBITS[13].mQuatIndex == q &&
501
             CUBITS[14].mQuatIndex == q &&
502
             CUBITS[15].mQuatIndex == q &&
503
             CUBITS[16].mQuatIndex == q &&
504
             CUBITS[17].mQuatIndex == q &&
505
             CUBITS[18].mQuatIndex == q &&
506
             CUBITS[19].mQuatIndex == q  );
507
    }
508

  
509 489
///////////////////////////////////////////////////////////////////////////////////////////////////
510 490

  
511 491
  public int getObjectName(int numLayers)
src/main/java/org/distorted/objects/TwistyRex.java
160 160
    super(size, size, quat, texture, mesh, effects, moves, ObjectList.REX, res, scrWidth);
161 161
    }
162 162

  
163
///////////////////////////////////////////////////////////////////////////////////////////////////
164

  
165
  int[] getSolvedQuats(int cubit, int numLayers)
166
    {
167
    int status = retCubitSolvedStatus(cubit,numLayers);
168
    return status<0 ? null : buildSolvedQuats(MovementRex.FACE_AXIS[status],QUATS);
169
    }
170

  
163 171
///////////////////////////////////////////////////////////////////////////////////////////////////
164 172

  
165 173
  float getScreenRatio()
......
487 495
      }
488 496
    }
489 497

  
490
///////////////////////////////////////////////////////////////////////////////////////////////////
491
// The Rex is solved if and only if:
492
//
493
// 1) all 12 of its edge cubits are rotated with the same quat
494
// 2) all its face & corner cubits are rotated with the same quat like the edge ones,
495
//    and optionally they also might be upside down.
496
//
497
// i.e.
498
// corners ( 0, 1, 2, 3, 4, 5, 6, 7) and faces (24,25) - might be extra QUAT[1]
499
// corners ( 8, 9,10,11,12,13,14,15) and faces (26,27) - might be extra QUAT[2]
500
// corners (16,17,18,19,20,21,22,23) and faces (28,29) - might be extra QUAT[3]
501

  
502
  public boolean isSolved()
503
    {
504
    int q1,q = CUBITS[30].mQuatIndex;
505

  
506
    for(int i=31; i<42; i++)
507
      {
508
      if( CUBITS[i].mQuatIndex != q) return false;
509
      }
510

  
511
    q1 = mulQuat(q,1);
512

  
513
    for(int i=0; i<8; i++)
514
      {
515
      if( CUBITS[i].mQuatIndex != q && CUBITS[i].mQuatIndex != q1 ) return false;
516
      }
517

  
518
    if( CUBITS[24].mQuatIndex != q && CUBITS[24].mQuatIndex != q1 ) return false;
519
    if( CUBITS[25].mQuatIndex != q && CUBITS[25].mQuatIndex != q1 ) return false;
520

  
521
    q1 = mulQuat(q,2);
522

  
523
    for(int i=8; i<16; i++)
524
      {
525
      if( CUBITS[i].mQuatIndex != q && CUBITS[i].mQuatIndex != q1 ) return false;
526
      }
527

  
528
    if( CUBITS[26].mQuatIndex != q && CUBITS[26].mQuatIndex != q1 ) return false;
529
    if( CUBITS[27].mQuatIndex != q && CUBITS[27].mQuatIndex != q1 ) return false;
530

  
531
    q1 = mulQuat(q,3);
532

  
533
    for(int i=16; i<24; i++)
534
      {
535
      if( CUBITS[i].mQuatIndex != q && CUBITS[i].mQuatIndex != q1 ) return false;
536
      }
537

  
538
    if( CUBITS[28].mQuatIndex != q && CUBITS[28].mQuatIndex != q1 ) return false;
539
    if( CUBITS[29].mQuatIndex != q && CUBITS[29].mQuatIndex != q1 ) return false;
540

  
541
    return true;
542
    }
543

  
544 498
///////////////////////////////////////////////////////////////////////////////////////////////////
545 499

  
546 500
  public int getObjectName(int numLayers)
src/main/java/org/distorted/objects/TwistySkewb.java
197 197
    super(size, 2*size-2, quat, texture, mesh, effects, moves, ObjectList.SKEW, res, scrWidth);
198 198
    }
199 199

  
200
///////////////////////////////////////////////////////////////////////////////////////////////////
201

  
202
  int[] getSolvedQuats(int cubit, int numLayers)
203
    {
204
    int status = retCubitSolvedStatus(cubit,numLayers);
205
    return status<0 ? null : buildSolvedQuats(MovementSkewb.FACE_AXIS[status],QUATS);
206
    }
207

  
200 208
///////////////////////////////////////////////////////////////////////////////////////////////////
201 209

  
202 210
  private int getNumCorners()
......
605 613
      }
606 614
    }
607 615

  
608
///////////////////////////////////////////////////////////////////////////////////////////////////
609
// The Skewb is solved if and only if:
610
//
611
// 1) all of its corner and edge cubits are rotated with the same quat
612
// 2) all its face cubits are rotated with the same quat like the corner ones,
613
//    and optionally they also might be upside down.
614
//
615
// i.e.
616
// cubits [ 8] and [ 9] - might be extra QUAT[1]
617
// cubits [10] and [11] - might be extra QUAT[2]
618
// cubits [12] and [13] - might be extra QUAT[3]
619

  
620
  public boolean isSolved()
621
    {
622
    int q = CUBITS[0].mQuatIndex;
623

  
624
    int numLayers      = getNumLayers();
625
    int numCorners     = getNumCorners();
626
    int numEdges       = getNumEdges(numLayers);
627
    int cornersAndEdges= numCorners + numEdges;
628
    int centersPerFace = getNumCentersPerFace(numLayers);
629
    int cubit, q1=q;
630

  
631
    for(cubit=0; cubit<cornersAndEdges; cubit++)
632
      {
633
      if( CUBITS[cubit].mQuatIndex != q ) return false;
634
      }
635

  
636
    for(int face=0; face<6; face++)
637
      {
638
      if( face%2==0 ) q1 = mulQuat(q, (face/2)+1);
639

  
640
      for(int center=0; center<centersPerFace; center++)
641
        {
642
        if( CUBITS[cubit].mQuatIndex != q && CUBITS[cubit].mQuatIndex != q1 ) return false;
643
        cubit++;
644
        }
645
      }
646

  
647
    return true;
648
    }
649

  
650 616
///////////////////////////////////////////////////////////////////////////////////////////////////
651 617

  
652 618
  public int getObjectName(int numLayers)
src/main/java/org/distorted/objects/TwistySquare1.java
176 176
    mCornerQuat = new int[8];
177 177
    }
178 178

  
179
///////////////////////////////////////////////////////////////////////////////////////////////////
180

  
181
  int[] getSolvedQuats(int cubit, int numLayers)
182
    {
183
    int status = retCubitSolvedStatus(cubit,numLayers);
184
    return status<0 ? null : buildSolvedQuats(MovementSquare.FACE_AXIS[status],QUATS);
185
    }
186

  
179 187
///////////////////////////////////////////////////////////////////////////////////////////////////
180 188

  
181 189
  ObjectShape getObjectShape(int cubit, int numLayers)
......
513 521
      }
514 522
    }
515 523

  
516
///////////////////////////////////////////////////////////////////////////////////////////////////
517

  
518
  public boolean isSolved()
519
    {
520
    int index = CUBITS[0].mQuatIndex;
521

  
522
    for(int i=1; i<NUM_CUBITS; i++)
523
      {
524
      if( CUBITS[i].mQuatIndex != index ) return false;
525
      }
526

  
527
    return true;
528
    }
529

  
530 524
///////////////////////////////////////////////////////////////////////////////////////////////////
531 525

  
532 526
  public int getObjectName(int numLayers)
src/main/java/org/distorted/objects/TwistySquare2.java
181 181
    super(size, quat, texture, mesh, effects, moves, ObjectList.SQU2, res, scrWidth);
182 182
    }
183 183

  
184
///////////////////////////////////////////////////////////////////////////////////////////////////
185
// Square-2 is solved iff
186
// a) all of its cubits are rotated with the same quat
187
// b) its two 'middle' cubits are rotated with the same quat, the 6 'front' and 6 'back'
188
// edges and corners with this quat multiplied by QUATS[18] (i.e. those are upside down)
189
// and all the 12 left and right edges and corners also with the same quat multiplied by
190
// QUATS[12] - i.e. also upside down.
191

  
192
  private static final int[] S18 = new int[] {18};
193
  private static final int[] S12 = new int[] {12};
194

  
195
  int[] getSolvedQuats(int cubit, int numLayers)
196
    {
197
    switch(cubit)
198
      {
199
      case  0: case  1: return null;
200
      case  2: case  4: case  6: case  8:
201
      case 10: case 12: case 14: case 16:
202
      case 19: case 21: case 23: case 25: return S18;
203
      case  3: case  5: case  7: case  9:
204
      case 11: case 13: case 15: case 17:
205
      case 18: case 20: case 22: case 24: return S12;
206
      }
207

  
208
    return null;
209
    }
210

  
184 211
///////////////////////////////////////////////////////////////////////////////////////////////////
185 212

  
186 213
  ObjectShape getObjectShape(int cubit, int numLayers)
......
327 354
      }
328 355
    }
329 356

  
330
///////////////////////////////////////////////////////////////////////////////////////////////////
331
// Square-2 is solved iff
332
// a) all of its cubits are rotated with the same quat
333
// b) its two 'middle' cubits are rotated with the same quat, the 6 'front' and 6 'back'
334
// edges and corners with this quat multiplied by QUATS[18] (i.e. those are upside down)
335
// and all the 12 left and right edges and corners also with the same quat multiplied by
336
// QUATS[12] - i.e. also upside down.
337

  
338
  public boolean isSolved()
339
    {
340
    int index = CUBITS[0].mQuatIndex;
341

  
342
    if( CUBITS[1].mQuatIndex!=index ) return false;
343

  
344
    int indexX = mulQuat(index,12);  // QUATS[12] = 180deg (1,0,0)
345
    int indexZ = mulQuat(index,18);  // QUATS[18] = 180deg (0,0,1)
346

  
347
    for(int i=2; i<18; i+=2)
348
      {
349
      if( CUBITS[i].mQuatIndex != index && CUBITS[i].mQuatIndex != indexZ ) return false;
350
      }
351
    for(int i=3; i<18; i+=2)
352
      {
353
      if( CUBITS[i].mQuatIndex != index && CUBITS[i].mQuatIndex != indexX ) return false;
354
      }
355
    for(int i=18; i<NUM_CUBITS; i+=2)
356
      {
357
      if( CUBITS[i].mQuatIndex != index && CUBITS[i].mQuatIndex != indexX ) return false;
358
      }
359
    for(int i=19; i<NUM_CUBITS; i+=2)
360
      {
361
      if( CUBITS[i].mQuatIndex != index && CUBITS[i].mQuatIndex != indexZ ) return false;
362
      }
363

  
364
    return true;
365
    }
366

  
367 357
///////////////////////////////////////////////////////////////////////////////////////////////////
368 358

  
369 359
  public int getObjectName(int numLayers)
src/main/java/org/distorted/objects/TwistyUltimate.java
240 240
    super(size, size, quat, texture, mesh, effects, moves, ObjectList.ULTI, res, scrWidth);
241 241
    }
242 242

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

  
245
  int[] getSolvedQuats(int cubit, int numLayers)
246
    {
247
    int status = retCubitSolvedStatus(cubit,numLayers);
248
    return status<0 ? null : buildSolvedQuats(MovementUltimate.FACE_AXIS[status],QUATS);
249
    }
250

  
243 251
///////////////////////////////////////////////////////////////////////////////////////////////////
244 252

  
245 253
  ObjectShape getObjectShape(int cubit, int numLayers)
......
422 430
      }
423 431
    }
424 432

  
425
///////////////////////////////////////////////////////////////////////////////////////////////////
426

  
427
  public boolean isSolved()
428
    {
429
    int index = CUBITS[0].mQuatIndex;
430

  
431
    for(int i=1; i<NUM_CUBITS; i++)
432
      {
433
      if( CUBITS[i].mQuatIndex != index ) return false;
434
      }
435

  
436
    return true;
437
    }
438

  
439 433
///////////////////////////////////////////////////////////////////////////////////////////////////
440 434

  
441 435
  public int getObjectName(int numLayers)

Also available in: Unified diff