Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / RubikCube.java @ 55fa2499

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.graphics.Canvas;
23
import android.graphics.Paint;
24

    
25
import org.distorted.library.effect.VertexEffectDeform;
26
import org.distorted.library.effect.VertexEffectMove;
27
import org.distorted.library.effect.VertexEffectRotate;
28
import org.distorted.library.effect.VertexEffectSink;
29
import org.distorted.library.main.DistortedEffects;
30
import org.distorted.library.main.DistortedTexture;
31
import org.distorted.library.mesh.MeshBase;
32
import org.distorted.library.mesh.MeshJoined;
33
import org.distorted.library.mesh.MeshRectangles;
34
import org.distorted.library.type.Static1D;
35
import org.distorted.library.type.Static3D;
36
import org.distorted.library.type.Static4D;
37

    
38
///////////////////////////////////////////////////////////////////////////////////////////////////
39

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

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

    
52
  private static final int[] FACE_COLORS = new int[]
53
         {
54
           0xffffff00, 0xffffffff,   // AXIS[0]right (right-YELLOW) AXIS[0]left (left  -WHITE)
55
           0xff0000ff, 0xff00ff00,   // AXIS[1]right (top  -BLUE  ) AXIS[1]left (bottom-GREEN)
56
           0xffff0000, 0xffb5651d    // AXIS[2]right (front-RED   ) AXIS[2]left (back  -BROWN)
57
         };
58

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

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

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

    
96
  private static MeshBase mMeshBig = null;
97
  private static MeshBase mMeshSma = null;
98

    
99
///////////////////////////////////////////////////////////////////////////////////////////////////
100

    
101
  RubikCube(int size, Static4D quatCur, Static4D quatAcc, DistortedTexture texture, MeshRectangles mesh, DistortedEffects effects, int[][] moves)
102
    {
103
    super(size, 60, quatCur,quatAcc,texture,mesh,effects,moves, RubikObjectList.CUBE);
104
    }
105

    
106
///////////////////////////////////////////////////////////////////////////////////////////////////
107
// paint the square with upper-right cornder at (left,top) and side length 'side' with texture
108
// for face 'face'.
109

    
110
  void createFaceTexture(Canvas canvas, Paint paint, int face, int left, int top, int side)
111
    {
112
    final float R = side*0.10f;
113
    final float M = side*0.05f;
114

    
115
    paint.setColor(FACE_COLORS[face]);
116
    canvas.drawRoundRect( left+M, top+M, left+side-M, top+side-M, R, R, paint);
117
    }
118

    
119
///////////////////////////////////////////////////////////////////////////////////////////////////
120

    
121
  Static3D[] getCubitPositions(int size)
122
    {
123
    int numCubits = size>1 ? 6*size*size - 12*size + 8 : 1;
124
    Static3D[] tmp = new Static3D[numCubits];
125

    
126
    float diff = 0.5f*(size-1);
127
    int currentPosition = 0;
128

    
129
    for(int x = 0; x<size; x++)
130
      for(int y = 0; y<size; y++)
131
        for(int z = 0; z<size; z++)
132
          if( x==0 || x==size-1 || y==0 || y==size-1 || z==0 || z==size-1 )
133
            {
134
            tmp[currentPosition++] = new Static3D(x-diff,y-diff,z-diff);
135
            }
136

    
137
    return tmp;
138
    }
139

    
140
///////////////////////////////////////////////////////////////////////////////////////////////////
141

    
142
  Static4D[] getQuats()
143
    {
144
    return QUATS;
145
    }
146

    
147
///////////////////////////////////////////////////////////////////////////////////////////////////
148

    
149
  int getNumFaces()
150
    {
151
    return FACE_COLORS.length;
152
    }
153

    
154
///////////////////////////////////////////////////////////////////////////////////////////////////
155

    
156
  float getScreenRatio()
157
    {
158
    return 0.5f;
159
    }
