Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / RubikCube.java @ ad38d800

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.effect.VertexEffectDeform;
27
import org.distorted.library.effect.VertexEffectMove;
28
import org.distorted.library.effect.VertexEffectRotate;
29
import org.distorted.library.effect.VertexEffectSink;
30
import org.distorted.library.main.DistortedEffects;
31
import org.distorted.library.main.DistortedTexture;
32
import org.distorted.library.mesh.MeshBase;
33
import org.distorted.library.mesh.MeshJoined;
34
import org.distorted.library.mesh.MeshRectangles;
35
import org.distorted.library.type.Static1D;
36
import org.distorted.library.type.Static3D;
37
import org.distorted.library.type.Static4D;
38

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

    
41
class RubikCube extends RubikObject
42
{
43
  static final float SQ2 = (float)Math.sqrt(2);
44

    
45
  // the three rotation axis of a RubikCube. Must be normalized.
46
  static final Static3D[] ROT_AXIS = new Static3D[]
47
         {
48
           new Static3D(1,0,0),
49
           new Static3D(0,1,0),
50
           new Static3D(0,0,1)
51
         };
52

    
53
  // the six axis that determine the faces
54
  static final Static3D[] FACE_AXIS = new Static3D[]
55
         {
56
           new Static3D(1,0,0), new Static3D(-1,0,0),
57
           new Static3D(0,1,0), new Static3D(0,-1,0),
58
           new Static3D(0,0,1), new Static3D(0,0,-1)
59
         };
60

    
61
  private static final int[] FACE_COLORS = new int[]
62
         {
63
           0xffffff00, 0xffffffff,   // FACE_AXIS[0] (right-YELLOW) FACE_AXIS[1] (left  -WHITE)
64
           0xff0000ff, 0xff00ff00,   // FACE_AXIS[2] (top  -BLUE  ) FACE_AXIS[3] (bottom-GREEN)
65
           0xffff0000, 0xffb5651d    // FACE_AXIS[4] (front-RED   ) FACE_AXIS[5] (back  -BROWN)
66
         };
67

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

    
82
         new Static4D( SQ2/2,  SQ2/2,  0.0f ,   0.0f),
83
         new Static4D( SQ2/2, -SQ2/2,  0.0f ,   0.0f),
84
         new Static4D( SQ2/2,   0.0f,  SQ2/2,   0.0f),
85
         new Static4D(-SQ2/2,   0.0f,  SQ2/2,   0.0f),
86
         new Static4D( SQ2/2,   0.0f,   0.0f,  SQ2/2),
87
         new Static4D( SQ2/2,   0.0f,   0.0f, -SQ2/2),
88
         new Static4D(  0.0f,  SQ2/2,  SQ2/2,   0.0f),
89
         new Static4D(  0.0f,  SQ2/2, -SQ2/2,   0.0f),
90
         new Static4D(  0.0f,  SQ2/2,   0.0f,  SQ2/2),
91
         new Static4D(  0.0f,  SQ2/2,   0.0f, -SQ2/2),
92
         new Static4D(  0.0f,   0.0f,  SQ2/2,  SQ2/2),
93
         new Static4D(  0.0f,   0.0f,  SQ2/2, -SQ2/2),
94

    
95
         new Static4D(  0.5f,   0.5f,   0.5f,   0.5f),
96
         new Static4D(  0.5f,   0.5f,  -0.5f,   0.5f),
97
         new Static4D(  0.5f,   0.5f,  -0.5f,  -0.5f),
98
         new Static4D(  0.5f,  -0.5f,   0.5f,  -0.5f),
99
         new Static4D( -0.5f,  -0.5f,  -0.5f,   0.5f),
100
         new Static4D( -0.5f,   0.5f,  -0.5f,  -0.5f),
101
         new Static4D( -0.5f,   0.5f,   0.5f,  -0.5f),
102
         new Static4D( -0.5f,   0.5f,   0.5f,   0.5f)
103
         };
104

    
105
  private static MeshBase[] mMeshes;
