Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / TwistyPyraminx.java @ b3c9061a

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
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.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 TwistyPyraminx extends TwistyObject
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[] FACE_COLORS = new int[]
51
         {
52
           COLOR_GREEN , COLOR_YELLOW,
53
           COLOR_BLUE  , COLOR_RED
54
         };
55

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

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

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

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

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

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

    
116
  private static MeshBase[] mMeshes;
117

    
118
///////////////////////////////////////////////////////////////////////////////////////////////////
119

    
120
  TwistyPyraminx(int size, Static4D quat, DistortedTexture texture, MeshSquare mesh,
121
                 DistortedEffects effects, int[][] moves, Resources res, int scrWidth)
122
    {
123
    super(size, size, quat, texture, mesh, effects, moves, ObjectList.PYRA, res, scrWidth);
124
    }
125

    
126
///////////////////////////////////////////////////////////////////////////////////////////////////
127

    
128
  double[][] getVertices(int cubitType)
129
    {
130
    if( cubitType==0 ) return VERTICES_OCTA;
131
    if( cubitType==1 ) return VERTICES_TETRA;
132
    return null;
133
    }
134

    
135
///////////////////////////////////////////////////////////////////////////////////////////////////
136

    
137
  int[][] getVertIndexes(int cubitType)
138
    {
139
    if( cubitType==0 ) return VERT_INDEXES_OCTA;
140
    if( cubitType==1 ) return VERT_INDEXES_TETRA;
141
    return null;
142
    }
143

    
144
///////////////////////////////////////////////////////////////////////////////////////////////////
145

    
146
  int getNumCubitTypes(int numLayers)
147
    {
148
    return 2;
149
    }
150

    
151
///////////////////////////////////////////////////////////////////////////////////////////////////
152

    
153
  private void addTetrahedralLattice(int size, int index, float[][] pos)
154
    {
155
    final float DX = 1.0f;
156
    final float DY = SQ2/2;
157
    final float DZ = 1.0f;
158

    
159
    float startX = 0.0f;
160
    float startY =-DY*(size-1)/2;
161
    float startZ = DZ*(size-1)/2;
162

    
163
    for(int layer=0; layer<size; layer++)
164
      {
165
      float currX = startX;
166
      float currY = startY;
167

    
168
      for(int x=0; x<layer+1; x++)
169
        {
170
        float currZ = startZ;
171

    
172
        for(int z=0; z<size-layer; z++)
173
          {
174
          pos[index] = new float[] {currX,currY,currZ};
175
          index++;
176
          currZ -= DZ;
177
          }
178

    
179
        currX += DX;
180
        }
181

    
182
      startX-=DX/2;
183
      startY+=DY;
184
      startZ-=DZ/2;
185
      }
186
    }
187

    
188
///////////////////////////////////////////////////////////////////////////////////////////////////
189
// there are (n^3-n)/6 octahedrons and ((n+1)^3 - (n+1))/6 tetrahedrons
190

    
191
  float[][] getCubitPositions(int size)
192
    {
193
    int numOcta = (size-1)*size*(size+1)/6;
194
    int numTetra= size*(size+1)*(size+2)/6;
195
    float[][] ret = new float[numOcta+numTetra][];
196

    
197
    addTetrahedralLattice(size-1,      0,ret);
198
    addTetrahedralLattice(size  ,numOcta,ret);
199

    
200
    return ret;
201
    }
202

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

    
205
  Static4D[] getQuats()
206
    {
207
    return QUATS;
208
    }
209

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

    
212
  int getNumFaces()
213
    {
214
    return FACE_COLORS.length;
215
    }
216

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

    
219
  int getNumStickerTypes(int numLayers)
220
    {
221
    return STICKERS.length;
222
    }
223

    
224
///////////////////////////////////////////////////////////////////////////////////////////////////
225

    
226
  float[] getCuts(int size)
227
    {
228
    float[] cuts = new float[size-1];
229

    
230
    for(int i=0; i<size-1; i++)
231
      {
232
      cuts[i] = (1.0f-0.25f*size+i)*(SQ6/3);
233
      }
234

    
235
    return cuts;
236
    }
237

    
238
///////////////////////////////////////////////////////////////////////////////////////////////////
239

    
240
  int getNumCubitFaces()
241
    {
242
    return 8;
243
    }
