Project

General

Profile

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

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

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

    
35
import java.util.Random;
36

    
37
import static org.distorted.effects.scramble.ScrambleEffect.START_AXIS;
38

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

    
41
public class TwistyHelicopter extends TwistyObject
42
{
43
  private static final float SQ2 = (float)Math.sqrt(2);
44

    
45
  private static final int FACES_PER_CUBIT =6;
46

    
47
  // the six rotation axis of a Helicopter. Must be normalized.
48
  static final Static3D[] ROT_AXIS = new Static3D[]
49
         {
50
           new Static3D(     0, +SQ2/2, -SQ2/2),
51
           new Static3D(     0, -SQ2/2, -SQ2/2),
52
           new Static3D(+SQ2/2,      0, -SQ2/2),
53
           new Static3D(-SQ2/2,      0, -SQ2/2),
54
           new Static3D(+SQ2/2, -SQ2/2,      0),
55
           new Static3D(-SQ2/2, -SQ2/2,      0)
56
         };
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_BROWN
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 Static3D[] CENTERS = new Static3D[]
102
         {
103
           new Static3D(   DIST_CORNER,   DIST_CORNER,   DIST_CORNER ),
104
           new Static3D(   DIST_CORNER,   DIST_CORNER,  -DIST_CORNER ),
105
           new Static3D(   DIST_CORNER,  -DIST_CORNER,   DIST_CORNER ),
106
           new Static3D(   DIST_CORNER,  -DIST_CORNER,  -DIST_CORNER ),
107
           new Static3D(  -DIST_CORNER,   DIST_CORNER,   DIST_CORNER ),
108
           new Static3D(  -DIST_CORNER,   DIST_CORNER,  -DIST_CORNER ),
109
           new Static3D(  -DIST_CORNER,  -DIST_CORNER,   DIST_CORNER ),
110
           new Static3D(  -DIST_CORNER,  -DIST_CORNER,  -DIST_CORNER ),
111

    
112
           new Static3D(   DIST_CENTER,     XY_CENTER,     XY_CENTER ),
113
           new Static3D(   DIST_CENTER,     XY_CENTER,    -XY_CENTER ),
114
           new Static3D(   DIST_CENTER,    -XY_CENTER,     XY_CENTER ),
115
           new Static3D(   DIST_CENTER,    -XY_CENTER,    -XY_CENTER ),
116

    
117
           new Static3D(  -DIST_CENTER,     XY_CENTER,     XY_CENTER ),
118
           new Static3D(  -DIST_CENTER,     XY_CENTER,    -XY_CENTER ),
119
           new Static3D(  -DIST_CENTER,    -XY_CENTER,     XY_CENTER ),
120
           new Static3D(  -DIST_CENTER,    -XY_CENTER,    -XY_CENTER ),
121

    
122
           new Static3D(   XY_CENTER  ,   DIST_CENTER,     XY_CENTER ),
123
           new Static3D(   XY_CENTER  ,   DIST_CENTER,    -XY_CENTER ),
124
           new Static3D(  -XY_CENTER  ,   DIST_CENTER,     XY_CENTER ),
125
           new Static3D(  -XY_CENTER  ,   DIST_CENTER,    -XY_CENTER ),
126

    
127
           new Static3D(   XY_CENTER  ,  -DIST_CENTER,     XY_CENTER ),
128
           new Static3D(   XY_CENTER  ,  -DIST_CENTER,    -XY_CENTER ),
129
           new Static3D(  -XY_CENTER  ,  -DIST_CENTER,     XY_CENTER ),
130
           new Static3D(  -XY_CENTER  ,  -DIST_CENTER,    -XY_CENTER ),
131

    
132
           new Static3D(   XY_CENTER  ,     XY_CENTER,   DIST_CENTER ),
133
           new Static3D(   XY_CENTER  ,    -XY_CENTER,   DIST_CENTER ),
134
           new Static3D(  -XY_CENTER  ,     XY_CENTER,   DIST_CENTER ),
135
           new Static3D(  -XY_CENTER  ,    -XY_CENTER,   DIST_CENTER ),
136

    
137
           new Static3D(   XY_CENTER  ,     XY_CENTER,  -DIST_CENTER ),
138
           new Static3D(   XY_CENTER  ,    -XY_CENTER,  -DIST_CENTER ),
139
           new Static3D(  -XY_CENTER  ,     XY_CENTER,  -DIST_CENTER ),
140
           new Static3D(  -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 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 MeshBase mCornerMesh, mFaceMesh;
190

    
191
///////////////////////////////////////////////////////////////////////////////////////////////////
192

    
193
  TwistyHelicopter(int size, Static4D quat, DistortedTexture texture,
194
                   MeshSquare mesh, DistortedEffects effects, int[][] moves, Resources res, int scrWidth)
195
    {
196
    super(size, 60, quat, texture, mesh, effects, moves, ObjectList.HELI, res, scrWidth);
197
    }
198

    
199
///////////////////////////////////////////////////////////////////////////////////////////////////
200

    
201
  float getScreenRatio()
202
    {
203
    return 1.5f;
204
    }
205

    
206
///////////////////////////////////////////////////////////////////////////////////////////////////
207

    
208
  Static4D[] getQuats()
209
    {
210
    return QUATS;
211
    }
212

    
213
///////////////////////////////////////////////////////////////////////////////////////////////////
214

    
215
  boolean shouldResetTextureMaps()
216
    {
217
    return false;
218
    }
219

    
220
///////////////////////////////////////////////////////////////////////////////////////////////////
221

    
222
  int getNumFaces()
223
    {
224
    return FACE_COLORS.length;
225
    }
226

    
227
///////////////////////////////////////////////////////////////////////////////////////////////////
228

    
229
  int getNumStickerTypes()
230
    {
231
    return 1;
232
    }
233

    
234
///////////////////////////////////////////////////////////////////////////////////////////////////
235

    
236
  float getBasicStep()
237
    {
238
    return SQ2/2;
239
    }
240

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

    
243
  int getNumCubitFaces()
244
    {
245
    return FACES_PER_CUBIT;
246
    }
247

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

    
250
  Static3D[] getCubitPositions(int size)
251
    {
252
    return CENTERS;
253
    }
254

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

    
257
  MeshBase createCubitMesh(int cubit)
258
    {
259
    MeshBase mesh;
260

    
261
    if( cubit<8 )
262
      {
263
      if( mCornerMesh==null ) mCornerMesh = CubitFactory.getInstance().createHelicopterCornerMesh();
264
      mesh = mCornerMesh.copy(true);
265
      }
266
    else
267
      {
268
      if( mFaceMesh==null ) mFaceMesh = CubitFactory.getInstance().createHelicopterFaceMesh();
269
      mesh = mFaceMesh.copy(true);
270
      }
271

    
272
    int index = QUAT_INDICES[cubit];
273
    MatrixEffectQuaternion quat = new MatrixEffectQuaternion( QUATS[index], new Static3D(0,0,0) );
274
    mesh.apply(quat,0xffffffff,0);
275

    
276
    return mesh;
277
    }
278

    
279
///////////////////////////////////////////////////////////////////////////////////////////////////
280

    
281
  int getFaceColor(int cubit, int cubitface, int size)
282
    {
283
    return mFaceMap[cubit][cubitface];
284
    }
285

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

    
288
  void createFaceTexture(Canvas canvas, Paint paint, int face, int left)
289
    {
290
    float STROKE = 0.035f*TEXTURE_HEIGHT;
291
    float L= left+0.125f*TEXTURE_HEIGHT;
292
    float H= 0.375f*TEXTURE_HEIGHT;
293
    float LEN = 0.5f*TEXTURE_HEIGHT;
294

    
295
    paint.setAntiAlias(true);
296
    paint.setStrokeWidth(STROKE);
297
    paint.setColor(FACE_COLORS[face]);
298
    paint.setStyle(Paint.Style.FILL);
299

    
300
    canvas.drawRect(left,0,left+TEXTURE_HEIGHT,TEXTURE_HEIGHT,paint);
301

    
302
    paint.setColor(INTERIOR_COLOR);
303
    paint.setStyle(Paint.Style.STROKE);
304

    
305
    canvas.drawLine( L    , H,  L+LEN, H    , paint);
306
    canvas.drawLine( L    , H,  L+LEN, H+LEN, paint);
307
    canvas.drawLine( L+LEN, H,  L+LEN, H+LEN, paint);
308

    
309
    float S1 = 0.125f*TEXTURE_HEIGHT;
310
    float S2 = 0.070f*TEXTURE_HEIGHT;
311
    float X  = 0.7f*S2;
312

    
313
    float LA = left+0.625f*TEXTURE_HEIGHT;
314
    float RA = left+0.125f*TEXTURE_HEIGHT;
315
    float TA = 0.375f*TEXTURE_HEIGHT;
316
    float BA = 0.875f*TEXTURE_HEIGHT;
317

    
318
    canvas.drawArc( LA-S1, TA     , LA     , TA+S1, 270, 90, false, paint);
319
    canvas.drawArc( RA+X , TA     , RA+X+S2, TA+S2, 135,135, false, paint);
320
    canvas.drawArc( LA-S2, BA-X-S2, LA     , BA-X ,   0,135, false, paint);
321
    }
322

    
323
///////////////////////////////////////////////////////////////////////////////////////////////////
324

    
325
  float returnMultiplier()
326
    {
327
    return 2.0f;
328
    }
329

    
330
///////////////////////////////////////////////////////////////////////////////////////////////////
331

    
332
  float[] getRowChances()
333
    {
334
    float[] chances = new float[3];
335

    
336
    chances[0] = 0.5f;
337
    chances[1] = 0.5f;
338
    chances[2] = 1.0f;
339

    
340
    return chances;
341
    }
342

    
343
///////////////////////////////////////////////////////////////////////////////////////////////////
344
// PUBLIC API
345

    
346
  public Static3D[] getRotationAxis()
347
    {
348
    return ROT_AXIS;
349
    }
350

    
351
///////////////////////////////////////////////////////////////////////////////////////////////////
352

    
353
  public int getBasicAngle()
354
    {
355
    return 2;
356
    }
357

    
358
///////////////////////////////////////////////////////////////////////////////////////////////////
359

    
360
  public int randomizeNewRotAxis(Random rnd, int oldRotAxis)
361
    {
362
    int numAxis = ROTATION_AXIS.length;
363

    
364
    if( oldRotAxis == START_AXIS )
365
      {
366
      return rnd.nextInt(numAxis);
367
      }
368
    else
369
      {
370
      int newVector = rnd.nextInt(numAxis-2);
371

    
372
      switch(oldRotAxis)
373
        {
374
        case  0:
375
        case  1: return newVector+2;
376
        case  2:
377
        case  3: return (newVector==0 || newVector==1) ? newVector:newVector+2;
378
        default: return newVector;
379
        }
380
      }
381
    }
382

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

    
385
  public int randomizeNewRow(Random rnd, int oldRotAxis, int oldRow, int newRotAxis)
386
    {
387
    float rowFloat = rnd.nextFloat();
388

    
389
    for(int row=0; row<mRowChances.length; row++)
390
      {
391
      if( rowFloat<=mRowChances[row] ) return row;
392
      }
393

    
394
    return 0;
395
    }
396

    
397
///////////////////////////////////////////////////////////////////////////////////////////////////
398
// remember about the double cover or unit quaternions!
399

    
400
  private int mulQuat(int q1, int q2)
401
    {
402
    Static4D result = RubikSurfaceView.quatMultiply(QUATS[q1],QUATS[q2]);
403

    
404
    float rX = result.get0();
405
    float rY = result.get1();
406
    float rZ = result.get2();
407
    float rW = result.get3();
408

    
409
    final float MAX_ERROR = 0.1f;
410
    float dX,dY,dZ,dW;
411

    
412
    for(int i=0; i<QUATS.length; i++)
413
      {
414
      dX = QUATS[i].get0() - rX;
415
      dY = QUATS[i].get1() - rY;
416
      dZ = QUATS[i].get2() - rZ;
417
      dW = QUATS[i].get3() - rW;
418

    
419
      if( dX<MAX_ERROR && dX>-MAX_ERROR &&
420
          dY<MAX_ERROR && dY>-MAX_ERROR &&
421
          dZ<MAX_ERROR && dZ>-MAX_ERROR &&
422
          dW<MAX_ERROR && dW>-MAX_ERROR  ) return i;
423

    
424
      dX = QUATS[i].get0() + rX;
425
      dY = QUATS[i].get1() + rY;
426
      dZ = QUATS[i].get2() + rZ;
427
      dW = QUATS[i].get3() + rW;
428

    
429
      if( dX<MAX_ERROR && dX>-MAX_ERROR &&
430
          dY<MAX_ERROR && dY>-MAX_ERROR &&
431
          dZ<MAX_ERROR && dZ>-MAX_ERROR &&
432
          dW<MAX_ERROR && dW>-MAX_ERROR  ) return i;
433
      }
434

    
435
    return -1;
436
    }
437

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

    
451
  public boolean isSolved()
452
    {
453
    int q = CUBITS[0].mQuatIndex;
454

    
455
    if ( CUBITS[1].mQuatIndex == q &&
456
         CUBITS[2].mQuatIndex == q &&
457
         CUBITS[3].mQuatIndex == q &&
458
         CUBITS[4].mQuatIndex == q &&
459
         CUBITS[5].mQuatIndex == q &&
460
         CUBITS[6].mQuatIndex == q &&
461
         CUBITS[7].mQuatIndex == q  )
462
      {
463
      int q1 = mulQuat(q,1);
464
      int q2 = mulQuat(q,8);
465
      int q3 = mulQuat(q,9);
466

    
467
      for(int index=8; index<16; index++)
468
        {
469
        int qIndex = CUBITS[index].mQuatIndex;
470
        if( qIndex!=q && qIndex!=q1 && qIndex!=q2 && qIndex!=q3 ) return false;
471
        }
472

    
473
      q1 = mulQuat(q, 2);
474
      q2 = mulQuat(q,12);
475
      q3 = mulQuat(q,13);
476

    
477
      for(int index=16; index<24; index++)
478
        {
479
        int qIndex = CUBITS[index].mQuatIndex;
480
        if( qIndex!=q && qIndex!=q1 && qIndex!=q2 && qIndex!=q3 ) return false;
481
        }
482

    
483
      q1 = mulQuat(q, 3);
484
      q2 = mulQuat(q,14);
485
      q3 = mulQuat(q,15);
486

    
487
      for(int index=24; index<32; index++)
488
        {
489
        int qIndex = CUBITS[index].mQuatIndex;
490
        if( qIndex!=q && qIndex!=q1 && qIndex!=q2 && qIndex!=q3 ) return false;
491
        }
492

    
493
      return true;
494
      }
495

    
496
    return false;
497
    }
498

    
499
///////////////////////////////////////////////////////////////////////////////////////////////////
500
// only needed for solvers - there are no Helicopter solvers ATM)
501

    
502
  public String retObjectString()
503
    {
504
    return "";
505
    }
506

    
507
}
(16-16/19)