Project

General

Profile

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

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

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.ObjectShape;
26
import org.distorted.helpers.ObjectSticker;
27
import org.distorted.library.effect.MatrixEffectQuaternion;
28
import org.distorted.library.main.DistortedEffects;
29
import org.distorted.library.main.DistortedTexture;
30
import org.distorted.library.mesh.MeshBase;
31
import org.distorted.library.mesh.MeshSquare;
32
import org.distorted.library.type.Static3D;
33
import org.distorted.library.type.Static4D;
34
import org.distorted.main.R;
35

    
36
import java.util.Random;
37

    
38
///////////////////////////////////////////////////////////////////////////////////////////////////
39

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

    
44
  // the four rotation axis of a RubikRedi. Must be normalized.
45
  static final Static3D[] ROT_AXIS = new Static3D[]
46
         {
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
           new Static3D(+SQ3/3,-SQ3/3,-SQ3/3)
51
         };
52

    
53
  private static final int[] BASIC_ANGLE = new int[] { 3,3,3,3 };
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 RubikRedi
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 float DIST_CORNER = 1.0f;
81
  private static final float DIST_EDGE   = 1.5f;
82

    
83
  // centers of the 8 corners + 12 edges ( i.e. of the all 20 cubits)
84
  private static final float[][] CENTERS = new float[][]