244

    
245
///////////////////////////////////////////////////////////////////////////////////////////////////
246

    
247
  float getScreenRatio()
248
    {
249
    return 0.82f;
250
    }
251

    
252
///////////////////////////////////////////////////////////////////////////////////////////////////
253

    
254
  boolean shouldResetTextureMaps()
255
    {
256
    return false;
257
    }
258

    
259
///////////////////////////////////////////////////////////////////////////////////////////////////
260

    
261
  private int getNumOctahedrons(int numLayers)
262
    {
263
    return (numLayers-1)*numLayers*(numLayers+1)/6;
264
    }
265

    
266
///////////////////////////////////////////////////////////////////////////////////////////////////
267

    
268
  private int faceColor(int cubit, int axis)
269
    {
270
    return CUBITS[cubit].mRotationRow[axis] == 1 ? axis : NUM_FACES;
271
    }
272

    
273
///////////////////////////////////////////////////////////////////////////////////////////////////
274

    
275
  int getFaceColor(int cubit, int cubitface, int size)
276
    {
277
    if( cubit< (size-1)*size*(size+1)/6 )
278
      {
279
      switch( cubitface )
280
        {
281
        case 0: return faceColor(cubit,0);
282
        case 2: return faceColor(cubit,1);
283
        case 5: return faceColor(cubit,3);
284
        case 7: return faceColor(cubit,2);
285
        default:return NUM_FACES;
286
        }
287
      }
288
    else
289
      {
290
      return cubitface<NUM_FACES ? faceColor(cubit,cubitface) : NUM_FACES;
291
      }
292
    }
293

    
294
///////////////////////////////////////////////////////////////////////////////////////////////////
295

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

    
305
    MeshBase mesh;
306
    int numO = getNumOctahedrons(numLayers);
307

    
308
    if( cubit<numO )
309
      {
310
      if( mMeshes[0]==null )
311
        {
312
        float[][] bands     = new float[][] { {0.05f,35,0.5f,0.8f,6,2,2} };
313
        int[] bandIndexes   = new int[] { 0,0,0,0,0,0,0,0 };
314
        float[][] corners   = new float[][] { {0.04f,0.20f} };
315
        int[] cornerIndexes = new int[] { 0,0,0,0,0,0 };
316
        float[][] centers   = new float[][] { {0.0f, 0.0f, 0.0f} };
317
        int[] centerIndexes = new int[] { 0,0,0,0,0,0 };
318

    
319
        FactoryCubit factory = FactoryCubit.getInstance();
320

    
321
        factory.createNewFaceTransform(VERTICES_OCTA,VERT_INDEXES_OCTA);
322
        mMeshes[0] = factory.createRoundedSolid(VERTICES_OCTA, VERT_INDEXES_OCTA,
323
                                                bands, bandIndexes,
324
                                                corners, cornerIndexes,
325
                                                centers, centerIndexes,
326
                                                getNumCubitFaces() );
327
        }
328
      mesh = mMeshes[0].copy(true);
329
      }
330
    else
331
      {
332
      if( mMeshes[1]==null )
333
        {
334
        float[][] bands     = new float[][] { {0.05f,35,0.5f,0.8f,6,2,2} };
335
        int[] bandIndexes   = new int[] { 0,0,0,0 };
336
        float[][] corners   = new float[][] { {0.06f,0.15f} };
337
        int[] cornerIndexes = new int[] { 0,0,0,0 };
338
        float[][] centers   = new float[][] { {0.0f, 0.0f, 0.0f} };
339
        int[] centerIndexes = new int[] { 0,0,0,0 };
340

    
341
        FactoryCubit factory = FactoryCubit.getInstance();
342

    
343
        factory.createNewFaceTransform(VERTICES_TETRA,VERT_INDEXES_TETRA);
344
        mMeshes[1] = factory.createRoundedSolid(VERTICES_TETRA, VERT_INDEXES_TETRA,
345
                                                bands, bandIndexes,
346
                                                corners, cornerIndexes,
347
                                                centers, centerIndexes,
348
                                                getNumCubitFaces() );
349

    
350
        factory.printStickerCoords();
351
        }
352
      mesh = mMeshes[1].copy(true);
353
      }
354

    
355
    return mesh;
356
    }
