Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / TwistyHelicopter.java @ 7d8cc029

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

    
239
///////////////////////////////////////////////////////////////////////////////////////////////////
240

    
241
  float getScreenRatio()
242
    {
243
    return 1.6f;
244
    }
245

    
246
///////////////////////////////////////////////////////////////////////////////////////////////////
247

    
248
  Static4D[] getQuats()
249
    {
250
    return QUATS;
251
    }
252

    
253
///////////////////////////////////////////////////////////////////////////////////////////////////
254

    
255
  boolean shouldResetTextureMaps()
256
    {
257
    return false;
258
    }
259

    
260
///////////////////////////////////////////////////////////////////////////////////////////////////
261

    
262
  int getNumFaces()
263
    {
264
    return FACE_COLORS.length;
265
    }
266

    
267
///////////////////////////////////////////////////////////////////////////////////////////////////
268

    
269
  int getNumStickerTypes(int numLayers)
270
    {
271
    return STICKERS.length;
272
    }
273

    
274
///////////////////////////////////////////////////////////////////////////////////////////////////
275

    
276
  float[] getCuts(int size)
277
    {
278
    float[] cuts = new float[2];
279

    
280
    cuts[0] = -SQ2/4;
281
    cuts[1] = +SQ2/4;
282

    
283
    return cuts;
284
    }
285

    
286
///////////////////////////////////////////////////////////////////////////////////////////////////
287

    
288
  int getNumCubitFaces()
289
    {
290
    return FACES_PER_CUBIT;
291
    }
292

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

    
295
  float[][] getCubitPositions(int size)
296
    {
297
    return CENTERS;
298
    }
299

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

    
302
  MeshBase createCubitMesh(int cubit, int numLayers)
303
    {
304
    if( mMeshes==null )
305
      {
306
      FactoryCubit factory = FactoryCubit.getInstance();
307
      factory.clear();
308
      mMeshes = new MeshBase[2];
309
      }
310

    
311
    MeshBase mesh;
312

    
313
    if( cubit<8 )
314
      {
315
      if( mMeshes[0]==null )
316
        {
317
        float[][] bands= new float[][]
318
          {
319
             {0.028f,35,0.16f,0.7f,7,3,3},
320
             {0.000f, 0,1.00f,0.0f,3,1,5}
321
          };
322
        int[] bandIndexes   = new int[] { 0,0,0,1,1,1 };
323
        float[][] corners   = new float[][] { {0.08f,0.15f}, {0.08f,0.20f} };
324
        int[] cornerIndexes = new int[] { 1,1,1,0,0 };
325
        float[][] centers   = new float[][] { {-0.25f, -0.25f, -0.25f} };
326
        int[] centerIndexes = new int[] { 0,0,0,-1,0 };
327

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

    
353
        FactoryCubit factory = FactoryCubit.getInstance();
354
        factory.createNewFaceTransform(VERTICES_FACE,VERT_INDEXES_FACE);
355
        mMeshes[1] = factory.createRoundedSolid(VERTICES_FACE, VERT_INDEXES_FACE,
356
                                                bands, bandIndexes,
357
                                                corners, cornerIndexes,
358
                                                centers, centerIndexes,
359
                                                getNumCubitFaces() );
360
        }
361
      mesh = mMeshes[1].copy(true);
362
      }
363

    
364
    int index = QUAT_INDICES[cubit];
365
    MatrixEffectQuaternion quat = new MatrixEffectQuaternion( QUATS[index], new Static3D(0,0,0) );
366
    mesh.apply(quat,0xffffffff,0);
367

    
368
    return mesh;
369
    }
370

    
371
///////////////////////////////////////////////////////////////////////////////////////////////////
372

    
373
  int getFaceColor(int cubit, int cubitface, int size)
374
    {
375
    return mFaceMap[cubit][cubitface];
376
    }
377

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

    
380
  void createFaceTexture(Canvas canvas, Paint paint, int face, int left, int top)
381
    {
382
    float R = 0.03f;
383
    float S = 0.05f;
384

    
385
    FactorySticker factory = FactorySticker.getInstance();
386
    factory.drawRoundedPolygon(canvas, paint, left, top, STICKERS[0], S, FACE_COLORS[face], R);
387
    }
