Project

General

Profile

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

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

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