106

    
107
///////////////////////////////////////////////////////////////////////////////////////////////////
108

    
109
  RubikCube(int size, Static4D quat, DistortedTexture texture,
110
            MeshRectangles mesh, DistortedEffects effects, int[][] moves, Resources res, int scrWidth)
111
    {
112
    super(size, 60, quat, texture, mesh, effects, moves, RubikObjectList.CUBE, res, scrWidth);
113
    }
114

    
115
///////////////////////////////////////////////////////////////////////////////////////////////////
116
// paint the square with upper-right corner at (left,top) and side length 'side' with texture
117
// for face 'face'.
118

    
119
  void createFaceTexture(Canvas canvas, Paint paint, int face, int left, int top, int side)
120
    {
121
    final float R = side*0.10f;
122
    final float M = side*0.05f;
123

    
124
    paint.setColor(FACE_COLORS[face]);
125
    canvas.drawRoundRect( left+M, top+M, left+side-M, top+side-M, R, R, paint);
126
    }
127

    
128
///////////////////////////////////////////////////////////////////////////////////////////////////
129

    
130
  Static3D[] getCubitPositions(int size)
131
    {
132
    int numCubits = size>1 ? 6*size*size - 12*size + 8 : 1;
133
    Static3D[] tmp = new Static3D[numCubits];
134

    
135
    float diff = 0.5f*(size-1);
136
    int currentPosition = 0;
137

    
138
    for(int x = 0; x<size; x++)
139
      for(int y = 0; y<size; y++)
140
        for(int z = 0; z<size; z++)
141
          if( x==0 || x==size-1 || y==0 || y==size-1 || z==0 || z==size-1 )
142
            {
143
            tmp[currentPosition++] = new Static3D(x-diff,y-diff,z-diff);
144
            }
145

    
146
    return tmp;
147
    }
148

    
149
///////////////////////////////////////////////////////////////////////////////////////////////////
150

    
151
  Static4D[] getQuats()
152
    {
153
    return QUATS;
154
    }
155

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

    
158
  int getNumFaces()
159
    {
160
    return FACE_COLORS.length;
161
    }
162

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

    
165
  int getNumCubitFaces()
166
    {
167
    return FACE_COLORS.length;
168
    }
169

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

    
172
  float getScreenRatio()
173
    {
174
    return 0.5f;
175
    }
176

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

    
179
  int getFaceColor(int cubit, int cubitface, int size)
180
    {
181
    boolean belongs = isOnFace(cubit, cubitface/2, cubitface%2==0 ? size-1:0 );
182
    return belongs ? cubitface : NUM_FACES;
183
    }
184

    
185
///////////////////////////////////////////////////////////////////////////////////////////////////
186

    
187
  MeshBase createCubitMesh(int cubit)
188
    {
189
    int size   = getSize();
190
    int ordinal= RubikObjectList.CUBE.ordinal();
191
    int index  = RubikObjectList.getSizeIndex(ordinal,size);
192
    float[] loc;
193

    
194
    switch(size)
195
      {
196
      case 5 : loc = new float[] { -0.5f, 0.05f, 0.1f, 0.35f, 0.35f, 0.1f, 0.05f };
197
               break;
198
      case 2 : loc = new float[] { -0.5f, 0.03f, 0.05f, 0.07f, 0.20f, 0.30f, 0.20f, 0.07f, 0.05f, 0.03f };
199
               break;
200
      default: loc = new float[] { -0.5f, 0.04f, 0.06f, 0.25f, 0.30f, 0.25f, 0.06f, 0.04f };
201
      }
202

    
203
    return createCubitMesh(index,loc);
204
    }
205

    
206
///////////////////////////////////////////////////////////////////////////////////////////////////
207

    
208
  MeshBase createCubitMesh(int index, float[] loc)
