Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / TwistyHelicopter.java @ 680469e6

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

    
37
import java.util.Random;
38

    
39
///////////////////////////////////////////////////////////////////////////////////////////////////
40

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

    
45
  // the six rotation axis of a Helicopter. Must be normalized.
46
  static final Static3D[] ROT_AXIS = new Static3D[]
47
         {
48
           new Static3D(     0, +SQ2/2, -SQ2/2),
49
           new Static3D(     0, -SQ2/2, -SQ2/2),
50
           new Static3D(+SQ2/2,      0, -SQ2/2),
51
           new Static3D(-SQ2/2,      0, -SQ2/2),
52
           new Static3D(+SQ2/2, -SQ2/2,      0),
53
           new Static3D(-SQ2/2, -SQ2/2,      0)
54
         };
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 final float[][] STICKERS = new float[][]
225
          {
226
            { -0.5f, 0.25f, 0.25f, -0.5f, 0.25f, 0.25f }
227
          };
228

    
229
  private static MeshBase[] mMeshes;
230

    
231
///////////////////////////////////////////////////////////////////////////////////////////////////
232

    
233
  TwistyHelicopter(int size, Static4D quat, DistortedTexture texture,
234
                   MeshSquare mesh, DistortedEffects effects, int[][] moves, Resources res, int scrWidth)
235
    {
236
    super(size, size, quat, texture, mesh, effects, moves, ObjectList.HELI, res, scrWidth);
237

    
238
    createFaceDataStructures();
239
    }
240

    
241
///////////////////////////////////////////////////////////////////////////////////////////////////
242

    
243
  double[][] getVertices(int cubitType)
244
    {
245
    if( cubitType==0 ) return VERTICES_CORNER;
246
    if( cubitType==1 ) return VERTICES_FACE;
247
    return null;
248
    }
249

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

    
252
  int[][] getVertIndexes(int cubitType)
253
    {
254
    if( cubitType==0 ) return VERT_INDEXES_CORNER;
255
    if( cubitType==1 ) return VERT_INDEXES_FACE;
256
    return null;
257
    }
258

    
259
///////////////////////////////////////////////////////////////////////////////////////////////////
260

    
261
  int getNumCubitTypes(int numLayers)
262
    {
263
    return 2;
264
    }
265

    
266
///////////////////////////////////////////////////////////////////////////////////////////////////
267

    
268
  float getScreenRatio()
269
    {
270
    return 1.6f;
271
    }
272

    
273
///////////////////////////////////////////////////////////////////////////////////////////////////
274

    
275
  Static4D[] getQuats()
276
    {
277
    return QUATS;
278
    }
279

    
280
///////////////////////////////////////////////////////////////////////////////////////////////////
281

    
282
  boolean shouldResetTextureMaps()
283
    {
284
    return false;
285
    }
286

    
287
///////////////////////////////////////////////////////////////////////////////////////////////////
288

    
289
  int getNumFaces()
290
    {
291
    return FACE_COLORS.length;
292
    }
293

    
294
///////////////////////////////////////////////////////////////////////////////////////////////////
295

    
296
  int getNumStickerTypes(int numLayers)
297
    {
298
    return STICKERS.length;
299
    }
300

    
301
///////////////////////////////////////////////////////////////////////////////////////////////////
302

    
303
  float[] getCuts(int size)
304
    {
305
    float[] cuts = new float[2];
306

    
307
    cuts[0] = -SQ2/4;
308
    cuts[1] = +SQ2/4;
309

    
310
    return cuts;
311
    }
312

    
313
///////////////////////////////////////////////////////////////////////////////////////////////////
314

    
315
  int getNumCubitFaces()
316
    {
317
    return FACES_PER_CUBIT;
318
    }
319

    
320
///////////////////////////////////////////////////////////////////////////////////////////////////
321

    
322
  float[][] getCubitPositions(int size)
323
    {
324
    return CENTERS;
325
    }
326

    
327
///////////////////////////////////////////////////////////////////////////////////////////////////
328

    
329
  MeshBase createCubitMesh(int cubit, int numLayers)
