Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / TwistyCube.java @ 925ed78f

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[] BASIC_ANGLE = new int[] { 4,4,4 };
51

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

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

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

    
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
         new Static4D( -0.5f,   0.5f,   0.5f,  -0.5f),
93
         new Static4D( -0.5f,   0.5f,   0.5f,   0.5f)
94
         };
95

    
96
  private static final double[][] VERTICES = new double[][]
97
          {
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
              {-0.5,-0.5, 0.5 },
105
              {-0.5,-0.5,-0.5 },
106
          };
107

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

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

    
123
  private static MeshBase[] mMeshes;
124

    
125
///////////////////////////////////////////////////////////////////////////////////////////////////
126

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

    
133
///////////////////////////////////////////////////////////////////////////////////////////////////
134

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

    
144
    int ordinal= ObjectList.CUBE.ordinal();
145
    int index  = ObjectList.getSizeIndex(ordinal,getNumLayers());
146

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

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

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

    
167
      FactoryCubit factory = FactoryCubit.getInstance();
168

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

    
177
    return mMeshes[index].copy(true);
178
    }
179

    
180
///////////////////////////////////////////////////////////////////////////////////////////////////
181

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

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

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

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

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

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

    
209
    return tmp;
210
    }
211

    
212
///////////////////////////////////////////////////////////////////////////////////////////////////
213

    
214
  Static4D[] getQuats()
215
    {
216
    return QUATS;
217
    }
218

    
219
///////////////////////////////////////////////////////////////////////////////////////////////////
220

    
221
  boolean shouldResetTextureMaps()
222
    {
223
    return false;
224
    }
225

    
226
///////////////////////////////////////////////////////////////////////////////////////////////////
227

    
228
  int getNumFaces()
229
    {
230
    return FACE_COLORS.length;
231
    }
232

    
233
///////////////////////////////////////////////////////////////////////////////////////////////////
234

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

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

    
244
    return cuts;
245
    }
246

    
247
///////////////////////////////////////////////////////////////////////////////////////////////////
248

    
249
  int getNumStickerTypes(int numLayers)
250
    {
251
    return STICKERS.length;
252
    }
253

    
254
///////////////////////////////////////////////////////////////////////////////////////////////////
255

    
256
  int getNumCubitFaces()
257
    {
258
    return FACE_COLORS.length;
259
    }
260

    
261
///////////////////////////////////////////////////////////////////////////////////////////////////
262

    
263
  float getScreenRatio()
264
    {
265
    return 0.5f;
266
    }
267

    
268
///////////////////////////////////////////////////////////////////////////////////////////////////
269

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

    
275
///////////////////////////////////////////////////////////////////////////////////////////////////
276

    
277
  float returnMultiplier()
278
    {
279
    return getNumLayers();
280
    }
281

    
282
///////////////////////////////////////////////////////////////////////////////////////////////////
283
// PUBLIC API
284

    
285
  public Static3D[] getRotationAxis()
286
    {
287
    return ROT_AXIS;
288
    }
289

    
290
///////////////////////////////////////////////////////////////////////////////////////////////////
291

    
292
  public int[] getBasicAngle()
293
    {
294
    return BASIC_ANGLE;
295
    }
296

    
297
///////////////////////////////////////////////////////////////////////////////////////////////////
298

    
299
  public void randomizeNewScramble(int[][] scramble, Random rnd, int num)
300
    {
301
    if( num==0 )
302
      {
303
      scramble[num][0] = rnd.nextInt(NUM_AXIS);
304
      }
305
    else
306
      {
307
      int newVector = rnd.nextInt(NUM_AXIS -1);
308
      scramble[num][0] = (newVector>=scramble[num-1][0] ? newVector+1 : newVector);
309
      }
310

    
311
    float rowFloat = rnd.nextFloat();
312
    int numLayers = getNumLayers();
313

    
314
    for(int row=0; row<numLayers; row++)
315
      {
316
      if( rowFloat*numLayers <= row+1 )
317
        {
318
        scramble[num][1] = row;
319
        break;
320
        }
321
      }
322

    
323
    switch( rnd.nextInt(4) )
324
      {
325
      case 0: scramble[num][2] = -2; break;
326
      case 1: scramble[num][2] = -1; break;
327
      case 2: scramble[num][2] =  1; break;
328
      case 3: scramble[num][2] =  2; break;
329
      }
330
    }
331

    
332
///////////////////////////////////////////////////////////////////////////////////////////////////
333

    
334
  public boolean isSolved()
335
    {
336
    int index = CUBITS[0].mQuatIndex;
337

    
338
    for(int i=1; i<NUM_CUBITS; i++)
339
      {
340
      if( thereIsVisibleDifference(CUBITS[i], index) ) return false;
341
      }
342

    
343
    return true;
344
    }
