Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / TwistyRedi.java @ ecf3f149

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

    
24
import org.distorted.helpers.FactoryCubit;
25
import org.distorted.helpers.ObjectSticker;
26
import org.distorted.library.effect.MatrixEffectQuaternion;
27
import org.distorted.library.main.DistortedEffects;
28
import org.distorted.library.main.DistortedTexture;
29
import org.distorted.library.mesh.MeshBase;
30
import org.distorted.library.mesh.MeshSquare;
31
import org.distorted.library.type.Static3D;
32
import org.distorted.library.type.Static4D;
33
import org.distorted.main.R;
34

    
35
import java.util.Random;
36

    
37
///////////////////////////////////////////////////////////////////////////////////////////////////
38

    
39
public class TwistyRedi extends TwistyObject
40
{
41
  private static final int FACES_PER_CUBIT =9;
42

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

    
52
  private static final int[] BASIC_ANGLE = new int[] { 3,3,3,3 };
53

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

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

    
69
           new Static4D(  0.5f,  0.5f,  0.5f,  0.5f ),
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
         };
78

    
79
  private static final float DIST_CORNER = 1.0f;
80
  private static final float DIST_EDGE   = 1.5f;
81

    
82
  // centers of the 8 corners + 12 edges ( i.e. of the all 20 cubits)
83
  private static final float[][] CENTERS = new float[][]
84
         {
85
             { DIST_CORNER, DIST_CORNER, DIST_CORNER },
86
             { DIST_CORNER, DIST_CORNER,-DIST_CORNER },
87
             { DIST_CORNER,-DIST_CORNER, DIST_CORNER },
88
             { DIST_CORNER,-DIST_CORNER,-DIST_CORNER },
89
             {-DIST_CORNER, DIST_CORNER, DIST_CORNER },
90
             {-DIST_CORNER, DIST_CORNER,-DIST_CORNER },
91
             {-DIST_CORNER,-DIST_CORNER, DIST_CORNER },
92
             {-DIST_CORNER,-DIST_CORNER,-DIST_CORNER },
93

    
94
             {      0.0f, DIST_EDGE, DIST_EDGE },
95
             { DIST_EDGE,      0.0f, DIST_EDGE },
96
             {      0.0f,-DIST_EDGE, DIST_EDGE },
97
             {-DIST_EDGE,      0.0f, DIST_EDGE },
98
             { DIST_EDGE, DIST_EDGE,      0.0f },
99
             { DIST_EDGE,-DIST_EDGE,      0.0f },
100
             {-DIST_EDGE,-DIST_EDGE,      0.0f },
101
             {-DIST_EDGE, DIST_EDGE,      0.0f },
102
             {      0.0f, DIST_EDGE,-DIST_EDGE },
103
             { DIST_EDGE,      0.0f,-DIST_EDGE },
104
             {      0.0f,-DIST_EDGE,-DIST_EDGE },
105
             {-DIST_EDGE,      0.0f,-DIST_EDGE }
106
         };
107

    
108
  // Colors of the faces of cubits.
109
  // YELLOW 0 WHITE 1 BLUE 2 GREEN 3 RED 4  ORANGE 5
110
  // YELLOW 6 WHITE 7 BLUE 8 GREEN 9 RED 10 ORANGE 11
111
  private static final int[][] mFaceMap = new int[][]
112
         {
113
           {  4, 2, 0 },
114
           {  2, 5, 0 },
115
           {  3, 4, 0 },
116
           {  5, 3, 0 },
117
           {  1, 2, 4 },
118
           {  5, 2, 1 },
119
           {  4, 3, 1 },
120
           {  1, 3, 5 },
121

    
122
           { 10, 8,12 },
123
           {  6,10,12 },
124
           { 10, 9,12 },
125
           {  7,10,12 },
126
           {  8, 6,12 },
127
           {  9, 6,12 },
128
           {  9, 7,12 },
129
           {  8, 7,12 },
130
           { 11, 8,12 },
131
           {  6,11,12 },
132
           { 11, 9,12 },
133
           {  7,11,12 },
134
         };
135

    
136
  private static final double[][] VERTICES_CORNER = new double[][]
