Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / TwistyPyraminx.java @ 8db55f55

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.ObjectShape;
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.MeshSquare;
29
import org.distorted.library.type.Static3D;
30
import org.distorted.library.type.Static4D;
31
import org.distorted.main.R;
32

    
33
import java.util.Random;
34

    
35
///////////////////////////////////////////////////////////////////////////////////////////////////
36

    
37
public class TwistyPyraminx extends TwistyObject
38
{
39
  static final float SCREEN_RATIO = 0.88f;
40

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

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

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

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

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

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

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

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

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

    
117
  private static float[] mRowChances;
118

    
119
  private static final ObjectSticker[] mStickers;
120

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

    
130
///////////////////////////////////////////////////////////////////////////////////////////////////
131

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

    
138
///////////////////////////////////////////////////////////////////////////////////////////////////
139

    
140
  int[] getSolvedQuats(int cubit, int numLayers)
141
    {
142
    int status = retCubitSolvedStatus(cubit,numLayers);
143
    return status<0 ? null : buildSolvedQuats(MovementPyraminx.FACE_AXIS[status],QUATS);
144
    }
145

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

    
148
  private float[] getRowChances(int numLayers)
149
    {
150
    int total = numLayers*(numLayers+1)/2;
151
    float running=0.0f;
152
    float[] chances = new float[numLayers];
153

    
154
    for(int i=0; i<numLayers; i++)
155
      {
156
      running += (numLayers-i);
157
      chances[i] = running / total;
158
      }
159

    
160
    return chances;
161
    }
162

    
163
///////////////////////////////////////////////////////////////////////////////////////////////////
164

    
165
  private void addTetrahedralLattice(int size, int index, float[][] pos)
166
    {
167
    final float DX = 1.0f;
168
    final float DY = SQ2/2;
169
    final float DZ = 1.0f;
170

    
171
    float startX = 0.0f;
172
    float startY =-DY*(size-1)/2;
173
    float startZ = DZ*(size-1)/2;
174

    
175
    for(int layer=0; layer<size; layer++)
176
      {
177
      float currX = startX;
178
      float currY = startY;
179

    
180
      for(int x=0; x<layer+1; x++)
181
        {
182
        float currZ = startZ;
183

    
184
        for(int z=0; z<size-layer; z++)
185
          {
186
          pos[index] = new float[] {currX,currY,currZ};
187
          index++;
188
          currZ -= DZ;
189
          }
190

    
191
        currX += DX;
192
        }
193

    
194
      startX-=DX/2;
195
      startY+=DY;
196
      startZ-=DZ/2;
197
      }
198
    }
199

    
200
///////////////////////////////////////////////////////////////////////////////////////////////////
201
// there are (n^3-n)/6 octahedrons and ((n+1)^3 - (n+1))/6 tetrahedrons
202

    
203
  float[][] getCubitPositions(int size)
204
    {
205
    int numOcta = (size-1)*size*(size+1)/6;
206
    int numTetra= size*(size+1)*(size+2)/6;
207
    float[][] ret = new float[numOcta+numTetra][];
208

    
209
    addTetrahedralLattice(size-1,      0,ret);
210
    addTetrahedralLattice(size  ,numOcta,ret);
211

    
212
    return ret;
213
    }
214

    
215
///////////////////////////////////////////////////////////////////////////////////////////////////
216

    
217
  Static4D[] getQuats()
218
    {
219
    return QUATS;
220
    }
221

    
222
///////////////////////////////////////////////////////////////////////////////////////////////////
223

    
224
  int getNumFaces()
225
    {
226
    return FACE_COLORS.length;
227
    }
228

    
229
///////////////////////////////////////////////////////////////////////////////////////////////////
230

    
231
  int getSolvedFunctionIndex()
232
    {
233
    return 0;
234
    }
235

    
236
///////////////////////////////////////////////////////////////////////////////////////////////////
237

    
238
  int getNumStickerTypes(int numLayers)
239
    {
240
    return STICKERS.length;
241
    }
242

    
243
///////////////////////////////////////////////////////////////////////////////////////////////////
244

    
245
  float[][] getCuts(int size)
246
    {
247
    float[][] cuts = new float[4][size-1];
248

    
249
    for(int i=0; i<size-1; i++)
250
      {
251
      float cut = (1.0f-0.25f*size+i)*(SQ6/3);
252
      cuts[0][i] = cut;
253
      cuts[1][i] = cut;
254
      cuts[2][i] = cut;
255
      cuts[3][i] = cut;
256
      }
257

    
258
    return cuts;
259
    }
260

    
261
///////////////////////////////////////////////////////////////////////////////////////////////////
262

    
263
  int getNumCubitFaces()
264
    {
265
    return 8;
266
    }
267

    
268
///////////////////////////////////////////////////////////////////////////////////////////////////
269

    
270
  float getScreenRatio()
271
    {
272
    return SCREEN_RATIO;
273
    }
274

    
275
///////////////////////////////////////////////////////////////////////////////////////////////////
276

    
277
  boolean shouldResetTextureMaps()
278
    {
279
    return false;
280
    }
281

    
282
///////////////////////////////////////////////////////////////////////////////////////////////////
283

    
284
  private int getNumOctahedrons(int numLayers)
285
    {
286
    return (numLayers-1)*numLayers*(numLayers+1)/6;
287
    }
288

    
289
///////////////////////////////////////////////////////////////////////////////////////////////////
290

    
291
  private int faceColor(int cubit, int axis)
292
    {
293
    return CUBITS[cubit].mRotationRow[axis] == 1 ? axis : NUM_FACES;
294
    }
295

    
296
///////////////////////////////////////////////////////////////////////////////////////////////////
297

    
298
  int getFaceColor(int cubit, int cubitface, int size)
299
    {
300
    if( cubit< (size-1)*size*(size+1)/6 )
301
      {
302
      switch( cubitface )
303
        {
304
        case 0: return faceColor(cubit,0);
305
        case 2: return faceColor(cubit,1);
306
        case 5: return faceColor(cubit,3);
307
        case 7: return faceColor(cubit,2);
308
        default:return NUM_FACES;
309
        }
310
      }
311
    else
312
      {
313
      return cubitface<NUM_FACES ? faceColor(cubit,cubitface) : NUM_FACES;
314
      }
315
    }
316

    
317
///////////////////////////////////////////////////////////////////////////////////////////////////
318

    
319
  ObjectShape getObjectShape(int cubit, int numLayers)
320
    {
321
    int variant = getCubitVariant(cubit,numLayers);
322

    
323
    if( variant==0 )
324
      {
325
      int N = numLayers==3? 6 : 5;
326
      int E = numLayers==3? 2 : 1;
327
      float[][] bands     = new float[][] { {0.05f,35,0.5f,0.8f,N,E,E} };
328
      int[] bandIndices   = new int[] { 0,0,0,0,0,0,0,0 };
329
      float[][] corners   = new float[][] { {0.04f,0.20f} };
330
      int[] cornerIndices = new int[] { 0,0,0,0,0,0 };
331
      float[][] centers   = new float[][] { {0.0f, 0.0f, 0.0f} };
332
      int[] centerIndices = new int[] { 0,0,0,0,0,0 };
333
      return new ObjectShape(VERTICES_OCTA,VERT_INDEXES_OCTA,bands,bandIndices,corners,cornerIndices,centers,centerIndices,getNumCubitFaces(), null);
334
      }
335
    else
336
      {
337
      int N = numLayers==3? 6 : 5;
338
      int E = numLayers==3? 2 : 1;
339
      float[][] bands     = new float[][] { {0.05f,35,0.5f,0.8f,N,E,E} };
340
      int[] bandIndices   = new int[] { 0,0,0,0 };
341
      float[][] corners   = new float[][] { {0.06f,0.15f} };
342
      int[] cornerIndices = new int[] { 0,0,0,0 };
343
      float[][] centers   = new float[][] { {0.0f, 0.0f, 0.0f} };
344
      int[] centerIndices = new int[] { 0,0,0,0 };
345
      return new ObjectShape(VERTICES_TETRA,VERT_INDEXES_TETRA,bands,bandIndices,corners,cornerIndices,centers,centerIndices,getNumCubitFaces(), null);
346
      }
347
    }
348

    
349
///////////////////////////////////////////////////////////////////////////////////////////////////
350

    
351
  Static4D getQuat(int cubit, int numLayers)
352
    {
353
    return QUATS[0];
354
    }
355

    
356
///////////////////////////////////////////////////////////////////////////////////////////////////
357

    
358
  int getNumCubitVariants(int numLayers)
359
    {
360
    return 2;
361
    }
362

    
363
///////////////////////////////////////////////////////////////////////////////////////////////////
364

    
365
  int getCubitVariant(int cubit, int numLayers)
366
    {
367
    return cubit<getNumOctahedrons(numLayers) ? 0:1;
368
    }
369

    
370
///////////////////////////////////////////////////////////////////////////////////////////////////
371

    
372
  int getColor(int face)
373
    {
374
    return FACE_COLORS[face];
375
    }
376

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

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

    
384
///////////////////////////////////////////////////////////////////////////////////////////////////
385
// SQ6/3 = height of the tetrahedron
386

    
387
  float returnMultiplier()
388
    {
389
    return getNumLayers()/(SQ6/3);
390
    }
391

    
392
///////////////////////////////////////////////////////////////////////////////////////////////////
393
// PUBLIC API
394

    
395
  public Static3D[] getRotationAxis()
396
    {
397
    return ROT_AXIS;
398
    }
399

    
400
///////////////////////////////////////////////////////////////////////////////////////////////////
401

    
402
  public int[] getBasicAngle()
403
    {
404
    return BASIC_ANGLE;
405
    }
406

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

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

    
413
    if( mRowChances==null ) mRowChances = getRowChances(numLayers);
414

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

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

    
441
    float rowFloat = rnd.nextFloat();
442

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

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

    
459
///////////////////////////////////////////////////////////////////////////////////////////////////
460

    
461
  public int getObjectName(int numLayers)
462
    {
463
    switch(numLayers)
464
      {
465
      case 3: return R.string.pyra3;
466
      case 4: return R.string.pyra4;
467
      case 5: return R.string.pyra5;
468
      }
469
    return R.string.pyra3;
470
    }
471

    
472
///////////////////////////////////////////////////////////////////////////////////////////////////
473

    
474
  public int getInventor(int numLayers)
475
    {
476
    switch(numLayers)
477
      {
478
      case 3: return R.string.pyra3_inventor;
479
      case 4: return R.string.pyra4_inventor;
480
      case 5: return R.string.pyra5_inventor;
481
      }
482
    return R.string.pyra3_inventor;
483
    }
484

    
485
///////////////////////////////////////////////////////////////////////////////////////////////////
486

    
487
  public int getComplexity(int numLayers)
488
    {
489
    switch(numLayers)
490
      {
491
      case 3: return 4;
492
      case 4: return 6;
493
      case 5: return 8;
494
      }
495
    return 4;
496
    }
497
}
(34-34/41)