Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / TwistyRedi.java @ 9ce78850

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

    
37
import java.util.Random;
38

    
39
///////////////////////////////////////////////////////////////////////////////////////////////////
40

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

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

    
54
  private static final int[] BASIC_ANGLE = new int[] { 3,3,3,3 };
55

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

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

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

    
81
  private static final float DIST_CORNER = 1.0f;
82
  private static final float DIST_EDGE   = 1.5f;
83

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

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

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

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

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

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

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

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

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

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

    
192
  private static MeshBase[] mMeshes;
193

    
194
  private static int[][] mScrambleTable;
195
  private static int[] mPossibleAxis, mPossibleLayers;
196
  private static int[] mNumOccurences;
197

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

    
200
  TwistyRedi(int size, Static4D quat, DistortedTexture texture, MeshSquare mesh,
201
             DistortedEffects effects, int[][] moves, Resources res, int scrWidth)
202
    {
203
    super(size, size, quat, texture, mesh, effects, moves, ObjectList.REDI, res, scrWidth);
204
    }
205

    
206
///////////////////////////////////////////////////////////////////////////////////////////////////
207

    
208
  float getScreenRatio()
209
    {
210
    return 0.50f;
211
    }
212

    
213
///////////////////////////////////////////////////////////////////////////////////////////////////
214

    
215
  Static4D[] getQuats()
216
    {
217
    return QUATS;
218
    }
219

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

    
222
  int getNumFaces()
223
    {
224
    return FACE_COLORS.length;
225
    }
226

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

    
229
  boolean shouldResetTextureMaps()
230
    {
231
    return false;
232
    }
233

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

    
236
  int getNumStickerTypes(int numLayers)
237
    {
238
    return STICKERS.length;
239
    }
240

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

    
243
  float[][] getCuts(int size)
244
    {
245
    float[] cut = new float[] { -SQ3/3 -0.05f, +SQ3/3 +0.05f };
246
    return new float[][] { cut,cut,cut,cut };
247
    }
248

    
249
///////////////////////////////////////////////////////////////////////////////////////////////////
250

    
251
  int getNumCubitFaces()
252
    {
253
    return FACES_PER_CUBIT;
254
    }
255

    
256
///////////////////////////////////////////////////////////////////////////////////////////////////
257

    
258
  float[][] getCubitPositions(int size)
259
    {
260
    return CENTERS;
261
    }
262

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

    
265
  private Static4D getQuat(int cubit)
266
    {
267
    switch(cubit)
268
      {
269
      case  0: return QUATS[0];                          //  unit quat
270
      case  1: return new Static4D( SQ2/2,0,0,SQ2/2);    //  90 along X
271
      case  2: return new Static4D(-SQ2/2,0,0,SQ2/2);    // -90 along X
272
      case  3: return QUATS[1];                          // 180 along X
273
      case  4: return new Static4D(0, SQ2/2,0,SQ2/2);    //  90 along Y
274
      case  5: return QUATS[2];                          // 180 along Y
275
      case  6: return QUATS[3];                          // 180 along Z
276
      case  7: return new Static4D(SQ2/2,0,-SQ2/2,0);    // 180 along (SQ2/2,0,-SQ2/2)
277

    
278
      case  8: return QUATS[0];
279
      case  9: return QUATS[5];
280
      case 10: return QUATS[3];
281
      case 11: return QUATS[11];
282
      case 12: return QUATS[4];
283
      case 13: return QUATS[7];
284
      case 14: return QUATS[9];
285
      case 15: return QUATS[10];
286
      case 16: return QUATS[2];
287
      case 17: return QUATS[8];
288
      case 18: return QUATS[1];
289
      case 19: return QUATS[6];
290
      }
291

    
292
    return null;
293
    }
294

    
295
///////////////////////////////////////////////////////////////////////////////////////////////////
296

    
297
  MeshBase createCubitMesh(int cubit, int numLayers)