330
    {
331
    if( mMeshes==null )
332
      {
333
      FactoryCubit factory = FactoryCubit.getInstance();
334
      factory.clear();
335
      mMeshes = new MeshBase[2];
336
      }
337

    
338
    MeshBase mesh;
339

    
340
    if( cubit<8 )
341
      {
342
      if( mMeshes[0]==null )
343
        {
344
        float[][] bands= new float[][]
345
          {
346
             {0.028f,35,0.16f,0.7f,7,3,3},
347
             {0.000f, 0,1.00f,0.0f,3,1,5}
348
          };
349
        int[] bandIndexes   = new int[] { 0,0,0,1,1,1 };
350
        float[][] corners   = new float[][] { {0.08f,0.15f}, {0.08f,0.20f} };
351
        int[] cornerIndexes = new int[] { 1,1,1,0,0 };
352
        float[][] centers   = new float[][] { {-0.25f, -0.25f, -0.25f} };
353
        int[] centerIndexes = new int[] { 0,0,0,-1,0 };
354

    
355
        FactoryCubit factory = FactoryCubit.getInstance();
356
        factory.createNewFaceTransform(VERTICES_CORNER,VERT_INDEXES_CORNER);
357
        mMeshes[0] = factory.createRoundedSolid(VERTICES_CORNER, VERT_INDEXES_CORNER,
358
                                                bands, bandIndexes,
359
                                                corners, cornerIndexes,
360
                                                centers, centerIndexes,
361
                                                getNumCubitFaces() );
362
        }
363
      mesh = mMeshes[0].copy(true);
364
      }
365
    else
366
      {
367
      if( mMeshes[1]==null )
368
        {
369
        float[][] bands= new float[][]
370
          {
371
             {0.028f,35,0.16f,0.7f,7,3,3},
372
             {0.000f, 0,1.00f,0.0f,3,1,3}
373
          };
374
        int[] bandIndexes   = new int[] { 0,1,1,1 };
375
        float[][] corners   = new float[][] { {0.06f,0.15f}, {0.06f,0.20f} };
376
        int[] cornerIndexes = new int[] { 0,1,1,-1 };
377
        float[][] centers   = new float[][] { {-1.0f/12, -1.0f/12, -1.0f/4} };
378
        int[] centerIndexes = new int[] { 0,0,0,-1 };
379

    
380
        FactoryCubit factory = FactoryCubit.getInstance();
381
        factory.createNewFaceTransform(VERTICES_FACE,VERT_INDEXES_FACE);
382
        mMeshes[1] = factory.createRoundedSolid(VERTICES_FACE, VERT_INDEXES_FACE,
383
                                                bands, bandIndexes,
384
                                                corners, cornerIndexes,
385
                                                centers, centerIndexes,
386
                                                getNumCubitFaces() );
387
        }
388
      mesh = mMeshes[1].copy(true);
389
      }
390

    
391
    int index = QUAT_INDICES[cubit];
392
    MatrixEffectQuaternion quat = new MatrixEffectQuaternion( QUATS[index], new Static3D(0,0,0) );
393
    mesh.apply(quat,0xffffffff,0);
394

    
395
    return mesh;
396
    }
397

    
398
///////////////////////////////////////////////////////////////////////////////////////////////////
399

    
400
  int getFaceColor(int cubit, int cubitface, int size)
401
    {
402
    return mFaceMap[cubit][cubitface];
403
    }
404

    
405
///////////////////////////////////////////////////////////////////////////////////////////////////
406

    
407
  void createFaceTexture(Canvas canvas, Paint paint, int face, int left, int top)
408
    {
409
    float R = 0.03f;
410
    float S = 0.05f;
411

    
412
    FactorySticker factory = FactorySticker.getInstance();
413
    factory.drawRoundedPolygon(canvas, paint, left, top, STICKERS[0], S, FACE_COLORS[face], R);
414
    }
415

    
416
///////////////////////////////////////////////////////////////////////////////////////////////////
417

    
418
  float returnMultiplier()
419
    {
420
    return 2.0f;
421
    }
422

    
423
///////////////////////////////////////////////////////////////////////////////////////////////////
424

    
425
  float[] getRowChances(int numLayers)
426
    {
427
    float[] chances = new float[3];
428

    
429
    chances[0] = 0.5f;
430
    chances[1] = 0.5f;
431
    chances[2] = 1.0f;
432

    
433
    return chances;
434
    }
435

    
436
///////////////////////////////////////////////////////////////////////////////////////////////////
437
// PUBLIC API
438

    
439
  public Static3D[] getRotationAxis()
440
    {
441
    return ROT_AXIS;
442
    }
443

    
444
///////////////////////////////////////////////////////////////////////////////////////////////////
445

    
446
  public int getBasicAngle()
447
    {
448
    return 2;
449
    }
450

    
451
///////////////////////////////////////////////////////////////////////////////////////////////////
452

    
453
  public void randomizeNewScramble(int[][] scramble, Random rnd, int num)