209
    {
210
    if( mMeshes==null )
211
      {
212
      mMeshes = new MeshBase[RubikObjectList.CUBE.getNumVariants()];
213
      }
214

    
215
    if( mMeshes[index]==null )
216
      {
217
      final int MESHES=6;
218
      int association = 1;
219
      MeshBase[] meshes = new MeshRectangles[MESHES];
220
      meshes[0] = new MeshRectangles(loc,loc);
221
      meshes[0].setEffectAssociation(0,association,0);
222

    
223
      for(int i=1; i<MESHES; i++)
224
        {
225
        association <<=1;
226
        meshes[i] = meshes[0].copy(true);
227
        meshes[i].setEffectAssociation(0,association,0);
228
        }
229

    
230
      mMeshes[index] = new MeshJoined(meshes);
231

    
232
      Static3D axisY   = new Static3D(0,1,0);
233
      Static3D axisX   = new Static3D(1,0,0);
234
      Static3D center  = new Static3D(0,0,0);
235
      Static1D angle90 = new Static1D(90);
236
      Static1D angle180= new Static1D(180);
237
      Static1D angle270= new Static1D(270);
238

    
239
      float d1 = 1.0f;
240
      float d2 =-0.05f;
241
      float d3 = 0.12f;
242

    
243
      Static3D dCen0 = new Static3D( d1*(+0.5f), d1*(+0.5f), d1*(+0.5f) );
244
      Static3D dCen1 = new Static3D( d1*(+0.5f), d1*(+0.5f), d1*(-0.5f) );
245
      Static3D dCen2 = new Static3D( d1*(+0.5f), d1*(-0.5f), d1*(+0.5f) );
246
      Static3D dCen3 = new Static3D( d1*(+0.5f), d1*(-0.5f), d1*(-0.5f) );
247
      Static3D dCen4 = new Static3D( d1*(-0.5f), d1*(+0.5f), d1*(+0.5f) );
248
      Static3D dCen5 = new Static3D( d1*(-0.5f), d1*(+0.5f), d1*(-0.5f) );
249
      Static3D dCen6 = new Static3D( d1*(-0.5f), d1*(-0.5f), d1*(+0.5f) );
250
      Static3D dCen7 = new Static3D( d1*(-0.5f), d1*(-0.5f), d1*(-0.5f) );
251

    
252
      Static3D dVec0 = new Static3D( d2*(+0.5f), d2*(+0.5f), d2*(+0.5f) );
253
      Static3D dVec1 = new Static3D( d2*(+0.5f), d2*(+0.5f), d2*(-0.5f) );
254
      Static3D dVec2 = new Static3D( d2*(+0.5f), d2*(-0.5f), d2*(+0.5f) );
255
      Static3D dVec3 = new Static3D( d2*(+0.5f), d2*(-0.5f), d2*(-0.5f) );
256
      Static3D dVec4 = new Static3D( d2*(-0.5f), d2*(+0.5f), d2*(+0.5f) );
257
      Static3D dVec5 = new Static3D( d2*(-0.5f), d2*(+0.5f), d2*(-0.5f) );
258
      Static3D dVec6 = new Static3D( d2*(-0.5f), d2*(-0.5f), d2*(+0.5f) );
259
      Static3D dVec7 = new Static3D( d2*(-0.5f), d2*(-0.5f), d2*(-0.5f) );
260

    
261
      Static4D dReg  = new Static4D(0,0,0,d3);
262
      Static1D dRad  = new Static1D(1);
263

    
264
      VertexEffectMove   effect0 = new VertexEffectMove(new Static3D(0,0,+0.5f));
265
      effect0.setMeshAssociation(63,-1);  // all 6 sides
266
      VertexEffectRotate effect1 = new VertexEffectRotate( angle180, axisX, center );
267
      effect1.setMeshAssociation(32,-1);  // back
268
      VertexEffectRotate effect2 = new VertexEffectRotate( angle90 , axisX, center );
269
      effect2.setMeshAssociation( 8,-1);  // bottom
270
      VertexEffectRotate effect3 = new VertexEffectRotate( angle270, axisX, center );
271
      effect3.setMeshAssociation( 4,-1);  // top
272
      VertexEffectRotate effect4 = new VertexEffectRotate( angle270, axisY, center );
273
      effect4.setMeshAssociation( 2,-1);  // left
274
      VertexEffectRotate effect5 = new VertexEffectRotate( angle90 , axisY, center );
275
      effect5.setMeshAssociation( 1,-1);  // right
276

    
277
      VertexEffectDeform effect6 = new VertexEffectDeform(dVec0, dRad, dCen0, dReg);
278
      VertexEffectDeform effect7 = new VertexEffectDeform(dVec1, dRad, dCen1, dReg);
279
      VertexEffectDeform effect8 = new VertexEffectDeform(dVec2, dRad, dCen2, dReg);
280
      VertexEffectDeform effect9 = new VertexEffectDeform(dVec3, dRad, dCen3, dReg);
281
      VertexEffectDeform effect10= new VertexEffectDeform(dVec4, dRad, dCen4, dReg);
282
      VertexEffectDeform effect11= new VertexEffectDeform(dVec5, dRad, dCen5, dReg);
283
      VertexEffectDeform effect12= new VertexEffectDeform(dVec6, dRad, dCen6, dReg);
284
      VertexEffectDeform effect13= new VertexEffectDeform(dVec7, dRad, dCen7, dReg);
285

    
286
      VertexEffectSink   effect14= new VertexEffectSink( new Static1D(1.5f), center, new Static4D(0,0,0,0.72f) );
287

    
288
      mMeshes[index].apply(effect0);
289
      mMeshes[index].apply(effect1);
290
      mMeshes[index].apply(effect2);
291
      mMeshes[index].apply(effect3);
292
      mMeshes[index].apply(effect4);
293
      mMeshes[index].apply(effect5);
294
      mMeshes[index].apply(effect6);
295
      mMeshes[index].apply(effect7);
296
      mMeshes[index].apply(effect8);
297
      mMeshes[index].apply(effect9);
298
      mMeshes[index].apply(effect10);
299
      mMeshes[index].apply(effect11);
300
      mMeshes[index].apply(effect12);
301
      mMeshes[index].apply(effect13);
302
      mMeshes[index].apply(effect14);
303

    
304
      mMeshes[index].mergeEffComponents();
305
      }
306

    
307
    return mMeshes[index].copy(true);
308
    }
