Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / TwistyRex.java @ 749ef882

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
import org.distorted.main.RubikSurfaceView;
37

    
38
import java.util.Random;
39

    
40
import static org.distorted.helpers.FactoryCubit.REX_D;
41

    
42
///////////////////////////////////////////////////////////////////////////////////////////////////
43

    
44
public class TwistyRex extends TwistyObject
45
{
46
  private static final int FACES_PER_CUBIT =6;
47

    
48
  // the four rotation axis of a RubikRex. Must be normalized.
49
  static final Static3D[] ROT_AXIS = new Static3D[]
50
         {
51
           new Static3D(+SQ3/3,+SQ3/3,+SQ3/3),
52
           new Static3D(+SQ3/3,+SQ3/3,-SQ3/3),
53
           new Static3D(+SQ3/3,-SQ3/3,+SQ3/3),
54
           new Static3D(+SQ3/3,-SQ3/3,-SQ3/3)
55
         };
56

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

    
64
  // All legal rotation quats of a RubikRex
65
  private static final Static4D[] QUATS = new Static4D[]
66
         {
67
           new Static4D(  0.0f,  0.0f,  0.0f,  1.0f ),
68
           new Static4D(  1.0f,  0.0f,  0.0f,  0.0f ),
69
           new Static4D(  0.0f,  1.0f,  0.0f,  0.0f ),
70
           new Static4D(  0.0f,  0.0f,  1.0f,  0.0f ),
71

    
72
           new Static4D(  0.5f,  0.5f,  0.5f,  0.5f ),
73
           new Static4D(  0.5f,  0.5f,  0.5f, -0.5f ),
74
           new Static4D(  0.5f,  0.5f, -0.5f,  0.5f ),
75
           new Static4D(  0.5f,  0.5f, -0.5f, -0.5f ),
76
           new Static4D(  0.5f, -0.5f,  0.5f,  0.5f ),
77
           new Static4D(  0.5f, -0.5f,  0.5f, -0.5f ),
78
           new Static4D(  0.5f, -0.5f, -0.5f,  0.5f ),
79
           new Static4D(  0.5f, -0.5f, -0.5f, -0.5f )
80
         };
81

    
82
  private static final int[][] mFaceMap =
83
         {
84
           {  0, 18,18,18,18,18 },
85
           {  0, 18,18,18,18,18 },
86
           {  0, 18,18,18,18,18 },
87
           {  0, 18,18,18,18,18 },
88
           {  1, 18,18,18,18,18 },
89
           {  1, 18,18,18,18,18 },
90
           {  1, 18,18,18,18,18 },
91
           {  1, 18,18,18,18,18 },
92
           {  2, 18,18,18,18,18 },
93
           {  2, 18,18,18,18,18 },
94
           {  2, 18,18,18,18,18 },
95
           {  2, 18,18,18,18,18 },
96
           {  3, 18,18,18,18,18 },
97
           {  3, 18,18,18,18,18 },
98
           {  3, 18,18,18,18,18 },
99
           {  3, 18,18,18,18,18 },
100
           {  4, 18,18,18,18,18 },
101
           {  4, 18,18,18,18,18 },
102
           {  4, 18,18,18,18,18 },
103
           {  4, 18,18,18,18,18 },
104
           {  5, 18,18,18,18,18 },
105
           {  5, 18,18,18,18,18 },
106
           {  5, 18,18,18,18,18 },
107
           {  5, 18,18,18,18,18 },
108

    
109
           {  6, 18,18,18,18,18 },
110
           {  7, 18,18,18,18,18 },
111
           {  8, 18,18,18,18,18 },
112
           {  9, 18,18,18,18,18 },
113
           { 10, 18,18,18,18,18 },
114
           { 11, 18,18,18,18,18 },
115

    
116
           { 16,14, 18,18,18,18 },
117
           { 16,12, 18,18,18,18 },
118
           { 16,15, 18,18,18,18 },
119
           { 16,13, 18,18,18,18 },
120
           { 12,14, 18,18,18,18 },
121
           { 15,12, 18,18,18,18 },
122
           { 15,13, 18,18,18,18 },
123
           { 13,14, 18,18,18,18 },
124
           { 14,17, 18,18,18,18 },
125
           { 12,17, 18,18,18,18 },
126
           { 17,15, 18,18,18,18 },
127
           { 13,17, 18,18,18,18 },
128
         };
129

    
130
  private static MeshBase mCornerMesh, mFaceMesh, mEdgeMesh;
131

    
132
///////////////////////////////////////////////////////////////////////////////////////////////////
133

    
134
  TwistyRex(int size, Static4D quat, DistortedTexture texture, MeshSquare mesh,
135
            DistortedEffects effects, int[][] moves, Resources res, int scrWidth)
136
    {
137
    super(size, size, quat, texture, mesh, effects, moves, ObjectList.REX, res, scrWidth);
138
    }
139

    
140
///////////////////////////////////////////////////////////////////////////////////////////////////
141

    
142
  float getScreenRatio()
143
    {
144
    return 1.5f;
145
    }
146

    
147
///////////////////////////////////////////////////////////////////////////////////////////////////
148

    
149
  Static4D[] getQuats()
150
    {
151
    return QUATS;
152
    }
153

    
154
///////////////////////////////////////////////////////////////////////////////////////////////////
155

    
156
  int getNumFaces()
157
    {
158
    return FACE_COLORS.length;
159
    }
160

    
161
///////////////////////////////////////////////////////////////////////////////////////////////////
162

    
163
  boolean shouldResetTextureMaps()
164
    {
165
    return false;
166
    }
167

    
168
///////////////////////////////////////////////////////////////////////////////////////////////////
169

    
170
  int getNumStickerTypes(int numLayers)
171
    {
172
    return 3;
173
    }
174

    
175
///////////////////////////////////////////////////////////////////////////////////////////////////
176

    
177
  float[] getCuts(int numLayers)
178
    {
179
    float C = SQ3*0.15f;   // bit less than 1/6 of the length of the main diagonal
180

    
181
    return new float[] {-C,+C};
182
    }
183

    
184
///////////////////////////////////////////////////////////////////////////////////////////////////
185

    
186
  int getNumCubitFaces()
187
    {
188
    return FACES_PER_CUBIT;
189
    }
190

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

    
193
  float[][] getCubitPositions(int numLayers)
194
    {
195
    final float DIST = 0.50f;
196
    final float DIST2= (1+2*REX_D)/6;
197

    
198
    final float[][] CENTERS = new float[42][];
199

    
200
    CENTERS[ 0] = new float[] { +DIST , +DIST2, +DIST2};
201
    CENTERS[ 1] = new float[] { +DIST , +DIST2, -DIST2};
202
    CENTERS[ 2] = new float[] { +DIST , -DIST2, -DIST2};
203
    CENTERS[ 3] = new float[] { +DIST , -DIST2, +DIST2};
204
    CENTERS[ 4] = new float[] { -DIST , +DIST2, +DIST2};
205
    CENTERS[ 5] = new float[] { -DIST , +DIST2, -DIST2};
206
    CENTERS[ 6] = new float[] { -DIST , -DIST2, -DIST2};
207
    CENTERS[ 7] = new float[] { -DIST , -DIST2, +DIST2};
208
    CENTERS[ 8] = new float[] { +DIST2, +DIST , +DIST2};
209
    CENTERS[ 9] = new float[] { +DIST2, +DIST , -DIST2};
210
    CENTERS[10] = new float[] { -DIST2, +DIST , -DIST2};
211
    CENTERS[11] = new float[] { -DIST2, +DIST , +DIST2};
212
    CENTERS[12] = new float[] { +DIST2, -DIST , +DIST2};
213
    CENTERS[13] = new float[] { +DIST2, -DIST , -DIST2};
214
    CENTERS[14] = new float[] { -DIST2, -DIST , -DIST2};
215
    CENTERS[15] = new float[] { -DIST2, -DIST , +DIST2};
216
    CENTERS[16] = new float[] { +DIST2, +DIST2, +DIST };
217
    CENTERS[17] = new float[] { +DIST2, -DIST2, +DIST };
218
    CENTERS[18] = new float[] { -DIST2, -DIST2, +DIST };
219
    CENTERS[19] = new float[] { -DIST2, +DIST2, +DIST };
220
    CENTERS[20] = new float[] { +DIST2, +DIST2, -DIST };
221
    CENTERS[21] = new float[] { +DIST2, -DIST2, -DIST };
222
    CENTERS[22] = new float[] { -DIST2, -DIST2, -DIST };
223
    CENTERS[23] = new float[] { -DIST2, +DIST2, -DIST };
224

    
225
    CENTERS[24] = new float[] { +DIST , +0.00f, +0.00f};
226
    CENTERS[25] = new float[] { -DIST , +0.00f, +0.00f};
227
    CENTERS[26] = new float[] { +0.00f, +DIST , +0.00f};
228
    CENTERS[27] = new float[] { +0.00f, -DIST , +0.00f};
229
    CENTERS[28] = new float[] { +0.00f, +0.00f, +DIST };
230
    CENTERS[29] = new float[] { +0.00f, +0.00f, -DIST };
231

    
232
    CENTERS[30] = new float[] { +0.00f, +DIST , +DIST };
233
    CENTERS[31] = new float[] { +DIST , +0.00f, +DIST };
234
    CENTERS[32] = new float[] { +0.00f, -DIST , +DIST };
235
    CENTERS[33] = new float[] { -DIST , +0.00f, +DIST };
236
    CENTERS[34] = new float[] { +DIST , +DIST , +0.00f};
237
    CENTERS[35] = new float[] { +DIST , -DIST , +0.00f};
238
    CENTERS[36] = new float[] { -DIST , -DIST , +0.00f};
239
    CENTERS[37] = new float[] { -DIST , +DIST , +0.00f};
240
    CENTERS[38] = new float[] { +0.00f, +DIST , -DIST };
241
    CENTERS[39] = new float[] { +DIST , +0.00f, -DIST };
242
    CENTERS[40] = new float[] { +0.00f, -DIST , -DIST };
243
    CENTERS[41] = new float[] { -DIST , +0.00f, -DIST };
244

    
245
    return CENTERS;
246
    }
247

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

    
250
  private Static4D getQuat(int cubit)
251
    {
252
    switch(cubit)
253
      {
254
      case  0: return new Static4D(+SQ2/2,     0,+SQ2/2,     0);
255
      case  1: return QUATS[5];
256
      case  2: return new Static4D(     0,-SQ2/2,     0, SQ2/2);
257
      case  3: return QUATS[8];
258
      case  4: return QUATS[6];
259
      case  5: return new Static4D(-SQ2/2,     0,+SQ2/2,     0);
260
      case  6: return QUATS[11];
261
      case  7: return new Static4D(     0,+SQ2/2,     0, SQ2/2);
262
      case  8: return new Static4D(+SQ2/2,     0,     0, SQ2/2);
263
      case  9: return QUATS[10];
264
      case 10: return new Static4D(     0,+SQ2/2,+SQ2/2,     0);
265
      case 11: return QUATS[4];
266
      case 12: return QUATS[9];
267
      case 13: return new Static4D(-SQ2/2,     0,     0, SQ2/2);
268
      case 14: return QUATS[7];
269
      case 15: return new Static4D(     0,-SQ2/2,+SQ2/2,     0);
270
      case 16: return new Static4D(     0,     0,-SQ2/2, SQ2/2);
271
      case 17: return QUATS[0];
272
      case 18: return new Static4D(     0,     0,+SQ2/2, SQ2/2);
273
      case 19: return QUATS[3];
274
      case 20: return QUATS[1];
275
      case 21: return new Static4D(+SQ2/2,-SQ2/2,     0,     0);
276
      case 22: return QUATS[2];
277
      case 23: return new Static4D(+SQ2/2,+SQ2/2,     0,     0);
278

    
279
      case 24: return new Static4D(     0,-SQ2/2,     0, SQ2/2);
280
      case 25: return new Static4D(     0,+SQ2/2,     0, SQ2/2);
281
      case 26: return new Static4D(+SQ2/2,     0,     0, SQ2/2);
282
      case 27: return new Static4D(-SQ2/2,     0,     0, SQ2/2);
283
      case 28: return QUATS[0];
284
      case 29: return QUATS[1];
285

    
286
      case 30: return QUATS[0];
287
      case 31: return new Static4D(     0,     0,+SQ2/2, SQ2/2);
288
      case 32: return QUATS[3];
289
      case 33: return new Static4D(     0,     0,-SQ2/2, SQ2/2);
290
      case 34: return new Static4D(     0,-SQ2/2,     0, SQ2/2);
291
      case 35: return QUATS[7];
292
      case 36: return QUATS[9];
293
      case 37: return new Static4D(     0,+SQ2/2,     0, SQ2/2);
294
      case 38: return new Static4D(+SQ2/2,     0,     0, SQ2/2);
295
      case 39: return QUATS[8];
296
      case 40: return QUATS[1];
297
      case 41: return QUATS[6];
298
      }
299

    
300
    return QUATS[0];
301
    }
302

    
303
///////////////////////////////////////////////////////////////////////////////////////////////////
304

    
305
  MeshBase createCubitMesh(int cubit, int numLayers)
306
    {
307
    MeshBase mesh;
308

    
309
    if( cubit<24 )
310
      {
311
      if( mCornerMesh==null ) mCornerMesh = FactoryCubit.getInstance().createRexCornerMesh();
312
      mesh = mCornerMesh.copy(true);
313
      }
314
    else if( cubit<30 )
315
      {
316
      if( mFaceMesh==null ) mFaceMesh = FactoryCubit.getInstance().createRexFaceMesh();
317
      mesh = mFaceMesh.copy(true);
318
      }
319
    else
320
      {
321
      if( mEdgeMesh==null ) mEdgeMesh = FactoryCubit.getInstance().createRexEdgeMesh();
322
      mesh = mEdgeMesh.copy(true);
323
      }
324

    
325
    MatrixEffectQuaternion quat = new MatrixEffectQuaternion( getQuat(cubit), new Static3D(0,0,0) );
326
    mesh.apply(quat,0xffffffff,0);
327

    
328
    return mesh;
329
    }
330

    
331
///////////////////////////////////////////////////////////////////////////////////////////////////
332

    
333
  int getFaceColor(int cubit, int cubitface, int numLayers)
334
    {
335
    return mFaceMap[cubit][cubitface];
336
    }
337

    
338
///////////////////////////////////////////////////////////////////////////////////////////////////
339

    
340
  void createFaceTexture(Canvas canvas, Paint paint, int face, int left, int top)
341
    {
342
    int COLORS = FACE_COLORS.length;
343
    FactorySticker factory = FactorySticker.getInstance();
344
    float S1 = 0.050f;
345
    float S2 = 0.051f;
346
    float R1 = 0.07f;
347
    float R2 = 0.02f;
348
    float R3 = 0.06f;
349
    float R4 = 0.04f;
350

    
351
    if( face<COLORS )
352
      {
353
      factory.drawRexCornerSticker(canvas, paint, left, top, FACE_COLORS[face%COLORS], S1, R2, R3);
354
      }
355
    else if( face<2*COLORS )
356
      {
357
      float[] vertices = { -REX_D,0.0f, 0.0f, -REX_D, +REX_D, 0.0f, 0.0f, +REX_D};
358
      factory.drawRoundedPolygon(canvas, paint, left, top, vertices, S1, FACE_COLORS[face%COLORS], R4);
359
      }
360
    else
361
      {
362
      factory.drawRexEdgeSticker(canvas, paint, left, top, FACE_COLORS[face%COLORS], S2, R1);
363
      }
364
    }
365

    
366
///////////////////////////////////////////////////////////////////////////////////////////////////
367

    
368
  float returnMultiplier()
369
    {
370
    return 2.0f;
371
    }
372

    
373
///////////////////////////////////////////////////////////////////////////////////////////////////
374

    
375
  float[] getRowChances(int numLayers)
376
    {
377
    return new float[] { 0.5f, 0.5f, 1.0f };
378
    }
379

    
380
///////////////////////////////////////////////////////////////////////////////////////////////////
381
// PUBLIC API
382

    
383
  public Static3D[] getRotationAxis()
384
    {
385
    return ROT_AXIS;
386
    }
387

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

    
390
  public int getBasicAngle()
391
    {
392
    return 3;
393
    }
394

    
395
///////////////////////////////////////////////////////////////////////////////////////////////////
396

    
397
  public void randomizeNewScramble(int[][] scramble, Random rnd, int num)
398
    {
399
    if( num==0 )
400
      {
401
      scramble[num][0] = rnd.nextInt(ROTATION_AXIS.length);
402
      }
403
    else
404
      {
405
      int newVector = rnd.nextInt(ROTATION_AXIS.length-1);
406
      scramble[num][0] = (newVector>=scramble[num-1][0] ? newVector+1 : newVector);
407
      }
408

    
409
    float rowFloat = rnd.nextFloat();
410

    
411
    for(int row=0; row<mRowChances.length; row++)
412
      {
413
      if( rowFloat<=mRowChances[row] )
414
        {
415
        scramble[num][1] = row;
416
        break;
417
        }
418
      }
419

    
420
    switch( rnd.nextInt(2) )
421
      {
422
      case 0: scramble[num][2] = -1; break;
423
      case 1: scramble[num][2] =  1; break;
424
      }
425
    }
426

    
427
///////////////////////////////////////////////////////////////////////////////////////////////////
428
// remember about the double cover or unit quaternions!
429

    
430
  private int mulQuat(int q1, int q2)
431
    {
432
    Static4D result = RubikSurfaceView.quatMultiply(QUATS[q1],QUATS[q2]);
433

    
434
    float rX = result.get0();
435
    float rY = result.get1();
436
    float rZ = result.get2();
437
    float rW = result.get3();
438

    
439
    final float MAX_ERROR = 0.1f;
440
    float dX,dY,dZ,dW;
441

    
442
    for(int i=0; i<QUATS.length; i++)
443
      {
444
      dX = QUATS[i].get0() - rX;
445
      dY = QUATS[i].get1() - rY;
446
      dZ = QUATS[i].get2() - rZ;
447
      dW = QUATS[i].get3() - rW;
448

    
449
      if( dX<MAX_ERROR && dX>-MAX_ERROR &&
450
          dY<MAX_ERROR && dY>-MAX_ERROR &&
451
          dZ<MAX_ERROR && dZ>-MAX_ERROR &&
452
          dW<MAX_ERROR && dW>-MAX_ERROR  ) return i;
453

    
454
      dX = QUATS[i].get0() + rX;
455
      dY = QUATS[i].get1() + rY;
456
      dZ = QUATS[i].get2() + rZ;
457
      dW = QUATS[i].get3() + rW;
458

    
459
      if( dX<MAX_ERROR && dX>-MAX_ERROR &&
460
          dY<MAX_ERROR && dY>-MAX_ERROR &&
461
          dZ<MAX_ERROR && dZ>-MAX_ERROR &&
462
          dW<MAX_ERROR && dW>-MAX_ERROR  ) return i;
463
      }
464

    
465
    return -1;
466
    }
467

    
468
///////////////////////////////////////////////////////////////////////////////////////////////////
469
// The Rex is solved if and only if:
470
//
471
// 1) all 12 of its edge cubits are rotated with the same quat
472
// 2) all its face & corner cubits are rotated with the same quat like the edge ones,
473
//    and optionally they also might be upside down.
474
//
475
// i.e.
476
// corners ( 0, 1, 2, 3, 4, 5, 6, 7) and faces (24,25) - might be extra QUAT[1]
477
// corners ( 8, 9,10,11,12,13,14,15) and faces (26,27) - might be extra QUAT[2]
478
// corners (16,17,18,19,20,21,22,23) and faces (28,29) - might be extra QUAT[3]
479

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

    
484
    for(int i=31; i<42; i++)
485
      {
486
      if( CUBITS[i].mQuatIndex != q) return false;
487
      }
488

    
489
    q1 = mulQuat(q,1);
490

    
491
    for(int i=0; i<8; i++)
492
      {
493
      if( CUBITS[i].mQuatIndex != q && CUBITS[i].mQuatIndex != q1 ) return false;
494
      }
495

    
496
    if( CUBITS[24].mQuatIndex != q && CUBITS[24].mQuatIndex != q1 ) return false;
497
    if( CUBITS[25].mQuatIndex != q && CUBITS[25].mQuatIndex != q1 ) return false;
498

    
499
    q1 = mulQuat(q,2);
500

    
501
    for(int i=8; i<16; i++)
502
      {
503
      if( CUBITS[i].mQuatIndex != q && CUBITS[i].mQuatIndex != q1 ) return false;
504
      }
505

    
506
    if( CUBITS[26].mQuatIndex != q && CUBITS[26].mQuatIndex != q1 ) return false;
507
    if( CUBITS[27].mQuatIndex != q && CUBITS[27].mQuatIndex != q1 ) return false;
508

    
509
    q1 = mulQuat(q,3);
510

    
511
    for(int i=16; i<24; i++)
512
      {
513
      if( CUBITS[i].mQuatIndex != q && CUBITS[i].mQuatIndex != q1 ) return false;
514
      }
515

    
516
    if( CUBITS[28].mQuatIndex != q && CUBITS[28].mQuatIndex != q1 ) return false;
517
    if( CUBITS[29].mQuatIndex != q && CUBITS[29].mQuatIndex != q1 ) return false;
518

    
519
    return true;
520
    }
521

    
522
///////////////////////////////////////////////////////////////////////////////////////////////////
523
// only needed for solvers - there are no Rex solvers ATM
524

    
525
  public String retObjectString()
526
    {
527
    return "";
528
    }
529

    
530
///////////////////////////////////////////////////////////////////////////////////////////////////
531

    
532
  public int getObjectName(int numLayers)
533
    {
534
    return R.string.rex3;
535
    }
536

    
537
///////////////////////////////////////////////////////////////////////////////////////////////////
538

    
539
  public int getInventor(int numLayers)
540
    {
541
    return R.string.rex3_inventor;
542
    }
543

    
544
///////////////////////////////////////////////////////////////////////////////////////////////////
545

    
546
  public int getComplexity(int numLayers)
547
    {
548
    return 3;
549
    }
550
}
(32-32/33)