Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / TwistyCube.java @ 67b2d57b

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2019 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.main.DistortedEffects;
29
import org.distorted.library.main.DistortedTexture;
30
import org.distorted.library.mesh.MeshBase;
31
import org.distorted.library.mesh.MeshSquare;
32
import org.distorted.library.type.Static3D;
33
import org.distorted.library.type.Static4D;
34
import org.distorted.main.R;
35

    
36
import java.util.Random;
37

    
38
///////////////////////////////////////////////////////////////////////////////////////////////////
39

    
40
class TwistyCube extends TwistyObject
41
{
42
  // the three rotation axis of a RubikCube. Must be normalized.
43
  static final Static3D[] ROT_AXIS = new Static3D[]
44
         {
45
           new Static3D(1,0,0),
46
           new Static3D(0,1,0),
47
           new Static3D(0,0,1)
48
         };
49

    
50
  private static final int[] FACE_COLORS = new int[]
51
         {
52
           COLOR_YELLOW, COLOR_WHITE,
53
           COLOR_BLUE  , COLOR_GREEN,
54
           COLOR_RED   , COLOR_ORANGE
55
         };
56

    
57
  // All legal rotation quats of a RubikCube of any size.
58
  // Here's how to compute this:
59
  // 1) compute how many rotations there are (RubikCube of any size = 24)
60
  // 2) take the AXIS, angles of rotation (90 in RubikCube's case) compute the basic quaternions
61
  // (i.e. rotations of 1 basic angle along each of the axis) and from there start semi-randomly
62
  // multiplying them and eventually you'll find all (24) legal rotations.
63
  // Example program in C, res/raw/compute_quats.c , is included.
64
  private static final Static4D[] QUATS = new Static4D[]
65
         {
66
         new Static4D(  0.0f,   0.0f,   0.0f,   1.0f),
67
         new Static4D(  1.0f,   0.0f,   0.0f,   0.0f),
68
         new Static4D(  0.0f,   1.0f,   0.0f,   0.0f),
69
         new Static4D(  0.0f,   0.0f,   1.0f,   0.0f),
70

    
71
         new Static4D( SQ2/2,  SQ2/2,  0.0f ,   0.0f),
72
         new Static4D( SQ2/2, -SQ2/2,  0.0f ,   0.0f),
73
         new Static4D( SQ2/2,   0.0f,  SQ2/2,   0.0f),
74
         new Static4D(-SQ2/2,   0.0f,  SQ2/2,   0.0f),
75
         new Static4D( SQ2/2,   0.0f,   0.0f,  SQ2/2),
76
         new Static4D( SQ2/2,   0.0f,   0.0f, -SQ2/2),
77
         new Static4D(  0.0f,  SQ2/2,  SQ2/2,   0.0f),
78
         new Static4D(  0.0f,  SQ2/2, -SQ2/2,   0.0f),
79
         new Static4D(  0.0f,  SQ2/2,   0.0f,  SQ2/2),
80
         new Static4D(  0.0f,  SQ2/2,   0.0f, -SQ2/2),
81
         new Static4D(  0.0f,   0.0f,  SQ2/2,  SQ2/2),
82
         new Static4D(  0.0f,   0.0f,  SQ2/2, -SQ2/2),
83

    
84
         new Static4D(  0.5f,   0.5f,   0.5f,   0.5f),
85
         new Static4D(  0.5f,   0.5f,  -0.5f,   0.5f),
86
         new Static4D(  0.5f,   0.5f,  -0.5f,  -0.5f),
87
         new Static4D(  0.5f,  -0.5f,   0.5f,  -0.5f),
88
         new Static4D( -0.5f,  -0.5f,  -0.5f,   0.5f),
89
         new Static4D( -0.5f,   0.5f,  -0.5f,  -0.5f),
90
         new Static4D( -0.5f,   0.5f,   0.5f,  -0.5f),
91
         new Static4D( -0.5f,   0.5f,   0.5f,   0.5f)
92
         };
93

    
94
  private static final double[][] VERTICES = new double[][]
95
          {
96
              { 0.5, 0.5, 0.5 },
97
              { 0.5, 0.5,-0.5 },
98
              { 0.5,-0.5, 0.5 },
99
              { 0.5,-0.5,-0.5 },
100
              {-0.5, 0.5, 0.5 },
101
              {-0.5, 0.5,-0.5 },
102
              {-0.5,-0.5, 0.5 },
103
              {-0.5,-0.5,-0.5 },
104
          };
105

    
106
  private static final int[][] VERT_INDEXES = new int[][]
107
          {
108
              {2,3,1,0},   // counterclockwise!
109
              {7,6,4,5},
110
              {4,0,1,5},
111
              {7,3,2,6},
112
              {6,2,0,4},
113
              {3,7,5,1}
114
          };
115

    
116
  private static final float[][] STICKERS = new float[][]
117
          {
118
              { -0.5f, -0.5f, 0.5f, -0.5f, 0.5f, 0.5f, -0.5f, 0.5f }
119
          };
120

    
121
  private static MeshBase[] mMeshes;
122

    
123
///////////////////////////////////////////////////////////////////////////////////////////////////
124

    
125
  TwistyCube(int size, Static4D quat, DistortedTexture texture,
126
             MeshSquare mesh, DistortedEffects effects, int[][] moves, Resources res, int scrWidth)
127
    {
128
    super(size, size, quat, texture, mesh, effects, moves, ObjectList.CUBE, res, scrWidth);
129
    }
130

    
131
///////////////////////////////////////////////////////////////////////////////////////////////////
132

    
133
  MeshBase createCubitMesh(int cubit, int numLayers)
134
    {
135
    if( mMeshes==null )
136
      {
137
      FactoryCubit factory = FactoryCubit.getInstance();
138
      factory.clear();
139
      mMeshes = new MeshBase[ObjectList.CUBE.getNumVariants()];
140
      }
141

    
142
    int ordinal= ObjectList.CUBE.ordinal();
143
    int index  = ObjectList.getSizeIndex(ordinal,getNumLayers());
144

    
145
    if( mMeshes[index]==null )
146
      {
147
      int extraI, extraV, num;
148
      float height;
149

    
150
      switch(numLayers)
151
        {
152
        case 2 : num = 6; extraI = 2; extraV = 2; height = 0.045f; break;
153
        case 3 : num = 5; extraI = 2; extraV = 2; height = 0.045f; break;
154
        case 4 : num = 5; extraI = 1; extraV = 1; height = 0.045f; break;
155
        default: num = 5; extraI = 0; extraV = 0; height = 0.045f; break;
156
        }
157

    
158
      float[][] bands     = new float[][] { {height,35,0.5f,0.7f,num,extraI,extraV} };
159
      int[] bandIndexes   = new int[] { 0,0,0,0,0,0};
160
      float[][] corners   = new float[][] { {0.036f,0.12f} };
161
      int[] cornerIndexes = new int[] { 0,0,0,0,0,0,0,0 };
162
      float[][] centers   = new float[][] { {0.0f, 0.0f, 0.0f} };
163
      int[] centerIndexes = new int[] { 0,0,0,0,0,0,0,0 };
164

    
165
      FactoryCubit factory = FactoryCubit.getInstance();
166

    
167
      factory.createNewFaceTransform(VERTICES,VERT_INDEXES);
168
      mMeshes[index] = factory.createRoundedSolid(VERTICES, VERT_INDEXES,
169
                                                  bands, bandIndexes,
170
                                                  corners, cornerIndexes,
171
                                                  centers, centerIndexes,
172
                                                  getNumCubitFaces() );
173
      }
174

    
175
    return mMeshes[index].copy(true);
176
    }
177

    
178
///////////////////////////////////////////////////////////////////////////////////////////////////
179

    
180
  void createFaceTexture(Canvas canvas, Paint paint, int face, int left, int top)
181
    {
182
    float R = 0.10f;
183
    float S = 0.08f;
184

    
185
    FactorySticker factory = FactorySticker.getInstance();
186
    factory.drawRoundedPolygon(canvas, paint, left, top, STICKERS[0], S, FACE_COLORS[face], R);
187
    }
188

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

    
191
  float[][] getCubitPositions(int numLayers)
192
    {
193
    int numCubits = numLayers>1 ? 6*numLayers*numLayers - 12*numLayers + 8 : 1;
194
    float[][] tmp = new float[numCubits][];
195

    
196
    float diff = 0.5f*(numLayers-1);
197
    int currentPosition = 0;
198

    
199
    for(int x = 0; x<numLayers; x++)
200
      for(int y = 0; y<numLayers; y++)
201
        for(int z = 0; z<numLayers; z++)
202
          if( x==0 || x==numLayers-1 || y==0 || y==numLayers-1 || z==0 || z==numLayers-1 )
203
            {
204
            tmp[currentPosition++] = new float[] {x-diff,y-diff,z-diff};
205
            }
206

    
207
    return tmp;
208
    }
209

    
210
///////////////////////////////////////////////////////////////////////////////////////////////////
211

    
212
  Static4D[] getQuats()
213
    {
214
    return QUATS;
215
    }
216

    
217
///////////////////////////////////////////////////////////////////////////////////////////////////
218

    
219
  boolean shouldResetTextureMaps()
220
    {
221
    return false;
222
    }
223

    
224
///////////////////////////////////////////////////////////////////////////////////////////////////
225

    
226
  int getNumFaces()
227
    {
228
    return FACE_COLORS.length;
229
    }
230

    
231
///////////////////////////////////////////////////////////////////////////////////////////////////
232

    
233
  float[] getCuts(int numLayers)
234
    {
235
    float[] cuts = new float[numLayers-1];
236

    
237
    for(int i=0; i<numLayers-1; i++)
238
      {
239
      cuts[i] = (2-numLayers)*0.5f + i;
240
      }
241

    
242
    return cuts;
243
    }
244

    
245
///////////////////////////////////////////////////////////////////////////////////////////////////
246

    
247
  int getNumStickerTypes(int numLayers)
248
    {
249
    return STICKERS.length;
250
    }
251

    
252
///////////////////////////////////////////////////////////////////////////////////////////////////
253

    
254
  int getNumCubitFaces()
255
    {
256
    return FACE_COLORS.length;
257
    }
258

    
259
///////////////////////////////////////////////////////////////////////////////////////////////////
260

    
261
  float getScreenRatio()
262
    {
263
    return 0.5f;
264
    }
265

    
266
///////////////////////////////////////////////////////////////////////////////////////////////////
267

    
268
  int getFaceColor(int cubit, int cubitface, int size)
269
    {
270
    return CUBITS[cubit].mRotationRow[cubitface/2] == (cubitface%2==0 ? (1<<(size-1)):1) ? cubitface : NUM_FACES;
271
    }
272

    
273
///////////////////////////////////////////////////////////////////////////////////////////////////
274

    
275
  float returnMultiplier()
276
    {
277
    return getNumLayers();
278
    }
279

    
280
///////////////////////////////////////////////////////////////////////////////////////////////////
281

    
282
  float[] getRowChances(int numLayers)
283
    {
284
    float[] chances = new float[numLayers];
285

    
286
    for(int i=0; i<numLayers; i++)
287
      {
288
      chances[i] = (i+1.0f) / numLayers;
289
      }
290

    
291
    return chances;
292
    }
293

    
294
///////////////////////////////////////////////////////////////////////////////////////////////////
295
// PUBLIC API
296

    
297
  public Static3D[] getRotationAxis()
298
    {
299
    return ROT_AXIS;
300
    }
301

    
302
///////////////////////////////////////////////////////////////////////////////////////////////////
303

    
304
  public int getBasicAngle()
305
    {
306
    return 4;
307
    }
308

    
309
///////////////////////////////////////////////////////////////////////////////////////////////////
310

    
311
  public void randomizeNewScramble(int[][] scramble, Random rnd, int num)
312
    {
313
    if( num==0 )
314
      {
315
      scramble[num][0] = rnd.nextInt(ROTATION_AXIS.length);
316
      }
317
    else
318
      {
319
      int newVector = rnd.nextInt(ROTATION_AXIS.length-1);
320
      scramble[num][0] = (newVector>=scramble[num-1][0] ? newVector+1 : newVector);
321
      }
322

    
323
    float rowFloat = rnd.nextFloat();
324

    
325
    for(int row=0; row<mRowChances.length; row++)
326
      {
327
      if( rowFloat<=mRowChances[row] )
328
        {
329
        scramble[num][1] = row;
330
        break;
331
        }
332
      }
333

    
334
    switch( rnd.nextInt(4) )
335
      {
336
      case 0: scramble[num][2] = -2; break;
337
      case 1: scramble[num][2] = -1; break;
338
      case 2: scramble[num][2] =  1; break;
339
      case 3: scramble[num][2] =  2; break;
340
      }
341
    }
342

    
343
///////////////////////////////////////////////////////////////////////////////////////////////////
344

    
345
  public boolean isSolved()
346
    {
347
    int index = CUBITS[0].mQuatIndex;
348

    
349
    for(int i=1; i<NUM_CUBITS; i++)
350
      {
351
      if( thereIsVisibleDifference(CUBITS[i], index) ) return false;
352
      }
353

    
354
    return true;
355
    }
356

    
357
///////////////////////////////////////////////////////////////////////////////////////////////////
358
// order: Up --> Right --> Front --> Down --> Left --> Back
359
// (because the first implemented Solver - the two-phase Cube3 one - expects such order)
360
//
361
// Solved 3x3x3 Cube maps to "UUUUUUUUURRRRRRRRRFFFFFFFFFDDDDDDDDDLLLLLLLLLBBBBBBBBB"
362
//
363
// s : size of the cube; let index = a*s + b    (i.e. a,b = row,column)
364
//
365
// Up    :   index --> b<s-1 ? (s-1)*(s+4b)+a : 6*s*s -13*s +8 +a
366
// Right :   index --> 6*s*s - 12*s + 7 - index
367
// Front :   index --> if b==0  : s*s - 1 - index
368
//                     if b==s-1: 6*s*s -11*s +6 - index
369
//                     else
370
//                         a==0: s*s + s-1 + 4*(b-1)*(s-1) + 2*(s-2) + s
371
//                         else: s*s + s-1 + 4*(b-1)*(s-1) + 2*(s-1-a)
372
// Down  :   index --> b==0 ? (s-1-a) : s*s + s-1 + 4*(b-1)*(s-1) - a
373
// Left  :   index --> (s-1-a)*s + b
374
// Back  :   index --> if b==s-1: s*(s-1-a)
375
//                     if b==0  : 5*s*s -12*s + 8 + (s-1-a)*s
376
//                     else
377
//                        if a==s-1: s*s + 4*(s-2-b)*(s-1)
378
//                        else     : s*s + 4*(s-2-b)*(s-1) + s + (s-2-a)*2
379

    
380
  public String retObjectString()
381
    {
382
    StringBuilder objectString = new StringBuilder();
383
    int layers = getNumLayers();
384
    int len = layers*layers;
385
    int cubitIndex, row, col, color,face;
386

    
387
    final int RIGHT= 0;
388
    final int LEFT = 1;
389
    final int UP   = 2;
390
    final int DOWN = 3;
391
    final int FRONT= 4;
392
    final int BACK = 5;
393

    
394
    // 'I' - interior, theoretically can happen
395
    final char[] FACE_NAMES = { 'R', 'L', 'U', 'D', 'F', 'B', 'I'};
396

    
397
    face = UP;
398

    
399
    for(int i=0; i<len; i++)
400
      {
401
      row = i/layers;
402
      col = i%layers;
403

    
404
      cubitIndex = col<layers-1 ? (layers-1)*(layers+4*col) + row : 6*layers*layers - 13*layers + 8 + row;
405
      color = getCubitFaceColorIndex(cubitIndex,face);
406
      objectString.append(FACE_NAMES[color]);
407
      }
408

    
409
    face = RIGHT;
410

    
411
    for(int i=0; i<len; i++)
412
      {
413
      cubitIndex = 6*layers*layers - 12*layers +7 - i;
414
      color = getCubitFaceColorIndex(cubitIndex,face);
415
      objectString.append(FACE_NAMES[color]);
416
      }
417

    
418
    face = FRONT;
419

    
420
    for(int i=0; i<len; i++)
421
      {
422
      row = i/layers;
423
      col = i%layers;
424

    
425
      if( col==layers-1 ) cubitIndex = 6*layers*layers - 11*layers + 6 -i;
426
      else if(   col==0 ) cubitIndex = layers*layers - 1 - i;
427
      else
428
        {
429
        if( row==0 ) cubitIndex = layers*layers + layers-1 + 4*(col-1)*(layers-1) + 2*(layers-2) + layers;
430
        else         cubitIndex = layers*layers + layers-1 + 4*(col-1)*(layers-1) + 2*(layers-1-row);
431
        }
432

    
433
      color = getCubitFaceColorIndex(cubitIndex,face);
434
      objectString.append(FACE_NAMES[color]);
435
      }
436

    
437
    face = DOWN;
438

    
439
    for(int i=0; i<len; i++)
440
      {
441
      row = i/layers;
442
      col = i%layers;
443

    
444
      cubitIndex = col==0 ? layers-1-row : layers*layers + layers-1 + 4*(col-1)*(layers-1) - row;
445
      color = getCubitFaceColorIndex(cubitIndex,face);
446
      objectString.append(FACE_NAMES[color]);
447
      }
448

    
449
    face = LEFT;
450

    
451
    for(int i=0; i<len; i++)
452
      {
453
      row = i/layers;
454
      col = i%layers;
455

    
456
      cubitIndex = (layers-1-row)*layers + col;
457
      color = getCubitFaceColorIndex(cubitIndex,face);
458
      objectString.append(FACE_NAMES[color]);
459
      }
460

    
461
    face = BACK;
462

    
463
    for(int i=0; i<len; i++)
464
      {
465
      row = i/layers;
466
      col = i%layers;
467

    
468
      if( col==layers-1 ) cubitIndex = layers*(layers-1-row);
469
      else if(   col==0 ) cubitIndex = 5*layers*layers - 12*layers + 8 + (layers-1-row)*layers;
470
      else
471
        {
472
        if( row==layers-1 ) cubitIndex = layers*layers + 4*(layers-2-col)*(layers-1);
473
        else                cubitIndex = layers*layers + 4*(layers-2-col)*(layers-1) + layers + 2*(layers-2-row);
474
        }
475

    
476
      color = getCubitFaceColorIndex(cubitIndex,face);
477
      objectString.append(FACE_NAMES[color]);
478
      }
479

    
480
    return objectString.toString();
481
    }
482

    
483
///////////////////////////////////////////////////////////////////////////////////////////////////
484

    
485
  public int getObjectName(int numLayers)
486
    {
487
    switch(numLayers)
488
      {
489
      case 2: return R.string.cube2;
490
      case 3: return R.string.cube3;
491
      case 4: return R.string.cube4;
492
      case 5: return R.string.cube5;
493
      }
494
    return R.string.cube3;
495
    }
496

    
497
///////////////////////////////////////////////////////////////////////////////////////////////////
498

    
499
  public int getInventor(int numLayers)
500
    {
501
    switch(numLayers)
502
      {
503
      case 2: return R.string.cube2_inventor;
504
      case 3: return R.string.cube3_inventor;
505
      case 4: return R.string.cube4_inventor;
506
      case 5: return R.string.cube5_inventor;
507
      }
508
    return R.string.cube3_inventor;
509
    }
510

    
511
///////////////////////////////////////////////////////////////////////////////////////////////////
512

    
513
  public int getComplexity(int numLayers)
514
    {
515
    switch(numLayers)
516
      {
517
      case 2: return 4;
518
      case 3: return 6;
519
      case 4: return 8;
520
      case 5: return 10;
521
      }
522
    return 6;
523
    }
524
}
(19-19/33)