Project

General

Profile

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

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

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 MeshBase[] mMeshes;
95

    
96
///////////////////////////////////////////////////////////////////////////////////////////////////
97

    
98
  TwistyCube(int size, Static4D quat, DistortedTexture texture,
99
             MeshSquare mesh, DistortedEffects effects, int[][] moves, Resources res, int scrWidth)
100
    {
101
    super(size, size, quat, texture, mesh, effects, moves, ObjectList.CUBE, res, scrWidth);
102
    }
103

    
104
///////////////////////////////////////////////////////////////////////////////////////////////////
105

    
106
  MeshBase createCubitMesh(int cubit, int numLayers)
107
    {
108
    if( mMeshes==null )
109
      {
110
      mMeshes = new MeshBase[ObjectList.CUBE.getNumVariants()];
111
      }
112

    
113
    int ordinal= ObjectList.CUBE.ordinal();
114
    int index  = ObjectList.getSizeIndex(ordinal,getNumLayers());
115

    
116
    if( mMeshes[index]==null )
117
      {
118
      mMeshes[index] = FactoryCubit.getInstance().createCubeMesh(index);
119
      }
120

    
121
    return mMeshes[index].copy(true);
122
    }
123

    
124
///////////////////////////////////////////////////////////////////////////////////////////////////
125

    
126
  void createFaceTexture(Canvas canvas, Paint paint, int face, int left, int top)
127
    {
128
    float F =  0.5f;
129
    float R = 0.10f;
130
    float S = 0.08f;
131
    float[] vertices = { -F,-F, +F,-F, +F,+F, -F,+F};
132

    
133
    FactorySticker factory = FactorySticker.getInstance();
134
    factory.drawRoundedPolygon(canvas, paint, left, top, vertices, S, FACE_COLORS[face], R);
135
    }
136

    
137
///////////////////////////////////////////////////////////////////////////////////////////////////
138

    
139
  float[][] getCubitPositions(int size)
140
    {
141
    int numCubits = size>1 ? 6*size*size - 12*size + 8 : 1;
142
    float[][] tmp = new float[numCubits][];
143

    
144
    float diff = 0.5f*(size-1);
145
    int currentPosition = 0;
146

    
147
    for(int x = 0; x<size; x++)
148
      for(int y = 0; y<size; y++)
149
        for(int z = 0; z<size; z++)
150
          if( x==0 || x==size-1 || y==0 || y==size-1 || z==0 || z==size-1 )
151
            {
152
            tmp[currentPosition++] = new float[] {x-diff,y-diff,z-diff};
153
            }
154

    
155
    return tmp;
156
    }
157

    
158
///////////////////////////////////////////////////////////////////////////////////////////////////
159

    
160
  Static4D[] getQuats()
161
    {
162
    return QUATS;
163
    }
164

    
165
///////////////////////////////////////////////////////////////////////////////////////////////////
166

    
167
  boolean shouldResetTextureMaps()
168
    {
169
    return false;
170
    }
171

    
172
///////////////////////////////////////////////////////////////////////////////////////////////////
173

    
174
  int getNumFaces()
175
    {
176
    return FACE_COLORS.length;
177
    }
178

    
179
///////////////////////////////////////////////////////////////////////////////////////////////////
180

    
181
  float[] getCuts(int numLayers)
182
    {
183
    float[] cuts = new float[numLayers-1];
184

    
185
    for(int i=0; i<numLayers-1; i++)
186
      {
187
      cuts[i] = (2-numLayers)*0.5f + i;
188
      }
189

    
190
    return cuts;
191
    }
192

    
193
///////////////////////////////////////////////////////////////////////////////////////////////////
194

    
195
  int getNumStickerTypes(int numLayers)
196
    {
197
    return 1;
198
    }
199

    
200
///////////////////////////////////////////////////////////////////////////////////////////////////
201

    
202
  int getNumCubitFaces()
203
    {
204
    return FACE_COLORS.length;
205
    }
206

    
207
///////////////////////////////////////////////////////////////////////////////////////////////////
208

    
209
  float getScreenRatio()
210
    {
211
    return 0.5f;
212
    }
213

    
214
///////////////////////////////////////////////////////////////////////////////////////////////////
215

    
216
  int getFaceColor(int cubit, int cubitface, int size)
