Project

General

Profile

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

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

1 ee35e63c Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2020 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.library.effect.MatrixEffectQuaternion;
27
import org.distorted.library.main.DistortedEffects;
28
import org.distorted.library.main.DistortedTexture;
29
import org.distorted.library.mesh.MeshBase;
30
import org.distorted.library.mesh.MeshSquare;
31
import org.distorted.library.type.Static3D;
32
import org.distorted.library.type.Static4D;
33 6fd4a72c Leszek Koltunski
import org.distorted.main.R;
34 ee35e63c Leszek Koltunski
import org.distorted.main.RubikSurfaceView;
35
36
import java.util.Random;
37
38
import static org.distorted.effects.scramble.ScrambleEffect.START_AXIS;
39
40
///////////////////////////////////////////////////////////////////////////////////////////////////
41
42 9c2f0c91 Leszek Koltunski
public class TwistyHelicopter extends TwistyObject
43 ee35e63c Leszek Koltunski
{
44
  private static final int FACES_PER_CUBIT =6;
45
46
  // the six rotation axis of a Helicopter. Must be normalized.
47
  static final Static3D[] ROT_AXIS = new Static3D[]
48
         {
49
           new Static3D(     0, +SQ2/2, -SQ2/2),
50
           new Static3D(     0, -SQ2/2, -SQ2/2),
51
           new Static3D(+SQ2/2,      0, -SQ2/2),
52
           new Static3D(-SQ2/2,      0, -SQ2/2),
53
           new Static3D(+SQ2/2, -SQ2/2,      0),
54
           new Static3D(-SQ2/2, -SQ2/2,      0)
55
         };
56
57
  private static final int[] FACE_COLORS = new int[]
58
         {
59 ece1b58d Leszek Koltunski
           COLOR_YELLOW, COLOR_WHITE,
60
           COLOR_BLUE  , COLOR_GREEN,
61 323b217c Leszek Koltunski
           COLOR_RED   , COLOR_ORANGE
62 ee35e63c Leszek Koltunski
         };
63
64
  // All legal rotation quats of a HELICOPTER (same as the Cube!)
65
  private static final Static4D[] QUATS = new Static4D[]
66
         {
67
           new Static4D( 0.00f,  0.00f,  0.00f,  1.00f ),
68
           new Static4D( 1.00f,  0.00f,  0.00f,  0.00f ),
69
           new Static4D( 0.00f,  1.00f,  0.00f,  0.00f ),
70
           new Static4D( 0.00f,  0.00f,  1.00f,  0.00f ),
71
72
           new Static4D( SQ2/2,  SQ2/2,  0.00f,  0.00f ),
73
           new Static4D( SQ2/2, -SQ2/2,  0.00f,  0.00f ),
74
           new Static4D( SQ2/2,  0.00f,  SQ2/2,  0.00f ),
75
           new Static4D( SQ2/2,  0.00f, -SQ2/2,  0.00f ),
76
           new Static4D( SQ2/2,  0.00f,  0.00f,  SQ2/2 ),
77
           new Static4D( SQ2/2,  0.00f,  0.00f, -SQ2/2 ),
78
           new Static4D( 0.00f,  SQ2/2,  SQ2/2,  0.00f ),
79
           new Static4D( 0.00f,  SQ2/2, -SQ2/2,  0.00f ),
80
           new Static4D( 0.00f,  SQ2/2,  0.00f,  SQ2/2 ),
81
           new Static4D( 0.00f,  SQ2/2,  0.00f, -SQ2/2 ),
82
           new Static4D( 0.00f,  0.00f,  SQ2/2,  SQ2/2 ),
83
           new Static4D( 0.00f,  0.00f,  SQ2/2, -SQ2/2 ),
84
85
           new Static4D( 0.50f,  0.50f,  0.50f,  0.50f ),
86
           new Static4D( 0.50f,  0.50f,  0.50f, -0.50f ),
87
           new Static4D( 0.50f,  0.50f, -0.50f,  0.50f ),
88
           new Static4D( 0.50f,  0.50f, -0.50f, -0.50f ),
89
           new Static4D( 0.50f, -0.50f,  0.50f,  0.50f ),
90
           new Static4D( 0.50f, -0.50f,  0.50f, -0.50f ),
91
           new Static4D( 0.50f, -0.50f, -0.50f,  0.50f ),
92
           new Static4D( 0.50f, -0.50f, -0.50f, -0.50f )
93
         };
94
95
  private static final float DIST_CORNER = 0.50f;
96 b0a56742 Leszek Koltunski
  private static final float DIST_CENTER = 0.50f;
97 ee35e63c Leszek Koltunski
  private static final float XY_CENTER   = DIST_CORNER/3;
98
99
  // centers of the 8 corners + 6*4 face triangles ( i.e. of the all 32 cubits)
100
  private static final Static3D[] CENTERS = new Static3D[]
101
         {
102
           new Static3D(   DIST_CORNER,   DIST_CORNER,   DIST_CORNER ),
103
           new Static3D(   DIST_CORNER,   DIST_CORNER,  -DIST_CORNER ),
104
           new Static3D(   DIST_CORNER,  -DIST_CORNER,   DIST_CORNER ),
105
           new Static3D(   DIST_CORNER,  -DIST_CORNER,  -DIST_CORNER ),
106
           new Static3D(  -DIST_CORNER,   DIST_CORNER,   DIST_CORNER ),
107
           new Static3D(  -DIST_CORNER,   DIST_CORNER,  -DIST_CORNER ),
108
           new Static3D(  -DIST_CORNER,  -DIST_CORNER,   DIST_CORNER ),
109
           new Static3D(  -DIST_CORNER,  -DIST_CORNER,  -DIST_CORNER ),
110
111
           new Static3D(   DIST_CENTER,     XY_CENTER,     XY_CENTER ),
112
           new Static3D(   DIST_CENTER,     XY_CENTER,    -XY_CENTER ),
113
           new Static3D(   DIST_CENTER,    -XY_CENTER,     XY_CENTER ),
114
           new Static3D(   DIST_CENTER,    -XY_CENTER,    -XY_CENTER ),
115
116
           new Static3D(  -DIST_CENTER,     XY_CENTER,     XY_CENTER ),
117
           new Static3D(  -DIST_CENTER,     XY_CENTER,    -XY_CENTER ),
118
           new Static3D(  -DIST_CENTER,    -XY_CENTER,     XY_CENTER ),
119
           new Static3D(  -DIST_CENTER,    -XY_CENTER,    -XY_CENTER ),
120
121
           new Static3D(   XY_CENTER  ,   DIST_CENTER,     XY_CENTER ),
122
           new Static3D(   XY_CENTER  ,   DIST_CENTER,    -XY_CENTER ),
123
           new Static3D(  -XY_CENTER  ,   DIST_CENTER,     XY_CENTER ),
124
           new Static3D(  -XY_CENTER  ,   DIST_CENTER,    -XY_CENTER ),
125
126
           new Static3D(   XY_CENTER  ,  -DIST_CENTER,     XY_CENTER ),
127
           new Static3D(   XY_CENTER  ,  -DIST_CENTER,    -XY_CENTER ),
128
           new Static3D(  -XY_CENTER  ,  -DIST_CENTER,     XY_CENTER ),
129
           new Static3D(  -XY_CENTER  ,  -DIST_CENTER,    -XY_CENTER ),
130
131
           new Static3D(   XY_CENTER  ,     XY_CENTER,   DIST_CENTER ),
132
           new Static3D(   XY_CENTER  ,    -XY_CENTER,   DIST_CENTER ),
133
           new Static3D(  -XY_CENTER  ,     XY_CENTER,   DIST_CENTER ),
134
           new Static3D(  -XY_CENTER  ,    -XY_CENTER,   DIST_CENTER ),
135
136
           new Static3D(   XY_CENTER  ,     XY_CENTER,  -DIST_CENTER ),
137
           new Static3D(   XY_CENTER  ,    -XY_CENTER,  -DIST_CENTER ),
138
           new Static3D(  -XY_CENTER  ,     XY_CENTER,  -DIST_CENTER ),
139
           new Static3D(  -XY_CENTER  ,    -XY_CENTER,  -DIST_CENTER ),
140
         };
141
142
  // Colors of the faces of cubits. Each cubit has 6 faces
143
  private static final int[][] mFaceMap = new int[][]
144
         {
145
           { 4,2,0, 6,6,6 },
146 20a0214b Leszek Koltunski
           { 0,2,5, 6,6,6 },
147
           { 4,0,3, 6,6,6 },
148 ee35e63c Leszek Koltunski
           { 5,3,0, 6,6,6 },
149
           { 1,2,4, 6,6,6 },
150
           { 5,2,1, 6,6,6 },
151
           { 4,3,1, 6,6,6 },
152
           { 1,3,5, 6,6,6 },
153
154
           { 0 , 6,6,6,6,6 },
155
           { 0 , 6,6,6,6,6 },
156
           { 0 , 6,6,6,6,6 },
157
           { 0 , 6,6,6,6,6 },
158
159
           { 1 , 6,6,6,6,6 },
160
           { 1 , 6,6,6,6,6 },
161
           { 1 , 6,6,6,6,6 },
162
           { 1 , 6,6,6,6,6 },
163
164
           { 2 , 6,6,6,6,6 },
165
           { 2 , 6,6,6,6,6 },
166
           { 2 , 6,6,6,6,6 },
167
           { 2 , 6,6,6,6,6 },
168
169
           { 3 , 6,6,6,6,6 },
170
           { 3 , 6,6,6,6,6 },
171
           { 3 , 6,6,6,6,6 },
172
           { 3 , 6,6,6,6,6 },
173
174
           { 4 , 6,6,6,6,6 },
175
           { 4 , 6,6,6,6,6 },
176
           { 4 , 6,6,6,6,6 },
177
           { 4 , 6,6,6,6,6 },
178
179
           { 5 , 6,6,6,6,6 },
180
           { 5 , 6,6,6,6,6 },
181
           { 5 , 6,6,6,6,6 },
182
           { 5 , 6,6,6,6,6 },
183
         };
184
185 a64e07d0 Leszek Koltunski
  private static final int[] QUAT_INDICES =
186 20a0214b Leszek Koltunski
      { 0,13,14,1,12,2,3,7,20,6,13,17,7,23,18,12,22,10,8,16,11,21,19,9,3,15,14,0,5,2,1,4 };
187
188 ee35e63c Leszek Koltunski
  private static MeshBase mCornerMesh, mFaceMesh;
189
190
///////////////////////////////////////////////////////////////////////////////////////////////////
191
192 9c2f0c91 Leszek Koltunski
  TwistyHelicopter(int size, Static4D quat, DistortedTexture texture,
193
                   MeshSquare mesh, DistortedEffects effects, int[][] moves, Resources res, int scrWidth)
194 ee35e63c Leszek Koltunski
    {
195 d99f3a48 Leszek Koltunski
    super(size, size, 60, quat, texture, mesh, effects, moves, ObjectList.HELI, res, scrWidth);
196 ee35e63c Leszek Koltunski
    }
197
198
///////////////////////////////////////////////////////////////////////////////////////////////////
199
200
  float getScreenRatio()
201
    {
202 e06e1b7e Leszek Koltunski
    return 1.6f;
203 ee35e63c Leszek Koltunski
    }
204
205
///////////////////////////////////////////////////////////////////////////////////////////////////
206
207
  Static4D[] getQuats()
208
    {
209
    return QUATS;
210
    }
211
212 eaee1ddc Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
213
214
  boolean shouldResetTextureMaps()
215
    {
216
    return false;
217
    }
218
219 ee35e63c Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
220
221
  int getNumFaces()
222
    {
223
    return FACE_COLORS.length;
224
    }
225
226
///////////////////////////////////////////////////////////////////////////////////////////////////
227
228 a64e07d0 Leszek Koltunski
  int getNumStickerTypes(int numLayers)
229 ee35e63c Leszek Koltunski
    {
230
    return 1;
231
    }
232
233 7403cdfa Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
234
235 a97e02b7 Leszek Koltunski
  float[] getCuts(int size)
236 7403cdfa Leszek Koltunski
    {
237 a97e02b7 Leszek Koltunski
    float[] cuts = new float[2];
238
239
    cuts[0] = -SQ2/4;
240
    cuts[1] = +SQ2/4;
241
242
    return cuts;
243 7403cdfa Leszek Koltunski
    }
244
245 ee35e63c Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
246
247
  int getNumCubitFaces()
248
    {
249
    return FACES_PER_CUBIT;
250
    }
251
252
///////////////////////////////////////////////////////////////////////////////////////////////////
253
254
  Static3D[] getCubitPositions(int size)
255
    {
256
    return CENTERS;
257
    }
258
259
///////////////////////////////////////////////////////////////////////////////////////////////////
260
261 a64e07d0 Leszek Koltunski
  MeshBase createCubitMesh(int cubit, int numLayers)
262 ee35e63c Leszek Koltunski
    {
263
    MeshBase mesh;
264
265
    if( cubit<8 )
266
      {
267 b89898c5 Leszek Koltunski
      if( mCornerMesh==null ) mCornerMesh = FactoryCubit.getInstance().createHelicopterCornerMesh();
268 ee35e63c Leszek Koltunski
      mesh = mCornerMesh.copy(true);
269
      }
270
    else
271
      {
272 b89898c5 Leszek Koltunski
      if( mFaceMesh==null ) mFaceMesh = FactoryCubit.getInstance().createHelicopterFaceMesh();
273 ee35e63c Leszek Koltunski
      mesh = mFaceMesh.copy(true);
274
      }
275
276 20a0214b Leszek Koltunski
    int index = QUAT_INDICES[cubit];
277 ee35e63c Leszek Koltunski
    MatrixEffectQuaternion quat = new MatrixEffectQuaternion( QUATS[index], new Static3D(0,0,0) );
278
    mesh.apply(quat,0xffffffff,0);
279
280
    return mesh;
281
    }
282
283
///////////////////////////////////////////////////////////////////////////////////////////////////
284
285
  int getFaceColor(int cubit, int cubitface, int size)
286
    {
287
    return mFaceMap[cubit][cubitface];
288
    }
289
290
///////////////////////////////////////////////////////////////////////////////////////////////////
291
292 ae755eda Leszek Koltunski
  void createFaceTexture(Canvas canvas, Paint paint, int face, int left, int top)
293 ee35e63c Leszek Koltunski
    {
294 e06e1b7e Leszek Koltunski
    float R = 0.023f;
295 76c2bd07 Leszek Koltunski
    float S = 0.035f;
296
    float E = 0.5f;
297
    float[] vertices = { -E+E/4,E/4, E/4,-E+E/4, E/4,E/4};
298 ee35e63c Leszek Koltunski
299 b89898c5 Leszek Koltunski
    FactorySticker factory = FactorySticker.getInstance();
300 ae755eda Leszek Koltunski
    factory.drawRoundedPolygon(canvas, paint, left, top, vertices, S, FACE_COLORS[face], R);
301 ee35e63c Leszek Koltunski
    }
302
303
///////////////////////////////////////////////////////////////////////////////////////////////////
304
305
  float returnMultiplier()
306
    {
307
    return 2.0f;
308
    }
309
310
///////////////////////////////////////////////////////////////////////////////////////////////////
311
312 a64e07d0 Leszek Koltunski
  float[] getRowChances(int numLayers)
313 ee35e63c Leszek Koltunski
    {
314 475cbfe7 Leszek Koltunski
    float[] chances = new float[3];
315 ee35e63c Leszek Koltunski
316
    chances[0] = 0.5f;
317
    chances[1] = 0.5f;
318 475cbfe7 Leszek Koltunski
    chances[2] = 1.0f;
319 ee35e63c Leszek Koltunski
320
    return chances;
321
    }
322
323
///////////////////////////////////////////////////////////////////////////////////////////////////
324
// PUBLIC API
325
326
  public Static3D[] getRotationAxis()
327
    {
328
    return ROT_AXIS;
329
    }
330
331
///////////////////////////////////////////////////////////////////////////////////////////////////
332
333
  public int getBasicAngle()
334
    {
335
    return 2;
336
    }
337
338
///////////////////////////////////////////////////////////////////////////////////////////////////
339
340
  public int randomizeNewRotAxis(Random rnd, int oldRotAxis)
341
    {
342
    int numAxis = ROTATION_AXIS.length;
343
344
    if( oldRotAxis == START_AXIS )
345
      {
346
      return rnd.nextInt(numAxis);
347
      }
348
    else
349
      {
350
      int newVector = rnd.nextInt(numAxis-2);
351
352
      switch(oldRotAxis)
353
        {
354
        case  0:
355
        case  1: return newVector+2;
356
        case  2:
357
        case  3: return (newVector==0 || newVector==1) ? newVector:newVector+2;
358
        default: return newVector;
359
        }
360
      }
361
    }
362
363
///////////////////////////////////////////////////////////////////////////////////////////////////
364
365
  public int randomizeNewRow(Random rnd, int oldRotAxis, int oldRow, int newRotAxis)
366
    {
367
    float rowFloat = rnd.nextFloat();
368
369
    for(int row=0; row<mRowChances.length; row++)
370
      {
371
      if( rowFloat<=mRowChances[row] ) return row;
372
      }
373
374
    return 0;
375
    }
376
377
///////////////////////////////////////////////////////////////////////////////////////////////////
378
// remember about the double cover or unit quaternions!
379
380
  private int mulQuat(int q1, int q2)
381
    {
382
    Static4D result = RubikSurfaceView.quatMultiply(QUATS[q1],QUATS[q2]);
383
384
    float rX = result.get0();
385
    float rY = result.get1();
386
    float rZ = result.get2();
387
    float rW = result.get3();
388
389
    final float MAX_ERROR = 0.1f;
390
    float dX,dY,dZ,dW;
391
392
    for(int i=0; i<QUATS.length; i++)
393
      {
394
      dX = QUATS[i].get0() - rX;
395
      dY = QUATS[i].get1() - rY;
396
      dZ = QUATS[i].get2() - rZ;
397
      dW = QUATS[i].get3() - rW;
398
399
      if( dX<MAX_ERROR && dX>-MAX_ERROR &&
400
          dY<MAX_ERROR && dY>-MAX_ERROR &&
401
          dZ<MAX_ERROR && dZ>-MAX_ERROR &&
402
          dW<MAX_ERROR && dW>-MAX_ERROR  ) return i;
403
404
      dX = QUATS[i].get0() + rX;
405
      dY = QUATS[i].get1() + rY;
406
      dZ = QUATS[i].get2() + rZ;
407
      dW = QUATS[i].get3() + rW;
408
409
      if( dX<MAX_ERROR && dX>-MAX_ERROR &&
410
          dY<MAX_ERROR && dY>-MAX_ERROR &&
411
          dZ<MAX_ERROR && dZ>-MAX_ERROR &&
412
          dW<MAX_ERROR && dW>-MAX_ERROR  ) return i;
413
      }
414
415
    return -1;
416
    }
417
418
///////////////////////////////////////////////////////////////////////////////////////////////////
419
// The Helicopter is solved if and only if:
420
//
421
// 1) all of its corner cubits are rotated with the same quat
422
// 2) all its face cubits are rotated with the same quat like the corner ones,
423
//    and optionally they also might be turned by a multiple of 90 degrees along
424
//    a vector perpendicular to the face they lie on.
425
//
426
// i.e.
427
// cubits  8, 9,10,11,12,13,14,15 - might be extra QUAT 1,8,9
428
// cubits 16,17,18,19,20,21,22,23 - might be extra QUAT 2,12,13
429
// cubits 24,25,26,27,28,29,30,31 - might be extra QUAT 3,14,15
430
431
  public boolean isSolved()
432
    {
433
    int q = CUBITS[0].mQuatIndex;
434
435
    if ( CUBITS[1].mQuatIndex == q &&
436
         CUBITS[2].mQuatIndex == q &&
437
         CUBITS[3].mQuatIndex == q &&
438
         CUBITS[4].mQuatIndex == q &&
439
         CUBITS[5].mQuatIndex == q &&
440
         CUBITS[6].mQuatIndex == q &&
441
         CUBITS[7].mQuatIndex == q  )
442
      {
443
      int q1 = mulQuat(q,1);
444
      int q2 = mulQuat(q,8);
445
      int q3 = mulQuat(q,9);
446
447
      for(int index=8; index<16; index++)
448
        {
449
        int qIndex = CUBITS[index].mQuatIndex;
450
        if( qIndex!=q && qIndex!=q1 && qIndex!=q2 && qIndex!=q3 ) return false;
451
        }
452
453
      q1 = mulQuat(q, 2);
454
      q2 = mulQuat(q,12);
455
      q3 = mulQuat(q,13);
456
457
      for(int index=16; index<24; index++)
458
        {
459
        int qIndex = CUBITS[index].mQuatIndex;
460
        if( qIndex!=q && qIndex!=q1 && qIndex!=q2 && qIndex!=q3 ) return false;
461
        }
462
463
      q1 = mulQuat(q, 3);
464
      q2 = mulQuat(q,14);
465
      q3 = mulQuat(q,15);
466
467
      for(int index=24; index<32; index++)
468
        {
469
        int qIndex = CUBITS[index].mQuatIndex;
470
        if( qIndex!=q && qIndex!=q1 && qIndex!=q2 && qIndex!=q3 ) return false;
471
        }
472
473
      return true;
474
      }
475
476
    return false;
477
    }
478
479
///////////////////////////////////////////////////////////////////////////////////////////////////
480
// only needed for solvers - there are no Helicopter solvers ATM)
481
482
  public String retObjectString()
483
    {
484
    return "";
485
    }
486 6fd4a72c Leszek Koltunski
487
///////////////////////////////////////////////////////////////////////////////////////////////////
488
489
  public int getObjectName(int numLayers)
490
    {
491
    return R.string.heli3;
492
    }
493
494
///////////////////////////////////////////////////////////////////////////////////////////////////
495
496
  public int getInventor(int numLayers)
497
    {
498
    return R.string.heli3_inventor;
499
    }
500
501
///////////////////////////////////////////////////////////////////////////////////////////////////
502
503
  public int getComplexity(int numLayers)
504
    {
505
    return 8;
506
    }
507 ee35e63c Leszek Koltunski
}