Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / TwistyHelicopter.java @ 749ef882

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 749ef882 Leszek Koltunski
import org.distorted.helpers.FactoryCubit;
27
import org.distorted.helpers.FactorySticker;
28 ee35e63c Leszek Koltunski
import org.distorted.library.effect.MatrixEffectQuaternion;
29
import org.distorted.library.main.DistortedEffects;
30
import org.distorted.library.main.DistortedTexture;
31
import org.distorted.library.mesh.MeshBase;
32
import org.distorted.library.mesh.MeshSquare;
33
import org.distorted.library.type.Static3D;
34
import org.distorted.library.type.Static4D;
35 6fd4a72c Leszek Koltunski
import org.distorted.main.R;
36 ee35e63c Leszek Koltunski
import org.distorted.main.RubikSurfaceView;
37
38
import java.util.Random;
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 e6cf7283 Leszek Koltunski
  private static final float[][] CENTERS = new float[][]
101 ee35e63c Leszek Koltunski
         {
102 e6cf7283 Leszek Koltunski
             {   DIST_CORNER,   DIST_CORNER,   DIST_CORNER },
103
             {   DIST_CORNER,   DIST_CORNER,  -DIST_CORNER },
104
             {   DIST_CORNER,  -DIST_CORNER,   DIST_CORNER },
105
             {   DIST_CORNER,  -DIST_CORNER,  -DIST_CORNER },
106
             {  -DIST_CORNER,   DIST_CORNER,   DIST_CORNER },
107
             {  -DIST_CORNER,   DIST_CORNER,  -DIST_CORNER },
108
             {  -DIST_CORNER,  -DIST_CORNER,   DIST_CORNER },
109
             {  -DIST_CORNER,  -DIST_CORNER,  -DIST_CORNER },
110
111
             {   DIST_CENTER,     XY_CENTER,     XY_CENTER },
112
             {   DIST_CENTER,     XY_CENTER,    -XY_CENTER },
113
             {   DIST_CENTER,    -XY_CENTER,     XY_CENTER },
114
             {   DIST_CENTER,    -XY_CENTER,    -XY_CENTER },
115
116
             {  -DIST_CENTER,     XY_CENTER,     XY_CENTER },
117
             {  -DIST_CENTER,     XY_CENTER,    -XY_CENTER },
118
             {  -DIST_CENTER,    -XY_CENTER,     XY_CENTER },
119
             {  -DIST_CENTER,    -XY_CENTER,    -XY_CENTER },
120
121
             {   XY_CENTER  ,   DIST_CENTER,     XY_CENTER },
122
             {   XY_CENTER  ,   DIST_CENTER,    -XY_CENTER },
123
             {  -XY_CENTER  ,   DIST_CENTER,     XY_CENTER },
124
             {  -XY_CENTER  ,   DIST_CENTER,    -XY_CENTER },
125
126
             {   XY_CENTER  ,  -DIST_CENTER,     XY_CENTER },
127
             {   XY_CENTER  ,  -DIST_CENTER,    -XY_CENTER },
128
             {  -XY_CENTER  ,  -DIST_CENTER,     XY_CENTER },
129
             {  -XY_CENTER  ,  -DIST_CENTER,    -XY_CENTER },
130
131
             {   XY_CENTER  ,     XY_CENTER,   DIST_CENTER },
132
             {   XY_CENTER  ,    -XY_CENTER,   DIST_CENTER },
133
             {  -XY_CENTER  ,     XY_CENTER,   DIST_CENTER },
134
             {  -XY_CENTER  ,    -XY_CENTER,   DIST_CENTER },
135
136
             {   XY_CENTER  ,     XY_CENTER,  -DIST_CENTER },
137
             {   XY_CENTER  ,    -XY_CENTER,  -DIST_CENTER },
138
             {  -XY_CENTER  ,     XY_CENTER,  -DIST_CENTER },
139
             {  -XY_CENTER  ,    -XY_CENTER,  -DIST_CENTER },
140 ee35e63c Leszek Koltunski
         };
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 db875721 Leszek Koltunski
    super(size, size, 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 e6cf7283 Leszek Koltunski
  float[][] getCubitPositions(int size)
255 ee35e63c Leszek Koltunski
    {
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 5043d5d0 Leszek Koltunski
  public void randomizeNewScramble(int[][] scramble, Random rnd, int num)
341 ee35e63c Leszek Koltunski
    {
342 5043d5d0 Leszek Koltunski
    if( num==0 )
343 ee35e63c Leszek Koltunski
      {
344 5043d5d0 Leszek Koltunski
      scramble[num][0] = rnd.nextInt(ROTATION_AXIS.length);
345 ee35e63c Leszek Koltunski
      }
346
    else
347
      {
348 bbc6471c Leszek Koltunski
      int newVector = rnd.nextInt(ROTATION_AXIS.length-2);
349 ee35e63c Leszek Koltunski
350 5043d5d0 Leszek Koltunski
      switch(scramble[num-1][0])
351 ee35e63c Leszek Koltunski
        {
352
        case  0:
353 5043d5d0 Leszek Koltunski
        case  1: scramble[num][0] = newVector+2;
354 bbc6471c Leszek Koltunski
                 break;
355 ee35e63c Leszek Koltunski
        case  2:
356 5043d5d0 Leszek Koltunski
        case  3: scramble[num][0] = (newVector==0 || newVector==1) ? newVector:newVector+2;
357 bbc6471c Leszek Koltunski
                 break;
358 5043d5d0 Leszek Koltunski
        default: scramble[num][0] = newVector;
359 bbc6471c Leszek Koltunski
                 break;
360 ee35e63c Leszek Koltunski
        }
361
      }
362
363
    float rowFloat = rnd.nextFloat();
364
365
    for(int row=0; row<mRowChances.length; row++)
366
      {
367 bbc6471c Leszek Koltunski
      if( rowFloat<=mRowChances[row] )
368
        {
369 5043d5d0 Leszek Koltunski
        scramble[num][1] = row;
370 bbc6471c Leszek Koltunski
        break;
371
        }
372 ee35e63c Leszek Koltunski
      }
373
374 5043d5d0 Leszek Koltunski
    switch( rnd.nextInt(2) )
375
      {
376
      case 0: scramble[num][2] = -1; break;
377
      case 1: scramble[num][2] =  1; break;
378
      }
379 ee35e63c Leszek Koltunski
    }
380
381
///////////////////////////////////////////////////////////////////////////////////////////////////
382
// remember about the double cover or unit quaternions!
383
384
  private int mulQuat(int q1, int q2)
385
    {
386
    Static4D result = RubikSurfaceView.quatMultiply(QUATS[q1],QUATS[q2]);
387
388
    float rX = result.get0();
389
    float rY = result.get1();
390
    float rZ = result.get2();
391
    float rW = result.get3();
392
393
    final float MAX_ERROR = 0.1f;
394
    float dX,dY,dZ,dW;
395
396
    for(int i=0; i<QUATS.length; i++)
397
      {
398
      dX = QUATS[i].get0() - rX;
399
      dY = QUATS[i].get1() - rY;
400
      dZ = QUATS[i].get2() - rZ;
401
      dW = QUATS[i].get3() - rW;
402
403
      if( dX<MAX_ERROR && dX>-MAX_ERROR &&
404
          dY<MAX_ERROR && dY>-MAX_ERROR &&
405
          dZ<MAX_ERROR && dZ>-MAX_ERROR &&
406
          dW<MAX_ERROR && dW>-MAX_ERROR  ) return i;
407
408
      dX = QUATS[i].get0() + rX;
409
      dY = QUATS[i].get1() + rY;
410
      dZ = QUATS[i].get2() + rZ;
411
      dW = QUATS[i].get3() + rW;
412
413
      if( dX<MAX_ERROR && dX>-MAX_ERROR &&
414
          dY<MAX_ERROR && dY>-MAX_ERROR &&
415
          dZ<MAX_ERROR && dZ>-MAX_ERROR &&
416
          dW<MAX_ERROR && dW>-MAX_ERROR  ) return i;
417
      }
418
419
    return -1;
420
    }
421
422
///////////////////////////////////////////////////////////////////////////////////////////////////
423
// The Helicopter is solved if and only if:
424
//
425
// 1) all of its corner cubits are rotated with the same quat
426
// 2) all its face cubits are rotated with the same quat like the corner ones,
427
//    and optionally they also might be turned by a multiple of 90 degrees along
428
//    a vector perpendicular to the face they lie on.
429
//
430
// i.e.
431
// cubits  8, 9,10,11,12,13,14,15 - might be extra QUAT 1,8,9
432
// cubits 16,17,18,19,20,21,22,23 - might be extra QUAT 2,12,13
433
// cubits 24,25,26,27,28,29,30,31 - might be extra QUAT 3,14,15
434
435
  public boolean isSolved()
436
    {
437
    int q = CUBITS[0].mQuatIndex;
438
439
    if ( CUBITS[1].mQuatIndex == q &&
440
         CUBITS[2].mQuatIndex == q &&
441
         CUBITS[3].mQuatIndex == q &&
442
         CUBITS[4].mQuatIndex == q &&
443
         CUBITS[5].mQuatIndex == q &&
444
         CUBITS[6].mQuatIndex == q &&
445
         CUBITS[7].mQuatIndex == q  )
446
      {
447
      int q1 = mulQuat(q,1);
448
      int q2 = mulQuat(q,8);
449
      int q3 = mulQuat(q,9);
450
451
      for(int index=8; index<16; index++)
452
        {
453
        int qIndex = CUBITS[index].mQuatIndex;
454
        if( qIndex!=q && qIndex!=q1 && qIndex!=q2 && qIndex!=q3 ) return false;
455
        }
456
457
      q1 = mulQuat(q, 2);
458
      q2 = mulQuat(q,12);
459
      q3 = mulQuat(q,13);
460
461
      for(int index=16; index<24; index++)
462
        {
463
        int qIndex = CUBITS[index].mQuatIndex;
464
        if( qIndex!=q && qIndex!=q1 && qIndex!=q2 && qIndex!=q3 ) return false;
465
        }
466
467
      q1 = mulQuat(q, 3);
468
      q2 = mulQuat(q,14);
469
      q3 = mulQuat(q,15);
470
471
      for(int index=24; index<32; index++)
472
        {
473
        int qIndex = CUBITS[index].mQuatIndex;
474
        if( qIndex!=q && qIndex!=q1 && qIndex!=q2 && qIndex!=q3 ) return false;
475
        }
476
477
      return true;
478
      }
479
480
    return false;
481
    }
482
483
///////////////////////////////////////////////////////////////////////////////////////////////////
484
// only needed for solvers - there are no Helicopter solvers ATM)
485
486
  public String retObjectString()
487
    {
488
    return "";
489
    }
490 6fd4a72c Leszek Koltunski
491
///////////////////////////////////////////////////////////////////////////////////////////////////
492
493
  public int getObjectName(int numLayers)
494
    {
495
    return R.string.heli3;
496
    }
497
498
///////////////////////////////////////////////////////////////////////////////////////////////////
499
500
  public int getInventor(int numLayers)
501
    {
502
    return R.string.heli3_inventor;
503
    }
504
505
///////////////////////////////////////////////////////////////////////////////////////////////////
506
507
  public int getComplexity(int numLayers)
508
    {
509
    return 8;
510
    }
511 ee35e63c Leszek Koltunski
}