Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / TwistyHelicopter.java @ 29bc084f

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[] BASIC_ANGLE = new int[] { 2,2,2,2,2,2 };
57

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

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

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

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

    
96
  private static final float DIST_CORNER = 0.50f;
97
  private static final float DIST_CENTER = 0.50f;
98
  private static final float XY_CENTER   = DIST_CORNER/3;
99

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

    
112
             {   DIST_CENTER,     XY_CENTER,     XY_CENTER },
113
             {   DIST_CENTER,     XY_CENTER,    -XY_CENTER },
114
             {   DIST_CENTER,    -XY_CENTER,     XY_CENTER },
115
             {   DIST_CENTER,    -XY_CENTER,    -XY_CENTER },
116

    
117
             {  -DIST_CENTER,     XY_CENTER,     XY_CENTER },
118
             {  -DIST_CENTER,     XY_CENTER,    -XY_CENTER },
119
             {  -DIST_CENTER,    -XY_CENTER,     XY_CENTER },
120
             {  -DIST_CENTER,    -XY_CENTER,    -XY_CENTER },
121

    
122
             {   XY_CENTER  ,   DIST_CENTER,     XY_CENTER },
123
             {   XY_CENTER  ,   DIST_CENTER,    -XY_CENTER },
124
             {  -XY_CENTER  ,   DIST_CENTER,     XY_CENTER },
125
             {  -XY_CENTER  ,   DIST_CENTER,    -XY_CENTER },
126

    
127
             {   XY_CENTER  ,  -DIST_CENTER,     XY_CENTER },
128
             {   XY_CENTER  ,  -DIST_CENTER,    -XY_CENTER },
129
             {  -XY_CENTER  ,  -DIST_CENTER,     XY_CENTER },
130
             {  -XY_CENTER  ,  -DIST_CENTER,    -XY_CENTER },
131

    
132
             {   XY_CENTER  ,     XY_CENTER,   DIST_CENTER },
133
             {   XY_CENTER  ,    -XY_CENTER,   DIST_CENTER },
134
             {  -XY_CENTER  ,     XY_CENTER,   DIST_CENTER },
135
             {  -XY_CENTER  ,    -XY_CENTER,   DIST_CENTER },
136

    
137
             {   XY_CENTER  ,     XY_CENTER,  -DIST_CENTER },
138
             {   XY_CENTER  ,    -XY_CENTER,  -DIST_CENTER },
139
             {  -XY_CENTER  ,     XY_CENTER,  -DIST_CENTER },
140
             {  -XY_CENTER  ,    -XY_CENTER,  -DIST_CENTER },
141
         };
142

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

    
155
           { 0 , 6,6,6,6,6 },
156
           { 0 , 6,6,6,6,6 },
157
           { 0 , 6,6,6,6,6 },
158
           { 0 , 6,6,6,6,6 },
159

    
160
           { 1 , 6,6,6,6,6 },
161
           { 1 , 6,6,6,6,6 },
162
           { 1 , 6,6,6,6,6 },
163
           { 1 , 6,6,6,6,6 },
164

    
165
           { 2 , 6,6,6,6,6 },
166
           { 2 , 6,6,6,6,6 },
167
           { 2 , 6,6,6,6,6 },
168
           { 2 , 6,6,6,6,6 },
169

    
170
           { 3 , 6,6,6,6,6 },
171
           { 3 , 6,6,6,6,6 },
172
           { 3 , 6,6,6,6,6 },
173
           { 3 , 6,6,6,6,6 },
174

    
175
           { 4 , 6,6,6,6,6 },
176
           { 4 , 6,6,6,6,6 },
177
           { 4 , 6,6,6,6,6 },
178
           { 4 , 6,6,6,6,6 },
179

    
180
           { 5 , 6,6,6,6,6 },
181
           { 5 , 6,6,6,6,6 },
182
           { 5 , 6,6,6,6,6 },
183
           { 5 , 6,6,6,6,6 },
184
         };
185

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

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

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

    
208
  private static final float E = 0.1666666f;
209

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

    
218
  private static final int[][] VERT_INDEXES_FACE = new int[][]
219
          {
220
            { 0,1,2 },
221
            { 2,1,3 },
222
            { 0,1,3 },
223
            { 2,0,3 }
224
          };
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 MeshBase[] mMeshes;
232

    
233
///////////////////////////////////////////////////////////////////////////////////////////////////
234

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

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

    
243
  float getScreenRatio()
244
    {
245
    return 1.6f;
246
    }
247

    
248
///////////////////////////////////////////////////////////////////////////////////////////////////
249

    
250
  Static4D[] getQuats()
251
    {
252
    return QUATS;
253
    }
254

    
255
///////////////////////////////////////////////////////////////////////////////////////////////////
256

    
257
  boolean shouldResetTextureMaps()
258
    {
259
    return false;
260
    }
261

    
262
///////////////////////////////////////////////////////////////////////////////////////////////////
263

    
264
  int getNumFaces()
265
    {
266
    return FACE_COLORS.length;
267
    }
268

    
269
///////////////////////////////////////////////////////////////////////////////////////////////////
270

    
271
  int getNumStickerTypes(int numLayers)
272
    {
273
    return STICKERS.length;
274
    }
275

    
276
///////////////////////////////////////////////////////////////////////////////////////////////////
277

    
278
  float[][] getCuts(int size)