298
    {
299
    if( mMeshes==null )
300
      {
301
      FactoryCubit factory = FactoryCubit.getInstance();
302
      factory.clear();
303
      mMeshes = new MeshBase[2];
304
      }
305

    
306
    MeshBase mesh;
307

    
308
    if( cubit<8 )
309
      {
310
      if( mMeshes[0]==null )
311
        {
312
        float[][] bands= new float[][]
313
          {
314
             {0.06f,35,0.5f,0.7f,5,2,2},
315
             {0.01f,35,0.2f,0.4f,5,2,2}
316
          };
317
        int[] bandIndexes   = new int[] { 0,0,0,1,1,1,1,1,1 };
318
        float[][] corners   = new float[][] { {0.06f,0.12f} };
319
        int[] cornerIndexes = new int[]  { -1,0,-1,0,0,0,-1,-1 };
320
        float[][] centers   = new float[][] { { 0.0f, 0.0f, 0.0f} };
321
        int[] centerIndexes = new int[] { -1,0,-1,0,0,0,-1,-1 };
322

    
323
        FactoryCubit factory = FactoryCubit.getInstance();
324
        factory.createNewFaceTransform(VERTICES_CORNER,VERT_INDEXES_CORNER);
325
        mMeshes[0] = factory.createRoundedSolid(VERTICES_CORNER, VERT_INDEXES_CORNER,
326
                                                bands, bandIndexes,
327
                                                corners, cornerIndexes,
328
                                                centers, centerIndexes,
329
                                                getNumCubitFaces() );
330
        }
331
      mesh = mMeshes[0].copy(true);
332
      }
333
    else
334
      {
335
      if( mMeshes[1]==null )
336
        {
337
        float[][] bands= new float[][]
338
          {
339
            {0.038f,35,0.250f,0.7f, 7,2,2},
340
            {0.020f,35,0.125f,0.2f, 3,1,2},
341
            {0.020f,35,0.125f,0.2f, 3,1,1}
342
          };
343
        int[] bandIndexes   = new int[] { 0,0,1,1,2,2 };
344
        float[][] corners   = new float[][] { {0.06f,0.20f} };
345
        int[] cornerIndexes = new int[] { 0,0,-1,-1,-1,-1,-1,-1 };
346
        float[][] centers   = new float[][] { { 0.0f,-0.75f,-0.75f} };
347
        int[] centerIndexes = new int[] { 0,0,-1,-1,-1,-1,-1,-1 };
348

    
349
        FactoryCubit factory = FactoryCubit.getInstance();
350
        factory.createNewFaceTransform(VERTICES_EDGE,VERT_INDEXES_EDGE);
351
        mMeshes[1] = factory.createRoundedSolid(VERTICES_EDGE, VERT_INDEXES_EDGE,
352
                                                bands, bandIndexes,
353
                                                corners, cornerIndexes,
354
                                                centers, centerIndexes,
355
                                                getNumCubitFaces() );
356
        }
357
      mesh = mMeshes[1].copy(true);
358
      }
359

    
360
    MatrixEffectQuaternion quat = new MatrixEffectQuaternion( getQuat(cubit), new Static3D(0,0,0) );
361
    mesh.apply(quat,0xffffffff,0);
362

    
363
    return mesh;
364
    }
365

    
366
///////////////////////////////////////////////////////////////////////////////////////////////////
367

    
368
  int getFaceColor(int cubit, int cubitface, int size)
369
    {
370
    return cubitface<3 ? mFaceMap[cubit][cubitface] : STICKERS.length*FACE_COLORS.length;
371
    }
372

    
373
///////////////////////////////////////////////////////////////////////////////////////////////////
374

    
375
  void createFaceTexture(Canvas canvas, Paint paint, int face, int left, int top)
376
    {
377
    int COLORS = FACE_COLORS.length;
378
    int stickerType = face/COLORS;
379
    float R,S;
380

    
381
    switch(stickerType)
382
      {
383
      case 0:  R = 0.09f; S = 0.09f; break;
384
      case 1:  R = 0.06f; S = 0.06f; break;
385
      default: R = 0.00f; S = 0.00f; break;
386
      }
387

    
388
    FactorySticker factory = FactorySticker.getInstance();
389
    factory.drawRoundedPolygon(canvas, paint, left, top, STICKERS[stickerType], null, S, FACE_COLORS[face%COLORS], R);
390
    }
391

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

    
394
  float returnMultiplier()
395
    {
396
    return 2.0f;
397
    }
398

    
399
///////////////////////////////////////////////////////////////////////////////////////////////////
400
// PUBLIC API
401

    
402
  public Static3D[] getRotationAxis()
403
    {
404
    return ROT_AXIS;
405
    }
406

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

    
409
  public int[] getBasicAngle()
410
    {
411
    return BASIC_ANGLE;
412
    }
413

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

    
416
  private void initializeScrambleTable(int[] first)
417
    {
418
    if( mScrambleTable ==null ) mScrambleTable = new int[NUM_AXIS][2];
419
    if( mPossibleAxis  ==null ) mPossibleAxis  = new int[NUM_AXIS-1];
420
    if( mPossibleLayers==null ) mPossibleLayers= new int[NUM_AXIS-1];
421
    if( mNumOccurences ==null ) mNumOccurences = new int[NUM_AXIS-1];
422

    
423
    for(int i=0; i<NUM_AXIS; i++)
424
      for(int j=0; j<2; j++)
425
        {
426
        mScrambleTable[i][j] = 0;
427
        }
428

    
429
    mScrambleTable[first[0]][first[1]/2] = 1;
430
    }