309

    
310
///////////////////////////////////////////////////////////////////////////////////////////////////
311
// PUBLIC API
312

    
313
  public Static3D[] getRotationAxis()
314
    {
315
    return ROT_AXIS;
316
    }
317

    
318
///////////////////////////////////////////////////////////////////////////////////////////////////
319

    
320
  public int getBasicAngle()
321
    {
322
    return 4;
323
    }
324

    
325
///////////////////////////////////////////////////////////////////////////////////////////////////
326

    
327
  public float returnMultiplier()
328
    {
329
    return getSize();
330
    }
331

    
332
///////////////////////////////////////////////////////////////////////////////////////////////////
333

    
334
  public float[] getRowChances()
335
    {
336
    int size = getSize();
337
    float[] chances = new float[size];
338

    
339
    for(int i=0; i<size; i++)
340
      {
341
      chances[i] = (i+1.0f) / size;
342
      }
343

    
344
    return chances;
345
    }
346

    
347
///////////////////////////////////////////////////////////////////////////////////////////////////
348

    
349
  public float returnRotationFactor(float offset)
350
    {
351
    return 1.0f;
352
    }
353

    
354
///////////////////////////////////////////////////////////////////////////////////////////////////
355
// order: Up --> Right --> Front --> Down --> Left --> Back
356
// (because the first implemented Solver - the two-phase Cube3 one - expects such order)
357
//
358
// Solved 3x3x3 Cube maps to "UUUUUUUUURRRRRRRRRFFFFFFFFFDDDDDDDDDLLLLLLLLLBBBBBBBBB"
359
//
360
// s : size of the cube; let index = a*s + b    (i.e. a,b = row,column)
361
//
362
// Up    :   index --> b<s-1 ? (s-1)*(s+4b)+a : 6*s*s -13*s +8 +a
363
// Right :   index --> 6*s*s - 12*s + 7 - index
364
// Front :   index --> if b==0  : s*s - 1 - index
365
//                     if b==s-1: 6*s*s -11*s +6 - index
366
//                     else
367
//                         a==0: s*s + s-1 + 4*(b-1)*(s-1) + 2*(s-2) + s
368
//                         else: s*s + s-1 + 4*(b-1)*(s-1) + 2*(s-1-a)
369
// Down  :   index --> b==0 ? (s-1-a) : s*s + s-1 + 4*(b-1)*(s-1) - a
370
// Left  :   index --> (s-1-a)*s + b
371
// Back  :   index --> if b==s-1: s*(s-1-a)
372
//                     if b==0  : 5*s*s -12*s + 8 + (s-1-a)*s
373
//                     else
374
//                        if a==s-1: s*s + 4*(s-2-b)*(s-1)
375
//                        else     : s*s + 4*(s-2-b)*(s-1) + s + (s-2-a)*2
376

    
377
  public String retObjectString()
