Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / TwistyPyraminx.java @ 47d98cd5

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2019 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.main.DistortedEffects;
27
import org.distorted.library.main.DistortedTexture;
28
import org.distorted.library.mesh.MeshBase;
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 TwistyPyraminx extends TwistyObject
39
{
40
  static final float SCREEN_RATIO = 0.88f;
41

    
42
  static final Static3D[] ROT_AXIS = new Static3D[]
43
         {
44
           new Static3D(     0,-SQ3/3,-SQ6/3),
45
           new Static3D(     0,-SQ3/3,+SQ6/3),
46
           new Static3D(+SQ6/3,+SQ3/3,     0),
47
           new Static3D(-SQ6/3,+SQ3/3,     0),
48
         };
49

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

    
52
  private static final int[] FACE_COLORS = new int[]
53
         {
54
           COLOR_GREEN , COLOR_YELLOW,
55
           COLOR_BLUE  , COLOR_RED
56
         };
57

    
58
  // computed with res/raw/compute_quats.c
59
  private static final Static4D[] QUATS = new Static4D[]
60
         {
61
           new Static4D(  0.0f,   0.0f,   0.0f,  1.0f),
62
           new Static4D(  0.0f,   1.0f,   0.0f,  0.0f),
63
           new Static4D( SQ2/2,   0.5f,   0.0f,  0.5f),
64
           new Static4D(-SQ2/2,   0.5f,   0.0f,  0.5f),
65
           new Static4D(  0.0f,  -0.5f, -SQ2/2,  0.5f),
66
           new Static4D(  0.0f,  -0.5f,  SQ2/2,  0.5f),
67
           new Static4D( SQ2/2,   0.5f,   0.0f, -0.5f),
68
           new Static4D(-SQ2/2,   0.5f,   0.0f, -0.5f),
69
           new Static4D(  0.0f,  -0.5f, -SQ2/2, -0.5f),
70
           new Static4D(  0.0f,  -0.5f,  SQ2/2, -0.5f),
71
           new Static4D( SQ2/2,   0.0f,  SQ2/2,  0.0f),
72
           new Static4D(-SQ2/2,   0.0f,  SQ2/2,  0.0f)
73
         };
74

    
75
  private static final double[][] VERTICES_TETRA = new double[][]
76
          {
77
             {-0.5, SQ2/4, 0.0},
78
             { 0.5, SQ2/4, 0.0},
79
             { 0.0,-SQ2/4, 0.5},
80
             { 0.0,-SQ2/4,-0.5}
81
          };
82

    
83
  private static final int[][] VERT_INDEXES_TETRA = new int[][]
84
          {
85
             {2,1,0},   // counterclockwise!
86
             {3,0,1},
87
             {3,2,0},
88
             {2,3,1}
89
          };
90

    
91
  private static final double[][] VERTICES_OCTA = new double[][]
92
          {
93
             { 0.5,   0.0, 0.5},
94
             { 0.5,   0.0,-0.5},
95
             {-0.5,   0.0,-0.5},
96
             {-0.5,   0.0, 0.5},
97
             { 0.0, SQ2/2, 0.0},
98
             { 0.0,-SQ2/2, 0.0}
99
          };
100

    
101
  private static final int[][] VERT_INDEXES_OCTA = new int[][]
102
          {
103
             {3,0,4},   // counterclockwise!
104
             {0,1,4},
105
             {1,2,4},
106
             {2,3,4},
107
             {5,0,3},
108
             {5,1,0},
109
             {5,2,1},
110
             {5,3,2}
111
          };
112

    
113
  private static final float[][] STICKERS = new float[][]
114
          {
115
             { -0.4330127f, -0.25f, 0.4330127f, -0.25f, 0.0f, 0.5f }
116
          };
117

    
118
  private static MeshBase[] mMeshes;
119
  private static float[] mRowChances;
120

    
121
  private static final ObjectSticker[] mStickers;
122

    
123
  static
124
    {
125
    mStickers = new ObjectSticker[STICKERS.length];
126
    final float stroke = 0.08f;
127
    final float radius = 0.06f;
128
    final float[] radii= {radius,radius,radius};
129
    mStickers[0] = new ObjectSticker(STICKERS[0],null,radii,stroke);
130
    }
131

    
132
///////////////////////////////////////////////////////////////////////////////////////////////////
133

    
134
  TwistyPyraminx(int size, Static4D quat, DistortedTexture texture, MeshSquare mesh,
135
                 DistortedEffects effects, int[][] moves, Resources res, int scrWidth)
136
    {
137
    super(size, size, quat, texture, mesh, effects, moves, ObjectList.PYRA, res, scrWidth);
138
    }
139

    
140
///////////////////////////////////////////////////////////////////////////////////////////////////
141

    
142
  private float[] getRowChances(int numLayers)
143
    {
144
    int total = numLayers*(numLayers+1)/2;
145
    float running=0.0f;
146
    float[] chances = new float[numLayers];
147

    
148
    for(int i=0; i<numLayers; i++)
149
      {
150
      running += (numLayers-i);
151
      chances[i] = running / total;
152
      }
153

    
154
    return chances;
155
    }
156

    
157
///////////////////////////////////////////////////////////////////////////////////////////////////
158

    
159
  private void addTetrahedralLattice(int size, int index, float[][] pos)
160
    {
161
    final float DX = 1.0f;
162
    final float DY = SQ2/2;
163
    final float DZ = 1.0f;
164

    
165
    float startX = 0.0f;
166
    float startY =-DY*(size-1)/2;
167
    float startZ = DZ*(size-1)/2;
168

    
169
    for(int layer=0; layer<size; layer++)
170
      {
171
      float currX = startX;
172
      float currY = startY;
173

    
174
      for(int x=0; x<layer+1; x++)
175
        {
176
        float currZ = startZ;
177

    
178
        for(int z=0; z<size-layer; z++)
179
          {
180
          pos[index] = new float[] {currX,currY,currZ};
181
          index++;
182
          currZ -= DZ;
183
          }
184

    
185
        currX += DX;
186
        }
187

    
188
      startX-=DX/2;
189
      startY+=DY;
190
      startZ-=DZ/2;
191
      }
192
    }
193

    
194
///////////////////////////////////////////////////////////////////////////////////////////////////
195
// there are (n^3-n)/6 octahedrons and ((n+1)^3 - (n+1))/6 tetrahedrons
196

    
197
  float[][] getCubitPositions(int size)
198
    {
199
    int numOcta = (size-1)*size*(size+1)/6;
200
    int numTetra= size*(size+1)*(size+2)/6;
201
    float[][] ret = new float[numOcta+numTetra][];
202

    
203
    addTetrahedralLattice(size-1,      0,ret);
204
    addTetrahedralLattice(size  ,numOcta,ret);
205

    
206
    return ret;
207
    }
208

    
209
///////////////////////////////////////////////////////////////////////////////////////////////////
210

    
211
  Static4D[] getQuats()
212
    {
213
    return QUATS;
214
    }
215

    
216
///////////////////////////////////////////////////////////////////////////////////////////////////
217

    
218
  int getNumFaces()
219
    {
220
    return FACE_COLORS.length;
221
    }
222

    
223
///////////////////////////////////////////////////////////////////////////////////////////////////
224

    
225
  int getNumStickerTypes(int numLayers)
226
    {
227
    return STICKERS.length;
228
    }
229

    
230
///////////////////////////////////////////////////////////////////////////////////////////////////
231

    
232
  float[][] getCuts(int size)
233
    {
234
    float[][] cuts = new float[4][size-1];
235

    
236
    for(int i=0; i<size-1; i++)
237
      {
238
      float cut = (1.0f-0.25f*size+i)*(SQ6/3);
239
      cuts[0][i] = cut;
240
      cuts[1][i] = cut;
241
      cuts[2][i] = cut;
242
      cuts[3][i] = cut;
243
      }
244

    
245
    return cuts;
246
    }
247

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

    
250
  int getNumCubitFaces()
251
    {
252
    return 8;
253
    }
254

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

    
257
  float getScreenRatio()
258
    {
259
    return SCREEN_RATIO;
260
    }
261

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

    
264
  boolean shouldResetTextureMaps()
265
    {
266
    return false;
267
    }
268

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

    
271
  private int getNumOctahedrons(int numLayers)
272
    {
273
    return (numLayers-1)*numLayers*(numLayers+1)/6;
274
    }
275

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

    
278
  private int faceColor(int cubit, int axis)
279
    {
280
    return CUBITS[cubit].mRotationRow[axis] == 1 ? axis : NUM_FACES;
281
    }
282

    
283
///////////////////////////////////////////////////////////////////////////////////////////////////
284

    
285
  int getFaceColor(int cubit, int cubitface, int size)
286
    {
287
    if( cubit< (size-1)*size*(size+1)/6 )
288
      {
289
      switch( cubitface )
290
        {
291
        case 0: return faceColor(cubit,0);
292
        case 2: return faceColor(cubit,1);
293
        case 5: return faceColor(cubit,3);
294
        case 7: return faceColor(cubit,2);
295
        default:return NUM_FACES;
296
        }
297
      }
298
    else
299
      {
300
      return cubitface<NUM_FACES ? faceColor(cubit,cubitface) : NUM_FACES;
301
      }
302
    }
303

    
304
///////////////////////////////////////////////////////////////////////////////////////////////////
305

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

    
315
    MeshBase mesh;
316
    int numO = getNumOctahedrons(numLayers);
317

    
318
    if( cubit<numO )
319
      {
320
      if( mMeshes[0]==null )
321
        {
322
        float[][] bands     = new float[][] { {0.05f,35,0.5f,0.8f,6,2,2} };
323
        int[] bandIndexes   = new int[] { 0,0,0,0,0,0,0,0 };
324
        float[][] corners   = new float[][] { {0.04f,0.20f} };
325
        int[] cornerIndexes = new int[] { 0,0,0,0,0,0 };
326
        float[][] centers   = new float[][] { {0.0f, 0.0f, 0.0f} };
327
        int[] centerIndexes = new int[] { 0,0,0,0,0,0 };
328

    
329
        FactoryCubit factory = FactoryCubit.getInstance();
330

    
331
        factory.createNewFaceTransform(VERTICES_OCTA,VERT_INDEXES_OCTA);
332
        mMeshes[0] = factory.createRoundedSolid(VERTICES_OCTA, VERT_INDEXES_OCTA,
333
                                                bands, bandIndexes,
334
                                                corners, cornerIndexes,
335
                                                centers, centerIndexes,
336
                                                getNumCubitFaces(), null );
337
        }
338
      mesh = mMeshes[0].copy(true);
339
      }
340
    else
341
      {
342
      if( mMeshes[1]==null )
343
        {
344
        float[][] bands     = new float[][] { {0.05f,35,0.5f,0.8f,6,2,2} };
345
        int[] bandIndexes   = new int[] { 0,0,0,0 };
346
        float[][] corners   = new float[][] { {0.06f,0.15f} };
347
        int[] cornerIndexes = new int[] { 0,0,0,0 };
348
        float[][] centers   = new float[][] { {0.0f, 0.0f, 0.0f} };
349
        int[] centerIndexes = new int[] { 0,0,0,0 };
350

    
351
        FactoryCubit factory = FactoryCubit.getInstance();
352

    
353
        factory.createNewFaceTransform(VERTICES_TETRA,VERT_INDEXES_TETRA);
354
        mMeshes[1] = factory.createRoundedSolid(VERTICES_TETRA, VERT_INDEXES_TETRA,
355
                                                bands, bandIndexes,
356
                                                corners, cornerIndexes,
357
                                                centers, centerIndexes,
358
                                                getNumCubitFaces(), null );
359

    
360
        factory.printStickerCoords();
361
        }
362
      mesh = mMeshes[1].copy(true);
363
      }
364

    
365
    return mesh;
366
    }
