Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / TwistySkewb.java @ 596d62a4

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2020 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Magic Cube.                                                              //
5
//                                                                                               //
6
// Magic Cube is free software: you can redistribute it and/or modify                            //
7
// it under the terms of the GNU General Public License as published by                          //
8
// the Free Software Foundation, either version 2 of the License, or                             //
9
// (at your option) any later version.                                                           //
10
//                                                                                               //
11
// Magic Cube is distributed in the hope that it will be useful,                                 //
12
// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
14
// GNU General Public License for more details.                                                  //
15
//                                                                                               //
16
// You should have received a copy of the GNU General Public License                             //
17
// along with Magic Cube.  If not, see <http://www.gnu.org/licenses/>.                           //
18
///////////////////////////////////////////////////////////////////////////////////////////////////
19

    
20
package org.distorted.objects;
21

    
22
import android.content.res.Resources;
23
import android.graphics.Canvas;
24
import android.graphics.Paint;
25

    
26
import org.distorted.helpers.FactoryCubit;
27
import org.distorted.helpers.FactorySticker;
28
import org.distorted.library.effect.MatrixEffectQuaternion;
29
import org.distorted.library.main.DistortedEffects;
30
import org.distorted.library.main.DistortedTexture;
31
import org.distorted.library.mesh.MeshBase;
32
import org.distorted.library.mesh.MeshSquare;
33
import org.distorted.library.type.Static3D;
34
import org.distorted.library.type.Static4D;
35
import org.distorted.main.R;
36
import org.distorted.main.RubikSurfaceView;
37

    
38
import java.util.Random;
39

    
40
///////////////////////////////////////////////////////////////////////////////////////////////////
41

    
42
public class TwistySkewb extends TwistyObject
43
{
44
  private static final int FACES_PER_CUBIT =6;
45

    
46
  // the four rotation axis of a RubikSkewb. Must be normalized.
47
  static final Static3D[] ROT_AXIS = new Static3D[]
48
         {
49
           new Static3D(+SQ3/3,+SQ3/3,+SQ3/3),
50
           new Static3D(+SQ3/3,+SQ3/3,-SQ3/3),
51
           new Static3D(+SQ3/3,-SQ3/3,+SQ3/3),
52
           new Static3D(+SQ3/3,-SQ3/3,-SQ3/3)
53
         };
54

    
55
  private static final int[] FACE_COLORS = new int[]
56
         {
57
           COLOR_YELLOW, COLOR_WHITE,
58
           COLOR_BLUE  , COLOR_GREEN,
59
           COLOR_RED   , COLOR_ORANGE
60
         };
61

    
62
  // All legal rotation quats of a RubikSkewb
63
  private static final Static4D[] QUATS = new Static4D[]
64
         {
65
           new Static4D(  0.0f,  0.0f,  0.0f,  1.0f ),
66
           new Static4D(  1.0f,  0.0f,  0.0f,  0.0f ),
67
           new Static4D(  0.0f,  1.0f,  0.0f,  0.0f ),
68
           new Static4D(  0.0f,  0.0f,  1.0f,  0.0f ),
69

    
70
           new Static4D(  0.5f,  0.5f,  0.5f,  0.5f ),
71
           new Static4D(  0.5f,  0.5f,  0.5f, -0.5f ),
72
           new Static4D(  0.5f,  0.5f, -0.5f,  0.5f ),
73
           new Static4D(  0.5f,  0.5f, -0.5f, -0.5f ),
74
           new Static4D(  0.5f, -0.5f,  0.5f,  0.5f ),
75
           new Static4D(  0.5f, -0.5f,  0.5f, -0.5f ),
76
           new Static4D(  0.5f, -0.5f, -0.5f,  0.5f ),
77
           new Static4D(  0.5f, -0.5f, -0.5f, -0.5f )
78
         };
79

    
80
  private static final int[][] mCornerMap =
81
         {
82
           {  4, 2, 0, 18,18,18 },
83
           {  2, 5, 0, 18,18,18 },
84
           {  3, 4, 0, 18,18,18 },
85
           {  5, 3, 0, 18,18,18 },
86
           {  1, 2, 4, 18,18,18 },
87
           {  5, 2, 1, 18,18,18 },
88
           {  4, 3, 1, 18,18,18 },
89
           {  1, 3, 5, 18,18,18 },
90
         };
91

    
92
  private static final int[][] mEdgeMap =
93
         {
94
           { 10, 8, 18,18,18,18 },
95
           {  6,10, 18,18,18,18 },
96
           { 10, 9, 18,18,18,18 },
97
           {  7,10, 18,18,18,18 },
98
           {  8, 6, 18,18,18,18 },
99
           {  9, 6, 18,18,18,18 },
100
           {  9, 7, 18,18,18,18 },
101
           {  8, 7, 18,18,18,18 },
102
           { 11, 8, 18,18,18,18 },
103
           {  6,11, 18,18,18,18 },
104
           { 11, 9, 18,18,18,18 },
105
           {  7,11, 18,18,18,18 }
106
         };
107

    
108
  private static final int[][] mCenterMap =
109
         {
110
           { 12, 18,18,18,18,18 },
111
           { 13, 18,18,18,18,18 },
112
           { 14, 18,18,18,18,18 },
113
           { 15, 18,18,18,18,18 },
114
           { 16, 18,18,18,18,18 },
115
           { 17, 18,18,18,18,18 },
116
         };
117

    
118
  private static final double[][] VERTICES_CORNER = new double[][]
119
          {
120
             // TODO
121
          };
122

    
123
  private static final int[][] VERT_INDEXES_CORNER = new int[][]
124
          {
125
             // TODO
126
          };
127

    
128
  private static final double[][] VERTICES_EDGE = new double[][]
129
          {
130
             {-0.5, 0.0, 0.0},
131
             { 0.5, 0.0, 0.0},
132
             { 0.0,-0.5, 0.0},
133
             { 0.0, 0.0,-0.5}
134
          };
135

    
136
  private static final int[][] VERT_INDEXES_EDGE = new int[][]
137
          {
138
             {2,1,0},   // counterclockwise!
139
             {3,0,1},
140
             {2,3,1},
141
             {3,2,0},
142
          };
143

    
144
  private static final double[][] VERTICES_FACE = new double[][]
145
          {
146
             // TODO
147
          };
148

    
149
  private static final int[][] VERT_INDEXES_FACE = new int[][]
150
          {
151
             // TODO
152
          };
153

    
154
  private static MeshBase[] mMeshes;
155

    
156
///////////////////////////////////////////////////////////////////////////////////////////////////
157

    
158
  TwistySkewb(int size, Static4D quat, DistortedTexture texture,
159
              MeshSquare mesh, DistortedEffects effects, int[][] moves, Resources res, int scrWidth)
160
    {
161
    super(size, 2*size-2, quat, texture, mesh, effects, moves, ObjectList.SKEW, res, scrWidth);
162
    }
163

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

    
166
  double[][] getVertices(int cubitType)
167
    {
168
    if( cubitType==0 ) return VERTICES_CORNER;
169
    if( cubitType==1 ) return VERTICES_EDGE;
170
    if( cubitType==2 ) return VERTICES_FACE;
171
    return null;
172
    }
173

    
174
///////////////////////////////////////////////////////////////////////////////////////////////////
175

    
176
  int[][] getVertIndexes(int cubitType)
177
    {
178
    if( cubitType==0 ) return VERT_INDEXES_CORNER;
179
    if( cubitType==1 ) return VERT_INDEXES_EDGE;
180
    if( cubitType==2 ) return VERT_INDEXES_FACE;
181
    return null;
182
    }
183

    
184
///////////////////////////////////////////////////////////////////////////////////////////////////
185

    
186
  int getNumCubitTypes(int numLayers)
187
    {
188
    return numLayers==2 ? 2 : 3;
189
    }
190

    
191
///////////////////////////////////////////////////////////////////////////////////////////////////
192

    
193
  private int getNumCorners()
194
    {
195
    return 8;
196
    }
197

    
198
///////////////////////////////////////////////////////////////////////////////////////////////////
199

    
200
  private int getNumEdges(int layers)
201
    {
202
    return (layers-2)*12;
203
    }
204

    
205
///////////////////////////////////////////////////////////////////////////////////////////////////
206

    
207
  private int getNumCentersPerFace(int layers)
208
    {
209
    return ((layers-2)*(layers-2) + (layers-1)*(layers-1));
210
    }
211

    
212
///////////////////////////////////////////////////////////////////////////////////////////////////
213

    
214
  float getScreenRatio()
215
    {
216
    return 1.0f;
217
    }
218

    
219
///////////////////////////////////////////////////////////////////////////////////////////////////
220

    
221
  Static4D[] getQuats()
222
    {
223
    return QUATS;
224
    }
225

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

    
228
  int getNumFaces()
229
    {
230
    return FACE_COLORS.length;
231
    }
232

    
233
///////////////////////////////////////////////////////////////////////////////////////////////////
234

    
235
  boolean shouldResetTextureMaps()
236
    {
237
    return false;
238
    }
239

    
240
///////////////////////////////////////////////////////////////////////////////////////////////////
241

    
242
  int getNumStickerTypes(int numLayers)
243
    {
244
    return 3;
245
    }
246

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

    
249
  float[] getCuts(int numLayers)
250
    {
251
    float[] cuts = new float[numLayers-1];
252

    
253
    switch(numLayers)
254
      {
255
      case 2: cuts[0] = 0;
256
              break;
257
      case 3: cuts[0] = -SQ3/12;
258
              cuts[1] = +SQ3/12;
259
              break;
260
      case 4: cuts[0] = -SQ3/9;
261
              cuts[1] = 0;
262
              cuts[2] = +SQ3/9;
263
              break;
264
      }
265
    return cuts;
266
    }
267

    
268
///////////////////////////////////////////////////////////////////////////////////////////////////
269

    
270
  int getNumCubitFaces()
271
    {
272
    return FACES_PER_CUBIT;
273
    }
274

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

    
277
  float[][] getCubitPositions(int numLayers)
278
    {
279
    final float DIST_CORNER = (numLayers-1)*0.50f;
280
    final float DIST_EDGE   = (numLayers-1)*0.50f;
281
    final float DIST_CENTER = (numLayers-1)*0.50f;
282

    
283
    final int numCorners = getNumCorners();
284
    final int numEdges   = getNumEdges(numLayers);
285
    final int numCenters = 6*getNumCentersPerFace(numLayers);
286

    
287
    final float[][] CENTERS = new float[numCorners+numEdges+numCenters][];
288

    
289
    /// CORNERS //////////////////////////////////////////////
290

    
291
    CENTERS[0] = new float[] { DIST_CORNER, DIST_CORNER, DIST_CORNER };
292
    CENTERS[1] = new float[] { DIST_CORNER, DIST_CORNER,-DIST_CORNER };
293
    CENTERS[2] = new float[] { DIST_CORNER,-DIST_CORNER, DIST_CORNER };
294
    CENTERS[3] = new float[] { DIST_CORNER,-DIST_CORNER,-DIST_CORNER };
295
    CENTERS[4] = new float[] {-DIST_CORNER, DIST_CORNER, DIST_CORNER };
296
    CENTERS[5] = new float[] {-DIST_CORNER, DIST_CORNER,-DIST_CORNER };
297
    CENTERS[6] = new float[] {-DIST_CORNER,-DIST_CORNER, DIST_CORNER };
298
    CENTERS[7] = new float[] {-DIST_CORNER,-DIST_CORNER,-DIST_CORNER };
299

    
300
    /// EDGES ///////////////////////////////////////////////
301

    
302
    final float[][]  edgeTable =
303
        {
304
            {0,+DIST_EDGE,+DIST_EDGE},
305
            {+DIST_EDGE,0,+DIST_EDGE},
306
            {0,-DIST_EDGE,+DIST_EDGE},
307
            {-DIST_EDGE,0,+DIST_EDGE},
308
            {+DIST_EDGE,+DIST_EDGE,0},
309
            {+DIST_EDGE,-DIST_EDGE,0},
310
            {-DIST_EDGE,-DIST_EDGE,0},
311
            {-DIST_EDGE,+DIST_EDGE,0},
312
            {0,+DIST_EDGE,-DIST_EDGE},
313
            {+DIST_EDGE,0,-DIST_EDGE},
314
            {0,-DIST_EDGE,-DIST_EDGE},
315
            {-DIST_EDGE,0,-DIST_EDGE}
316
        };
317

    
318
    int index=8;
319

    
320
    for (float[] edges : edgeTable)
321
      {
322
      float c = (3-numLayers)*0.5f;
323

    
324
      for (int j=0; j<numLayers-2; j++, c+=1.0f, index++)
325
        {
326
        CENTERS[index] = new float[] { edges[0]==0 ? c : edges[0] ,
327
                                       edges[1]==0 ? c : edges[1] ,
328
                                       edges[2]==0 ? c : edges[2] };
329
        }
330
      }
331

    
332
    /// CENTERS //////////////////////////////////////////////
333

    
334
    final float X= -1000.0f;
335
    final float Y= -1001.0f;
336

    
337
    final float[][]  centerTable =
338
        {
339
            {+DIST_CENTER,X,Y},
340
            {-DIST_CENTER,X,Y},
341
            {X,+DIST_CENTER,Y},
342
            {X,-DIST_CENTER,Y},
343
            {X,Y,+DIST_CENTER},
344
            {X,Y,-DIST_CENTER}
345
        };
346

    
347
    float x,y, cen0, cen1, cen2;
348

    
349
    for( float[] centers : centerTable )
350
      {
351
      x = (2-numLayers)*0.5f;
352

    
353
      for(int i=0; i<numLayers-1; i++, x+=1.0f)
354
        {
355
        y = (2-numLayers)*0.5f;
356

    
357
        for(int j=0; j<numLayers-1; j++, y+=1.0f, index++)
358
          {
359
               if( centers[0]==Y ) cen0 = y;
360
          else if( centers[0]==X ) cen0 = x;
361
          else                     cen0 = centers[0];
362

    
363
               if( centers[1]==Y ) cen1 = y;
364
          else if( centers[1]==X ) cen1 = x;
365
          else                     cen1 = centers[1];
366

    
367
               if( centers[2]==Y ) cen2 = y;
368
          else if( centers[2]==X ) cen2 = x;
369
          else                     cen2 = centers[2];
370

    
371
          CENTERS[index] = new float[] {cen0,cen1,cen2};
372
          }
373
        }
374

    
375
      x = (3-numLayers)*0.5f;
376

    
377
      for(int i=0; i<numLayers-2; i++, x+=1.0f)
378
        {
379
        y = (3-numLayers)*0.5f;
380

    
381
        for(int j=0; j<numLayers-2; j++, y+=1.0f, index++)
382
          {
383
               if( centers[0]==Y ) cen0 = y;
384
          else if( centers[0]==X ) cen0 = x;
385
          else                     cen0 = centers[0];
386

    
387
               if( centers[1]==Y ) cen1 = y;
388
          else if( centers[1]==X ) cen1 = x;
389
          else                     cen1 = centers[1];
390

    
391
               if( centers[2]==Y ) cen2 = y;
392
          else if( centers[2]==X ) cen2 = x;
393
          else                     cen2 = centers[2];
394

    
395
          CENTERS[index] = new float[] {cen0,cen1,cen2};
396
          }
397
        }
398
      }
399

    
400
    return CENTERS;
401
    }
402

    
403
///////////////////////////////////////////////////////////////////////////////////////////////////
404

    
405
  private Static4D getQuat(int cubit, int numLayers)
406
    {
407
    int numCorners = getNumCorners();
408
    int numEdges   = getNumEdges(numLayers);
409

    
410
    if( cubit<numCorners )
411
      {
412
      switch(cubit)
413
        {
414
        case  0: return QUATS[0];                          //  unit quat
415
        case  1: return new Static4D( SQ2/2,0,0,SQ2/2);    //  90 along X
416
        case  2: return new Static4D(-SQ2/2,0,0,SQ2/2);    // -90 along X
417
        case  3: return QUATS[1];                          // 180 along X
418
        case  4: return new Static4D(0, SQ2/2,0,SQ2/2);    //  90 along Y
419
        case  5: return QUATS[2];                          // 180 along Y
420
        case  6: return QUATS[3];                          // 180 along Z
421
        case  7: return new Static4D(SQ2/2,0,-SQ2/2,0);    // 180 along (SQ2/2,0,-SQ2/2)
422
        }
423
      }
424
    else if( cubit<numCorners+numEdges )
425
      {
426
      int edge = (cubit-numCorners)/(numLayers-2);
427

    
428
      switch(edge)
429
        {
430
        case  0: return QUATS[ 0];
431
        case  1: return QUATS[ 5];
432
        case  2: return QUATS[ 3];
433
        case  3: return QUATS[11];
434
        case  4: return QUATS[ 4];
435
        case  5: return QUATS[ 7];
436
        case  6: return QUATS[ 9];
437
        case  7: return QUATS[10];
438
        case  8: return QUATS[ 2];
439
        case  9: return QUATS[ 8];
440
        case 10: return QUATS[ 1];
441
        case 11: return QUATS[ 6];
442
        }
443
      }
444
    else
445
      {
446
      int center = (cubit-numCorners-numEdges)/getNumCentersPerFace(numLayers);
447

    
448
      switch(center)
449
        {
450
        case 0: return new Static4D(0,-SQ2/2,0,SQ2/2);    // -90 along Y
451
        case 1: return new Static4D(0, SQ2/2,0,SQ2/2);    //  90 along Y
452
        case 2: return new Static4D( SQ2/2,0,0,SQ2/2);    //  90 along X
453
        case 3: return new Static4D(-SQ2/2,0,0,SQ2/2);    // -90 along X
454
        case 4: return QUATS[0];                          //  unit quaternion
455
        case 5: return QUATS[1];                          // 180 along X
456
        }
457
      }
458

    
459
    return null;
460
    }
461

    
462
///////////////////////////////////////////////////////////////////////////////////////////////////
463

    
464
  MeshBase createCubitMesh(int cubit, int numLayers)
465
    {
466
    if( mMeshes==null )
467
      {
468
      FactoryCubit factory = FactoryCubit.getInstance();
469
      factory.clear();
470
      mMeshes = new MeshBase[3];
471
      }
472

    
473
    MeshBase mesh;
474

    
475
    int numCorners = getNumCorners();
476
    int numEdges   = getNumEdges(numLayers);
477

    
478
    if( cubit<numCorners )
479
      {
480
      if( mMeshes[0]==null )
481
        {
482
        mMeshes[0] = FactoryCubit.getInstance().createSkewbCornerMesh();
483
        }
484
      mesh = mMeshes[0].copy(true);
485
      }
486
    else if( cubit<numCorners+numEdges )
487
      {
488
      if( mMeshes[1]==null )
489
        {
490
        float[][] bands= new float[][]
491
          {
492
             {0.035f,30,0.16f,0.8f,7,2,5},
493
             {0.020f,45,0.16f,0.2f,3,1,2}
494
          };
495
        int[] bandIndexes   = new int[] { 0,0,1,1 };
496
        float[][] corners   = new float[][] { {0.07f,0.20f}, {0.02f,0.30f} };
497
        int[] cornerIndexes = new int[] { 0,0,1,1 };
498

    
499
        FactoryCubit factory = FactoryCubit.getInstance();
500

    
501
        factory.createNewFaceTransform(VERTICES_EDGE,VERT_INDEXES_EDGE);
502
        mMeshes[1] = factory.createRoundedSolid(VERTICES_EDGE, VERT_INDEXES_EDGE,
503
                                                bands, bandIndexes,
504
                                                corners, cornerIndexes,
505
                                                getNumCubitFaces() );
506
        }
507
      mesh = mMeshes[1].copy(true);
508
      }
509
    else
510
      {
511
      if( mMeshes[2]==null )
512
        {
513
        mMeshes[2] = FactoryCubit.getInstance().createSkewbFaceMesh();
514
        }
515
      mesh = mMeshes[2].copy(true);
516
      }
517

    
518
    MatrixEffectQuaternion quat = new MatrixEffectQuaternion( getQuat(cubit,numLayers), new Static3D(0,0,0) );
519
    mesh.apply(quat,0xffffffff,0);
520

    
521
    return mesh;
522
    }
523

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

    
526
  int getFaceColor(int cubit, int cubitface, int numLayers)
527
    {
528
    int numCorners = getNumCorners();
529
    int numEdges   = getNumEdges(numLayers);
530

    
531
    if( cubit<numCorners )
532
      {
533
      return mCornerMap[cubit][cubitface];
534
      }
535
    else if( cubit<numCorners+numEdges )
536
      {
537
      int edge = (cubit-numCorners)/(numLayers-2);
538
      return mEdgeMap[edge][cubitface];
539
      }
540
    else
541
      {
542
      int center = (cubit-numCorners-numEdges)/getNumCentersPerFace(numLayers);
543
      return mCenterMap[center][cubitface];
544
      }
545
    }
546

    
547
///////////////////////////////////////////////////////////////////////////////////////////////////
548

    
549
  void createFaceTexture(Canvas canvas, Paint paint, int face, int left, int top)
550
    {
551
    int COLORS = FACE_COLORS.length;
552
    float R,S;
553
    float[] vertices;
554

    
555
    if( face<COLORS )
556
      {
557
      float E = 0.5f;
558
      R = 0.023f;
559
      S = 0.035f;
560
      vertices = new float[] { -E+E/4,E/4, E/4,-E+E/4, E/4,E/4};
561
      }
562
    else if( face<2*COLORS )
563
      {
564
      float E = 0.5f;
565
      R = 0.025f;
566
      S = 0.05f;
567
      vertices = new float[] { -E,E/3, 0,-2*E/3, +E,E/3 };
568
      }
569
    else
570
      {
571
      float E = SQ2/4;
572
      R = 0.055f;
573
      S = 0.035f;
574
      vertices = new float[] { -E,-E, +E,-E, +E,+E, -E,+E };
575
      }
576

    
577
    FactorySticker factory = FactorySticker.getInstance();
578
    factory.drawRoundedPolygon(canvas, paint, left, top, vertices, S, FACE_COLORS[face%COLORS], R);
579
    }
580

    
581
///////////////////////////////////////////////////////////////////////////////////////////////////
582

    
583
  float returnMultiplier()
584
    {
585
    return 2.0f;
586
    }
587

    
588
///////////////////////////////////////////////////////////////////////////////////////////////////
589

    
590
  float[] getRowChances(int numLayers)
591
    {
592
    float[] chances = new float[numLayers];
593

    
594
    switch(numLayers)
595
      {
596
      case 2: chances[0] = 0.5f;
597
              chances[1] = 1.0f;
598
              break;
599
      case 3: chances[0] = 0.5f;
600
              chances[1] = 0.5f;
601
              chances[2] = 1.0f;
602
              break;
603
      default:for(int i=0; i<numLayers; i++)
604
                {
605
                chances[i] = (float)(i+1)/numLayers;
606
                }
607
      }
608

    
609
    return chances;
610
    }
611

    
612
///////////////////////////////////////////////////////////////////////////////////////////////////
613
// PUBLIC API
614

    
615
  public Static3D[] getRotationAxis()
616
    {
617
    return ROT_AXIS;
618
    }
619

    
620
///////////////////////////////////////////////////////////////////////////////////////////////////
621

    
622
  public int getBasicAngle()
623
    {
624
    return 3;
625
    }
626

    
627
///////////////////////////////////////////////////////////////////////////////////////////////////
628

    
629
  public void randomizeNewScramble(int[][] scramble, Random rnd, int num)
630
    {
631
    if( num==0 )
632
      {
633
      scramble[num][0] = rnd.nextInt(ROTATION_AXIS.length);
634
      }
635
    else
636
      {
637
      int newVector = rnd.nextInt(ROTATION_AXIS.length-1);
638
      scramble[num][0] = (newVector>=scramble[num-1][0] ? newVector+1 : newVector);
639
      }
640

    
641
    float rowFloat = rnd.nextFloat();
642

    
643
    for(int row=0; row<mRowChances.length; row++)
644
      {
645
      if( rowFloat<=mRowChances[row] )
646
        {
647
        scramble[num][1] = row;
648
        break;
649
        }
650
      }
651

    
652
    switch( rnd.nextInt(2) )
653
      {
654
      case 0: scramble[num][2] = -1; break;
655
      case 1: scramble[num][2] =  1; break;
656
      }
657
    }
658

    
659
///////////////////////////////////////////////////////////////////////////////////////////////////
660
// remember about the double cover or unit quaternions!
661

    
662
  private int mulQuat(int q1, int q2)
663
    {
664
    Static4D result = RubikSurfaceView.quatMultiply(QUATS[q1],QUATS[q2]);
665

    
666
    float rX = result.get0();
667
    float rY = result.get1();
668
    float rZ = result.get2();
669
    float rW = result.get3();
670

    
671
    final float MAX_ERROR = 0.1f;
672
    float dX,dY,dZ,dW;
673

    
674
    for(int i=0; i<QUATS.length; i++)
675
      {
676
      dX = QUATS[i].get0() - rX;
677
      dY = QUATS[i].get1() - rY;
678
      dZ = QUATS[i].get2() - rZ;
679
      dW = QUATS[i].get3() - rW;
680

    
681
      if( dX<MAX_ERROR && dX>-MAX_ERROR &&
682
          dY<MAX_ERROR && dY>-MAX_ERROR &&
683
          dZ<MAX_ERROR && dZ>-MAX_ERROR &&
684
          dW<MAX_ERROR && dW>-MAX_ERROR  ) return i;
685

    
686
      dX = QUATS[i].get0() + rX;
687
      dY = QUATS[i].get1() + rY;
688
      dZ = QUATS[i].get2() + rZ;
689
      dW = QUATS[i].get3() + rW;
690

    
691
      if( dX<MAX_ERROR && dX>-MAX_ERROR &&
692
          dY<MAX_ERROR && dY>-MAX_ERROR &&
693
          dZ<MAX_ERROR && dZ>-MAX_ERROR &&
694
          dW<MAX_ERROR && dW>-MAX_ERROR  ) return i;
695
      }
696

    
697
    return -1;
698
    }
699

    
700
///////////////////////////////////////////////////////////////////////////////////////////////////
701
// The Skewb is solved if and only if:
702
//
703
// 1) all of its corner and edge cubits are rotated with the same quat
704
// 2) all its face cubits are rotated with the same quat like the corner ones,
705
//    and optionally they also might be upside down.
706
//
707
// i.e.
708
// cubits [ 8] and [ 9] - might be extra QUAT[1]
709
// cubits [10] and [11] - might be extra QUAT[2]
710
// cubits [12] and [13] - might be extra QUAT[3]
711

    
712
  public boolean isSolved()
713
    {
714
    int q = CUBITS[0].mQuatIndex;
715

    
716
    int numLayers      = getNumLayers();
717
    int numCorners     = getNumCorners();
718
    int numEdges       = getNumEdges(numLayers);
719
    int cornersAndEdges= numCorners + numEdges;
720
    int centersPerFace = getNumCentersPerFace(numLayers);
721
    int cubit, q1=q;
722

    
723
    for(cubit=0; cubit<cornersAndEdges; cubit++)
724
      {
725
      if( CUBITS[cubit].mQuatIndex != q ) return false;
726
      }
727

    
728
    for(int face=0; face<6; face++)
729
      {
730
      if( face%2==0 ) q1 = mulQuat(q, (face/2)+1);
731

    
732
      for(int center=0; center<centersPerFace; center++)
733
        {
734
        if( CUBITS[cubit].mQuatIndex != q && CUBITS[cubit].mQuatIndex != q1 ) return false;
735
        cubit++;
736
        }
737
      }
738

    
739
    return true;
740
    }
741

    
742
///////////////////////////////////////////////////////////////////////////////////////////////////
743
// only needed for solvers - there are no Skewb solvers ATM)
744

    
745
  public String retObjectString()
746
    {
747
    return "";
748
    }
749

    
750
///////////////////////////////////////////////////////////////////////////////////////////////////
751

    
752
  public int getObjectName(int numLayers)
753
    {
754
    switch(numLayers)
755
      {
756
      case 2: return R.string.skew2;
757
      case 3: return R.string.skew3;
758
      }
759
    return R.string.skew2;
760
    }
761

    
762
///////////////////////////////////////////////////////////////////////////////////////////////////
763

    
764
  public int getInventor(int numLayers)
765
    {
766
    switch(numLayers)
767
      {
768
      case 2: return R.string.skew2_inventor;
769
      case 3: return R.string.skew3_inventor;
770
      }
771
    return R.string.skew2_inventor;
772
    }
773

    
774
///////////////////////////////////////////////////////////////////////////////////////////////////
775

    
776
  public int getComplexity(int numLayers)
777
    {
778
    switch(numLayers)
779
      {
780
      case 2: return 5;
781
      case 3: return 9;
782
      }
783
    return 5;
784
    }
785
}
(33-33/33)