137
          {
138
             { 0.0f, 0.0f, 0.0f },
139
             {-0.5f, 0.5f, 0.5f },
140
             {-0.5f,-0.5f, 0.5f },
141
             { 0.5f, 0.5f, 0.5f },
142
             { 0.5f,-0.5f, 0.5f },
143
             { 0.5f, 0.5f,-0.5f },
144
             { 0.5f,-0.5f,-0.5f },
145
             {-0.5f, 0.5f,-0.5f },
146
          };
147

    
148
  private static final int[][] VERT_INDEXES_CORNER = new int[][]
149
          {
150
             { 2,4,3,1 },
151
             { 1,3,5,7 },
152
             { 4,6,5,3 },
153

    
154
             { 2,4,0 },
155
             { 5,7,0 },
156
             { 4,6,0 },
157
             { 7,1,0 },
158
             { 1,2,0 },
159
             { 6,5,0 }
160
          };
161

    
162
  private static final double[][] VERTICES_EDGE = new double[][]
163
          {
164
             {-0.5f, 0.0f, 0.0f},
165
             { 0.5f, 0.0f, 0.0f},
166
             {-0.5f,-1.0f, 0.0f},
167
             { 0.5f,-1.0f, 0.0f},
168
             { 0.0f,-1.5f, 0.0f},
169
             {-0.5f, 0.0f,-1.0f},
170
             { 0.5f, 0.0f,-1.0f},
171
             { 0.0f, 0.0f,-1.5f},
172
          };
173

    
174
  private static final int[][] VERT_INDEXES_EDGE = new int[][]
175
          {
176
             { 0,2,4,3,1 },
177
             { 0,1,6,7,5 },
178
             { 1,3,6 },
179
             { 0,2,5 },
180
             { 4,7,6,3 },
181
             { 4,7,5,2 }
182
          };
183

    
184
  private static final float[][] STICKERS = new float[][]
185
          {
186
             { -0.5f, -0.5f, 0.5f, -0.5f, 0.5f, 0.5f, -0.5f, 0.5f },
187
             { -0.3125f, 0.4375f, -0.3125f, -0.1875f, 0.0f, -0.5f, 0.3125f, -0.1875f, 0.3125f, 0.4375f }
188
          };
189

    
190
  private static MeshBase[] mMeshes;
191

    
192
  private static int[][] mScrambleTable;
193
  private static int[] mPossibleAxis, mPossibleLayers;
194
  private static int[] mNumOccurences;
195

    
196
  private static final ObjectSticker[] mStickers;
197

    
198
  static
199
    {
200
    mStickers = new ObjectSticker[STICKERS.length];
201
    final float R0 = 0.09f;
202
    final float R1 = 0.06f;
203
    final float[][] radii = { {R0,R0,R0,R0},{R1,R1,R1,R1,R1} };
204
    final float[] strokes = { 0.09f,0.06f };
205

    
206
    for(int s=0; s<STICKERS.length; s++)
207
      {
208
      mStickers[s] = new ObjectSticker(STICKERS[s],null,radii[s],strokes[s]);
209
      }
210
    }
211

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

    
214
  TwistyRedi(int size, Static4D quat, DistortedTexture texture, MeshSquare mesh,
215
             DistortedEffects effects, int[][] moves, Resources res, int scrWidth)
216
    {
217
    super(size, size, quat, texture, mesh, effects, moves, ObjectList.REDI, res, scrWidth);
218
    }
219

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

    
222
  float getScreenRatio()
223
    {
224
    return 0.50f;
225
    }
226

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

    
229
  Static4D[] getQuats()
230
    {
231
    return QUATS;
232
    }
233

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

    
236
  int getNumFaces()
237
    {
238
    return FACE_COLORS.length;
239
    }
240

    
241
///////////////////////////////////////////////////////////////////////////////////////////////////
242

    
243
  boolean shouldResetTextureMaps()
244
    {
245
    return false;
246
    }
247

    
248
///////////////////////////////////////////////////////////////////////////////////////////////////
249

    
250
  int getNumStickerTypes(int numLayers)
251
    {
252
    return STICKERS.length;
253
    }
254

    
255
///////////////////////////////////////////////////////////////////////////////////////////////////
256

    
257
  float[][] getCuts(int size)