367

    
368
///////////////////////////////////////////////////////////////////////////////////////////////////
369

    
370
  int getColor(int face)
371
    {
372
    return FACE_COLORS[face];
373
    }
374

    
375
///////////////////////////////////////////////////////////////////////////////////////////////////
376

    
377
  ObjectSticker retSticker(int face)
378
    {
379
    return mStickers[face/NUM_FACES];
380
    }
381

    
382
///////////////////////////////////////////////////////////////////////////////////////////////////
383
// SQ6/3 = height of the tetrahedron
384

    
385
  float returnMultiplier()
386
    {
387
    return getNumLayers()/(SQ6/3);
388
    }
389

    
390
///////////////////////////////////////////////////////////////////////////////////////////////////
391
// PUBLIC API
392

    
393
  public Static3D[] getRotationAxis()
394
    {
395
    return ROT_AXIS;
396
    }
397

    
398
///////////////////////////////////////////////////////////////////////////////////////////////////
399

    
400
  public int[] getBasicAngle()
401
    {
402
    return BASIC_ANGLE;
403
    }
404

    
405
///////////////////////////////////////////////////////////////////////////////////////////////////
406

    
407
  public void randomizeNewScramble(int[][] scramble, Random rnd, int curr, int total)
408
    {
409
    int numLayers = getNumLayers();
410

    
411
    if( mRowChances==null ) mRowChances = getRowChances(numLayers);
412

    
413
    if( curr==0 )
414
      {
415
      scramble[curr][0] = rnd.nextInt(NUM_AXIS);
416
      }
417
    else
418
      {
419
      int newVector = rnd.nextInt(NUM_AXIS-1);
420
      scramble[curr][0] = (newVector>=scramble[curr-1][0] ? newVector+1 : newVector);
421

    
422
      // Correct the situation when we first rotate the largest layer, then a tip (which doesn't
423
      // intersect anything besides the largest layer!) and then we try to rotate again along
424
      // the same axis like 2 rotations before - which carries the risk we rotate the largest
425
      // layer back to its spot again and the three moves end up being only a single tip rotation.
426
      if( curr>=2 && scramble[curr-1][1]==(numLayers-1) && scramble[curr][0]==scramble[curr-2][0] )
427
        {
428
        for(int ax=0; ax<NUM_AXIS; ax++)
429
          {
430
          if( scramble[curr-1][0]!=ax && scramble[curr-2][0]!=ax )
431
            {
432
            scramble[curr][0]=ax;
433
            break;
434
            }
435
          }
436
        }
437
      }
438

    
439
    float rowFloat = rnd.nextFloat();
440

    
441
    for(int row=0; row<numLayers; row++)
442
      {
443
      if( rowFloat<=mRowChances[row] )
444
        {
445
        scramble[curr][1] = row;
446
        break;
447
        }
448
      }
449

    
450
    switch( rnd.nextInt(2) )
451
      {
452
      case 0: scramble[curr][2] = -1; break;
453
      case 1: scramble[curr][2] =  1; break;
454
      }
455
    }
