Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / TwistyRex.java @ bbc6471c

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.R;
34
import org.distorted.main.RubikSurfaceView;
35

    
36
import java.util.Random;
37

    
38
import static org.distorted.objects.FactoryCubit.REX_D;
39

    
40
///////////////////////////////////////////////////////////////////////////////////////////////////
41

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

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

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

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

    
70
           new Static4D(  0.5f,  0.5f,  0.5f,  0.5f ),
71
           new Static4D(  0.5f,  0.5f,  0.5f, -0.5f ),
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
         };
79

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

    
107
           {  6, 18,18,18,18,18 },
108
           {  7, 18,18,18,18,18 },
109
           {  8, 18,18,18,18,18 },
110
           {  9, 18,18,18,18,18 },
111
           { 10, 18,18,18,18,18 },
112
           { 11, 18,18,18,18,18 },
113

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

    
128
  private static MeshBase mCornerMesh, mFaceMesh, mEdgeMesh;
129

    
130
///////////////////////////////////////////////////////////////////////////////////////////////////
131

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

    
138
///////////////////////////////////////////////////////////////////////////////////////////////////
139

    
140
  float getScreenRatio()
141
    {
142
    return 1.5f;
143
    }
144

    
145
///////////////////////////////////////////////////////////////////////////////////////////////////
146

    
147
  Static4D[] getQuats()
148
    {
149
    return QUATS;
150
    }
151

    
152
///////////////////////////////////////////////////////////////////////////////////////////////////
153

    
154
  int getNumFaces()
155
    {
156
    return FACE_COLORS.length;
157
    }
158

    
159
///////////////////////////////////////////////////////////////////////////////////////////////////
160

    
161
  boolean shouldResetTextureMaps()
162
    {
163
    return false;
164
    }
165

    
166
///////////////////////////////////////////////////////////////////////////////////////////////////
167

    
168
  int getNumStickerTypes(int numLayers)
169
    {
170
    return 3;
171
    }
172

    
173
///////////////////////////////////////////////////////////////////////////////////////////////////
174

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

    
179
    return new float[] {-C,+C};
180
    }
181

    
182
///////////////////////////////////////////////////////////////////////////////////////////////////
183

    
184
  int getNumCubitFaces()
185
    {
186
    return FACES_PER_CUBIT;
187
    }
188

    
189
///////////////////////////////////////////////////////////////////////////////////////////////////
190

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

    
196
    final float[][] CENTERS = new float[42][];
197

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

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

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

    
243
    return CENTERS;
244
    }
245

    
246
///////////////////////////////////////////////////////////////////////////////////////////////////
247

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

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

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

    
298
    return QUATS[0];
299
    }
300

    
301
///////////////////////////////////////////////////////////////////////////////////////////////////
302

    
303
  MeshBase createCubitMesh(int cubit, int numLayers)
304
    {
305
    MeshBase mesh;
306

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

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

    
326
    return mesh;
327
    }
328

    
329
///////////////////////////////////////////////////////////////////////////////////////////////////
330

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

    
336
///////////////////////////////////////////////////////////////////////////////////////////////////
337

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

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

    
364
///////////////////////////////////////////////////////////////////////////////////////////////////
365

    
366
  float returnMultiplier()
367
    {
368
    return 2.0f;
369
    }
370

    
371
///////////////////////////////////////////////////////////////////////////////////////////////////
372

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

    
378
///////////////////////////////////////////////////////////////////////////////////////////////////
379
// PUBLIC API
380

    
381
  public Static3D[] getRotationAxis()
382
    {
383
    return ROT_AXIS;
384
    }
385

    
386
///////////////////////////////////////////////////////////////////////////////////////////////////
387

    
388
  public int getBasicAngle()
389
    {
390
    return 3;
391
    }
392

    
393
///////////////////////////////////////////////////////////////////////////////////////////////////
394

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

    
408
    float rowFloat = rnd.nextFloat();
409

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

    
419
    int random = rnd.nextInt(remScrambles);
420
    int result = random<remDoubleScrambles ? 2:1;
421
    int sign   = rnd.nextInt(2);
422

    
423
    scramble[2] = sign==0 ? result : -result;
424
    }
425

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

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

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

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

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

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

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

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

    
464
    return -1;
465
    }
466

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

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

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

    
488
    q1 = mulQuat(q,1);
489

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

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

    
498
    q1 = mulQuat(q,2);
499

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

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

    
508
    q1 = mulQuat(q,3);
509

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

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

    
518
    return true;
519
    }
520

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

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

    
529
///////////////////////////////////////////////////////////////////////////////////////////////////
530

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

    
536
///////////////////////////////////////////////////////////////////////////////////////////////////
537

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

    
543
///////////////////////////////////////////////////////////////////////////////////////////////////
544

    
545
  public int getComplexity(int numLayers)
546
    {
547
    return 3;
548
    }
549
}
(34-34/35)