258
    {
259
    float[] cut = new float[] { -SQ3/3 -0.05f, +SQ3/3 +0.05f };
260
    return new float[][] { cut,cut,cut,cut };
261
    }
262

    
263
///////////////////////////////////////////////////////////////////////////////////////////////////
264

    
265
  int getNumCubitFaces()
266
    {
267
    return FACES_PER_CUBIT;
268
    }
269

    
270
///////////////////////////////////////////////////////////////////////////////////////////////////
271

    
272
  float[][] getCubitPositions(int size)
273
    {
274
    return CENTERS;
275
    }
276

    
277
///////////////////////////////////////////////////////////////////////////////////////////////////
278

    
279
  private Static4D getQuat(int cubit)
280
    {
281
    switch(cubit)
282
      {
283
      case  0: return QUATS[0];                          //  unit quat
284
      case  1: return new Static4D( SQ2/2,0,0,SQ2/2);    //  90 along X
285
      case  2: return new Static4D(-SQ2/2,0,0,SQ2/2);    // -90 along X
286
      case  3: return QUATS[1];                          // 180 along X
287
      case  4: return new Static4D(0, SQ2/2,0,SQ2/2);    //  90 along Y
288
      case  5: return QUATS[2];                          // 180 along Y
289
      case  6: return QUATS[3];                          // 180 along Z
290
      case  7: return new Static4D(SQ2/2,0,-SQ2/2,0);    // 180 along (SQ2/2,0,-SQ2/2)
291

    
292
      case  8: return QUATS[0];
293
      case  9: return QUATS[5];
294
      case 10: return QUATS[3];
295
      case 11: return QUATS[11];
296
      case 12: return QUATS[4];
297
      case 13: return QUATS[7];
298
      case 14: return QUATS[9];
299
      case 15: return QUATS[10];
300
      case 16: return QUATS[2];
301
      case 17: return QUATS[8];
302
      case 18: return QUATS[1];
303
      case 19: return QUATS[6];
304
      }
305

    
306
    return null;
307
    }
308

    
309
///////////////////////////////////////////////////////////////////////////////////////////////////
310

    
311
  MeshBase createCubitMesh(int cubit, int numLayers)
312
    {
313
    if( mMeshes==null )
314
      {
315
      FactoryCubit factory = FactoryCubit.getInstance();
316
      factory.clear();
317
      mMeshes = new MeshBase[2];
318
      }
319

    
320
    MeshBase mesh;
321

    
322
    if( cubit<8 )
323
      {
324
      if( mMeshes[0]==null )
325
        {
326
        float[][] bands= new float[][]
327
          {
328
             {0.06f,35,0.5f,0.7f,5,2,2},
329
             {0.01f,35,0.2f,0.4f,5,2,2}
330
          };
331
        int[] bandIndexes   = new int[] { 0,0,0,1,1,1,1,1,1 };
332
        float[][] corners   = new float[][] { {0.06f,0.12f} };
333
        int[] cornerIndexes = new int[]  { -1,0,-1,0,0,0,-1,-1 };
334
        float[][] centers   = new float[][] { { 0.0f, 0.0f, 0.0f} };
335
        int[] centerIndexes = new int[] { -1,0,-1,0,0,0,-1,-1 };
336

    
337
        FactoryCubit factory = FactoryCubit.getInstance();
338
        factory.createNewFaceTransform(VERTICES_CORNER,VERT_INDEXES_CORNER);
339
        mMeshes[0] = factory.createRoundedSolid(VERTICES_CORNER, VERT_INDEXES_CORNER,
340
                                                bands, bandIndexes,
341
                                                corners, cornerIndexes,
342
                                                centers, centerIndexes,
343
                                                getNumCubitFaces() );
344
        }
345
      mesh = mMeshes[0].copy(true);
346
      }
347
    else
348
      {
349
      if( mMeshes[1]==null )
350
        {
351
        float[][] bands= new float[][]
352
          {
353
            {0.038f,35,0.250f,0.7f, 7,2,2},
354
            {0.020f,35,0.125f,0.2f, 3,1,2},
355
            {0.020f,35,0.125f,0.2f, 3,1,1}
356
          };
357
        int[] bandIndexes   = new int[] { 0,0,1,1,2,2 };
358
        float[][] corners   = new float[][] { {0.06f,0.20f} };
359
        int[] cornerIndexes = new int[] { 0,0,-1,-1,-1,-1,-1,-1 };
360
        float[][] centers   = new float[][] { { 0.0f,-0.75f,-0.75f} };
361
        int[] centerIndexes = new int[] { 0,0,-1,-1,-1,-1,-1,-1 };
362

    
363
        FactoryCubit factory = FactoryCubit.getInstance();
364
        factory.createNewFaceTransform(VERTICES_EDGE,VERT_INDEXES_EDGE);
365
        mMeshes[1] = factory.createRoundedSolid(VERTICES_EDGE, VERT_INDEXES_EDGE,
366
                                                bands, bandIndexes,
367
                                                corners, cornerIndexes,
368
                                                centers, centerIndexes,
369
                                                getNumCubitFaces() );
370
        }
371
      mesh = mMeshes[1].copy(true);
372
      }
373

    
374
    MatrixEffectQuaternion quat = new MatrixEffectQuaternion( getQuat(cubit), new Static3D(0,0,0) );
375
    mesh.apply(quat,0xffffffff,0);
376

    
377
    return mesh;
378
    }
