Project

General

Profile

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

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

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 oldRotAxis, int oldRow,
258
                                   int numScramble, int remScrambles, int remDoubleScrambles)
259
    {
260
    if( numScramble==1 )
261
      {
262
      scramble[0] = rnd.nextInt(ROTATION_AXIS.length);
263
      }
264
    else
265
      {
266
      int newVector = rnd.nextInt(ROTATION_AXIS.length-1);
267
      scramble[0] = (newVector>=oldRotAxis ? newVector+1 : newVector);
268
      }
269

    
270
    float rowFloat = rnd.nextFloat();
271

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

    
281
    int random = rnd.nextInt(remScrambles);
282
    int result = random<remDoubleScrambles ? 2:1;
283
    int sign   = rnd.nextInt(2);
284

    
285
    scramble[2] = sign==0 ? result : -result;
286
    }
287

    
288
///////////////////////////////////////////////////////////////////////////////////////////////////
289

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

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

    
299
    return true;
300
    }
301

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

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

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

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

    
342
    face = UP;
343

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

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

    
354
    face = RIGHT;
355

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

    
363
    face = FRONT;
364

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

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

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

    
382
    face = DOWN;
383

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

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

    
394
    face = LEFT;
395

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

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

    
406
    face = BACK;
407

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

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

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

    
425
    return objectString.toString();
426
    }
427

    
428
///////////////////////////////////////////////////////////////////////////////////////////////////
429

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

    
442
///////////////////////////////////////////////////////////////////////////////////////////////////
443

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

    
456
///////////////////////////////////////////////////////////////////////////////////////////////////
457

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