Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / TwistyCube.java @ 722b2512

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
import static org.distorted.effects.scramble.ScrambleEffect.START_AXIS;
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
  Static3D[] getCubitPositions(int size)
140
    {
141
    int numCubits = size>1 ? 6*size*size - 12*size + 8 : 1;
142
    Static3D[] tmp = new Static3D[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 Static3D(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 ? size-1:0) ? 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 int randomizeNewRotAxis(Random rnd, int oldRotAxis)
260
    {
261
    int numAxis = ROTATION_AXIS.length;
262

    
263
    if( oldRotAxis == START_AXIS )
264
      {
265
      return rnd.nextInt(numAxis);
266
      }
267
    else
268
      {
269
      int newVector = rnd.nextInt(numAxis-1);
270
      return (newVector>=oldRotAxis ? newVector+1 : newVector);
271
      }
272
    }
273

    
274
///////////////////////////////////////////////////////////////////////////////////////////////////
275

    
276
  public int randomizeNewRow(Random rnd, int oldRotAxis, int oldRow, int newRotAxis)
277
    {
278
    float rowFloat = rnd.nextFloat();
279

    
280
    for(int row=0; row<mRowChances.length; row++)
281
      {
282
      if( rowFloat<=mRowChances[row] ) return row;
283
      }
284

    
285
    return 0;
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)