345

    
346
///////////////////////////////////////////////////////////////////////////////////////////////////
347
// order: Up --> Right --> Front --> Down --> Left --> Back
348
// (because the first implemented Solver - the two-phase Cube3 one - expects such order)
349
//
350
// Solved 3x3x3 Cube maps to "UUUUUUUUURRRRRRRRRFFFFFFFFFDDDDDDDDDLLLLLLLLLBBBBBBBBB"
351
//
352
// s : size of the cube; let index = a*s + b    (i.e. a,b = row,column)
353
//
354
// Up    :   index --> b<s-1 ? (s-1)*(s+4b)+a : 6*s*s -13*s +8 +a
355
// Right :   index --> 6*s*s - 12*s + 7 - index
356
// Front :   index --> if b==0  : s*s - 1 - index
357
//                     if b==s-1: 6*s*s -11*s +6 - index
358
//                     else
359
//                         a==0: s*s + s-1 + 4*(b-1)*(s-1) + 2*(s-2) + s
360
//                         else: s*s + s-1 + 4*(b-1)*(s-1) + 2*(s-1-a)
361
// Down  :   index --> b==0 ? (s-1-a) : s*s + s-1 + 4*(b-1)*(s-1) - a
362
// Left  :   index --> (s-1-a)*s + b
363
// Back  :   index --> if b==s-1: s*(s-1-a)
364
//                     if b==0  : 5*s*s -12*s + 8 + (s-1-a)*s
365
//                     else
366
//                        if a==s-1: s*s + 4*(s-2-b)*(s-1)
367
//                        else     : s*s + 4*(s-2-b)*(s-1) + s + (s-2-a)*2
368

    
369
  public String retObjectString()
370
    {
371
    StringBuilder objectString = new StringBuilder();
372
    int layers = getNumLayers();
373
    int len = layers*layers;
374
    int cubitIndex, row, col, color,face;
375

    
376
    final int RIGHT= 0;
377
    final int LEFT = 1;
378
    final int UP   = 2;
379
    final int DOWN = 3;
380
    final int FRONT= 4;
381
    final int BACK = 5;
382

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

    
386
    face = UP;
387

    
388
    for(int i=0; i<len; i++)
389
      {
390
      row = i/layers;
391
      col = i%layers;
392

    
393
      cubitIndex = col<layers-1 ? (layers-1)*(layers+4*col) + row : 6*layers*layers - 13*layers + 8 + row;
394
      color = getCubitFaceColorIndex(cubitIndex,face);
395
      objectString.append(FACE_NAMES[color]);
396
      }
397

    
398
    face = RIGHT;
399

    
400
    for(int i=0; i<len; i++)
401
      {
402
      cubitIndex = 6*layers*layers - 12*layers +7 - i;
403
      color = getCubitFaceColorIndex(cubitIndex,face);
404
      objectString.append(FACE_NAMES[color]);
405
      }
406

    
407
    face = FRONT;
408

    
409
    for(int i=0; i<len; i++)
410
      {
411
      row = i/layers;
412
      col = i%layers;
413

    
414
      if( col==layers-1 ) cubitIndex = 6*layers*layers - 11*layers + 6 -i;
415
      else if(   col==0 ) cubitIndex = layers*layers - 1 - i;
416
      else
417
        {
418
        if( row==0 ) cubitIndex = layers*layers + layers-1 + 4*(col-1)*(layers-1) + 2*(layers-2) + layers;
419
        else         cubitIndex = layers*layers + layers-1 + 4*(col-1)*(layers-1) + 2*(layers-1-row);
420
        }
421

    
422
      color = getCubitFaceColorIndex(cubitIndex,face);
423
      objectString.append(FACE_NAMES[color]);
424
      }
425

    
426
    face = DOWN;
427

    
428
    for(int i=0; i<len; i++)
429
      {
430
      row = i/layers;
431
      col = i%layers;
432

    
433
      cubitIndex = col==0 ? layers-1-row : layers*layers + layers-1 + 4*(col-1)*(layers-1) - row;
434
      color = getCubitFaceColorIndex(cubitIndex,face);
435
      objectString.append(FACE_NAMES[color]);
436
      }
437

    
438
    face = LEFT;
439

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

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

    
450
    face = BACK;
451

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

    
457
      if( col==layers-1 ) cubitIndex = layers*(layers-1-row);
458
      else if(   col==0 ) cubitIndex = 5*layers*layers - 12*layers + 8 + (layers-1-row)*layers;
459
      else
460
        {
461
        if( row==layers-1 ) cubitIndex = layers*layers + 4*(layers-2-col)*(layers-1);
462
        else                cubitIndex = layers*layers + 4*(layers-2-col)*(layers-1) + layers + 2*(layers-2-row);
463
        }
464

    
465
      color = getCubitFaceColorIndex(cubitIndex,face);
466
      objectString.append(FACE_NAMES[color]);
467
      }
468

    
469
    return objectString.toString();
470
    }
471

    
472
///////////////////////////////////////////////////////////////////////////////////////////////////
473

    
474
  public int getObjectName(int numLayers)
475
    {
476
    switch(numLayers)
477
      {
478
      case 2: return R.string.cube2;
479
      case 3: return R.string.cube3;
480
      case 4: return R.string.cube4;
481
      case 5: return R.string.cube5;
482
      }
483
    return R.string.cube3;
484
    }
485

    
486
///////////////////////////////////////////////////////////////////////////////////////////////////
487

    
488
  public int getInventor(int numLayers)
489
    {
490
    switch(numLayers)
491
      {
492
      case 2: return R.string.cube2_inventor;
493
      case 3: return R.string.cube3_inventor;
494
      case 4: return R.string.cube4_inventor;
495
      case 5: return R.string.cube5_inventor;
496
      }
497
    return R.string.cube3_inventor;
498
    }
499

    
500
///////////////////////////////////////////////////////////////////////////////////////////////////
501

    
502
  public int getComplexity(int numLayers)
503
    {
504
    switch(numLayers)
505
      {
506
      case 2: return 4;
507
      case 3: return 6;
508
      case 4: return 8;
509
      case 5: return 10;
510
      }
511
    return 6;
512
    }
513
}
(21-21/37)