Project

General

Profile

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

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

1 e844c116 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
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 1f9772f3 Leszek Koltunski
package org.distorted.objects;
21 e844c116 Leszek Koltunski
22 ccf9fec5 Leszek Koltunski
import android.content.res.Resources;
23 e844c116 Leszek Koltunski
import android.graphics.Canvas;
24
import android.graphics.Paint;
25
26
import org.distorted.library.main.DistortedEffects;
27
import org.distorted.library.main.DistortedTexture;
28
import org.distorted.library.mesh.MeshBase;
29 efa8aa48 Leszek Koltunski
import org.distorted.library.mesh.MeshSquare;
30 e844c116 Leszek Koltunski
import org.distorted.library.type.Static3D;
31
import org.distorted.library.type.Static4D;
32 6fd4a72c Leszek Koltunski
import org.distorted.main.R;
33 1ebc4767 Leszek Koltunski
import org.distorted.main.RubikSurfaceView;
34 e844c116 Leszek Koltunski
35 7c969a6d Leszek Koltunski
import java.util.Random;
36
37
import static org.distorted.effects.scramble.ScrambleEffect.START_AXIS;
38
39 e844c116 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
40
41 9c2f0c91 Leszek Koltunski
public class TwistyPyraminx extends TwistyObject
42 e844c116 Leszek Koltunski
{
43 ad38d800 Leszek Koltunski
  static final Static3D[] ROT_AXIS = new Static3D[]
44 e844c116 Leszek Koltunski
         {
45 ac940e24 Leszek Koltunski
           new Static3D(     0,-SQ3/3,-SQ6/3),
46
           new Static3D(     0,-SQ3/3,+SQ6/3),
47
           new Static3D(+SQ6/3,+SQ3/3,     0),
48
           new Static3D(-SQ6/3,+SQ3/3,     0),
49 ad38d800 Leszek Koltunski
         };
50
51 e844c116 Leszek Koltunski
  private static final int[] FACE_COLORS = new int[]
52
         {
53 ece1b58d Leszek Koltunski
           COLOR_GREEN , COLOR_YELLOW,
54
           COLOR_BLUE  , COLOR_RED
55 e844c116 Leszek Koltunski
         };
56
57 9f4c44fe Leszek Koltunski
  // computed with res/raw/compute_quats.c
58 10585385 Leszek Koltunski
  private static final Static4D[] QUATS = new Static4D[]
59 e844c116 Leszek Koltunski
         {
60 10585385 Leszek Koltunski
           new Static4D(  0.0f,   0.0f,   0.0f,  1.0f),
61 ac940e24 Leszek Koltunski
           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 e844c116 Leszek Koltunski
         };
73
74 ac940e24 Leszek Koltunski
  private static MeshBase mOctaMesh, mTetraMesh;
75 49f67f9b Leszek Koltunski
76 e844c116 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
77
78 ac940e24 Leszek Koltunski
  TwistyPyraminx(int size, Static4D quat, DistortedTexture texture, MeshSquare mesh,
79
                 DistortedEffects effects, int[][] moves, Resources res, int scrWidth)
80 e844c116 Leszek Koltunski
    {
81 d99f3a48 Leszek Koltunski
    super(size, size, 30, quat, texture, mesh, effects, moves, ObjectList.PYRA, res, scrWidth);
82 e844c116 Leszek Koltunski
    }
83
84
///////////////////////////////////////////////////////////////////////////////////////////////////
85
86 ac940e24 Leszek Koltunski
  private void addTetrahedralLattice(int size, int index, Static3D[] pos)
87 49f67f9b Leszek Koltunski
    {
88 ac940e24 Leszek Koltunski
    final float DX = 1.0f;
89
    final float DY = SQ2/2;
90
    final float DZ = 1.0f;
91 49f67f9b Leszek Koltunski
92 ac940e24 Leszek Koltunski
    float startX = 0.0f;
93
    float startY =-DY*(size-1)/2;
94
    float startZ = DZ*(size-1)/2;
95 769409d2 Leszek Koltunski
96 ac940e24 Leszek Koltunski
    for(int layer=0; layer<size; layer++)
97 49f67f9b Leszek Koltunski
      {
98 ac940e24 Leszek Koltunski
      float currX = startX;
99
      float currY = startY;
100
101
      for(int x=0; x<layer+1; x++)
102
        {
103
        float currZ = startZ;
104
105
        for(int z=0; z<size-layer; z++)
106
          {
107
          pos[index] = new Static3D(currX,currY,currZ);
108
          index++;
109
          currZ -= DZ;
110
          }
111
112
        currX += DX;
113
        }
114
115
      startX-=DX/2;
116
      startY+=DY;
117
      startZ-=DZ/2;
118 49f67f9b Leszek Koltunski
      }
119
    }
120
121
///////////////////////////////////////////////////////////////////////////////////////////////////
122 ac940e24 Leszek Koltunski
// there are (n^3-n)/6 octahedrons and ((n+1)^3 - (n+1))/6 tetrahedrons
123 49f67f9b Leszek Koltunski
124 e844c116 Leszek Koltunski
  Static3D[] getCubitPositions(int size)
125
    {
126 ac940e24 Leszek Koltunski
    int numOcta = (size-1)*size*(size+1)/6;
127
    int numTetra= size*(size+1)*(size+2)/6;
128
    Static3D[] ret = new Static3D[numOcta+numTetra];
129 49f67f9b Leszek Koltunski
130 ac940e24 Leszek Koltunski
    addTetrahedralLattice(size-1,      0,ret);
131
    addTetrahedralLattice(size  ,numOcta,ret);
132 49f67f9b Leszek Koltunski
133 ac940e24 Leszek Koltunski
    return ret;
134 e844c116 Leszek Koltunski
    }
135
136
///////////////////////////////////////////////////////////////////////////////////////////////////
137
138 10585385 Leszek Koltunski
  Static4D[] getQuats()
139 e844c116 Leszek Koltunski
    {
140 10585385 Leszek Koltunski
    return QUATS;
141 e844c116 Leszek Koltunski
    }
142
143
///////////////////////////////////////////////////////////////////////////////////////////////////
144
145
  int getNumFaces()
146
    {
147
    return FACE_COLORS.length;
148
    }
149
150 eab9d8f8 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
151
152 a64e07d0 Leszek Koltunski
  int getNumStickerTypes(int numLayers)
153 eab9d8f8 Leszek Koltunski
    {
154
    return 1;
155
    }
156
157 7403cdfa Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
158
159 a97e02b7 Leszek Koltunski
  float[] getCuts(int size)
160 7403cdfa Leszek Koltunski
    {
161 a97e02b7 Leszek Koltunski
    float[] cuts = new float[size-1];
162
163
    for(int i=0; i<size-1; i++)
164
      {
165
      cuts[i] = (1.0f-0.25f*size+i)*(SQ6/3);
166
      }
167
168
    return cuts;
169 7403cdfa Leszek Koltunski
    }
170
171 8f53e513 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
172
173
  int getNumCubitFaces()
174
    {
175 ac940e24 Leszek Koltunski
    return 8;
176 8f53e513 Leszek Koltunski
    }
177
178 f0fa83ae Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
179
180
  float getScreenRatio()
181
    {
182 7381193e Leszek Koltunski
    return 0.82f;
183 f0fa83ae Leszek Koltunski
    }
184
185 eaee1ddc Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
186
187
  boolean shouldResetTextureMaps()
188
    {
189
    return false;
190
    }
191
192 f6d06256 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
193
194 ac940e24 Leszek Koltunski
  private int faceColor(int cubit, int axis)
195 f6d06256 Leszek Koltunski
    {
196 ac940e24 Leszek Koltunski
    float row = CUBITS[cubit].mRotationRow[axis];
197
    return row*row < 0.1f ? axis : NUM_FACES;
198 f6d06256 Leszek Koltunski
    }
199
200 f0fa83ae Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
201
202 ac940e24 Leszek Koltunski
  int getFaceColor(int cubit, int cubitface, int size)
203 e844c116 Leszek Koltunski
    {
204 ac940e24 Leszek Koltunski
    if( cubit< (size-1)*size*(size+1)/6 )
205 40ab026e Leszek Koltunski
      {
206 ac940e24 Leszek Koltunski
      switch( cubitface )
207
        {
208
        case 0: return faceColor(cubit,0);
209
        case 2: return faceColor(cubit,1);
210
        case 5: return faceColor(cubit,3);
211
        case 7: return faceColor(cubit,2);
212
        default:return NUM_FACES;
213
        }
214 40ab026e Leszek Koltunski
      }
215 ac940e24 Leszek Koltunski
    else
216 89a11f7b Leszek Koltunski
      {
217 ac940e24 Leszek Koltunski
      return cubitface<NUM_FACES ? faceColor(cubit,cubitface) : NUM_FACES;
218 89a11f7b Leszek Koltunski
      }
219 e844c116 Leszek Koltunski
    }
220
221 40ab026e Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
222
223 a64e07d0 Leszek Koltunski
  MeshBase createCubitMesh(int cubit, int numLayers)
224 40ab026e Leszek Koltunski
    {
225 d99f3a48 Leszek Koltunski
    if( cubit< (numLayers-1)*numLayers*(numLayers+1)/6 )
226 40ab026e Leszek Koltunski
      {
227 b89898c5 Leszek Koltunski
      if( mOctaMesh==null ) mOctaMesh = FactoryCubit.getInstance().createOctaMesh();
228 ac940e24 Leszek Koltunski
      return mOctaMesh.copy(true);
229 40ab026e Leszek Koltunski
      }
230
    else
231
      {
232 b89898c5 Leszek Koltunski
      if( mTetraMesh==null ) mTetraMesh = FactoryCubit.getInstance().createTetraMesh();
233 ac940e24 Leszek Koltunski
      return mTetraMesh.copy(true);
234 40ab026e Leszek Koltunski
      }
235
    }
236
237 7289fd6c Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
238
239 ae755eda Leszek Koltunski
  void createFaceTexture(Canvas canvas, Paint paint, int face, int left, int top)
240 7289fd6c Leszek Koltunski
    {
241 ae755eda Leszek Koltunski
    float E = 0.75f;
242
    float F = 0.50f;
243 76c2bd07 Leszek Koltunski
    float R = 0.06f;
244
    float S = 0.08f;
245
    float[] vertices = { -F,-E/3, +F,-E/3, 0.0f,2*E/3};
246
247 b89898c5 Leszek Koltunski
    FactorySticker factory = FactorySticker.getInstance();
248 ae755eda Leszek Koltunski
    factory.drawRoundedPolygon(canvas, paint, left, top, vertices, S, FACE_COLORS[face], R);
249 7289fd6c Leszek Koltunski
    }
250
251 fb377dae Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
252 7403cdfa Leszek Koltunski
// SQ6/3 = height of the tetrahedron
253 fb377dae Leszek Koltunski
254
  float returnMultiplier()
255
    {
256 d99f3a48 Leszek Koltunski
    return getNumLayers()/(SQ6/3);
257 fb377dae Leszek Koltunski
    }
258
259 7c969a6d Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
260
261 a64e07d0 Leszek Koltunski
  float[] getRowChances(int numLayers)
262 7c969a6d Leszek Koltunski
    {
263 d99f3a48 Leszek Koltunski
    int total = numLayers*(numLayers+1)/2;
264 7c969a6d Leszek Koltunski
    float running=0.0f;
265 d99f3a48 Leszek Koltunski
    float[] chances = new float[numLayers];
266 7c969a6d Leszek Koltunski
267 d99f3a48 Leszek Koltunski
    for(int i=0; i<numLayers; i++)
268 7c969a6d Leszek Koltunski
      {
269 d99f3a48 Leszek Koltunski
      running += (numLayers-i);
270 7c969a6d Leszek Koltunski
      chances[i] = running / total;
271
      }
272
273
    return chances;
274
    }
275
276 e844c116 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
277
// PUBLIC API
278
279 12ad3fca Leszek Koltunski
  public Static3D[] getRotationAxis()
280
    {
281 ad38d800 Leszek Koltunski
    return ROT_AXIS;
282 12ad3fca Leszek Koltunski
    }
283
284
///////////////////////////////////////////////////////////////////////////////////////////////////
285
286 e844c116 Leszek Koltunski
  public int getBasicAngle()
287
    {
288
    return 3;
289
    }
290 39e74052 Leszek Koltunski
291 7c969a6d Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
292
293
  public int randomizeNewRotAxis(Random rnd, int oldRotAxis)
294
    {
295
    int numAxis = ROTATION_AXIS.length;
296
297
    if( oldRotAxis == START_AXIS )
298 5cf34c5f Leszek Koltunski
      {
299 7c969a6d Leszek Koltunski
      return rnd.nextInt(numAxis);
300
      }
301
    else
302
      {
303
      int newVector = rnd.nextInt(numAxis-1);
304
      return (newVector>=oldRotAxis ? newVector+1 : newVector);
305 5cf34c5f Leszek Koltunski
      }
306
    }
307
308 e46e17fb Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
309
310 7c969a6d Leszek Koltunski
  public int randomizeNewRow(Random rnd, int oldRotAxis, int oldRow, int newRotAxis)
311 e46e17fb Leszek Koltunski
    {
312 7c969a6d Leszek Koltunski
    float rowFloat = rnd.nextFloat();
313 e46e17fb Leszek Koltunski
314 7c969a6d Leszek Koltunski
    for(int row=0; row<mRowChances.length; row++)
315
      {
316
      if( rowFloat<=mRowChances[row] ) return row;
317
      }
318
319
    return 0;
320 e46e17fb Leszek Koltunski
    }
321 f0336037 Leszek Koltunski
322 6b6504fe Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
323
324
  public boolean isSolved()
325
    {
326
    int index = CUBITS[0].mQuatIndex;
327
328
    for(int i=1; i<NUM_CUBITS; i++)
329
      {
330
      if( !thereIsNoVisibleDifference(CUBITS[i], index) ) return false;
331
      }
332
333
    return true;
334
    }
335
336 1ebc4767 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
337
// return if the Cubit, when rotated with its own mQuatScramble, would have looked any different
338
// then if it were rotated by quaternion 'quat'.
339
// No it is not so simple as the quats need to be the same - imagine a 4x4x4 cube where the two
340
// middle squares get interchanged. No visible difference!
341
//
342
// So: this is true iff the cubit
343
// a) is a corner or edge and the quaternions are the same
344
// b) is inside one of the faces and after rotations by both quats it ends up on the same face.
345
346 6b6504fe Leszek Koltunski
  private boolean thereIsNoVisibleDifference(Cubit cubit, int quatIndex)
347 1ebc4767 Leszek Koltunski
    {
348
    if ( cubit.mQuatIndex == quatIndex ) return true;
349
350
    int belongsToHowManyFaces = 0;
351 d99f3a48 Leszek Koltunski
    int numLayers = getNumLayers()-1;
352 1ebc4767 Leszek Koltunski
    float row;
353
    final float MAX_ERROR = 0.01f;
354
355
    for(int i=0; i<NUM_AXIS; i++)
356
      {
357
      row = cubit.mRotationRow[i];
358 d99f3a48 Leszek Koltunski
      if( (row          <MAX_ERROR && row          >-MAX_ERROR) ||
359
          (row-numLayers<MAX_ERROR && row-numLayers>-MAX_ERROR)  ) belongsToHowManyFaces++;
360 1ebc4767 Leszek Koltunski
      }
361
362
    switch(belongsToHowManyFaces)
363
      {
364
      case 0 : return true ;  // 'inside' cubit that does not lie on any face
365
      case 1 :                // cubit that lies inside one of the faces
366
               Static3D orig = cubit.getOrigPosition();
367
               Static4D quat1 = QUATS[quatIndex];
368
               Static4D quat2 = QUATS[cubit.mQuatIndex];
369
370
               Static4D cubitCenter = new Static4D( orig.get0(), orig.get1(), orig.get2(), 0);
371
               Static4D rotated1 = RubikSurfaceView.rotateVectorByQuat( cubitCenter, quat1 );
372
               Static4D rotated2 = RubikSurfaceView.rotateVectorByQuat( cubitCenter, quat2 );
373
374 eb389a97 Leszek Koltunski
               float row1, row2;
375 1ebc4767 Leszek Koltunski
               float x1 = rotated1.get0();
376
               float y1 = rotated1.get1();
377
               float z1 = rotated1.get2();
378
               float x2 = rotated2.get0();
379
               float y2 = rotated2.get1();
380
               float z2 = rotated2.get2();
381
382
               for(int i=0; i<NUM_AXIS; i++)
383
                 {
384 eb389a97 Leszek Koltunski
                 row1 = computeRow(x1,y1,z1,i);
385
                 row2 = computeRow(x2,y2,z2,i);
386
387 bb490017 Leszek Koltunski
                 if( (row1==0 && row2==0) || (row1==numLayers && row2==numLayers) ) return true;
388 1ebc4767 Leszek Koltunski
                 }
389
               return false;
390
391
      default: return false;  // edge or corner
392
      }
393
    }
394
395 f0336037 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
396 ee35e63c Leszek Koltunski
// only needed for solvers - there are no Pyraminx solvers ATM)
397 f0336037 Leszek Koltunski
398 20931cf6 Leszek Koltunski
  public String retObjectString()
399 f0336037 Leszek Koltunski
    {
400
    return "";
401
    }
402 6fd4a72c Leszek Koltunski
403
///////////////////////////////////////////////////////////////////////////////////////////////////
404
405
  public int getObjectName(int numLayers)
406
    {
407
    switch(numLayers)
408
      {
409
      case 3: return R.string.pyra3;
410
      case 4: return R.string.pyra4;
411
      case 5: return R.string.pyra5;
412
      }
413
    return R.string.pyra3;
414
    }
415
416
///////////////////////////////////////////////////////////////////////////////////////////////////
417
418
  public int getInventor(int numLayers)
419
    {
420
    switch(numLayers)
421
      {
422
      case 3: return R.string.pyra3_inventor;
423
      case 4: return R.string.pyra4_inventor;
424
      case 5: return R.string.pyra5_inventor;
425
      }
426
    return R.string.pyra3_inventor;
427
    }
428
429
///////////////////////////////////////////////////////////////////////////////////////////////////
430
431
  public int getComplexity(int numLayers)
432
    {
433
    switch(numLayers)
434
      {
435
      case 3: return 4;
436
      case 4: return 6;
437
      case 5: return 8;
438
      }
439
    return 4;
440
    }
441 e844c116 Leszek Koltunski
}