Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / TwistyHelicopter.java @ 596d62a4

1
///////////////////////////////////////////////////////////////////////////////////////////////////
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.helpers.FactoryCubit;
27
import org.distorted.helpers.FactorySticker;
28
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
import org.distorted.main.R;
36
import org.distorted.main.RubikSurfaceView;
37

    
38
import java.util.Random;
39

    
40
///////////////////////////////////////////////////////////////////////////////////////////////////
41

    
42
public class TwistyHelicopter extends TwistyObject
43
{
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
           COLOR_YELLOW, COLOR_WHITE,
60
           COLOR_BLUE  , COLOR_GREEN,
61
           COLOR_RED   , COLOR_ORANGE
62
         };
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
  private static final float DIST_CENTER = 0.50f;
97
  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 float[][] CENTERS = new float[][]
101
         {
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
             {  -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
         };
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
           { 0,2,5, 6,6,6 },
147
           { 4,0,3, 6,6,6 },
148
           { 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
  private static final int[] QUAT_INDICES =
186
      { 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
  private final double[][] VERTICES_CORNER = new double[][]
189
          {
190
            // TODO
191
          };
192

    
193
  private final int[][] VERT_INDEXES_CORNER = new int[][]
194
          {
195
            // TODO
196
          };
197

    
198
  private final double[][] VERTICES_FACE = new double[][]
199
          {
200
            // TODO
201
          };
202

    
203
  private final int[][] VERT_INDEXES_FACE = new int[][]
204
          {
205
            // TODO
206
          };
207

    
208
  private static MeshBase mCornerMesh, mFaceMesh;
209

    
210
///////////////////////////////////////////////////////////////////////////////////////////////////
211

    
212
  TwistyHelicopter(int size, Static4D quat, DistortedTexture texture,
213
                   MeshSquare mesh, DistortedEffects effects, int[][] moves, Resources res, int scrWidth)
214
    {
215
    super(size, size, quat, texture, mesh, effects, moves, ObjectList.HELI, res, scrWidth);
216
    }
217

    
218
///////////////////////////////////////////////////////////////////////////////////////////////////
219

    
220
  double[][] getVertices(int cubitType)
221
    {
222
     if( cubitType==0 )  // Corner
223
      {
224
      return VERTICES_CORNER;
225
      }
226
    if( cubitType==1 )  // Face
227
      {
228
      return VERTICES_FACE;
229
      }
230

    
231
    return null;
232
    }
233

    
234
///////////////////////////////////////////////////////////////////////////////////////////////////
235

    
236
  int[][] getVertIndexes(int cubitType)
237
    {
238
    if( cubitType==0 )  // Corner
239
      {
240
      return VERT_INDEXES_CORNER;
241
      }
242
    if( cubitType==1 )  // Face
243
      {
244
      return VERT_INDEXES_FACE;
245
      }
246

    
247
    return null;
248
    }
249

    
250
///////////////////////////////////////////////////////////////////////////////////////////////////
251

    
252
  int getNumCubitTypes(int numLayers)
253
    {
254
    return 1;
255
    }
256

    
257
///////////////////////////////////////////////////////////////////////////////////////////////////
258

    
259
  float getScreenRatio()
260
    {
261
    return 1.6f;
262
    }
263

    
264
///////////////////////////////////////////////////////////////////////////////////////////////////
265

    
266
  Static4D[] getQuats()
267
    {
268
    return QUATS;
269
    }
270

    
271
///////////////////////////////////////////////////////////////////////////////////////////////////
272

    
273
  boolean shouldResetTextureMaps()
274
    {
275
    return false;
276
    }
277

    
278
///////////////////////////////////////////////////////////////////////////////////////////////////
279

    
280
  int getNumFaces()
281
    {
282
    return FACE_COLORS.length;
283
    }
284

    
285
///////////////////////////////////////////////////////////////////////////////////////////////////
286

    
287
  int getNumStickerTypes(int numLayers)
288
    {
289
    return 1;
290
    }
291

    
292
///////////////////////////////////////////////////////////////////////////////////////////////////
293

    
294
  float[] getCuts(int size)
295
    {
296
    float[] cuts = new float[2];
297

    
298
    cuts[0] = -SQ2/4;
299
    cuts[1] = +SQ2/4;
300

    
301
    return cuts;
302
    }
303

    
304
///////////////////////////////////////////////////////////////////////////////////////////////////
305

    
306
  int getNumCubitFaces()
307
    {
308
    return FACES_PER_CUBIT;
309
    }
310

    
311
///////////////////////////////////////////////////////////////////////////////////////////////////
312

    
313
  float[][] getCubitPositions(int size)
314
    {
315
    return CENTERS;
316
    }
317

    
318
///////////////////////////////////////////////////////////////////////////////////////////////////
319

    
320
  MeshBase createCubitMesh(int cubit, int numLayers)
321
    {
322
    MeshBase mesh;
323

    
324
    if( cubit<8 )
325
      {
326
      if( mCornerMesh==null ) mCornerMesh = FactoryCubit.getInstance().createHelicopterCornerMesh();
327
      mesh = mCornerMesh.copy(true);
328
      }
329
    else
330
      {
331
      if( mFaceMesh==null ) mFaceMesh = FactoryCubit.getInstance().createHelicopterFaceMesh();
332
      mesh = mFaceMesh.copy(true);
333
      }
334

    
335
    int index = QUAT_INDICES[cubit];
336
    MatrixEffectQuaternion quat = new MatrixEffectQuaternion( QUATS[index], new Static3D(0,0,0) );
337
    mesh.apply(quat,0xffffffff,0);
338

    
339
    return mesh;
340
    }
341

    
342
///////////////////////////////////////////////////////////////////////////////////////////////////
343

    
344
  int getFaceColor(int cubit, int cubitface, int size)
345
    {
346
    return mFaceMap[cubit][cubitface];
347
    }
348

    
349
///////////////////////////////////////////////////////////////////////////////////////////////////
350

    
351
  void createFaceTexture(Canvas canvas, Paint paint, int face, int left, int top)
352
    {
353
    float R = 0.023f;
354
    float S = 0.035f;
355
    float E = 0.5f;
356
    float[] vertices = { -E+E/4,E/4, E/4,-E+E/4, E/4,E/4};
357

    
358
    FactorySticker factory = FactorySticker.getInstance();
359
    factory.drawRoundedPolygon(canvas, paint, left, top, vertices, S, FACE_COLORS[face], R);
360
    }
361

    
362
///////////////////////////////////////////////////////////////////////////////////////////////////
363

    
364
  float returnMultiplier()
365
    {
366
    return 2.0f;
367
    }
368

    
369
///////////////////////////////////////////////////////////////////////////////////////////////////
370

    
371
  float[] getRowChances(int numLayers)
372
    {
373
    float[] chances = new float[3];
374

    
375
    chances[0] = 0.5f;
376
    chances[1] = 0.5f;
377
    chances[2] = 1.0f;
378

    
379
    return chances;
380
    }
381

    
382
///////////////////////////////////////////////////////////////////////////////////////////////////
383
// PUBLIC API
384

    
385
  public Static3D[] getRotationAxis()
386
    {
387
    return ROT_AXIS;
388
    }
389

    
390
///////////////////////////////////////////////////////////////////////////////////////////////////
391

    
392
  public int getBasicAngle()
393
    {
394
    return 2;
395
    }
396

    
397
///////////////////////////////////////////////////////////////////////////////////////////////////
398

    
399
  public void randomizeNewScramble(int[][] scramble, Random rnd, int num)
400
    {
401
    if( num==0 )
402
      {
403
      scramble[num][0] = rnd.nextInt(ROTATION_AXIS.length);
404
      }
405
    else
406
      {
407
      int newVector = rnd.nextInt(ROTATION_AXIS.length-2);
408

    
409
      switch(scramble[num-1][0])
410
        {
411
        case  0:
412
        case  1: scramble[num][0] = newVector+2;
413
                 break;
414
        case  2:
415
        case  3: scramble[num][0] = (newVector==0 || newVector==1) ? newVector:newVector+2;
416
                 break;
417
        default: scramble[num][0] = newVector;
418
                 break;
419
        }
420
      }
421

    
422
    float rowFloat = rnd.nextFloat();
423

    
424
    for(int row=0; row<mRowChances.length; row++)
425
      {
426
      if( rowFloat<=mRowChances[row] )
427
        {
428
        scramble[num][1] = row;
429
        break;
430
        }
431
      }
432

    
433
    switch( rnd.nextInt(2) )
434
      {
435
      case 0: scramble[num][2] = -1; break;
436
      case 1: scramble[num][2] =  1; break;
437
      }
438
    }
439

    
440
///////////////////////////////////////////////////////////////////////////////////////////////////
441
// remember about the double cover or unit quaternions!
442

    
443
  private int mulQuat(int q1, int q2)
444
    {
445
    Static4D result = RubikSurfaceView.quatMultiply(QUATS[q1],QUATS[q2]);
446

    
447
    float rX = result.get0();
448
    float rY = result.get1();
449
    float rZ = result.get2();
450
    float rW = result.get3();
451

    
452
    final float MAX_ERROR = 0.1f;
453
    float dX,dY,dZ,dW;
454

    
455
    for(int i=0; i<QUATS.length; i++)
456
      {
457
      dX = QUATS[i].get0() - rX;
458
      dY = QUATS[i].get1() - rY;
459
      dZ = QUATS[i].get2() - rZ;
460
      dW = QUATS[i].get3() - rW;
461

    
462
      if( dX<MAX_ERROR && dX>-MAX_ERROR &&
463
          dY<MAX_ERROR && dY>-MAX_ERROR &&
464
          dZ<MAX_ERROR && dZ>-MAX_ERROR &&
465
          dW<MAX_ERROR && dW>-MAX_ERROR  ) return i;
466

    
467
      dX = QUATS[i].get0() + rX;
468
      dY = QUATS[i].get1() + rY;
469
      dZ = QUATS[i].get2() + rZ;
470
      dW = QUATS[i].get3() + rW;
471

    
472
      if( dX<MAX_ERROR && dX>-MAX_ERROR &&
473
          dY<MAX_ERROR && dY>-MAX_ERROR &&
474
          dZ<MAX_ERROR && dZ>-MAX_ERROR &&
475
          dW<MAX_ERROR && dW>-MAX_ERROR  ) return i;
476
      }
477

    
478
    return -1;
479
    }
480

    
481
///////////////////////////////////////////////////////////////////////////////////////////////////
482
// The Helicopter is solved if and only if:
483
//
484
// 1) all of its corner cubits are rotated with the same quat
485
// 2) all its face cubits are rotated with the same quat like the corner ones,
486
//    and optionally they also might be turned by a multiple of 90 degrees along
487
//    a vector perpendicular to the face they lie on.
488
//
489
// i.e.
490
// cubits  8, 9,10,11,12,13,14,15 - might be extra QUAT 1,8,9
491
// cubits 16,17,18,19,20,21,22,23 - might be extra QUAT 2,12,13
492
// cubits 24,25,26,27,28,29,30,31 - might be extra QUAT 3,14,15
493

    
494
  public boolean isSolved()
495
    {
496
    int q = CUBITS[0].mQuatIndex;
497

    
498
    if ( CUBITS[1].mQuatIndex == q &&
499
         CUBITS[2].mQuatIndex == q &&
500
         CUBITS[3].mQuatIndex == q &&
501
         CUBITS[4].mQuatIndex == q &&
502
         CUBITS[5].mQuatIndex == q &&
503
         CUBITS[6].mQuatIndex == q &&
504
         CUBITS[7].mQuatIndex == q  )
505
      {
506
      int q1 = mulQuat(q,1);
507
      int q2 = mulQuat(q,8);
508
      int q3 = mulQuat(q,9);
509

    
510
      for(int index=8; index<16; index++)
511
        {
512
        int qIndex = CUBITS[index].mQuatIndex;
513
        if( qIndex!=q && qIndex!=q1 && qIndex!=q2 && qIndex!=q3 ) return false;
514
        }
515

    
516
      q1 = mulQuat(q, 2);
517
      q2 = mulQuat(q,12);
518
      q3 = mulQuat(q,13);
519

    
520
      for(int index=16; index<24; index++)
521
        {
522
        int qIndex = CUBITS[index].mQuatIndex;
523
        if( qIndex!=q && qIndex!=q1 && qIndex!=q2 && qIndex!=q3 ) return false;
524
        }
525

    
526
      q1 = mulQuat(q, 3);
527
      q2 = mulQuat(q,14);
528
      q3 = mulQuat(q,15);
529

    
530
      for(int index=24; index<32; index++)
531
        {
532
        int qIndex = CUBITS[index].mQuatIndex;
533
        if( qIndex!=q && qIndex!=q1 && qIndex!=q2 && qIndex!=q3 ) return false;
534
        }
535

    
536
      return true;
537
      }
538

    
539
    return false;
540
    }
541

    
542
///////////////////////////////////////////////////////////////////////////////////////////////////
543
// only needed for solvers - there are no Helicopter solvers ATM)
544

    
545
  public String retObjectString()
546
    {
547
    return "";
548
    }
549

    
550
///////////////////////////////////////////////////////////////////////////////////////////////////
551

    
552
  public int getObjectName(int numLayers)
553
    {
554
    return R.string.heli3;
555
    }
556

    
557
///////////////////////////////////////////////////////////////////////////////////////////////////
558

    
559
  public int getInventor(int numLayers)
560
    {
561
    return R.string.heli3_inventor;
562
    }
563

    
564
///////////////////////////////////////////////////////////////////////////////////////////////////
565

    
566
  public int getComplexity(int numLayers)
567
    {
568
    return 8;
569
    }
570
}
(24-24/33)