Project

General

Profile

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

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

1 ee35e63c Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
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 9c2f0c91 Leszek Koltunski
public class TwistyHelicopter extends TwistyObject
42 ee35e63c Leszek Koltunski
{
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 ece1b58d Leszek Koltunski
           COLOR_YELLOW, COLOR_WHITE,
61
           COLOR_BLUE  , COLOR_GREEN,
62
           COLOR_RED   , COLOR_BROWN
63 ee35e63c Leszek Koltunski
         };
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 b0a56742 Leszek Koltunski
  private static final float DIST_CENTER = 0.50f;
98 ee35e63c Leszek Koltunski
  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 20a0214b Leszek Koltunski
           { 0,2,5, 6,6,6 },
148
           { 4,0,3, 6,6,6 },
149 ee35e63c Leszek Koltunski
           { 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 20a0214b Leszek Koltunski
  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 ee35e63c Leszek Koltunski
  private static MeshBase mCornerMesh, mFaceMesh;
190
191
///////////////////////////////////////////////////////////////////////////////////////////////////
192
193 9c2f0c91 Leszek Koltunski
  TwistyHelicopter(int size, Static4D quat, DistortedTexture texture,
194
                   MeshSquare mesh, DistortedEffects effects, int[][] moves, Resources res, int scrWidth)
195 ee35e63c Leszek Koltunski
    {
196 9c2f0c91 Leszek Koltunski
    super(size, 60, quat, texture, mesh, effects, moves, ObjectList.HELI, res, scrWidth);
197 ee35e63c Leszek Koltunski
    }
198
199
///////////////////////////////////////////////////////////////////////////////////////////////////
200
201
  float getScreenRatio()
202
    {
203 7403cdfa Leszek Koltunski
    return 1.5f;
204 ee35e63c Leszek Koltunski
    }
205
206
///////////////////////////////////////////////////////////////////////////////////////////////////
207
208
  Static4D[] getQuats()
209
    {
210
    return QUATS;
211
    }
212
213 eaee1ddc Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
214
215
  boolean shouldResetTextureMaps()
216
    {
217
    return false;
218
    }
219
220 ee35e63c Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
221
222
  int getNumFaces()
223
    {
224
    return FACE_COLORS.length;
225
    }
226
227
///////////////////////////////////////////////////////////////////////////////////////////////////
228
229
  int getNumStickerTypes()
230
    {
231
    return 1;
232
    }
233
234 7403cdfa Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
235
236
  float getBasicStep()
237
    {
238
    return SQ2/2;
239
    }
240
241 ee35e63c Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
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 ac940e24 Leszek Koltunski
      if( mCornerMesh==null ) mCornerMesh = CubitFactory.getInstance().createHelicopterCornerMesh();
264 ee35e63c Leszek Koltunski
      mesh = mCornerMesh.copy(true);
265
      }
266
    else
267
      {
268 ac940e24 Leszek Koltunski
      if( mFaceMesh==null ) mFaceMesh = CubitFactory.getInstance().createHelicopterFaceMesh();
269 ee35e63c Leszek Koltunski
      mesh = mFaceMesh.copy(true);
270
      }
271
272 20a0214b Leszek Koltunski
    int index = QUAT_INDICES[cubit];
273 ee35e63c Leszek Koltunski
    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, int top, int side)
289
    {
290
    float STROKE = 0.035f*side;
291
    float L= left+0.125f*side;
292
    float H= 0.375f*side;
293
    float LEN = 0.5f*side;
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,top,left+side,top+side,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*side;
310
    float S2 = 0.070f*side;
311
    float X  = 0.7f*S2;
312
313
    float LA = left+0.625f*side;
314
    float RA = left+0.125f*side;
315
    float TA = 0.375f*side;
316
    float BA = 0.875f*side;
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 475cbfe7 Leszek Koltunski
    float[] chances = new float[3];
335 ee35e63c Leszek Koltunski
336
    chances[0] = 0.5f;
337
    chances[1] = 0.5f;
338 475cbfe7 Leszek Koltunski
    chances[2] = 1.0f;
339 ee35e63c Leszek Koltunski
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
}