85
         {
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
             {-DIST_CORNER,-DIST_CORNER,-DIST_CORNER },
94

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

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

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

    
137
  private static final double[][] VERTICES_CORNER = new double[][]
138
          {
139
             { 0.0f, 0.0f, 0.0f },
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
             {-0.5f, 0.5f,-0.5f },
147
          };
148

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

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

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

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

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

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

    
195
  private static final ObjectSticker[] mStickers;
196

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

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

    
211
///////////////////////////////////////////////////////////////////////////////////////////////////
212

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

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

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

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

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

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

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

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

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

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

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

    
254
///////////////////////////////////////////////////////////////////////////////////////////////////
255

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

    
262
///////////////////////////////////////////////////////////////////////////////////////////////////
263

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

    
269
///////////////////////////////////////////////////////////////////////////////////////////////////
270

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

    
276
///////////////////////////////////////////////////////////////////////////////////////////////////
277

    
278
  ObjectShape getObjectShape(int cubit, int numLayers)
279
    {
280
    int variant = getCubitVariant(cubit,numLayers);
281

    
282
    if( variant==0 )
283
      {
284
      float[][] bands= new float[][]
285
          {
286
            {0.06f,35,0.5f,0.7f,5,2,2},
287
            {0.01f,35,0.2f,0.4f,5,2,2}
288
          };
289
      int[] bandIndices   = new int[] { 0,0,0,1,1,1,1,1,1 };
290
      float[][] corners   = new float[][] { {0.06f,0.12f} };
291
      int[] cornerIndices = new int[]  { -1,0,-1,0,0,0,-1,-1 };
292
      float[][] centers   = new float[][] { { 0.0f, 0.0f, 0.0f} };
293
      int[] centerIndices = new int[] { -1,0,-1,0,0,0,-1,-1 };
294

    
295
      return new ObjectShape(VERTICES_CORNER,VERT_INDEXES_CORNER,bands,bandIndices,corners,cornerIndices,centers,centerIndices,getNumCubitFaces(), null);
296
      }
297
    else
298
      {
299
      float[][] bands= new float[][]
300
          {
301
            {0.038f,35,0.250f,0.7f, 7,2,2},
302
            {0.020f,35,0.125f,0.2f, 3,1,2},
303
            {0.020f,35,0.125f,0.2f, 3,1,1}
304
          };
305
      int[] bandIndices   = new int[] { 0,0,1,1,2,2 };
306
      float[][] corners   = new float[][] { {0.06f,0.20f} };
307
      int[] cornerIndices = new int[] { 0,0,-1,-1,-1,-1,-1,-1 };
308
      float[][] centers   = new float[][] { { 0.0f,-0.75f,-0.75f} };
309
      int[] centerIndices = new int[] { 0,0,-1,-1,-1,-1,-1,-1 };
310

    
311
      return new ObjectShape(VERTICES_EDGE,VERT_INDEXES_EDGE,bands,bandIndices,corners,cornerIndices,centers,centerIndices,getNumCubitFaces(), null);
312
      }
313
    }
314

    
315
///////////////////////////////////////////////////////////////////////////////////////////////////
316

    
317
  private Static4D getQuat(int cubit, int numLayers)
318
    {
319
    switch(cubit)
320
      {
321
      case  0: return QUATS[0];                          //  unit quat
322
      case  1: return new Static4D( SQ2/2,0,0,SQ2/2);    //  90 along X
323
      case  2: return new Static4D(-SQ2/2,0,0,SQ2/2);    // -90 along X
324
      case  3: return QUATS[1];                          // 180 along X
325
      case  4: return new Static4D(0, SQ2/2,0,SQ2/2);    //  90 along Y
326
      case  5: return QUATS[2];                          // 180 along Y
327
      case  6: return QUATS[3];                          // 180 along Z
328
      case  7: return new Static4D(SQ2/2,0,-SQ2/2,0);    // 180 along (SQ2/2,0,-SQ2/2)
329

    
330
      case  8: return QUATS[0];
331
      case  9: return QUATS[5];
332
      case 10: return QUATS[3];
333
      case 11: return QUATS[11];
334
      case 12: return QUATS[4];
335
      case 13: return QUATS[7];
336
      case 14: return QUATS[9];
337
      case 15: return QUATS[10];
338
      case 16: return QUATS[2];
339
      case 17: return QUATS[8];
340
      case 18: return QUATS[1];
341
      case 19: return QUATS[6];
342
      }
343

    
344
    return null;
345
    }
346

    
347
///////////////////////////////////////////////////////////////////////////////////////////////////
348

    
349
  private int getNumCubitVariants(int numLayers)
350
    {
351
    return 2;
352
    }
353

    
354
///////////////////////////////////////////////////////////////////////////////////////////////////
355

    
356
  int getCubitVariant(int cubit, int numLayers)
357
    {
358
    return cubit<8 ? 0:1;
359
    }
360

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

    
363
  MeshBase createCubitMesh(int cubit, int numLayers)
364
    {
365
    int variant = getCubitVariant(cubit,numLayers);
366

    
367
    if( mMeshes==null )
368
      {
369
      FactoryCubit factory = FactoryCubit.getInstance();
370
      factory.clear();
371
      mMeshes = new MeshBase[getNumCubitVariants(numLayers)];
372
      }
373

    
374
    if( mMeshes[variant]==null )
375
      {
376
      ObjectShape shape = getObjectShape(cubit,numLayers);
377
      FactoryCubit factory = FactoryCubit.getInstance();
378
      factory.createNewFaceTransform(shape);
379
      mMeshes[variant] = factory.createRoundedSolid(shape);
380
      }
381

    
382
    MeshBase mesh = mMeshes[variant].copy(true);
383
    MatrixEffectQuaternion quat = new MatrixEffectQuaternion( getQuat(cubit,numLayers), new Static3D(0,0,0) );
384
    mesh.apply(quat,0xffffffff,0);
385

    
386
    return mesh;
387
    }
388

    
389
///////////////////////////////////////////////////////////////////////////////////////////////////
390

    
391
  int getFaceColor(int cubit, int cubitface, int size)
392
    {
393
    return cubitface<3 ? mFaceMap[cubit][cubitface] : STICKERS.length*FACE_COLORS.length;
394
    }
395

    
396
///////////////////////////////////////////////////////////////////////////////////////////////////
397

    
398
  int getColor(int face)
399
    {
400
    return FACE_COLORS[face];
401
    }
402

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

    
405
  ObjectSticker retSticker(int face)
406
    {
407
    return mStickers[face/NUM_FACES];
408
    }
409

    
410
///////////////////////////////////////////////////////////////////////////////////////////////////
411

    
412
  float returnMultiplier()
413
    {
414
    return 2.0f;
415
    }
416

    
417
///////////////////////////////////////////////////////////////////////////////////////////////////
418
// PUBLIC API
419

    
420
  public Static3D[] getRotationAxis()
421
    {
422
    return ROT_AXIS;
423
    }
424

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

    
427
  public int[] getBasicAngle()
428
    {
429
    return BASIC_ANGLE;
430
    }
431

    
432
///////////////////////////////////////////////////////////////////////////////////////////////////
433

    
434
  private void initializeScrambleTable(int[] first)
435
    {
436
    if( mScrambleTable ==null ) mScrambleTable = new int[NUM_AXIS][2];
437
    if( mPossibleAxis  ==null ) mPossibleAxis  = new int[NUM_AXIS-1];
438
    if( mPossibleLayers==null ) mPossibleLayers= new int[NUM_AXIS-1];
439
    if( mNumOccurences ==null ) mNumOccurences = new int[NUM_AXIS-1];
440

    
441
    for(int i=0; i<NUM_AXIS; i++)
442
      for(int j=0; j<2; j++)
443
        {
444
        mScrambleTable[i][j] = 0;
445
        }
446

    
447
    mScrambleTable[first[0]][first[1]/2] = 1;
448
    }
449

    
450
///////////////////////////////////////////////////////////////////////////////////////////////////
451

    
452
  private boolean areOpposite(int oldAxis, int newAxis, int oldRow, int nom)
453
    {
454
    return (oldAxis+newAxis==3)^(oldRow<nom);
455
    }
456

    
457
///////////////////////////////////////////////////////////////////////////////////////////////////
458

    
459
  private int retNewRotationIndex(Random rnd, int nom, int[] oldRot)
460
    {
461
    int index=0, max=0;
462

    
463
    for(int ax=0; ax<NUM_AXIS; ax++)
464
      {
465
      if( ax!=oldRot[0] )
466
        {
467
        mPossibleAxis[index] = ax;
468
        mPossibleLayers[index] = areOpposite(oldRot[0],ax,oldRot[1],nom) ? 0:1;
469
        int tmp = mScrambleTable[mPossibleAxis[index]][mPossibleLayers[index]];
470
        if( tmp>max ) max=tmp;
471
        index++;
472
        }
473
      }
474

    
475
    for(int ax=0; ax<NUM_AXIS-1; ax++)
476
      {
477
      int value = mScrambleTable[mPossibleAxis[ax]][mPossibleLayers[ax]];
478
      mNumOccurences[ax] = max - value + (ax==0 ? 0 : mNumOccurences[ax-1]);
479
      }
480

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

    
483
    for(int ax=0; ax<NUM_AXIS-1; ax++)
484
      {
485
      if( random <= mNumOccurences[ax] )
486
        {
487
        index=ax;
488
        break;
489
        }
490
      }
491

    
492
    mScrambleTable[mPossibleAxis[index]][mPossibleLayers[index]]++;
493

    
494
    return index;
495
    }
496

    
497
///////////////////////////////////////////////////////////////////////////////////////////////////
498
// PUBLIC API
499

    
500
  public void randomizeNewScramble(int[][] scramble, Random rnd, int curr, int total)
501
    {
502
    if( curr==0 )
503
      {
504
      scramble[curr][0] = rnd.nextInt(NUM_AXIS);
505
      scramble[curr][1] = rnd.nextFloat()<=0.5f ? 0:2;
506
      initializeScrambleTable(scramble[curr]);
507
      }
508
    else
509
      {
510
      int index = retNewRotationIndex(rnd,1,scramble[curr-1]);
511
      scramble[curr][0] = mPossibleAxis[index];
512
      scramble[curr][1] = 2*mPossibleLayers[index];
513
      }
514

    
515
    switch( rnd.nextInt(2) )
516
      {
517
      case 0: scramble[curr][2] = -1; break;
518
      case 1: scramble[curr][2] =  1; break;
519
      }
520
    }
521

    
522
///////////////////////////////////////////////////////////////////////////////////////////////////
523
// The Redi is solved if and only if all cubits are rotated with the same quat.
524

    
525
  public boolean isSolved()
526
    {
527
    int q = CUBITS[0].mQuatIndex;
528

    
529
    return ( CUBITS[ 1].mQuatIndex == q &&
530
             CUBITS[ 2].mQuatIndex == q &&
531
             CUBITS[ 3].mQuatIndex == q &&
532
             CUBITS[ 4].mQuatIndex == q &&
533
             CUBITS[ 5].mQuatIndex == q &&
534
             CUBITS[ 6].mQuatIndex == q &&
535
             CUBITS[ 7].mQuatIndex == q &&
536
             CUBITS[ 8].mQuatIndex == q &&
537
             CUBITS[ 9].mQuatIndex == q &&
538
             CUBITS[10].mQuatIndex == q &&
539
             CUBITS[11].mQuatIndex == q &&
540
             CUBITS[12].mQuatIndex == q &&
541
             CUBITS[13].mQuatIndex == q &&
542
             CUBITS[14].mQuatIndex == q &&
543
             CUBITS[15].mQuatIndex == q &&
544
             CUBITS[16].mQuatIndex == q &&
545
             CUBITS[17].mQuatIndex == q &&
546
             CUBITS[18].mQuatIndex == q &&
547
             CUBITS[19].mQuatIndex == q  );
548
    }
549

    
550
///////////////////////////////////////////////////////////////////////////////////////////////////
551

    
552
  public int getObjectName(int numLayers)
553
    {
554
    return R.string.redi2;
555
    }
556

    
557
///////////////////////////////////////////////////////////////////////////////////////////////////
558

    
559
  public int getInventor(int numLayers)
560
    {
561
    return R.string.redi2_inventor;
562
    }
563

    
564
///////////////////////////////////////////////////////////////////////////////////////////////////
565

    
566
  public int getComplexity(int numLayers)
567
    {
568
    return 4;
569
    }
570
}
(35-35/41)