Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / TwistyDiamond.java @ e1dc3366

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

    
34
import java.util.Random;
35

    
36
///////////////////////////////////////////////////////////////////////////////////////////////////
37

    
38
public class TwistyDiamond extends TwistyObject
39
{
40
  private static final int FACES_PER_CUBIT =8;
41

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

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

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

    
61
  private static final int[] mFaceMap = new int[] {4,0,6,2,7,3,5,1};
62

    
63
  // All legal rotation quats of a Diamond: unit + three 180 deg turns + 8 generators
64
  private static final Static4D[] QUATS = new Static4D[]
65
         {
66
           new Static4D(  0.0f,  0.0f,   0.0f,  1.0f ),
67
           new Static4D(  0.0f,  1.0f,   0.0f,  0.0f ),
68
           new Static4D(+SQ2/2,  0.0f, -SQ2/2,  0.0f ),
69
           new Static4D(-SQ2/2,  0.0f, -SQ2/2,  0.0f ),
70

    
71
           new Static4D(+SQ2/2,  0.5f,   0.0f,  0.5f ),
72
           new Static4D(-SQ2/2,  0.5f,   0.0f,  0.5f ),
73
           new Static4D(  0.0f,  0.5f, +SQ2/2,  0.5f ),
74
           new Static4D(  0.0f,  0.5f, -SQ2/2,  0.5f ),
75
           new Static4D(+SQ2/2,  0.5f,   0.0f, -0.5f ),
76
           new Static4D(-SQ2/2,  0.5f,   0.0f, -0.5f ),
77
           new Static4D(  0.0f,  0.5f, +SQ2/2, -0.5f ),
78
           new Static4D(  0.0f,  0.5f, -SQ2/2, -0.5f )
79
         };
80

    
81
  private static final float DIST = 0.50f;
82

    
83
  private static final int[] mTetraToFaceMap = new int[] {1,2,3,0,5,6,7,4};
84

    
85
  private static final double[][] VERTICES_TETRA = new double[][]
86
          {
87
             {-0.5, SQ2/4, 0.0},
88
             { 0.5, SQ2/4, 0.0},
89
             { 0.0,-SQ2/4, 0.5},
90
             { 0.0,-SQ2/4,-0.5}
91
          };
92

    
93
  private static final int[][] VERT_INDEXES_TETRA = new int[][]
94
          {
95
             {2,1,0},   // counterclockwise!
96
             {2,3,1},
97
             {3,2,0},
98
             {3,0,1}
99
          };
100

    
101
  private static final double[][] VERTICES_OCTA = new double[][]
102
          {
103
             { 0.5,   0.0, 0.5},
104
             { 0.5,   0.0,-0.5},
105
             {-0.5,   0.0,-0.5},
106
             {-0.5,   0.0, 0.5},
107
             { 0.0, SQ2/2, 0.0},
108
             { 0.0,-SQ2/2, 0.0}
109
          };
110

    
111
  private static final int[][] VERT_INDEXES_OCTA = new int[][]
112
          {
113
             {3,0,4},   // counterclockwise!
114
             {0,1,4},
115
             {1,2,4},
116
             {2,3,4},
117
             {5,0,3},
118
             {5,1,0},
119
             {5,2,1},
120
             {5,3,2}
121
          };
122

    
123
  private static final float[][] STICKERS = new float[][]
124
          {
125
             { -0.4330127f, -0.25f, 0.4330127f, -0.25f, 0.0f, 0.5f }
126
          };
127

    
128
  private static final ObjectSticker[] mStickers;
129

    
130
  static
131
    {
132
    float radius = 0.06f;
133
    float stroke = 0.07f;
134
    float[] radii = new float[] {radius,radius,radius};
135
    mStickers = new ObjectSticker[STICKERS.length];
136
    mStickers[0] = new ObjectSticker(STICKERS[0],null,radii,stroke);
137
    }
138

    
139
  private int mCurrState;
140
  private int mIndexExcluded;
141
  private final ScrambleState[] mStates;
142
  private int[][] mScrambleTable;
143
  private int[] mNumOccurences;
144

    
145
///////////////////////////////////////////////////////////////////////////////////////////////////
146

    
147
  TwistyDiamond(int size, Static4D quat, DistortedTexture texture,
148
                MeshSquare mesh, DistortedEffects effects, int[][] moves, Resources res, int scrWidth)
149
    {
150
    super(size, size, quat, texture, mesh, effects, moves, ObjectList.DIAM, res, scrWidth);
151

    
152
    int[] tmp = new int[3*2*size];
153

    
154
    for(int i=0; i<2*size; i++)
155
      {
156
      tmp[3*i  ] = (i<size) ?  i:i-size;
157
      tmp[3*i+1] = (i%2==0) ? -1:1;
158
      tmp[3*i+2] = 0;
159
      }
160

    
161
    mStates = new ScrambleState[]
162
      {
163
      new ScrambleState( new int[][] {tmp,tmp,tmp,tmp} )
164
      };
165
    }
166

    
167
///////////////////////////////////////////////////////////////////////////////////////////////////
168

    
169
  int[] getSolvedQuats(int cubit, int numLayers)
170
    {
171
    int status = retCubitSolvedStatus(cubit,numLayers);
172
    return status<0 ? null : buildSolvedQuats(MovementDiamond.FACE_AXIS[mFaceMap[status]],QUATS);
173
    }
174

    
175
///////////////////////////////////////////////////////////////////////////////////////////////////
176

    
177
  float getScreenRatio()
178
    {
179
    return 0.65f;
180
    }
181

    
182
///////////////////////////////////////////////////////////////////////////////////////////////////
183

    
184
  Static4D[] getQuats()
185
    {
186
    return QUATS;
187
    }
188

    
189
///////////////////////////////////////////////////////////////////////////////////////////////////
190

    
191
  int getNumFaces()
192
    {
193
    return FACE_COLORS.length;
194
    }
195

    
196
///////////////////////////////////////////////////////////////////////////////////////////////////
197

    
198
  boolean shouldResetTextureMaps()
199
    {
200
    return false;
201
    }
202

    
203
///////////////////////////////////////////////////////////////////////////////////////////////////
204

    
205
  int getSolvedFunctionIndex()
206
    {
207
    return 0;
208
    }
209

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

    
212
  int getNumStickerTypes(int numLayers)
213
    {
214
    return STICKERS.length;
215
    }
216

    
217
///////////////////////////////////////////////////////////////////////////////////////////////////
218

    
219
  float[][] getCuts(int numLayers)
220
    {
221
    if( numLayers<2 )
222
      {
223
      return null;
224
      }
225
    else
226
      {
227
      float[][] cuts = new float[4][numLayers-1];
228
      float dist = SQ6*0.666f*DIST;
229
      float cut  = 0.5f*dist*(2-numLayers);
230

    
231
      for(int i=0; i<numLayers-1; i++)
232
        {
233
        cuts[0][i] = cut;
234
        cuts[1][i] = cut;
235
        cuts[2][i] = cut;
236
        cuts[3][i] = cut;
237
        cut += dist;
238
        }
239

    
240
      return cuts;
241
      }
242
    }
243

    
244
///////////////////////////////////////////////////////////////////////////////////////////////////
245

    
246
  int getNumCubitFaces()
247
    {
248
    return FACES_PER_CUBIT;
249
    }
250

    
251
///////////////////////////////////////////////////////////////////////////////////////////////////
252

    
253
  private int getNumOctahedrons(int layers)
254
    {
255
    return layers==1 ? 1 : 4*(layers-1)*(layers-1) + 2;
256
    }
257

    
258
///////////////////////////////////////////////////////////////////////////////////////////////////
259

    
260
  private int getNumTetrahedrons(int layers)
261
    {
262
    return 4*layers*(layers-1);
263
    }
264

    
265
///////////////////////////////////////////////////////////////////////////////////////////////////
266

    
267
  private int createOctaPositions(float[][] centers, int index, int layers, float height)
268
    {
269
    float x = DIST*(layers-1);
270
    float z = DIST*(layers+1);
271

    
272
    for(int i=0; i<layers; i++, index++)
273
      {
274
      z -= 2*DIST;
275
      centers[index][0] = x;
276
      centers[index][1] = height;
277
      centers[index][2] = z;
278
      }
279

    
280
    for(int i=0; i<layers-1; i++, index++)
281
      {
282
      x -= 2*DIST;
283
      centers[index][0] = x;
284
      centers[index][1] = height;
285
      centers[index][2] = z;
286
      }
287

    
288
    for(int i=0; i<layers-1; i++, index++)
289
      {
290
      z += 2*DIST;
291
      centers[index][0] = x;
292
      centers[index][1] = height;
293
      centers[index][2] = z;
294
      }
295

    
296
    for(int i=0; i<layers-2; i++, index++)
297
      {
298
      x += 2*DIST;
299
      centers[index][0] = x;
300
      centers[index][1] = height;
301
      centers[index][2] = z;
302
      }
303

    
304
    return index;
305
    }
306

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

    
309
  private int createTetraPositions(float[][] centers, int index, int layers, float height)
310
    {
311
    float x = DIST*(layers-1);
312
    float z = DIST*layers;
313

    
314
    for(int i=0; i<layers-1; i++, index++)
315
      {
316
      z -= 2*DIST;
317
      centers[index][0] = x;
318
      centers[index][1] = height;
319
      centers[index][2] = z;
320
      }
321

    
322
    x += DIST;
323
    z -= DIST;
324

    
325
    for(int i=0; i<layers-1; i++, index++)
326
      {
327
      x -= 2*DIST;
328
      centers[index][0] = x;
329
      centers[index][1] = height;
330
      centers[index][2] = z;
331
      }
332

    
333
    x -= DIST;
334
    z -= DIST;
335

    
336
    for(int i=0; i<layers-1; i++, index++)
337
      {
338
      z += 2*DIST;
339
      centers[index][0] = x;
340
      centers[index][1] = height;
341
      centers[index][2] = z;
342
      }
343

    
344
    x -= DIST;
345
    z += DIST;
346

    
347
    for(int i=0; i<layers-1; i++, index++)
348
      {
349
      x += 2*DIST;
350
      centers[index][0] = x;
351
      centers[index][1] = height;
352
      centers[index][2] = z;
353
      }
354

    
355
    return index;
356
    }
357

    
358
///////////////////////////////////////////////////////////////////////////////////////////////////
359

    
360
  float[][] getCubitPositions(int layers)
361
    {
362
    int numO = getNumOctahedrons(layers);
363
    int numT = getNumTetrahedrons(layers);
364
    int index = 0;
365
    float height = 0.0f;
366

    
367
    float[][] CENTERS = new float[numO+numT][3];
368

    
369
    index = createOctaPositions(CENTERS,index,layers,height);
370

    
371
    for(int i=layers-1; i>0; i--)
372
      {
373
      height += SQ2*DIST;
374
      index = createOctaPositions(CENTERS,index,i,+height);
375
      index = createOctaPositions(CENTERS,index,i,-height);
376
      }
377

    
378
    height = DIST*SQ2/2;
379

    
380
    for(int i=layers; i>1; i--)
381
      {
382
      index = createTetraPositions(CENTERS,index,i,+height);
383
      index = createTetraPositions(CENTERS,index,i,-height);
384
      height += SQ2*DIST;
385
      }
386

    
387
    return CENTERS;
388
    }
389

    
390
///////////////////////////////////////////////////////////////////////////////////////////////////
391

    
392
  private int retFaceTetraBelongsTo(int tetra, int numLayers)
393
    {
394
    for(int i=numLayers-1; i>0; i--)
395
      {
396
      if( tetra < 8*i ) return mTetraToFaceMap[tetra/i];
397
      tetra -= 8*i;
398
      }
399

    
400
    return -1;
401
    }
402

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

    
405
  ObjectShape getObjectShape(int cubit, int numLayers)
406
    {
407
    int variant = getCubitVariant(cubit,numLayers);
408
    int N = numLayers>3 ? 5:6;
409
    int E = numLayers>2 ? (numLayers>3 ? 0:1):2;
410

    
411
    if( variant==0 )
412
      {
413
      float[][] bands     = new float[][] { {0.05f,35,0.5f,0.8f,N,E,E} };
414
      int[] bandIndices   = new int[] { 0,0,0,0,0,0,0,0 };
415
      float[][] corners   = new float[][] { {0.04f,0.20f} };
416
      int[] cornerIndices = new int[] { 0,0,0,0,0,0 };
417
      float[][] centers   = new float[][] { {0.0f, 0.0f, 0.0f} };
418
      int[] centerIndices = new int[] { 0,0,0,0,0,0 };
419
      return new ObjectShape(VERTICES_OCTA,VERT_INDEXES_OCTA,bands,bandIndices,corners,cornerIndices,centers,centerIndices,getNumCubitFaces(), null);
420
      }
421
    else
422
      {
423
      float[][] bands     = new float[][] { {0.05f,35,0.5f,0.8f,N,E,E} };
424
      int[] bandIndices   = new int[] { 0,0,0,0 };
425
      float[][] corners   = new float[][] { {0.08f,0.15f} };
426
      int[] cornerIndices = new int[] { 0,0,0,0 };
427
      float[][] centers   = new float[][] { {0.0f, 0.0f, 0.0f} };
428
      int[] centerIndices = new int[] { 0,0,0,0 };
429
      return new ObjectShape(VERTICES_TETRA,VERT_INDEXES_TETRA,bands,bandIndices,corners,cornerIndices,centers,centerIndices,getNumCubitFaces(), null);
430
      }
431
    }
432

    
433
///////////////////////////////////////////////////////////////////////////////////////////////////
434

    
435
  Static4D getQuat(int cubit, int numLayers)
436
    {
437
    int numO = getNumOctahedrons(numLayers);
438

    
439
    if( cubit<numO ) return QUATS[0];
440

    
441
    switch( retFaceTetraBelongsTo(cubit-numO, numLayers) )
442
      {
443
      case 0: return QUATS[0];                          // unit quat
444
      case 1: return new Static4D(0,-SQ2/2,0,SQ2/2);    //  90 along Y
445
      case 2: return QUATS[1];                          // 180 along Y
446
      case 3: return new Static4D(0,+SQ2/2,0,SQ2/2);    //  90 along
447
      case 4: return new Static4D(0,     0,1,    0);    // 180 along Z
448
      case 5: return new Static4D(SQ2/2, 0,SQ2/2,0);    //
449
      case 6: return new Static4D(     1,0,0,    0);    // 180 along X
450
      case 7: return new Static4D(-SQ2/2,0,SQ2/2,0);    //
451
      }
452

    
453
    return null;
454
    }
455

    
456
///////////////////////////////////////////////////////////////////////////////////////////////////
457

    
458
  int getNumCubitVariants(int numLayers)
459
    {
460
    return 2;
461
    }
462

    
463
///////////////////////////////////////////////////////////////////////////////////////////////////
464

    
465
  int getCubitVariant(int cubit, int numLayers)
466
    {
467
    return cubit<getNumOctahedrons(numLayers) ? 0 : 1;
468
    }
469

    
470
///////////////////////////////////////////////////////////////////////////////////////////////////
471

    
472
  int getFaceColor(int cubit, int cubitface, int size)
473
    {
474
    int numO = getNumOctahedrons(size);
475

    
476
    if( cubit<numO )
477
      {
478
      int axis = 0;
479
      int layer= 1;
480

    
481
      switch(cubitface)
482
        {
483
        case 0: axis = 2; layer =             1; break;
484
        case 1: axis = 0; layer = (1<<(size-1)); break;
485
        case 2: axis = 3; layer =             1; break;
486
        case 3: axis = 1; layer = (1<<(size-1)); break;
487
        case 4: axis = 3; layer = (1<<(size-1)); break;
488
        case 5: axis = 1; layer =             1; break;
489
        case 6: axis = 2; layer = (1<<(size-1)); break;
490
        case 7: axis = 0; layer =             1; break;
491
        }
492

    
493
      return CUBITS[cubit].mRotationRow[axis] == layer ? cubitface : NUM_TEXTURES;
494
      }
495
    else
496
      {
497
      return cubitface>0 ? NUM_TEXTURES : retFaceTetraBelongsTo(cubit-numO, size);
498
      }
499
    }
500

    
501
///////////////////////////////////////////////////////////////////////////////////////////////////
502

    
503
  int getColor(int face)
504
    {
505
    return FACE_COLORS[face];
506
    }
507

    
508
///////////////////////////////////////////////////////////////////////////////////////////////////
509

    
510
  ObjectSticker retSticker(int face)
511
    {
512
    return mStickers[face/NUM_FACES];
513
    }
514

    
515
///////////////////////////////////////////////////////////////////////////////////////////////////
516

    
517
  float returnMultiplier()
518
    {
519
    return 1.5f;
520
    }
521

    
522
///////////////////////////////////////////////////////////////////////////////////////////////////
523

    
524
  private void initializeScrambling()
525
    {
526
    int numLayers = getNumLayers();
527

    
528
    if( mScrambleTable ==null )
529
      {
530
      mScrambleTable = new int[NUM_AXIS][numLayers];
531
      }
532
    if( mNumOccurences ==null )
533
      {
534
      int max=0;
535

    
536
      for (ScrambleState mState : mStates)
537
        {
538
        int tmp = mState.getTotal(-1);
539
        if (max < tmp) max = tmp;
540
        }
541

    
542
      mNumOccurences = new int[max];
543
      }
544

    
545
    for(int i=0; i<NUM_AXIS; i++)
546
      for(int j=0; j<numLayers; j++) mScrambleTable[i][j] = 0;
547
    }
548

    
549
///////////////////////////////////////////////////////////////////////////////////////////////////
550
// PUBLIC API
551

    
552
  public void randomizeNewScramble(int[][] scramble, Random rnd, int curr, int totalScrambles)
553
    {
554
    if( curr==0 )
555
      {
556
      mCurrState     = 0;
557
      mIndexExcluded =-1;
558
      initializeScrambling();
559
      }
560

    
561
    int[] info= mStates[mCurrState].getRandom(rnd, mIndexExcluded, mScrambleTable, mNumOccurences);
562

    
563
    scramble[curr][0] = info[0];
564
    scramble[curr][1] = info[1];
565
    scramble[curr][2] = info[2];
566

    
567
    mCurrState     = info[3];
568
    mIndexExcluded = info[0];
569
    }
570

    
571
///////////////////////////////////////////////////////////////////////////////////////////////////
572

    
573
  public Static3D[] getRotationAxis()
574
    {
575
    return ROT_AXIS;
576
    }
577

    
578
///////////////////////////////////////////////////////////////////////////////////////////////////
579

    
580
  public int[] getBasicAngle()
581
    {
582
    return BASIC_ANGLE;
583
    }
584

    
585
///////////////////////////////////////////////////////////////////////////////////////////////////
586

    
587
  public int getObjectName(int numLayers)
588
    {
589
    switch(numLayers)
590
      {
591
      case 2: return R.string.diam2;
592
      case 3: return R.string.diam3;
593
      case 4: return R.string.diam4;
594
      }
595

    
596
    return 0;
597
    }
598

    
599
///////////////////////////////////////////////////////////////////////////////////////////////////
600

    
601
  public int getInventor(int numLayers)
602
    {
603
    switch(numLayers)
604
      {
605
      case 2: return R.string.diam2_inventor;
606
      case 3: return R.string.diam3_inventor;
607
      case 4: return R.string.diam4_inventor;
608
      }
609

    
610
    return 0;
611
    }
612

    
613
///////////////////////////////////////////////////////////////////////////////////////////////////
614

    
615
  public int getComplexity(int numLayers)
616
    {
617
    switch(numLayers)
618
      {
619
      case 2: return 4;
620
      case 3: return 6;
621
      case 4: return 8;
622
      }
623

    
624
    return 0;
625
    }
626
}
(23-23/41)