379

    
380
///////////////////////////////////////////////////////////////////////////////////////////////////
381

    
382
  int getFaceColor(int cubit, int cubitface, int size)
383
    {
384
    return cubitface<3 ? mFaceMap[cubit][cubitface] : STICKERS.length*FACE_COLORS.length;
385
    }
386

    
387
///////////////////////////////////////////////////////////////////////////////////////////////////
388

    
389
  int getColor(int face)
390
    {
391
    return FACE_COLORS[face];
392
    }
393

    
394
///////////////////////////////////////////////////////////////////////////////////////////////////
395

    
396
  ObjectSticker retSticker(int face)
397
    {
398
    return mStickers[face/NUM_FACES];
399
    }
400

    
401
///////////////////////////////////////////////////////////////////////////////////////////////////
402

    
403
  float returnMultiplier()
404
    {
405
    return 2.0f;
406
    }
407

    
408
///////////////////////////////////////////////////////////////////////////////////////////////////
409
// PUBLIC API
410

    
411
  public Static3D[] getRotationAxis()
412
    {
413
    return ROT_AXIS;
414
    }
415

    
416
///////////////////////////////////////////////////////////////////////////////////////////////////
417

    
418
  public int[] getBasicAngle()
419
    {
420
    return BASIC_ANGLE;
421
    }
422

    
423
///////////////////////////////////////////////////////////////////////////////////////////////////
424

    
425
  private void initializeScrambleTable(int[] first)
426
    {
427
    if( mScrambleTable ==null ) mScrambleTable = new int[NUM_AXIS][2];
428
    if( mPossibleAxis  ==null ) mPossibleAxis  = new int[NUM_AXIS-1];
429
    if( mPossibleLayers==null ) mPossibleLayers= new int[NUM_AXIS-1];
430
    if( mNumOccurences ==null ) mNumOccurences = new int[NUM_AXIS-1];
431

    
432
    for(int i=0; i<NUM_AXIS; i++)
433
      for(int j=0; j<2; j++)
434
        {
435
        mScrambleTable[i][j] = 0;
436
        }
437

    
438
    mScrambleTable[first[0]][first[1]/2] = 1;
439
    }
440

    
441
///////////////////////////////////////////////////////////////////////////////////////////////////
442

    
443
  private boolean areOpposite(int oldAxis, int newAxis, int oldRow, int nom)
444
    {
445
    return (oldAxis+newAxis==3)^(oldRow<nom);
446
    }
447

    
448
///////////////////////////////////////////////////////////////////////////////////////////////////
449

    
450
  private int retNewRotationIndex(Random rnd, int nom, int[] oldRot)