217
    {
218
    return CUBITS[cubit].mRotationRow[cubitface/2] == (cubitface%2==0 ? (1<<(size-1)):1) ? cubitface : NUM_FACES;
219
    }
220

    
221
///////////////////////////////////////////////////////////////////////////////////////////////////
222

    
223
  float returnMultiplier()
224
    {
225
    return getNumLayers();
226
    }
227

    
228
///////////////////////////////////////////////////////////////////////////////////////////////////
229

    
230
  float[] getRowChances(int numLayers)
231
    {
232
    float[] chances = new float[numLayers];
233

    
234
    for(int i=0; i<numLayers; i++)
235
      {
236
      chances[i] = (i+1.0f) / numLayers;
237
      }
238

    
239
    return chances;
240
    }
241

    
242
///////////////////////////////////////////////////////////////////////////////////////////////////
243
// PUBLIC API
244

    
245
  public Static3D[] getRotationAxis()
246
    {
247
    return ROT_AXIS;
248
    }
249

    
250
///////////////////////////////////////////////////////////////////////////////////////////////////
251

    
252
  public int getBasicAngle()
253
    {
254
    return 4;
255
    }
256

    
257
///////////////////////////////////////////////////////////////////////////////////////////////////
258

    
259
  public void randomizeNewScramble(int[][] scramble, Random rnd, int num)
260
    {
261
    if( num==0 )
262
      {
263
      scramble[num][0] = rnd.nextInt(ROTATION_AXIS.length);
264
      }
265
    else
266
      {
267
      int newVector = rnd.nextInt(ROTATION_AXIS.length-1);
268
      scramble[num][0] = (newVector>=scramble[num-1][0] ? newVector+1 : newVector);
269
      }
270

    
271
    float rowFloat = rnd.nextFloat();
272

    
273
    for(int row=0; row<mRowChances.length; row++)
274
      {
275
      if( rowFloat<=mRowChances[row] )
276
        {
277
        scramble[num][1] = row;
278
        break;
279
        }
280
      }
281

    
282
    switch( rnd.nextInt(4) )
283
      {
284
      case 0: scramble[num][2] = -2; break;
285
      case 1: scramble[num][2] = -1; break;
286
      case 2: scramble[num][2] =  1; break;
287
      case 3: scramble[num][2] =  2; break;
288
      }
289
    }
290

    
291
///////////////////////////////////////////////////////////////////////////////////////////////////
292

    
293
  public boolean isSolved()
294
    {
295
    int index = CUBITS[0].mQuatIndex;
296

    
297
    for(int i=1; i<NUM_CUBITS; i++)
298
      {
299
      if( thereIsVisibleDifference(CUBITS[i], index) ) return false;
300
      }
301

    
302
    return true;
303
    }
304

    
305
///////////////////////////////////////////////////////////////////////////////////////////////////
306
// order: Up --> Right --> Front --> Down --> Left --> Back
307
// (because the first implemented Solver - the two-phase Cube3 one - expects such order)
308
//
309
// Solved 3x3x3 Cube maps to "UUUUUUUUURRRRRRRRRFFFFFFFFFDDDDDDDDDLLLLLLLLLBBBBBBBBB"
310
//
311
// s : size of the cube; let index = a*s + b    (i.e. a,b = row,column)
312
//
313
// Up    :   index --> b<s-1 ? (s-1)*(s+4b)+a : 6*s*s -13*s +8 +a
314
// Right :   index --> 6*s*s - 12*s + 7 - index
315
// Front :   index --> if b==0  : s*s - 1 - index
316
//                     if b==s-1: 6*s*s -11*s +6 - index
317
//                     else
318
//                         a==0: s*s + s-1 + 4*(b-1)*(s-1) + 2*(s-2) + s
319
//                         else: s*s + s-1 + 4*(b-1)*(s-1) + 2*(s-1-a)
320
// Down  :   index --> b==0 ? (s-1-a) : s*s + s-1 + 4*(b-1)*(s-1) - a
321
// Left  :   index --> (s-1-a)*s + b
322
// Back  :   index --> if b==s-1: s*(s-1-a)
323
//                     if b==0  : 5*s*s -12*s + 8 + (s-1-a)*s
324
//                     else
325
//                        if a==s-1: s*s + 4*(s-2-b)*(s-1)
326
//                        else     : s*s + 4*(s-2-b)*(s-1) + s + (s-2-a)*2
327

    
328
  public String retObjectString()