456

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

    
459
  public boolean isSolved()
460
    {
461
    int index = CUBITS[0].mQuatIndex;
462

    
463
    for(int i=1; i<NUM_CUBITS; i++)
464
      {
465
      if( thereIsVisibleDifference(CUBITS[i], index) ) return false;
466
      }
467

    
468
    return true;
469
    }
470

    
471
///////////////////////////////////////////////////////////////////////////////////////////////////
472

    
473
  public int getObjectName(int numLayers)
474
    {
475
    switch(numLayers)
476
      {
477
      case 3: return R.string.pyra3;
478
      case 4: return R.string.pyra4;
479
      case 5: return R.string.pyra5;
480
      }
481
    return R.string.pyra3;
482
    }
483

    
484
///////////////////////////////////////////////////////////////////////////////////////////////////
485

    
486
  public int getInventor(int numLayers)
487
    {
488
    switch(numLayers)
489
      {
490
      case 3: return R.string.pyra3_inventor;
491
      case 4: return R.string.pyra4_inventor;
492
      case 5: return R.string.pyra5_inventor;
493
      }
494
    return R.string.pyra3_inventor;
495
    }
496

    
497
///////////////////////////////////////////////////////////////////////////////////////////////////
498

    
499
  public int getComplexity(int numLayers)
500
    {
501
    switch(numLayers)
502
      {
503
      case 3: return 4;
504
      case 4: return 6;
505
      case 5: return 8;
506
      }
507
    return 4;
508
    }
509
}
(34-34/41)