160

    
161
///////////////////////////////////////////////////////////////////////////////////////////////////
162

    
163
  MeshBase createCubitMesh(int cubit)
164
    {
165
    return createCubitMesh(getSize()<=3);
166
    }
167

    
168
///////////////////////////////////////////////////////////////////////////////////////////////////
169

    
170
  MeshBase createCubitMesh(boolean big)
171
    {
172
    MeshBase mesh = big ? mMeshBig : mMeshSma;
173
    int size = big ? 14 : 9;
174

    
175
    if( mesh==null )
176
      {
177
      final int MESHES=6;
178
      int association = 1;
179
      MeshBase[] meshes = new MeshRectangles[MESHES];
180
      meshes[0] = new MeshRectangles(size,size);
181
      meshes[0].setEffectAssociation(0,association,0);
182

    
183
      for(int i=1; i<MESHES; i++)
184
        {
185
        association <<=1;
186
        meshes[i] = meshes[0].copy(true);
187
        meshes[i].setEffectAssociation(0,association,0);
188
        }
189

    
190
      mesh = new MeshJoined(meshes);
191

    
192
      Static3D axisY   = new Static3D(0,1,0);
193
      Static3D axisX   = new Static3D(1,0,0);
194
      Static3D center  = new Static3D(0,0,0);
195
      Static1D angle90 = new Static1D(90);
196
      Static1D angle180= new Static1D(180);
197
      Static1D angle270= new Static1D(270);
198

    
199
      float d1 = 1.0f;
200
      float d2 =-0.05f;
201
      float d3 = 0.12f;
202

    
203
      Static3D dCen0 = new Static3D( d1*(+0.5f), d1*(+0.5f), d1*(+0.5f) );
204
      Static3D dCen1 = new Static3D( d1*(+0.5f), d1*(+0.5f), d1*(-0.5f) );
205
      Static3D dCen2 = new Static3D( d1*(+0.5f), d1*(-0.5f), d1*(+0.5f) );
206
      Static3D dCen3 = new Static3D( d1*(+0.5f), d1*(-0.5f), d1*(-0.5f) );
207
      Static3D dCen4 = new Static3D( d1*(-0.5f), d1*(+0.5f), d1*(+0.5f) );
208
      Static3D dCen5 = new Static3D( d1*(-0.5f), d1*(+0.5f), d1*(-0.5f) );
209
      Static3D dCen6 = new Static3D( d1*(-0.5f), d1*(-0.5f), d1*(+0.5f) );
210
      Static3D dCen7 = new Static3D( d1*(-0.5f), d1*(-0.5f), d1*(-0.5f) );
211

    
212
      Static3D dVec0 = new Static3D( d2*(+0.5f), d2*(+0.5f), d2*(+0.5f) );
213
      Static3D dVec1 = new Static3D( d2*(+0.5f), d2*(+0.5f), d2*(-0.5f) );
214
      Static3D dVec2 = new Static3D( d2*(+0.5f), d2*(-0.5f), d2*(+0.5f) );
215
      Static3D dVec3 = new Static3D( d2*(+0.5f), d2*(-0.5f), d2*(-0.5f) );
216
      Static3D dVec4 = new Static3D( d2*(-0.5f), d2*(+0.5f), d2*(+0.5f) );
217
      Static3D dVec5 = new Static3D( d2*(-0.5f), d2*(+0.5f), d2*(-0.5f) );
218
      Static3D dVec6 = new Static3D( d2*(-0.5f), d2*(-0.5f), d2*(+0.5f) );
219
      Static3D dVec7 = new Static3D( d2*(-0.5f), d2*(-0.5f), d2*(-0.5f) );
220

    
221
      Static4D dReg  = new Static4D(0,0,0,d3);
222
      Static1D dRad  = new Static1D(1);
223

    
224
      VertexEffectMove   effect0 = new VertexEffectMove(new Static3D(0,0,+0.5f));
225
      effect0.setMeshAssociation(63,-1);  // all 6 sides
226
      VertexEffectRotate effect1 = new VertexEffectRotate( angle180, axisX, center );
227
      effect1.setMeshAssociation(32,-1);  // back
228
      VertexEffectRotate effect2 = new VertexEffectRotate( angle90 , axisX, center );
229
      effect2.setMeshAssociation( 8,-1);  // bottom
230
      VertexEffectRotate effect3 = new VertexEffectRotate( angle270, axisX, center );
231
      effect3.setMeshAssociation( 4,-1);  // top
232
      VertexEffectRotate effect4 = new VertexEffectRotate( angle270, axisY, center );
233
      effect4.setMeshAssociation( 2,-1);  // left
234
      VertexEffectRotate effect5 = new VertexEffectRotate( angle90 , axisY, center );
235
      effect5.setMeshAssociation( 1,-1);  // right
236

    
237
      VertexEffectDeform effect6 = new VertexEffectDeform(dVec0, dRad, dCen0, dReg);
238
      VertexEffectDeform effect7 = new VertexEffectDeform(dVec1, dRad, dCen1, dReg);
239
      VertexEffectDeform effect8 = new VertexEffectDeform(dVec2, dRad, dCen2, dReg);
240
      VertexEffectDeform effect9 = new VertexEffectDeform(dVec3, dRad, dCen3, dReg);
241
      VertexEffectDeform effect10= new VertexEffectDeform(dVec4, dRad, dCen4, dReg);
242
      VertexEffectDeform effect11= new VertexEffectDeform(dVec5, dRad, dCen5, dReg);
243
      VertexEffectDeform effect12= new VertexEffectDeform(dVec6, dRad, dCen6, dReg);
244
      VertexEffectDeform effect13= new VertexEffectDeform(dVec7, dRad, dCen7, dReg);
245

    
246
      VertexEffectSink   effect14= new VertexEffectSink( new Static1D(1.5f), center, new Static4D(0,0,0,0.72f) );
247

    
248
      mesh.apply(effect0);
249
      mesh.apply(effect1);
250
      mesh.apply(effect2);
251
      mesh.apply(effect3);
252
      mesh.apply(effect4);
253
      mesh.apply(effect5);
254
      mesh.apply(effect6);
255
      mesh.apply(effect7);
256
      mesh.apply(effect8);
257
      mesh.apply(effect9);
258
      mesh.apply(effect10);
259
      mesh.apply(effect11);
260
      mesh.apply(effect12);
261
      mesh.apply(effect13);
262
      mesh.apply(effect14);
263

    
264
      mesh.mergeEffComponents();
265
      }
266

    
267
    return mesh.copy(true);
268
    }