451
    {
452
    int index=0, max=0;
453

    
454
    for(int ax=0; ax<NUM_AXIS; ax++)
455
      {
456
      if( ax!=oldRot[0] )
457
        {
458
        mPossibleAxis[index] = ax;
459
        mPossibleLayers[index] = areOpposite(oldRot[0],ax,oldRot[1],nom) ? 0:1;
460
        int tmp = mScrambleTable[mPossibleAxis[index]][mPossibleLayers[index]];
461
        if( tmp>max ) max=tmp;
462
        index++;
463
        }
464
      }
465

    
466
    for(int ax=0; ax<NUM_AXIS-1; ax++)
467
      {
468
      int value = mScrambleTable[mPossibleAxis[ax]][mPossibleLayers[ax]];
469
      mNumOccurences[ax] = max - value + (ax==0 ? 0 : mNumOccurences[ax-1]);
470
      }
471

    
472
    float random= rnd.nextFloat()*mNumOccurences[NUM_AXIS-2];
473

    
474
    for(int ax=0; ax<NUM_AXIS-1; ax++)
475
      {
476
      if( random <= mNumOccurences[ax] )
477
        {
478
        index=ax;
479
        break;
480
        }
481
      }
482

    
483
    mScrambleTable[mPossibleAxis[index]][mPossibleLayers[index]]++;
484

    
485
    return index;
486
    }
487

    
488
///////////////////////////////////////////////////////////////////////////////////////////////////
489
// PUBLIC API
490

    
491
  public void randomizeNewScramble(int[][] scramble, Random rnd, int curr, int total)
492
    {
493
    if( curr==0 )
494
      {
495
      scramble[curr][0] = rnd.nextInt(NUM_AXIS);
496
      scramble[curr][1] = rnd.nextFloat()<=0.5f ? 0:2;
497
      initializeScrambleTable(scramble[curr]);
498
      }
499
    else
500
      {
501
      int index = retNewRotationIndex(rnd,1,scramble[curr-1]);
502
      scramble[curr][0] = mPossibleAxis[index];
503
      scramble[curr][1] = 2*mPossibleLayers[index];
504
      }
505

    
506
    switch( rnd.nextInt(2) )
507
      {
508
      case 0: scramble[curr][2] = -1; break;
509
      case 1: scramble[curr][2] =  1; break;
510
      }
511
    }
512

    
513
///////////////////////////////////////////////////////////////////////////////////////////////////
514
// The Redi is solved if and only if all cubits are rotated with the same quat.
515

    
516
  public boolean isSolved()
517
    {
518
    int q = CUBITS[0].mQuatIndex;
519

    
520
    return ( CUBITS[ 1].mQuatIndex == q &&
521
             CUBITS[ 2].mQuatIndex == q &&
522
             CUBITS[ 3].mQuatIndex == q &&
523
             CUBITS[ 4].mQuatIndex == q &&
524
             CUBITS[ 5].mQuatIndex == q &&
525
             CUBITS[ 6].mQuatIndex == q &&
526
             CUBITS[ 7].mQuatIndex == q &&
527
             CUBITS[ 8].mQuatIndex == q &&
528
             CUBITS[ 9].mQuatIndex == q &&
529
             CUBITS[10].mQuatIndex == q &&
530
             CUBITS[11].mQuatIndex == q &&
531
             CUBITS[12].mQuatIndex == q &&
532
             CUBITS[13].mQuatIndex == q &&
533
             CUBITS[14].mQuatIndex == q &&
534
             CUBITS[15].mQuatIndex == q &&
535
             CUBITS[16].mQuatIndex == q &&
536
             CUBITS[17].mQuatIndex == q &&
537
             CUBITS[18].mQuatIndex == q &&
538
             CUBITS[19].mQuatIndex == q  );
539
    }
540

    
541
///////////////////////////////////////////////////////////////////////////////////////////////////
542

    
543
  public int getObjectName(int numLayers)
544
    {
545
    return R.string.redi2;
546
    }
547

    
548
///////////////////////////////////////////////////////////////////////////////////////////////////
549

    
550
  public int getInventor(int numLayers)
551
    {
552
    return R.string.redi2_inventor;
553
    }
554

    
555
///////////////////////////////////////////////////////////////////////////////////////////////////
556

    
557
  public int getComplexity(int numLayers)
558
    {
559
    return 4;
560
    }
561
}
(35-35/41)