Project

General

Profile

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

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

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.ObjectShape;
26
import org.distorted.helpers.ObjectSticker;
27
import org.distorted.library.effect.MatrixEffectQuaternion;
28
import org.distorted.library.main.DistortedEffects;
29
import org.distorted.library.main.DistortedTexture;
30
import org.distorted.library.mesh.MeshBase;
31
import org.distorted.library.mesh.MeshSquare;
32
import org.distorted.library.type.Static3D;
33
import org.distorted.library.type.Static4D;
34
import org.distorted.main.R;
35

    
36
import java.util.Random;
37

    
38
///////////////////////////////////////////////////////////////////////////////////////////////////
39

    
40
public class TwistyHelicopter extends TwistyObject
41
{
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[] BASIC_ANGLE = new int[] { 2,2,2,2,2,2 };
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 static final double[][] VERTICES_CORNER = new double[][]
189
          {
190
            {-0.50f, 0.00f, 0.00f},
191
            { 0.00f,-0.50f, 0.00f},
192
            { 0.00f, 0.00f,-0.50f},
193
            {-0.25f,-0.25f,-0.25f},
194
            { 0.00f, 0.00f, 0.00f}
195
          };
196

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

    
207
  private static final float E = 0.1666666f;
208

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

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

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

    
230
  private static final ObjectSticker[] mStickers;
231

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

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

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

    
249
///////////////////////////////////////////////////////////////////////////////////////////////////
250

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

    
256
///////////////////////////////////////////////////////////////////////////////////////////////////
257

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

    
263
///////////////////////////////////////////////////////////////////////////////////////////////////
264

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

    
270
///////////////////////////////////////////////////////////////////////////////////////////////////
271

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

    
277
///////////////////////////////////////////////////////////////////////////////////////////////////
278

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

    
284
///////////////////////////////////////////////////////////////////////////////////////////////////
285

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

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

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

    
299
///////////////////////////////////////////////////////////////////////////////////////////////////
300

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

    
306
///////////////////////////////////////////////////////////////////////////////////////////////////
307

    
308
  ObjectShape getObjectShape(int cubit, int numLayers)
309
    {
310
    int variant = getCubitVariant(cubit,numLayers);
311

    
312
    if( variant==0 )
313
      {
314
      float[][] bands= new float[][] { {0.028f,35,0.16f,0.7f,7,3,3}, {0.000f, 0,1.00f,0.0f,3,1,5} };
315
      int[] bandIndices   = new int[] { 0,0,0,1,1,1 };
316
      float[][] corners   = new float[][] { {0.08f,0.15f}, {0.08f,0.20f} };
317
      int[] cornerIndices = new int[] { 1,1,1,0,0 };
318
      float[][] centers   = new float[][] { {-0.25f, -0.25f, -0.25f} };
319
      int[] centerIndices = new int[] { 0,0,0,-1,0 };
320
      return new ObjectShape(VERTICES_CORNER,VERT_INDEXES_CORNER,bands,bandIndices,corners,cornerIndices,centers,centerIndices,getNumCubitFaces(), null);
321
      }
322
    else
323
      {
324
      float[][] bands= new float[][] { {0.028f,35,0.16f,0.7f,7,3,3}, {0.000f, 0,1.00f,0.0f,3,1,3} };
325
      int[] bandIndices   = new int[] { 0,1,1,1 };
326
      float[][] corners   = new float[][] { {0.06f,0.15f}, {0.06f,0.20f} };
327
      int[] cornerIndices = new int[] { 0,1,1,-1 };
328
      float[][] centers   = new float[][] { {-1.0f/12, -1.0f/12, -1.0f/4} };
329
      int[] centerIndices = new int[] { 0,0,0,-1 };
330
      return new ObjectShape(VERTICES_FACE,VERT_INDEXES_FACE,bands,bandIndices,corners,cornerIndices,centers,centerIndices,getNumCubitFaces(), null);
331
      }
332
    }
333

    
334
///////////////////////////////////////////////////////////////////////////////////////////////////
335

    
336
  private Static4D getQuat(int cubit, int numLayers)
337
    {
338
    return QUATS[QUAT_INDICES[cubit]];
339
    }
340

    
341
///////////////////////////////////////////////////////////////////////////////////////////////////
342

    
343
  private int getNumCubitVariants(int numLayers)
344
    {
345
    return 2;
346
    }
347

    
348
///////////////////////////////////////////////////////////////////////////////////////////////////
349

    
350
  int getCubitVariant(int cubit, int numLayers)
351
    {
352
    return cubit<8 ? 0:1;
353
    }
354

    
355
///////////////////////////////////////////////////////////////////////////////////////////////////
356

    
357
  MeshBase createCubitMesh(int cubit, int numLayers)
358
    {
359
    int variant = getCubitVariant(cubit,numLayers);
360

    
361
    if( mMeshes==null )
362
      {
363
      FactoryCubit factory = FactoryCubit.getInstance();
364
      factory.clear();
365
      mMeshes = new MeshBase[getNumCubitVariants(numLayers)];
366
      }
367

    
368
    if( mMeshes[variant]==null )
369
      {
370
      ObjectShape shape = getObjectShape(cubit,numLayers);
371
      FactoryCubit factory = FactoryCubit.getInstance();
372
      factory.createNewFaceTransform(shape);
373
      mMeshes[variant] = factory.createRoundedSolid(shape);
374
      }
375

    
376
    MeshBase mesh = mMeshes[variant].copy(true);
377
    MatrixEffectQuaternion quat = new MatrixEffectQuaternion( getQuat(cubit,numLayers), new Static3D(0,0,0) );
378
    mesh.apply(quat,0xffffffff,0);
379

    
380
    return mesh;
381
    }
382

    
383
///////////////////////////////////////////////////////////////////////////////////////////////////
384

    
385
  int getFaceColor(int cubit, int cubitface, int size)
386
    {
387
    return mFaceMap[cubit][cubitface];
388
    }
389

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

    
392
  int getColor(int face)
393
    {
394
    return FACE_COLORS[face];
395
    }
396

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

    
399
  ObjectSticker retSticker(int face)
400
    {
401
    return mStickers[face/NUM_FACES];
402
    }
403

    
404
///////////////////////////////////////////////////////////////////////////////////////////////////
405

    
406
  float returnMultiplier()
407
    {
408
    return 2.0f;
409
    }
410

    
411
///////////////////////////////////////////////////////////////////////////////////////////////////
412
// PUBLIC API
413

    
414
  public Static3D[] getRotationAxis()
415
    {
416
    return ROT_AXIS;
417
    }
418

    
419
///////////////////////////////////////////////////////////////////////////////////////////////////
420

    
421
  public int[] getBasicAngle()
422
    {
423
    return BASIC_ANGLE;
424
    }
425

    
426
///////////////////////////////////////////////////////////////////////////////////////////////////
427

    
428
  public void randomizeNewScramble(int[][] scramble, Random rnd, int curr, int total)
429
    {
430
    if( curr==0 )
431
      {
432
      scramble[curr][0] = rnd.nextInt(NUM_AXIS);
433
      }
434
    else
435
      {
436
      int newVector = rnd.nextInt(NUM_AXIS -2);
437

    
438
      switch(scramble[curr-1][0])
439
        {
440
        case  0:
441
        case  1: scramble[curr][0] = newVector+2;
442
                 break;
443
        case  2:
444
        case  3: scramble[curr][0] = (newVector==0 || newVector==1) ? newVector:newVector+2;
445
                 break;
446
        default: scramble[curr][0] = newVector;
447
                 break;
448
        }
449
      }
450

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

    
453
    switch( rnd.nextInt(2) )
454
      {
455
      case 0: scramble[curr][2] = -1; break;
456
      case 1: scramble[curr][2] =  1; break;
457
      }
458
    }
459

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

    
473
  public boolean isSolved()
474
    {
475
    int q = CUBITS[0].mQuatIndex;
476

    
477
    if ( CUBITS[1].mQuatIndex == q &&
478
         CUBITS[2].mQuatIndex == q &&
479
         CUBITS[3].mQuatIndex == q &&
480
         CUBITS[4].mQuatIndex == q &&
481
         CUBITS[5].mQuatIndex == q &&
482
         CUBITS[6].mQuatIndex == q &&
483
         CUBITS[7].mQuatIndex == q  )
484
      {
485
      int q1 = mulQuat(q,1);
486
      int q2 = mulQuat(q,8);
487
      int q3 = mulQuat(q,9);
488

    
489
      for(int index=8; index<16; index++)
490
        {
491
        int qIndex = CUBITS[index].mQuatIndex;
492
        if( qIndex!=q && qIndex!=q1 && qIndex!=q2 && qIndex!=q3 ) return false;
493
        }
494

    
495
      q1 = mulQuat(q, 2);
496
      q2 = mulQuat(q,12);
497
      q3 = mulQuat(q,13);
498

    
499
      for(int index=16; index<24; index++)
500
        {
501
        int qIndex = CUBITS[index].mQuatIndex;
502
        if( qIndex!=q && qIndex!=q1 && qIndex!=q2 && qIndex!=q3 ) return false;
503
        }
504

    
505
      q1 = mulQuat(q, 3);
506
      q2 = mulQuat(q,14);
507
      q3 = mulQuat(q,15);
508

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

    
515
      return true;
516
      }
517

    
518
    return false;
519
    }
520

    
521
///////////////////////////////////////////////////////////////////////////////////////////////////
522

    
523
  public int getObjectName(int numLayers)
524
    {
525
    return R.string.heli3;
526
    }
527

    
528
///////////////////////////////////////////////////////////////////////////////////////////////////
529

    
530
  public int getInventor(int numLayers)
531
    {
532
    return R.string.heli3_inventor;
533
    }
534

    
535
///////////////////////////////////////////////////////////////////////////////////////////////////
536

    
537
  public int getComplexity(int numLayers)
538
    {
539
    return 8;
540
    }
541
}
(27-27/41)