Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / TwistyCube.java @ 221a4090

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
import org.distorted.main.RubikSurfaceView;
34

    
35
import java.util.Random;
36

    
37
import static org.distorted.effects.scramble.ScrambleEffect.START_AXIS;
38

    
39
///////////////////////////////////////////////////////////////////////////////////////////////////
40

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

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

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

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

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

    
95
  private static MeshBase[] mMeshes;
96

    
97
///////////////////////////////////////////////////////////////////////////////////////////////////
98

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

    
105
///////////////////////////////////////////////////////////////////////////////////////////////////
106

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

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

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

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

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

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

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

    
138
///////////////////////////////////////////////////////////////////////////////////////////////////
139

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

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

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

    
156
    return tmp;
157
    }
158

    
159
///////////////////////////////////////////////////////////////////////////////////////////////////
160

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

    
166
///////////////////////////////////////////////////////////////////////////////////////////////////
167

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

    
173
///////////////////////////////////////////////////////////////////////////////////////////////////
174

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

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

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

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

    
191
    return cuts;
192
    }
193

    
194
///////////////////////////////////////////////////////////////////////////////////////////////////
195

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

    
201
///////////////////////////////////////////////////////////////////////////////////////////////////
202

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

    
208
///////////////////////////////////////////////////////////////////////////////////////////////////
209

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

    
215
///////////////////////////////////////////////////////////////////////////////////////////////////
216

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

    
222
///////////////////////////////////////////////////////////////////////////////////////////////////
223

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

    
229
///////////////////////////////////////////////////////////////////////////////////////////////////
230

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

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

    
240
    return chances;
241
    }
242

    
243
///////////////////////////////////////////////////////////////////////////////////////////////////
244
// PUBLIC API
245

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

    
251
///////////////////////////////////////////////////////////////////////////////////////////////////
252

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

    
258
///////////////////////////////////////////////////////////////////////////////////////////////////
259

    
260
  public int randomizeNewRotAxis(Random rnd, int oldRotAxis)
261
    {
262
    int numAxis = ROTATION_AXIS.length;
263

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

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

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

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

    
286
    return 0;
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( !thereIsNoVisibleDifference(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)