269

    
270
///////////////////////////////////////////////////////////////////////////////////////////////////
271
// PUBLIC API
272

    
273
  public Static3D[] getRotationAxis()
274
    {
275
    return AXIS;
276
    }
277

    
278
///////////////////////////////////////////////////////////////////////////////////////////////////
279

    
280
  public int getBasicAngle()
281
    {
282
    return 4;
283
    }
284

    
285
///////////////////////////////////////////////////////////////////////////////////////////////////
286

    
287
  public float returnMultiplier()
288
    {
289
    return getSize();
290
    }
291

    
292
///////////////////////////////////////////////////////////////////////////////////////////////////
293

    
294
  public float[] getRowChances()
295
    {
296
    int size = getSize();
297
    float[] chances = new float[size];
298

    
299
    for(int i=0; i<size; i++)
300
      {
301
      chances[i] = (i+1.0f) / size;
302
      }
303

    
304
    return chances;
305
    }
306

    
307
///////////////////////////////////////////////////////////////////////////////////////////////////
308

    
309
  public float returnRotationFactor(float offset)
310
    {
311
    return 1.0f;
312
    }
313

    
314
///////////////////////////////////////////////////////////////////////////////////////////////////
315
// order: Up --> Right --> Front --> Down --> Left --> Back
316
// (because the first implemented Solver - the two-phase Cube3 one - expects such order)
317
//
318
// Solved 3x3x3 Cube maps to "UUUUUUUUURRRRRRRRRFFFFFFFFFDDDDDDDDDLLLLLLLLLBBBBBBBBB"
319
//
320
// s : size of the cube; let index = a*s + b    (i.e. a,b = row,column)
321
//
322
// Up    :   index --> b<s-1 ? (s-1)*(s+4b)+a : 6*s*s -13*s +8 +a
323
// Right :   index --> 6*s*s - 12*s + 7 - index
324
// Front :   index --> if b==0  : s*s - 1 - index
325
//                     if b==s-1: 6*s*s -11*s +6 - index
326
//                     else
327
//                         a==0: s*s + s-1 + 4*(b-1)*(s-1) + 2*(s-2) + s
328
//                         else: s*s + s-1 + 4*(b-1)*(s-1) + 2*(s-1-a)
329
// Down  :   index --> b==0 ? (s-1-a) : s*s + s-1 + 4*(b-1)*(s-1) - a
330
// Left  :   index --> (s-1-a)*s + b
331
// Back  :   index --> if b==s-1: s*(s-1-a)
332
//                     if b==0  : 5*s*s -12*s + 8 + (s-1-a)*s
333
//                     else
334
//                        if a==s-1: s*s + 4*(s-2-b)*(s-1)
335
//                        else     : s*s + 4*(s-2-b)*(s-1) + s + (s-2-a)*2
336

    
337
  public String retObjectString()