378
    {
379
    StringBuilder objectString = new StringBuilder();
380
    int size = getSize();
381
    int len = size*size;
382
    int cubitIndex, row, col;
383
    int color;
384

    
385
    final int RIGHT= 0;
386
    final int LEFT = 1;
387
    final int UP   = 2;
388
    final int DOWN = 3;
389
    final int FRONT= 4;
390
    final int BACK = 5;
391

    
392
    final char[] FACE_NAMES = { 'R', 'L', 'U', 'D', 'F', 'B'};
393

    
394
    for(int i=0; i<len; i++)
395
      {
396
      row = i/size;
397
      col = i%size;
398

    
399
      cubitIndex = col<size-1 ? (size-1)*(size+4*col) + row : 6*size*size - 13*size + 8 + row;
400
      color = getCubitFaceColorIndex(cubitIndex,UP);
401
      objectString.append(FACE_NAMES[color]);
402
      }
403

    
404
    for(int i=0; i<len; i++)
405
      {
406
      cubitIndex = 6*size*size - 12*size +7 - i;
407
      color = getCubitFaceColorIndex(cubitIndex,RIGHT);
408
      objectString.append(FACE_NAMES[color]);
409
      }
410

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

    
416
      if( col==size-1 ) cubitIndex = 6*size*size - 11*size + 6 -i;
417
      else if( col==0 ) cubitIndex = size*size - 1 - i;
418
      else
419
        {
420
        if( row==0 ) cubitIndex = size*size + size-1 + 4*(col-1)*(size-1) + 2*(size-2) + size;
421
        else         cubitIndex = size*size + size-1 + 4*(col-1)*(size-1) + 2*(size-1-row);
422
        }
423

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

    
428
    for(int i=0; i<len; i++)
429
      {
430
      row = i/size;
431
      col = i%size;
432

    
433
      cubitIndex = col==0 ? size-1-row : size*size + size-1 + 4*(col-1)*(size-1) - row;
434
      color = getCubitFaceColorIndex(cubitIndex,DOWN);
435
      objectString.append(FACE_NAMES[color]);
436
      }
437

    
438
    for(int i=0; i<len; i++)
439
      {
440
      row = i/size;
441
      col = i%size;
442

    
443
      cubitIndex = (size-1-row)*size + col;
444
      color = getCubitFaceColorIndex(cubitIndex,LEFT);
445
      objectString.append(FACE_NAMES[color]);
446
      }
447

    
448
    for(int i=0; i<len; i++)
449
      {
450
      row = i/size;
451
      col = i%size;
452

    
453
      if( col==size-1 ) cubitIndex = size*(size-1-row);
454
      else if( col==0 ) cubitIndex = 5*size*size - 12*size + 8 + (size-1-row)*size;
455
      else
456
        {
457
        if( row==size-1 ) cubitIndex = size*size + 4*(size-2-col)*(size-1);
458
        else              cubitIndex = size*size + 4*(size-2-col)*(size-1) + size + 2*(size-2-row);
459
        }
460

    
461
      color = getCubitFaceColorIndex(cubitIndex,BACK);
462
      objectString.append(FACE_NAMES[color]);
463
      }
464

    
465
    return objectString.toString();
466
    }
467
}
(2-2/10)