Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / TwistyCube.java @ eaf87d1d

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.library.main.DistortedEffects;
27
import org.distorted.library.main.DistortedTexture;
28
import org.distorted.library.mesh.MeshBase;
29
import org.distorted.library.mesh.MeshSquare;
30
import org.distorted.library.type.Static3D;
31
import org.distorted.library.type.Static4D;
32
import org.distorted.main.R;
33

    
34
import java.util.Random;
35

    
36
///////////////////////////////////////////////////////////////////////////////////////////////////
37

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

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

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

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

    
82
         new Static4D(  0.5f,   0.5f,   0.5f,   0.5f),
83
         new Static4D(  0.5f,   0.5f,  -0.5f,   0.5f),
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
         };
91

    
92
  private static MeshBase[] mMeshes;
93

    
94
///////////////////////////////////////////////////////////////////////////////////////////////////
95

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

    
102
///////////////////////////////////////////////////////////////////////////////////////////////////
103

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

    
111
    int ordinal= ObjectList.CUBE.ordinal();
112
    int index  = ObjectList.getSizeIndex(ordinal,getNumLayers());
113

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

    
119
    return mMeshes[index].copy(true);
120
    }
121

    
122
///////////////////////////////////////////////////////////////////////////////////////////////////
123

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

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

    
135
///////////////////////////////////////////////////////////////////////////////////////////////////
136

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

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

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

    
153
    return tmp;
154
    }
155

    
156
///////////////////////////////////////////////////////////////////////////////////////////////////
157

    
158
  Static4D[] getQuats()
159
    {
160
    return QUATS;
161
    }
162

    
163
///////////////////////////////////////////////////////////////////////////////////////////////////
164

    
165
  boolean shouldResetTextureMaps()
166
    {
167
    return false;
168
    }
169

    
170
///////////////////////////////////////////////////////////////////////////////////////////////////
171

    
172
  int getNumFaces()
173
    {
174
    return FACE_COLORS.length;
175
    }
176

    
177
///////////////////////////////////////////////////////////////////////////////////////////////////
178

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

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

    
188
    return cuts;
189
    }
190

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

    
193
  int getNumStickerTypes(int numLayers)
194
    {
195
    return 1;
196
    }
197

    
198
///////////////////////////////////////////////////////////////////////////////////////////////////
199

    
200
  int getNumCubitFaces()
201
    {
202
    return FACE_COLORS.length;
203
    }
204

    
205
///////////////////////////////////////////////////////////////////////////////////////////////////
206

    
207
  float getScreenRatio()
208
    {
209
    return 0.5f;
210
    }
211

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

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

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

    
221
  float returnMultiplier()
222
    {
223
    return getNumLayers();
224
    }
225

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

    
228
  float[] getRowChances(int numLayers)
229
    {
230
    float[] chances = new float[numLayers];
231

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

    
237
    return chances;
238
    }
239

    
240
///////////////////////////////////////////////////////////////////////////////////////////////////
241
// PUBLIC API
242

    
243
  public Static3D[] getRotationAxis()
244
    {
245
    return ROT_AXIS;
246
    }
247

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

    
250
  public int getBasicAngle()
251
    {
252
    return 4;
253
    }
254

    
255
///////////////////////////////////////////////////////////////////////////////////////////////////
256

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

    
269
    float rowFloat = rnd.nextFloat();
270

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

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

    
289
///////////////////////////////////////////////////////////////////////////////////////////////////
290

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

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

    
300
    return true;
301
    }
302

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

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

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

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

    
343
    face = UP;
344

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

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

    
355
    face = RIGHT;
356

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

    
364
    face = FRONT;
365

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

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

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

    
383
    face = DOWN;
384

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

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

    
395
    face = LEFT;
396

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

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

    
407
    face = BACK;
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 = layers*(layers-1-row);
415
      else if(   col==0 ) cubitIndex = 5*layers*layers - 12*layers + 8 + (layers-1-row)*layers;
416
      else
417
        {
418
        if( row==layers-1 ) cubitIndex = layers*layers + 4*(layers-2-col)*(layers-1);
419
        else                cubitIndex = layers*layers + 4*(layers-2-col)*(layers-1) + layers + 2*(layers-2-row);
420
        }
421

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

    
426
    return objectString.toString();
427
    }
428

    
429
///////////////////////////////////////////////////////////////////////////////////////////////////
430

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

    
443
///////////////////////////////////////////////////////////////////////////////////////////////////
444

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

    
457
///////////////////////////////////////////////////////////////////////////////////////////////////
458

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