Project

General

Profile

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

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

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

    
24
import org.distorted.helpers.FactoryCubit;
25
import org.distorted.helpers.ObjectSticker;
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
import org.distorted.main.R;
34

    
35
import java.util.Random;
36

    
37
///////////////////////////////////////////////////////////////////////////////////////////////////
38

    
39
public class TwistyHelicopter extends TwistyObject
40
{
41
  private static final int FACES_PER_CUBIT =6;
42

    
43
  // the six rotation axis of a Helicopter. Must be normalized.
44
  static final Static3D[] ROT_AXIS = new Static3D[]
45
         {
46
           new Static3D(     0, +SQ2/2, -SQ2/2),
47
           new Static3D(     0, -SQ2/2, -SQ2/2),
48
           new Static3D(+SQ2/2,      0, -SQ2/2),
49
           new Static3D(-SQ2/2,      0, -SQ2/2),
50
           new Static3D(+SQ2/2, -SQ2/2,      0),
51
           new Static3D(-SQ2/2, -SQ2/2,      0)
52
         };
53

    
54
  private static final int[] BASIC_ANGLE = new int[] { 2,2,2,2,2,2 };
55

    
56
  private static final int[] FACE_COLORS = new int[]
57
         {
58
           COLOR_YELLOW, COLOR_WHITE,
59
           COLOR_BLUE  , COLOR_GREEN,
60
           COLOR_RED   , COLOR_ORANGE
61
         };
62

    
63
  // All legal rotation quats of a HELICOPTER (same as the Cube!)
64
  private static final Static4D[] QUATS = new Static4D[]
65
         {
66
           new Static4D( 0.00f,  0.00f,  0.00f,  1.00f ),
67
           new Static4D( 1.00f,  0.00f,  0.00f,  0.00f ),
68
           new Static4D( 0.00f,  1.00f,  0.00f,  0.00f ),
69
           new Static4D( 0.00f,  0.00f,  1.00f,  0.00f ),
70

    
71
           new Static4D( SQ2/2,  SQ2/2,  0.00f,  0.00f ),
72
           new Static4D( SQ2/2, -SQ2/2,  0.00f,  0.00f ),
73
           new Static4D( SQ2/2,  0.00f,  SQ2/2,  0.00f ),
74
           new Static4D( SQ2/2,  0.00f, -SQ2/2,  0.00f ),
75
           new Static4D( SQ2/2,  0.00f,  0.00f,  SQ2/2 ),
76
           new Static4D( SQ2/2,  0.00f,  0.00f, -SQ2/2 ),
77
           new Static4D( 0.00f,  SQ2/2,  SQ2/2,  0.00f ),
78
           new Static4D( 0.00f,  SQ2/2, -SQ2/2,  0.00f ),
79
           new Static4D( 0.00f,  SQ2/2,  0.00f,  SQ2/2 ),
80
           new Static4D( 0.00f,  SQ2/2,  0.00f, -SQ2/2 ),
81
           new Static4D( 0.00f,  0.00f,  SQ2/2,  SQ2/2 ),
82
           new Static4D( 0.00f,  0.00f,  SQ2/2, -SQ2/2 ),
83

    
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
           new Static4D( 0.50f, -0.50f, -0.50f, -0.50f )
92
         };
93

    
94
  private static final float DIST_CORNER = 0.50f;
95
  private static final float DIST_CENTER = 0.50f;
96
  private static final float XY_CENTER   = DIST_CORNER/3;
97

    
98
  // centers of the 8 corners + 6*4 face triangles ( i.e. of the all 32 cubits)
99
  private static final float[][] CENTERS = new float[][]
100
         {
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
             {  -DIST_CORNER,  -DIST_CORNER,  -DIST_CORNER },
109

    
110
             {   DIST_CENTER,     XY_CENTER,     XY_CENTER },
111
             {   DIST_CENTER,     XY_CENTER,    -XY_CENTER },
112
             {   DIST_CENTER,    -XY_CENTER,     XY_CENTER },
113
             {   DIST_CENTER,    -XY_CENTER,    -XY_CENTER },
114

    
115
             {  -DIST_CENTER,     XY_CENTER,     XY_CENTER },
116
             {  -DIST_CENTER,     XY_CENTER,    -XY_CENTER },
117
             {  -DIST_CENTER,    -XY_CENTER,     XY_CENTER },
118
             {  -DIST_CENTER,    -XY_CENTER,    -XY_CENTER },
119

    
120
             {   XY_CENTER  ,   DIST_CENTER,     XY_CENTER },
121
             {   XY_CENTER  ,   DIST_CENTER,    -XY_CENTER },
122
             {  -XY_CENTER  ,   DIST_CENTER,     XY_CENTER },
123
             {  -XY_CENTER  ,   DIST_CENTER,    -XY_CENTER },
124

    
125
             {   XY_CENTER  ,  -DIST_CENTER,     XY_CENTER },
126
             {   XY_CENTER  ,  -DIST_CENTER,    -XY_CENTER },
127
             {  -XY_CENTER  ,  -DIST_CENTER,     XY_CENTER },
128
             {  -XY_CENTER  ,  -DIST_CENTER,    -XY_CENTER },
129

    
130
             {   XY_CENTER  ,     XY_CENTER,   DIST_CENTER },
131
             {   XY_CENTER  ,    -XY_CENTER,   DIST_CENTER },
132
             {  -XY_CENTER  ,     XY_CENTER,   DIST_CENTER },
133
             {  -XY_CENTER  ,    -XY_CENTER,   DIST_CENTER },
134

    
135
             {   XY_CENTER  ,     XY_CENTER,  -DIST_CENTER },
136
             {   XY_CENTER  ,    -XY_CENTER,  -DIST_CENTER },
137
             {  -XY_CENTER  ,     XY_CENTER,  -DIST_CENTER },
138
             {  -XY_CENTER  ,    -XY_CENTER,  -DIST_CENTER },
139
         };
140

    
141
  // Colors of the faces of cubits. Each cubit has 6 faces
142
  private static final int[][] mFaceMap = new int[][]
143
         {
144
           { 4,2,0, 6,6,6 },
145
           { 0,2,5, 6,6,6 },
146
           { 4,0,3, 6,6,6 },
147
           { 5,3,0, 6,6,6 },
148
           { 1,2,4, 6,6,6 },
149
           { 5,2,1, 6,6,6 },
150
           { 4,3,1, 6,6,6 },
151
           { 1,3,5, 6,6,6 },
152

    
153
           { 0 , 6,6,6,6,6 },
154
           { 0 , 6,6,6,6,6 },
155
           { 0 , 6,6,6,6,6 },
156
           { 0 , 6,6,6,6,6 },
157

    
158
           { 1 , 6,6,6,6,6 },
159
           { 1 , 6,6,6,6,6 },
160
           { 1 , 6,6,6,6,6 },
161
           { 1 , 6,6,6,6,6 },
162

    
163
           { 2 , 6,6,6,6,6 },
164
           { 2 , 6,6,6,6,6 },
165
           { 2 , 6,6,6,6,6 },
166
           { 2 , 6,6,6,6,6 },
167

    
168
           { 3 , 6,6,6,6,6 },
169
           { 3 , 6,6,6,6,6 },
170
           { 3 , 6,6,6,6,6 },
171
           { 3 , 6,6,6,6,6 },
172

    
173
           { 4 , 6,6,6,6,6 },
174
           { 4 , 6,6,6,6,6 },
175
           { 4 , 6,6,6,6,6 },
176
           { 4 , 6,6,6,6,6 },
177

    
178
           { 5 , 6,6,6,6,6 },
179
           { 5 , 6,6,6,6,6 },
180
           { 5 , 6,6,6,6,6 },
181
           { 5 , 6,6,6,6,6 },
182
         };
183

    
184
  private static final int[] QUAT_INDICES =
185
      { 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 };
186

    
187
  private static final double[][] VERTICES_CORNER = new double[][]
188
          {
189
            {-0.50f, 0.00f, 0.00f},
190
            { 0.00f,-0.50f, 0.00f},
191
            { 0.00f, 0.00f,-0.50f},
192
            {-0.25f,-0.25f,-0.25f},
193
            { 0.00f, 0.00f, 0.00f}
194
          };
195

    
196
  private static final int[][] VERT_INDEXES_CORNER = new int[][]
197
          {
198
            {0,1,4},
199
            {2,0,4},
200
            {1,2,4},
201
            {3,1,0},
202
            {3,2,1},
203
            {3,0,2}
204
          };
205

    
206
  private static final float E = 0.1666666f;
207

    
208
  private static final double[][] VERTICES_FACE = new double[][]
209
          {
210
            { 0.00f +E, 0.00f +E, 0.00f },
211
            {-0.50f +E, 0.00f +E, 0.00f },
212
            { 0.00f +E,-0.50f +E, 0.00f },
213
            {-0.25f +E,-0.25f +E,-0.25f },
214
          };
215

    
216
  private static final int[][] VERT_INDEXES_FACE = new int[][]
217
          {
218
            { 0,1,2 },
219
            { 2,1,3 },
220
            { 0,1,3 },
221
            { 2,0,3 }
222
          };
223

    
224
  private static MeshBase[] mMeshes;
225

    
226
  private static final float[][] STICKERS = new float[][]
227
          {
228
            { -0.5f, 0.25f, 0.25f, -0.5f, 0.25f, 0.25f }
229
          };
230

    
231
  private static final ObjectSticker[] mStickers;
232

    
233
  static
234
    {
235
    float radius = 0.03f;
236
    float stroke = 0.05f;
237
    float[] radii = new float[] {radius,radius,radius};
238
    mStickers = new ObjectSticker[STICKERS.length];
239
    mStickers[0] = new ObjectSticker(STICKERS[0],null,radii,stroke);
240
    }
241

    
242
///////////////////////////////////////////////////////////////////////////////////////////////////
243

    
244
  TwistyHelicopter(int size, Static4D quat, DistortedTexture texture,
245
                   MeshSquare mesh, DistortedEffects effects, int[][] moves, Resources res, int scrWidth)
246
    {
247
    super(size, size, quat, texture, mesh, effects, moves, ObjectList.HELI, res, scrWidth);
248
    }
249

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

    
252
  float getScreenRatio()
253
    {
254
    return 1.6f;
255
    }
256

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

    
259
  Static4D[] getQuats()
260
    {
261
    return QUATS;
262
    }
263

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

    
266
  boolean shouldResetTextureMaps()
267
    {
268
    return false;
269
    }
270

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

    
273
  int getNumFaces()
274
    {
275
    return FACE_COLORS.length;
276
    }
277

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

    
280
  int getNumStickerTypes(int numLayers)
281
    {
282
    return STICKERS.length;
283
    }
284

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

    
287
  float[][] getCuts(int size)
288
    {
289
    float[] cut = new float[] { -SQ2/4, +SQ2/4 };
290
    return new float[][] { cut,cut,cut,cut,cut,cut };
291
    }
292

    
293
///////////////////////////////////////////////////////////////////////////////////////////////////
294

    
295
  int getNumCubitFaces()
296
    {
297
    return FACES_PER_CUBIT;
298
    }
299

    
300
///////////////////////////////////////////////////////////////////////////////////////////////////
301

    
302
  float[][] getCubitPositions(int size)
303
    {
304
    return CENTERS;
305
    }
306

    
307
///////////////////////////////////////////////////////////////////////////////////////////////////
308

    
309
  MeshBase createCubitMesh(int cubit, int numLayers)
310
    {
311
    if( mMeshes==null )
312
      {
313
      FactoryCubit factory = FactoryCubit.getInstance();
314
      factory.clear();
315
      mMeshes = new MeshBase[2];
316
      }
317

    
318
    MeshBase mesh;
319

    
320
    if( cubit<8 )
321
      {
322
      if( mMeshes[0]==null )
323
        {
324
        float[][] bands= new float[][]
325
          {
326
             {0.028f,35,0.16f,0.7f,7,3,3},
327
             {0.000f, 0,1.00f,0.0f,3,1,5}
328
          };
329
        int[] bandIndexes   = new int[] { 0,0,0,1,1,1 };
330
        float[][] corners   = new float[][] { {0.08f,0.15f}, {0.08f,0.20f} };
331
        int[] cornerIndexes = new int[] { 1,1,1,0,0 };
332
        float[][] centers   = new float[][] { {-0.25f, -0.25f, -0.25f} };
333
        int[] centerIndexes = new int[] { 0,0,0,-1,0 };
334

    
335
        FactoryCubit factory = FactoryCubit.getInstance();
336
        factory.createNewFaceTransform(VERTICES_CORNER,VERT_INDEXES_CORNER);
337
        mMeshes[0] = factory.createRoundedSolid(VERTICES_CORNER, VERT_INDEXES_CORNER,
338
                                                bands, bandIndexes,
339
                                                corners, cornerIndexes,
340
                                                centers, centerIndexes,
341
                                                getNumCubitFaces() );
342
        }
343
      mesh = mMeshes[0].copy(true);
344
      }
345
    else
346
      {
347
      if( mMeshes[1]==null )
348
        {
349
        float[][] bands= new float[][]
350
          {
351
             {0.028f,35,0.16f,0.7f,7,3,3},
352
             {0.000f, 0,1.00f,0.0f,3,1,3}
353
          };
354
        int[] bandIndexes   = new int[] { 0,1,1,1 };
355
        float[][] corners   = new float[][] { {0.06f,0.15f}, {0.06f,0.20f} };
356
        int[] cornerIndexes = new int[] { 0,1,1,-1 };
357
        float[][] centers   = new float[][] { {-1.0f/12, -1.0f/12, -1.0f/4} };
358
        int[] centerIndexes = new int[] { 0,0,0,-1 };
359

    
360
        FactoryCubit factory = FactoryCubit.getInstance();
361
        factory.createNewFaceTransform(VERTICES_FACE,VERT_INDEXES_FACE);
362
        mMeshes[1] = factory.createRoundedSolid(VERTICES_FACE, VERT_INDEXES_FACE,
363
                                                bands, bandIndexes,
364
                                                corners, cornerIndexes,
365
                                                centers, centerIndexes,
366
                                                getNumCubitFaces() );
367
        }
368
      mesh = mMeshes[1].copy(true);
369
      }
370

    
371
    int index = QUAT_INDICES[cubit];
372
    MatrixEffectQuaternion quat = new MatrixEffectQuaternion( QUATS[index], new Static3D(0,0,0) );
373
    mesh.apply(quat,0xffffffff,0);
374

    
375
    return mesh;
376
    }
377

    
378
///////////////////////////////////////////////////////////////////////////////////////////////////
379

    
380
  int getFaceColor(int cubit, int cubitface, int size)
381
    {
382
    return mFaceMap[cubit][cubitface];
383
    }
384

    
385
///////////////////////////////////////////////////////////////////////////////////////////////////
386

    
387
  int getColor(int face)
388
    {
389
    return FACE_COLORS[face];
390
    }
391

    
392
///////////////////////////////////////////////////////////////////////////////////////////////////
393

    
394
  ObjectSticker retSticker(int face)
395
    {
396
    return mStickers[face/NUM_FACES];
397
    }
398

    
399
///////////////////////////////////////////////////////////////////////////////////////////////////
400

    
401
  float returnMultiplier()
402
    {
403
    return 2.0f;
404
    }
405

    
406
///////////////////////////////////////////////////////////////////////////////////////////////////
407
// PUBLIC API
408

    
409
  public Static3D[] getRotationAxis()
410
    {
411
    return ROT_AXIS;
412
    }
413

    
414
///////////////////////////////////////////////////////////////////////////////////////////////////
415

    
416
  public int[] getBasicAngle()
417
    {
418
    return BASIC_ANGLE;
419
    }
420

    
421
///////////////////////////////////////////////////////////////////////////////////////////////////
422

    
423
  public void randomizeNewScramble(int[][] scramble, Random rnd, int curr, int total)
424
    {
425
    if( curr==0 )
426
      {
427
      scramble[curr][0] = rnd.nextInt(NUM_AXIS);
428
      }
429
    else
430
      {
431
      int newVector = rnd.nextInt(NUM_AXIS -2);
432

    
433
      switch(scramble[curr-1][0])
434
        {
435
        case  0:
436
        case  1: scramble[curr][0] = newVector+2;
437
                 break;
438
        case  2:
439
        case  3: scramble[curr][0] = (newVector==0 || newVector==1) ? newVector:newVector+2;
440
                 break;
441
        default: scramble[curr][0] = newVector;
442
                 break;
443
        }
444
      }
445

    
446
    scramble[curr][1] = rnd.nextFloat()<=0.5f ? 0 : 2;
447

    
448
    switch( rnd.nextInt(2) )
449
      {
450
      case 0: scramble[curr][2] = -1; break;
451
      case 1: scramble[curr][2] =  1; break;
452
      }
453
    }
454

    
455
///////////////////////////////////////////////////////////////////////////////////////////////////
456
// The Helicopter is solved if and only if:
457
//
458
// 1) all of its corner cubits are rotated with the same quat
459
// 2) all its face cubits are rotated with the same quat like the corner ones,
460
//    and optionally they also might be turned by a multiple of 90 degrees along
461
//    a vector perpendicular to the face they lie on.
462
//
463
// i.e.
464
// cubits  8, 9,10,11,12,13,14,15 - might be extra QUAT 1,8,9
465
// cubits 16,17,18,19,20,21,22,23 - might be extra QUAT 2,12,13
466
// cubits 24,25,26,27,28,29,30,31 - might be extra QUAT 3,14,15
467

    
468
  public boolean isSolved()
469
    {
470
    int q = CUBITS[0].mQuatIndex;
471

    
472
    if ( CUBITS[1].mQuatIndex == q &&
473
         CUBITS[2].mQuatIndex == q &&
474
         CUBITS[3].mQuatIndex == q &&
475
         CUBITS[4].mQuatIndex == q &&
476
         CUBITS[5].mQuatIndex == q &&
477
         CUBITS[6].mQuatIndex == q &&
478
         CUBITS[7].mQuatIndex == q  )
479
      {
480
      int q1 = mulQuat(q,1);
481
      int q2 = mulQuat(q,8);
482
      int q3 = mulQuat(q,9);
483

    
484
      for(int index=8; index<16; index++)
485
        {
486
        int qIndex = CUBITS[index].mQuatIndex;
487
        if( qIndex!=q && qIndex!=q1 && qIndex!=q2 && qIndex!=q3 ) return false;
488
        }
489

    
490
      q1 = mulQuat(q, 2);
491
      q2 = mulQuat(q,12);
492
      q3 = mulQuat(q,13);
493

    
494
      for(int index=16; index<24; index++)
495
        {
496
        int qIndex = CUBITS[index].mQuatIndex;
497
        if( qIndex!=q && qIndex!=q1 && qIndex!=q2 && qIndex!=q3 ) return false;
498
        }
499

    
500
      q1 = mulQuat(q, 3);
501
      q2 = mulQuat(q,14);
502
      q3 = mulQuat(q,15);
503

    
504
      for(int index=24; index<32; index++)
505
        {
506
        int qIndex = CUBITS[index].mQuatIndex;
507
        if( qIndex!=q && qIndex!=q1 && qIndex!=q2 && qIndex!=q3 ) return false;
508
        }
509

    
510
      return true;
511
      }
512

    
513
    return false;
514
    }
515

    
516
///////////////////////////////////////////////////////////////////////////////////////////////////
517

    
518
  public int getObjectName(int numLayers)
519
    {
520
    return R.string.heli3;
521
    }
522

    
523
///////////////////////////////////////////////////////////////////////////////////////////////////
524

    
525
  public int getInventor(int numLayers)
526
    {
527
    return R.string.heli3_inventor;
528
    }
529

    
530
///////////////////////////////////////////////////////////////////////////////////////////////////
531

    
532
  public int getComplexity(int numLayers)
533
    {
534
    return 8;
535
    }
536
}
(27-27/41)