279
    {
280
    float[] cut = new float[] { -SQ2/4, +SQ2/4 };
281
    return new float[][] { cut,cut,cut,cut,cut,cut };
282
    }
283

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

    
286
  int getNumCubitFaces()
287
    {
288
    return FACES_PER_CUBIT;
289
    }
290

    
291
///////////////////////////////////////////////////////////////////////////////////////////////////
292

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

    
298
///////////////////////////////////////////////////////////////////////////////////////////////////
299

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

    
309
    MeshBase mesh;
310

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

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

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

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

    
366
    return mesh;
367
    }
368

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

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

    
376
///////////////////////////////////////////////////////////////////////////////////////////////////
377

    
378
  void createFaceTexture(Canvas canvas, Paint paint, int face, int left, int top)
379
    {
380
    float R = 0.03f;
381
    float S = 0.05f;
382
    float[] RS = new float[] {R,R,R};
383

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

    
388
///////////////////////////////////////////////////////////////////////////////////////////////////
389

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

    
395
///////////////////////////////////////////////////////////////////////////////////////////////////
396
// PUBLIC API
397

    
398
  public Static3D[] getRotationAxis()
399
    {
400
    return ROT_AXIS;
401
    }
402

    
403
///////////////////////////////////////////////////////////////////////////////////////////////////
404

    
405
  public int[] getBasicAngle()
406
    {
407
    return BASIC_ANGLE;
408
    }
409

    
410
///////////////////////////////////////////////////////////////////////////////////////////////////
411

    
412
  public void randomizeNewScramble(int[][] scramble, Random rnd, int curr, int total)
413
    {
414
    if( curr==0 )
415
      {
416
      scramble[curr][0] = rnd.nextInt(NUM_AXIS);
417
      }
418
    else
419
      {
420
      int newVector = rnd.nextInt(NUM_AXIS -2);
421

    
422
      switch(scramble[curr-1][0])
423
        {
424
        case  0:
425
        case  1: scramble[curr][0] = newVector+2;
426
                 break;
427
        case  2:
428
        case  3: scramble[curr][0] = (newVector==0 || newVector==1) ? newVector:newVector+2;
429
                 break;
430
        default: scramble[curr][0] = newVector;
431
                 break;
432
        }
433
      }
434

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

    
437
    switch( rnd.nextInt(2) )
438
      {
439
      case 0: scramble[curr][2] = -1; break;
440
      case 1: scramble[curr][2] =  1; break;
441
      }
442
    }
443

    
444
///////////////////////////////////////////////////////////////////////////////////////////////////
445
// The Helicopter is solved if and only if:
446
//
447
// 1) all of its corner cubits are rotated with the same quat
448
// 2) all its face cubits are rotated with the same quat like the corner ones,
449
//    and optionally they also might be turned by a multiple of 90 degrees along
450
//    a vector perpendicular to the face they lie on.
451
//
452
// i.e.
453
// cubits  8, 9,10,11,12,13,14,15 - might be extra QUAT 1,8,9
454
// cubits 16,17,18,19,20,21,22,23 - might be extra QUAT 2,12,13
455
// cubits 24,25,26,27,28,29,30,31 - might be extra QUAT 3,14,15
456

    
457
  public boolean isSolved()
458
    {
459
    int q = CUBITS[0].mQuatIndex;
460

    
461
    if ( CUBITS[1].mQuatIndex == q &&
462
         CUBITS[2].mQuatIndex == q &&
463
         CUBITS[3].mQuatIndex == q &&
464
         CUBITS[4].mQuatIndex == q &&
465
         CUBITS[5].mQuatIndex == q &&
466
         CUBITS[6].mQuatIndex == q &&
467
         CUBITS[7].mQuatIndex == q  )
468
      {
469
      int q1 = mulQuat(q,1);
470
      int q2 = mulQuat(q,8);
471
      int q3 = mulQuat(q,9);
472

    
473
      for(int index=8; index<16; index++)
474
        {
475
        int qIndex = CUBITS[index].mQuatIndex;
476
        if( qIndex!=q && qIndex!=q1 && qIndex!=q2 && qIndex!=q3 ) return false;
477
        }
478

    
479
      q1 = mulQuat(q, 2);
480
      q2 = mulQuat(q,12);
481
      q3 = mulQuat(q,13);
482

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

    
489
      q1 = mulQuat(q, 3);
490
      q2 = mulQuat(q,14);
491
      q3 = mulQuat(q,15);
492

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

    
499
      return true;
500
      }
501

    
502
    return false;
503
    }
504

    
505
///////////////////////////////////////////////////////////////////////////////////////////////////
506
// only needed for solvers - there are no Helicopter solvers ATM)
507

    
508
  public String retObjectString()
509
    {
510
    return "";
511
    }
512

    
513
///////////////////////////////////////////////////////////////////////////////////////////////////
514

    
515
  public int getObjectName(int numLayers)
516
    {
517
    return R.string.heli3;
518
    }
519

    
520
///////////////////////////////////////////////////////////////////////////////////////////////////
521

    
522
  public int getInventor(int numLayers)
523
    {
524
    return R.string.heli3_inventor;
525
    }
526

    
527
///////////////////////////////////////////////////////////////////////////////////////////////////
528

    
529
  public int getComplexity(int numLayers)
530
    {
531
    return 8;
532
    }
533
}
(27-27/41)