338
    {
339
    StringBuilder objectString = new StringBuilder();
340
    int size = getSize();
341
    int len = size*size;
342
    int cubitIndex, row, col;
343
    int color;
344

    
345
    final int RIGHT= 0;
346
    final int LEFT = 1;
347
    final int UP   = 2;
348
    final int DOWN = 3;
349
    final int FRONT= 4;
350
    final int BACK = 5;
351

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

    
354
    for(int i=0; i<len; i++)
355
      {
356
      row = i/size;
357
      col = i%size;
358

    
359
      cubitIndex = col<size-1 ? (size-1)*(size+4*col) + row : 6*size*size - 13*size + 8 + row;
360
      color = getCubitFaceColorIndex(cubitIndex,UP);
361
      objectString.append(FACE_NAMES[color]);
362
      }
363

    
364
    for(int i=0; i<len; i++)
365
      {
366
      cubitIndex = 6*size*size - 12*size +7 - i;
367
      color = getCubitFaceColorIndex(cubitIndex,RIGHT);
368
      objectString.append(FACE_NAMES[color]);
369
      }
370

    
371
    for(int i=0; i<len; i++)
372
      {
373
      row = i/size;
374
      col = i%size;
375

    
376
      if( col==size-1 ) cubitIndex = 6*size*size - 11*size + 6 -i;
377
      else if( col==0 ) cubitIndex = size*size - 1 - i;
378
      else
379
        {
380
        if( row==0 ) cubitIndex = size*size + size-1 + 4*(col-1)*(size-1) + 2*(size-2) + size;
381
        else         cubitIndex = size*size + size-1 + 4*(col-1)*(size-1) + 2*(size-1-row);
382
        }
383

    
384
      color = getCubitFaceColorIndex(cubitIndex,FRONT);
385
      objectString.append(FACE_NAMES[color]);
386
      }
387

    
388
    for(int i=0; i<len; i++)
389
      {
390
      row = i/size;
391
      col = i%size;
392

    
393
      cubitIndex = col==0 ? size-1-row : size*size + size-1 + 4*(col-1)*(size-1) - row;
394
      color = getCubitFaceColorIndex(cubitIndex,DOWN);
395
      objectString.append(FACE_NAMES[color]);
396
      }
397

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

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

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

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

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

    
425
    return objectString.toString();
426
    }
427
}
(2-2/8)