Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / TwistyPyraminx.java @ 329da839

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[] 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
///////////////////////////////////////////////////////////////////////////////////////////////////
122

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

    
129
///////////////////////////////////////////////////////////////////////////////////////////////////
130

    
131
  private float[] getRowChances(int numLayers)
132
    {
133
    int total = numLayers*(numLayers+1)/2;
134
    float running=0.0f;
135
    float[] chances = new float[numLayers];
136

    
137
    for(int i=0; i<numLayers; i++)
138
      {
139
      running += (numLayers-i);
140
      chances[i] = running / total;
141
      }
142

    
143
    return chances;
144
    }
145

    
146
///////////////////////////////////////////////////////////////////////////////////////////////////
147

    
148
  private void addTetrahedralLattice(int size, int index, float[][] pos)
149
    {
150
    final float DX = 1.0f;
151
    final float DY = SQ2/2;
152
    final float DZ = 1.0f;
153

    
154
    float startX = 0.0f;
155
    float startY =-DY*(size-1)/2;
156
    float startZ = DZ*(size-1)/2;
157

    
158
    for(int layer=0; layer<size; layer++)
159
      {
160
      float currX = startX;
161
      float currY = startY;
162

    
163
      for(int x=0; x<layer+1; x++)
164
        {
165
        float currZ = startZ;
166

    
167
        for(int z=0; z<size-layer; z++)
168
          {
169
          pos[index] = new float[] {currX,currY,currZ};
170
          index++;
171
          currZ -= DZ;
172
          }
173

    
174
        currX += DX;
175
        }
176

    
177
      startX-=DX/2;
178
      startY+=DY;
179
      startZ-=DZ/2;
180
      }
181
    }
182

    
183
///////////////////////////////////////////////////////////////////////////////////////////////////
184
// there are (n^3-n)/6 octahedrons and ((n+1)^3 - (n+1))/6 tetrahedrons
185

    
186
  float[][] getCubitPositions(int size)
187
    {
188
    int numOcta = (size-1)*size*(size+1)/6;
189
    int numTetra= size*(size+1)*(size+2)/6;
190
    float[][] ret = new float[numOcta+numTetra][];
191

    
192
    addTetrahedralLattice(size-1,      0,ret);
193
    addTetrahedralLattice(size  ,numOcta,ret);
194

    
195
    return ret;
196
    }
197

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

    
200
  Static4D[] getQuats()
201
    {
202
    return QUATS;
203
    }
204

    
205
///////////////////////////////////////////////////////////////////////////////////////////////////
206

    
207
  int getNumFaces()
208
    {
209
    return FACE_COLORS.length;
210
    }
211

    
212
///////////////////////////////////////////////////////////////////////////////////////////////////
213

    
214
  int getNumStickerTypes(int numLayers)
215
    {
216
    return STICKERS.length;
217
    }
218

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

    
221
  float[][] getCuts(int size)
222
    {
223
    float[][] cuts = new float[4][size-1];
224

    
225
    for(int i=0; i<size-1; i++)
226
      {
227
      float cut = (1.0f-0.25f*size+i)*(SQ6/3);
228
      cuts[0][i] = cut;
229
      cuts[1][i] = cut;
230
      cuts[2][i] = cut;
231
      cuts[3][i] = cut;
232
      }
233

    
234
    return cuts;
235
    }
236

    
237
///////////////////////////////////////////////////////////////////////////////////////////////////
238

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

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

    
246
  float getScreenRatio()
247
    {
248
    return 0.88f;
249
    }
250

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

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

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

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

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

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

    
272
///////////////////////////////////////////////////////////////////////////////////////////////////
273

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

    
293
///////////////////////////////////////////////////////////////////////////////////////////////////
294

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

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

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

    
318
        FactoryCubit factory = FactoryCubit.getInstance();
319

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

    
340
        FactoryCubit factory = FactoryCubit.getInstance();
341

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

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

    
354
    return mesh;
355
    }
356

    
357
///////////////////////////////////////////////////////////////////////////////////////////////////
358

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

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

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

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

    
376
///////////////////////////////////////////////////////////////////////////////////////////////////
377
// PUBLIC API
378

    
379
  public Static3D[] getRotationAxis()
380
    {
381
    return ROT_AXIS;
382
    }
383

    
384
///////////////////////////////////////////////////////////////////////////////////////////////////
385

    
386
  public int[] getBasicAngle()
387
    {
388
    return BASIC_ANGLE;
389
    }
390

    
391
///////////////////////////////////////////////////////////////////////////////////////////////////
392

    
393
  public void randomizeNewScramble(int[][] scramble, Random rnd, int curr, int total)
394
    {
395
    int numLayers = getNumLayers();
396

    
397
    if( mRowChances==null ) mRowChances = getRowChances(numLayers);
398

    
399
    if( curr==0 )
400
      {
401
      scramble[curr][0] = rnd.nextInt(NUM_AXIS);
402
      }
403
    else
404
      {
405
      int newVector = rnd.nextInt(NUM_AXIS-1);
406
      scramble[curr][0] = (newVector>=scramble[curr-1][0] ? newVector+1 : newVector);
407

    
408
      // Correct the situation when we first rotate the largest layer, then a tip (which doesn't
409
      // intersect anything besides the largest layer!) and then we try to rotate again along
410
      // the same axis like 2 rotations before - which carries the risk we rotate the largest
411
      // layer back to its spot again and the three moves end up being only a single tip rotation.
412
      if( curr>=2 && scramble[curr-1][1]==(numLayers-1) && scramble[curr][0]==scramble[curr-2][0] )
413
        {
414
        for(int ax=0; ax<NUM_AXIS; ax++)
415
          {
416
          if( scramble[curr-1][0]!=ax && scramble[curr-2][0]!=ax )
417
            {
418
            scramble[curr][0]=ax;
419
            break;
420
            }
421
          }
422
        }
423
      }
424

    
425
    float rowFloat = rnd.nextFloat();
426

    
427
    for(int row=0; row<numLayers; row++)
428
      {
429
      if( rowFloat<=mRowChances[row] )
430
        {
431
        scramble[curr][1] = row;
432
        break;
433
        }
434
      }
435

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

    
443
///////////////////////////////////////////////////////////////////////////////////////////////////
444

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

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

    
454
    return true;
455
    }
456

    
457
////////////////////////////////////////////////////////////////////////
458
// only needed for solvers - there are no Pyraminx solvers ATM)
459

    
460
  public String retObjectString()
461
    {
462
    return "";
463
    }
464

    
465
///////////////////////////////////////////////////////////////////////////////////////////////////
466

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

    
478
///////////////////////////////////////////////////////////////////////////////////////////////////
479

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

    
491
///////////////////////////////////////////////////////////////////////////////////////////////////
492

    
493
  public int getComplexity(int numLayers)
494
    {
495
    switch(numLayers)
496
      {
497
      case 3: return 4;
498
      case 4: return 6;
499
      case 5: return 8;
500
      }
501
    return 4;
502
    }
503
}
(34-34/41)