388

    
389
///////////////////////////////////////////////////////////////////////////////////////////////////
390

    
391
  float returnMultiplier()
392
    {
393
    return 2.0f;
394
    }
395

    
396
///////////////////////////////////////////////////////////////////////////////////////////////////
397

    
398
  float[] getRowChances(int numLayers)
399
    {
400
    float[] chances = new float[3];
401

    
402
    chances[0] = 0.5f;
403
    chances[1] = 0.5f;
404
    chances[2] = 1.0f;
405

    
406
    return chances;
407
    }
408

    
409
///////////////////////////////////////////////////////////////////////////////////////////////////
410
// PUBLIC API
411

    
412
  public Static3D[] getRotationAxis()
413
    {
414
    return ROT_AXIS;
415
    }
416

    
417
///////////////////////////////////////////////////////////////////////////////////////////////////
418

    
419
  public int getBasicAngle()
420
    {
421
    return 2;
422
    }
423

    
424
///////////////////////////////////////////////////////////////////////////////////////////////////
425

    
426
  public void randomizeNewScramble(int[][] scramble, Random rnd, int num)
427
    {
428
    if( num==0 )
429
      {
430
      scramble[num][0] = rnd.nextInt(ROTATION_AXIS.length);
431
      }
432
    else
433
      {
434
      int newVector = rnd.nextInt(ROTATION_AXIS.length-2);
435

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

    
449
    float rowFloat = rnd.nextFloat();
450

    
451
    for(int row=0; row<mRowChances.length; row++)
452
      {
453
      if( rowFloat<=mRowChances[row] )
454
        {
455
        scramble[num][1] = row;
456
        break;
457
        }
458
      }
459

    
460
    switch( rnd.nextInt(2) )
461
      {
462
      case 0: scramble[num][2] = -1; break;
463
      case 1: scramble[num][2] =  1; break;
464
      }
465
    }
466

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

    
480
  public boolean isSolved()
481
    {
482
    int q = CUBITS[0].mQuatIndex;
483

    
484
    if ( CUBITS[1].mQuatIndex == q &&
485
         CUBITS[2].mQuatIndex == q &&
486
         CUBITS[3].mQuatIndex == q &&
487
         CUBITS[4].mQuatIndex == q &&
488
         CUBITS[5].mQuatIndex == q &&
489
         CUBITS[6].mQuatIndex == q &&
490
         CUBITS[7].mQuatIndex == q  )
491
      {
492
      int q1 = mulQuat(q,1);
493
      int q2 = mulQuat(q,8);
494
      int q3 = mulQuat(q,9);
495

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

    
502
      q1 = mulQuat(q, 2);
503
      q2 = mulQuat(q,12);
504
      q3 = mulQuat(q,13);
505

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

    
512
      q1 = mulQuat(q, 3);
513
      q2 = mulQuat(q,14);
514
      q3 = mulQuat(q,15);
515

    
516
      for(int index=24; index<32; index++)
517
        {
518
        int qIndex = CUBITS[index].mQuatIndex;
519
        if( qIndex!=q && qIndex!=q1 && qIndex!=q2 && qIndex!=q3 ) return false;
520
        }
521

    
522
      return true;
523
      }
524

    
525
    return false;
526
    }
527

    
528
///////////////////////////////////////////////////////////////////////////////////////////////////
529
// only needed for solvers - there are no Helicopter solvers ATM)
530

    
531
  public String retObjectString()
532
    {
533
    return "";
534
    }
535

    
536
///////////////////////////////////////////////////////////////////////////////////////////////////
537

    
538
  public int getObjectName(int numLayers)
539
    {
540
    return R.string.heli3;
541
    }
542

    
543
///////////////////////////////////////////////////////////////////////////////////////////////////
544

    
545
  public int getInventor(int numLayers)
546
    {
547
    return R.string.heli3_inventor;
548
    }
549

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

    
552
  public int getComplexity(int numLayers)
553
    {
554
    return 8;
555
    }
556
}
(24-24/33)