454
    {
455
    if( num==0 )
456
      {
457
      scramble[num][0] = rnd.nextInt(ROTATION_AXIS.length);
458
      }
459
    else
460
      {
461
      int newVector = rnd.nextInt(ROTATION_AXIS.length-2);
462

    
463
      switch(scramble[num-1][0])
464
        {
465
        case  0:
466
        case  1: scramble[num][0] = newVector+2;
467
                 break;
468
        case  2:
469
        case  3: scramble[num][0] = (newVector==0 || newVector==1) ? newVector:newVector+2;
470
                 break;
471
        default: scramble[num][0] = newVector;
472
                 break;
473
        }
474
      }
475

    
476
    float rowFloat = rnd.nextFloat();
477

    
478
    for(int row=0; row<mRowChances.length; row++)
479
      {
480
      if( rowFloat<=mRowChances[row] )
481
        {
482
        scramble[num][1] = row;
483
        break;
484
        }
485
      }
486

    
487
    switch( rnd.nextInt(2) )
488
      {
489
      case 0: scramble[num][2] = -1; break;
490
      case 1: scramble[num][2] =  1; break;
491
      }
492
    }
493

    
494
///////////////////////////////////////////////////////////////////////////////////////////////////
495
// The Helicopter is solved if and only if:
496
//
497
// 1) all of its corner cubits are rotated with the same quat
498
// 2) all its face cubits are rotated with the same quat like the corner ones,
499
//    and optionally they also might be turned by a multiple of 90 degrees along
500
//    a vector perpendicular to the face they lie on.
501
//
502
// i.e.
503
// cubits  8, 9,10,11,12,13,14,15 - might be extra QUAT 1,8,9
504
// cubits 16,17,18,19,20,21,22,23 - might be extra QUAT 2,12,13
505
// cubits 24,25,26,27,28,29,30,31 - might be extra QUAT 3,14,15
506

    
507
  public boolean isSolved()
508
    {
509
    int q = CUBITS[0].mQuatIndex;
510

    
511
    if ( CUBITS[1].mQuatIndex == q &&
512
         CUBITS[2].mQuatIndex == q &&
513
         CUBITS[3].mQuatIndex == q &&
514
         CUBITS[4].mQuatIndex == q &&
515
         CUBITS[5].mQuatIndex == q &&
516
         CUBITS[6].mQuatIndex == q &&
517
         CUBITS[7].mQuatIndex == q  )
518
      {
519
      int q1 = mulQuat(q,1);
520
      int q2 = mulQuat(q,8);
521
      int q3 = mulQuat(q,9);
522

    
523
      for(int index=8; index<16; index++)
524
        {
525
        int qIndex = CUBITS[index].mQuatIndex;
526
        if( qIndex!=q && qIndex!=q1 && qIndex!=q2 && qIndex!=q3 ) return false;
527
        }
528

    
529
      q1 = mulQuat(q, 2);
530
      q2 = mulQuat(q,12);
531
      q3 = mulQuat(q,13);
532

    
533
      for(int index=16; index<24; index++)
534
        {
535
        int qIndex = CUBITS[index].mQuatIndex;
536
        if( qIndex!=q && qIndex!=q1 && qIndex!=q2 && qIndex!=q3 ) return false;
537
        }
538

    
539
      q1 = mulQuat(q, 3);
540
      q2 = mulQuat(q,14);
541
      q3 = mulQuat(q,15);
542

    
543
      for(int index=24; index<32; index++)
544
        {
545
        int qIndex = CUBITS[index].mQuatIndex;
546
        if( qIndex!=q && qIndex!=q1 && qIndex!=q2 && qIndex!=q3 ) return false;
547
        }
548

    
549
      return true;
550
      }
551

    
552
    return false;
553
    }
554

    
555
///////////////////////////////////////////////////////////////////////////////////////////////////
556
// only needed for solvers - there are no Helicopter solvers ATM)
557

    
558
  public String retObjectString()
559
    {
560
    return "";
561
    }
562

    
563
///////////////////////////////////////////////////////////////////////////////////////////////////
564

    
565
  public int getObjectName(int numLayers)
566
    {
567
    return R.string.heli3;
568
    }
569

    
570
///////////////////////////////////////////////////////////////////////////////////////////////////
571

    
572
  public int getInventor(int numLayers)
573
    {
574
    return R.string.heli3_inventor;
575
    }
576

    
577
///////////////////////////////////////////////////////////////////////////////////////////////////
578

    
579
  public int getComplexity(int numLayers)
580
    {
581
    return 8;
582
    }
583
}
(24-24/33)