Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / TwistyHelicopter.java @ 6db60be8

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

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

    
387
///////////////////////////////////////////////////////////////////////////////////////////////////
388

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

    
394
///////////////////////////////////////////////////////////////////////////////////////////////////
395
// PUBLIC API
396

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

    
402
///////////////////////////////////////////////////////////////////////////////////////////////////
403

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

    
409
///////////////////////////////////////////////////////////////////////////////////////////////////
410

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

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

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

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

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

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

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

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

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

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

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

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

    
498
      return true;
499
      }
500

    
501
    return false;
502
    }
503

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

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

    
512
///////////////////////////////////////////////////////////////////////////////////////////////////
513

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

    
519
///////////////////////////////////////////////////////////////////////////////////////////////////
520

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

    
526
///////////////////////////////////////////////////////////////////////////////////////////////////
527

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