Project

General

Profile

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

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

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 int[][] mScrambleTable;
191
  private static int[] mPossibleAxis, mPossibleLayers;
192
  private static int[] mNumOccurences;
193

    
194
  private static final ObjectSticker[] mStickers;
195

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

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

    
210
///////////////////////////////////////////////////////////////////////////////////////////////////
211

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

    
218
///////////////////////////////////////////////////////////////////////////////////////////////////
219

    
220
  float getScreenRatio()
221
    {
222
    return 0.50f;
223
    }
224

    
225
///////////////////////////////////////////////////////////////////////////////////////////////////
226

    
227
  Static4D[] getQuats()
228
    {
229
    return QUATS;
230
    }
231

    
232
///////////////////////////////////////////////////////////////////////////////////////////////////
233

    
234
  int getNumFaces()
235
    {
236
    return FACE_COLORS.length;
237
    }
238

    
239
///////////////////////////////////////////////////////////////////////////////////////////////////
240

    
241
  boolean shouldResetTextureMaps()
242
    {
243
    return false;
244
    }
245

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

    
248
  int getNumStickerTypes(int numLayers)
249
    {
250
    return STICKERS.length;
251
    }
252

    
253
///////////////////////////////////////////////////////////////////////////////////////////////////
254

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

    
261
///////////////////////////////////////////////////////////////////////////////////////////////////
262

    
263
  int getNumCubitFaces()
264
    {
265
    return FACES_PER_CUBIT;
266
    }
267

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

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

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

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

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

    
304
    return null;
305
    }
306

    
307
///////////////////////////////////////////////////////////////////////////////////////////////////
308

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

    
318
    MeshBase mesh;
319

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

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

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

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

    
375
    return mesh;
376
    }
377

    
378
///////////////////////////////////////////////////////////////////////////////////////////////////
379

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

    
385
///////////////////////////////////////////////////////////////////////////////////////////////////
386

    
387
  int getColor(int face)
388
    {
389
    return FACE_COLORS[face];
390
    }
391

    
392
///////////////////////////////////////////////////////////////////////////////////////////////////
393

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

    
399
///////////////////////////////////////////////////////////////////////////////////////////////////
400

    
401
  float returnMultiplier()
402
    {
403
    return 2.0f;
404
    }
405

    
406
///////////////////////////////////////////////////////////////////////////////////////////////////
407
// PUBLIC API
408

    
409
  public Static3D[] getRotationAxis()
410
    {
411
    return ROT_AXIS;
412
    }
413

    
414
///////////////////////////////////////////////////////////////////////////////////////////////////
415

    
416
  public int[] getBasicAngle()
417
    {
418
    return BASIC_ANGLE;
419
    }
420

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

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

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

    
436
    mScrambleTable[first[0]][first[1]/2] = 1;
437
    }
438

    
439
///////////////////////////////////////////////////////////////////////////////////////////////////
440

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

    
446
///////////////////////////////////////////////////////////////////////////////////////////////////
447

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

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

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

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

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

    
481
    mScrambleTable[mPossibleAxis[index]][mPossibleLayers[index]]++;
482

    
483
    return index;
484
    }
485

    
486
///////////////////////////////////////////////////////////////////////////////////////////////////
487
// PUBLIC API
488

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

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

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

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

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

    
539
///////////////////////////////////////////////////////////////////////////////////////////////////
540

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

    
546
///////////////////////////////////////////////////////////////////////////////////////////////////
547

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

    
553
///////////////////////////////////////////////////////////////////////////////////////////////////
554

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