329
    {
330
    StringBuilder objectString = new StringBuilder();
331
    int layers = getNumLayers();
332
    int len = layers*layers;
333
    int cubitIndex, row, col, color,face;
334

    
335
    final int RIGHT= 0;
336
    final int LEFT = 1;
337
    final int UP   = 2;
338
    final int DOWN = 3;
339
    final int FRONT= 4;
340
    final int BACK = 5;
341

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

    
345
    face = UP;
346

    
347
    for(int i=0; i<len; i++)
348
      {
349
      row = i/layers;
350
      col = i%layers;
351

    
352
      cubitIndex = col<layers-1 ? (layers-1)*(layers+4*col) + row : 6*layers*layers - 13*layers + 8 + row;
353
      color = getCubitFaceColorIndex(cubitIndex,face);
354
      objectString.append(FACE_NAMES[color]);
355
      }
356

    
357
    face = RIGHT;
358

    
359
    for(int i=0; i<len; i++)
360
      {
361
      cubitIndex = 6*layers*layers - 12*layers +7 - i;
362
      color = getCubitFaceColorIndex(cubitIndex,face);
363
      objectString.append(FACE_NAMES[color]);
364
      }
365

    
366
    face = FRONT;
367

    
368
    for(int i=0; i<len; i++)
369
      {
370
      row = i/layers;
371
      col = i%layers;
372

    
373
      if( col==layers-1 ) cubitIndex = 6*layers*layers - 11*layers + 6 -i;
374
      else if(   col==0 ) cubitIndex = layers*layers - 1 - i;
375
      else
376
        {
377
        if( row==0 ) cubitIndex = layers*layers + layers-1 + 4*(col-1)*(layers-1) + 2*(layers-2) + layers;
378
        else         cubitIndex = layers*layers + layers-1 + 4*(col-1)*(layers-1) + 2*(layers-1-row);
379
        }
380

    
381
      color = getCubitFaceColorIndex(cubitIndex,face);
382
      objectString.append(FACE_NAMES[color]);
383
      }
384

    
385
    face = DOWN;
386

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

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

    
397
    face = LEFT;
398

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

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

    
409
    face = BACK;
410

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

    
416
      if( col==layers-1 ) cubitIndex = layers*(layers-1-row);
417
      else if(   col==0 ) cubitIndex = 5*layers*layers - 12*layers + 8 + (layers-1-row)*layers;
418
      else
419
        {
420
        if( row==layers-1 ) cubitIndex = layers*layers + 4*(layers-2-col)*(layers-1);
421
        else                cubitIndex = layers*layers + 4*(layers-2-col)*(layers-1) + layers + 2*(layers-2-row);
422
        }
423

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

    
428
    return objectString.toString();
429
    }
430

    
431
///////////////////////////////////////////////////////////////////////////////////////////////////
432

    
433
  public int getObjectName(int numLayers)
434
    {
435
    switch(numLayers)
436
      {
437
      case 2: return R.string.cube2;
438
      case 3: return R.string.cube3;
439
      case 4: return R.string.cube4;
440
      case 5: return R.string.cube5;
441
      }
442
    return R.string.cube3;
443
    }
444

    
445
///////////////////////////////////////////////////////////////////////////////////////////////////
446

    
447
  public int getInventor(int numLayers)
448
    {
449
    switch(numLayers)
450
      {
451
      case 2: return R.string.cube2_inventor;
452
      case 3: return R.string.cube3_inventor;
453
      case 4: return R.string.cube4_inventor;
454
      case 5: return R.string.cube5_inventor;
455
      }
456
    return R.string.cube3_inventor;
457
    }
458

    
459
///////////////////////////////////////////////////////////////////////////////////////////////////
460

    
461
  public int getComplexity(int numLayers)
462
    {
463
    switch(numLayers)
464
      {
465
      case 2: return 4;
466
      case 3: return 6;
467
      case 4: return 8;
468
      case 5: return 10;
469
      }
470
    return 6;
471
    }
472
}
(19-19/33)