357

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

    
360
  void createFaceTexture(Canvas canvas, Paint paint, int face, int left, int top)
361
    {
362
    float R = 0.06f;
363
    float S = 0.08f;
364

    
365
    FactorySticker factory = FactorySticker.getInstance();
366
    factory.drawRoundedPolygon(canvas, paint, left, top, STICKERS[0], S, FACE_COLORS[face], R);
367
    }
368

    
369
///////////////////////////////////////////////////////////////////////////////////////////////////
370
// SQ6/3 = height of the tetrahedron
371

    
372
  float returnMultiplier()
373
    {
374
    return getNumLayers()/(SQ6/3);
375
    }
376

    
377
///////////////////////////////////////////////////////////////////////////////////////////////////
378

    
379
  float[] getRowChances(int numLayers)
380
    {
381
    int total = numLayers*(numLayers+1)/2;
382
    float running=0.0f;
383
    float[] chances = new float[numLayers];
384

    
385
    for(int i=0; i<numLayers; i++)
386
      {
387
      running += (numLayers-i);
388
      chances[i] = running / total;
389
      }
390

    
391
    return chances;
392
    }
393

    
394
///////////////////////////////////////////////////////////////////////////////////////////////////
395
// PUBLIC API
396

    
397
  public Static3D[] getRotationAxis()
398
    {
399
    return ROT_AXIS;
400
    }
401

    
402
///////////////////////////////////////////////////////////////////////////////////////////////////
403

    
404
  public int getBasicAngle()
405
    {
406
    return 3;
407
    }
408

    
409
///////////////////////////////////////////////////////////////////////////////////////////////////
410

    
411
  public void randomizeNewScramble(int[][] scramble, Random rnd, int num)
412
    {
413
    if( num==0 )
414
      {
415
      scramble[num][0] = rnd.nextInt(ROTATION_AXIS.length);
416
      }
417
    else
418
      {
419
      int newVector = rnd.nextInt(ROTATION_AXIS.length-1);
420
      scramble[num][0] = (newVector>=scramble[num-1][0] ? newVector+1 : newVector);
421
      }
422

    
423
    float rowFloat = rnd.nextFloat();
424

    
425
    for(int row=0; row<mRowChances.length; row++)
426
      {
427
      if( rowFloat<=mRowChances[row] )
428
        {
429
        scramble[num][1] = row;
430
        break;
431
        }
432
      }
433

    
434
    switch( rnd.nextInt(2) )
435
      {
436
      case 0: scramble[num][2] = -1; break;
437
      case 1: scramble[num][2] =  1; break;
438
      }
439
    }
440

    
441
///////////////////////////////////////////////////////////////////////////////////////////////////
442

    
443
  public boolean isSolved()
444
    {
445
    int index = CUBITS[0].mQuatIndex;
446

    
447
    for(int i=1; i<NUM_CUBITS; i++)
448
      {
449
      if( thereIsVisibleDifference(CUBITS[i], index) ) return false;
450
      }
451

    
452
    return true;
453
    }
454

    
455
////////////////////////////////////////////////////////////////////////
456
// only needed for solvers - there are no Pyraminx solvers ATM)
457

    
458
  public String retObjectString()
459
    {
460
    return "";
461
    }
462

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

    
465
  public int getObjectName(int numLayers)
466
    {
467
    switch(numLayers)
468
      {
469
      case 3: return R.string.pyra3;
470
      case 4: return R.string.pyra4;
471
      case 5: return R.string.pyra5;
472
      }
473
    return R.string.pyra3;
474
    }
475

    
476
///////////////////////////////////////////////////////////////////////////////////////////////////
477

    
478
  public int getInventor(int numLayers)
479
    {
480
    switch(numLayers)
481
      {
482
      case 3: return R.string.pyra3_inventor;
483
      case 4: return R.string.pyra4_inventor;
484
      case 5: return R.string.pyra5_inventor;
485
      }
486
    return R.string.pyra3_inventor;
487
    }
488

    
489
///////////////////////////////////////////////////////////////////////////////////////////////////
490

    
491
  public int getComplexity(int numLayers)
492
    {
493
    switch(numLayers)
494
      {
495
      case 3: return 4;
496
      case 4: return 6;
497
      case 5: return 8;
498
      }
499
    return 4;
500
    }
501
}
(30-30/33)