431

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

    
434
  private boolean areOpposite(int oldAxis, int newAxis, int oldRow, int nom)
435
    {
436
    return (oldAxis+newAxis==3)^(oldRow<nom);
437
    }
438

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

    
441
  private int retNewRotationIndex(Random rnd, int nom, int[] oldRot)
442
    {
443
    int index=0, max=0;
444

    
445
    for(int ax=0; ax<NUM_AXIS; ax++)
446
      {
447
      if( ax!=oldRot[0] )
448
        {
449
        mPossibleAxis[index] = ax;
450
        mPossibleLayers[index] = areOpposite(oldRot[0],ax,oldRot[1],nom) ? 0:1;
451
        int tmp = mScrambleTable[mPossibleAxis[index]][mPossibleLayers[index]];
452
        if( tmp>max ) max=tmp;
453
        index++;
454
        }
455
      }
456

    
457
    for(int ax=0; ax<NUM_AXIS-1; ax++)
458
      {
459
      int value = mScrambleTable[mPossibleAxis[ax]][mPossibleLayers[ax]];
460
      mNumOccurences[ax] = max - value + (ax==0 ? 0 : mNumOccurences[ax-1]);
461
      }
462

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

    
465
    for(int ax=0; ax<NUM_AXIS-1; ax++)
466
      {
467
      if( random <= mNumOccurences[ax] )
468
        {
469
        index=ax;
470
        break;
471
        }
472
      }
473

    
474
    mScrambleTable[mPossibleAxis[index]][mPossibleLayers[index]]++;
475

    
476
    return index;
477
    }
478

    
479
///////////////////////////////////////////////////////////////////////////////////////////////////
480
// PUBLIC API
481

    
482
  public void randomizeNewScramble(int[][] scramble, Random rnd, int curr, int total)
483
    {
484
    if( curr==0 )
485
      {
486
      scramble[curr][0] = rnd.nextInt(NUM_AXIS);
487
      scramble[curr][1] = rnd.nextFloat()<=0.5f ? 0:2;
488
      initializeScrambleTable(scramble[curr]);
489
      }
490
    else
491
      {
492
      int index = retNewRotationIndex(rnd,1,scramble[curr-1]);
493
      scramble[curr][0] = mPossibleAxis[index];
494
      scramble[curr][1] = 2*mPossibleLayers[index];
495
      }
496

    
497
    switch( rnd.nextInt(2) )
498
      {
499
      case 0: scramble[curr][2] = -1; break;
500
      case 1: scramble[curr][2] =  1; break;
501
      }
502
    }
503

    
504
///////////////////////////////////////////////////////////////////////////////////////////////////
505
// The Redi is solved if and only if all cubits are rotated with the same quat.
506

    
507
  public boolean isSolved()
508
    {
509
    int q = CUBITS[0].mQuatIndex;
510

    
511
    return ( CUBITS[ 1].mQuatIndex == q &&
512
             CUBITS[ 2].mQuatIndex == q &&
513
             CUBITS[ 3].mQuatIndex == q &&
514
             CUBITS[ 4].mQuatIndex == q &&
515
             CUBITS[ 5].mQuatIndex == q &&
516
             CUBITS[ 6].mQuatIndex == q &&
517
             CUBITS[ 7].mQuatIndex == q &&
518
             CUBITS[ 8].mQuatIndex == q &&
519
             CUBITS[ 9].mQuatIndex == q &&
520
             CUBITS[10].mQuatIndex == q &&
521
             CUBITS[11].mQuatIndex == q &&
522
             CUBITS[12].mQuatIndex == q &&
523
             CUBITS[13].mQuatIndex == q &&
524
             CUBITS[14].mQuatIndex == q &&
525
             CUBITS[15].mQuatIndex == q &&
526
             CUBITS[16].mQuatIndex == q &&
527
             CUBITS[17].mQuatIndex == q &&
528
             CUBITS[18].mQuatIndex == q &&
529
             CUBITS[19].mQuatIndex == q  );
530
    }
531

    
532
///////////////////////////////////////////////////////////////////////////////////////////////////
533
// only needed for solvers - there are no Redi solvers ATM)
534

    
535
  public String retObjectString()
536
    {
537
    return "";
538
    }
539

    
540
///////////////////////////////////////////////////////////////////////////////////////////////////
541

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

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

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

    
554
///////////////////////////////////////////////////////////////////////////////////////////////////
555

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