Project

General

Profile

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

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

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