Project

General

Profile

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

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

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 mMesh = null;
97

    
98
///////////////////////////////////////////////////////////////////////////////////////////////////
99

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

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

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

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

    
118
///////////////////////////////////////////////////////////////////////////////////////////////////
119

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

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

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

    
136
    return tmp;
137
    }
138

    
139
///////////////////////////////////////////////////////////////////////////////////////////////////
140

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

    
146
///////////////////////////////////////////////////////////////////////////////////////////////////
147

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

    
153
///////////////////////////////////////////////////////////////////////////////////////////////////
154

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

    
160
///////////////////////////////////////////////////////////////////////////////////////////////////
161

    
162
  MeshBase createCubitMesh(int cubit)
163
    {
164
    if( mMesh==null )
165
      {
166
      final int MESHES=6;
167
      int association = 1;
168
      MeshBase[] meshes = new MeshRectangles[MESHES];
169
      meshes[0] = new MeshRectangles(14,14);
170
      meshes[0].setEffectAssociation(0,association,0);
171

    
172
      for(int i=1; i<MESHES; i++)
173
        {
174
        association <<=1;
175
        meshes[i] = meshes[0].copy(true);
176
        meshes[i].setEffectAssociation(0,association,0);
177
        }
178

    
179
      mMesh = new MeshJoined(meshes);
180

    
181
      Static3D axisY   = new Static3D(0,1,0);
182
      Static3D axisX   = new Static3D(1,0,0);
183
      Static3D center  = new Static3D(0,0,0);
184
      Static1D angle90 = new Static1D(90);
185
      Static1D angle180= new Static1D(180);
186
      Static1D angle270= new Static1D(270);
187

    
188
      float d1 = 1.0f;
189
      float d2 =-0.05f;
190
      float d3 = 0.12f;
191

    
192
      Static3D dCen0 = new Static3D( d1*(+0.5f), d1*(+0.5f), d1*(+0.5f) );
193
      Static3D dCen1 = new Static3D( d1*(+0.5f), d1*(+0.5f), d1*(-0.5f) );
194
      Static3D dCen2 = new Static3D( d1*(+0.5f), d1*(-0.5f), d1*(+0.5f) );
195
      Static3D dCen3 = new Static3D( d1*(+0.5f), d1*(-0.5f), d1*(-0.5f) );
196
      Static3D dCen4 = new Static3D( d1*(-0.5f), d1*(+0.5f), d1*(+0.5f) );
197
      Static3D dCen5 = new Static3D( d1*(-0.5f), d1*(+0.5f), d1*(-0.5f) );
198
      Static3D dCen6 = new Static3D( d1*(-0.5f), d1*(-0.5f), d1*(+0.5f) );
199
      Static3D dCen7 = new Static3D( d1*(-0.5f), d1*(-0.5f), d1*(-0.5f) );
200

    
201
      Static3D dVec0 = new Static3D( d2*(+0.5f), d2*(+0.5f), d2*(+0.5f) );
202
      Static3D dVec1 = new Static3D( d2*(+0.5f), d2*(+0.5f), d2*(-0.5f) );
203
      Static3D dVec2 = new Static3D( d2*(+0.5f), d2*(-0.5f), d2*(+0.5f) );
204
      Static3D dVec3 = new Static3D( d2*(+0.5f), d2*(-0.5f), d2*(-0.5f) );
205
      Static3D dVec4 = new Static3D( d2*(-0.5f), d2*(+0.5f), d2*(+0.5f) );
206
      Static3D dVec5 = new Static3D( d2*(-0.5f), d2*(+0.5f), d2*(-0.5f) );
207
      Static3D dVec6 = new Static3D( d2*(-0.5f), d2*(-0.5f), d2*(+0.5f) );
208
      Static3D dVec7 = new Static3D( d2*(-0.5f), d2*(-0.5f), d2*(-0.5f) );
209

    
210
      Static4D dReg  = new Static4D(0,0,0,d3);
211
      Static1D dRad  = new Static1D(1);
212

    
213
      VertexEffectMove   effect0 = new VertexEffectMove(new Static3D(0,0,+0.5f));
214
      effect0.setMeshAssociation(63,-1);  // all 6 sides
215
      VertexEffectRotate effect1 = new VertexEffectRotate( angle180, axisX, center );
216
      effect1.setMeshAssociation(32,-1);  // back
217
      VertexEffectRotate effect2 = new VertexEffectRotate( angle90 , axisX, center );
218
      effect2.setMeshAssociation( 8,-1);  // bottom
219
      VertexEffectRotate effect3 = new VertexEffectRotate( angle270, axisX, center );
220
      effect3.setMeshAssociation( 4,-1);  // top
221
      VertexEffectRotate effect4 = new VertexEffectRotate( angle270, axisY, center );
222
      effect4.setMeshAssociation( 2,-1);  // left
223
      VertexEffectRotate effect5 = new VertexEffectRotate( angle90 , axisY, center );
224
      effect5.setMeshAssociation( 1,-1);  // right
225

    
226
      VertexEffectDeform effect6 = new VertexEffectDeform(dVec0, dRad, dCen0, dReg);
227
      VertexEffectDeform effect7 = new VertexEffectDeform(dVec1, dRad, dCen1, dReg);
228
      VertexEffectDeform effect8 = new VertexEffectDeform(dVec2, dRad, dCen2, dReg);
229
      VertexEffectDeform effect9 = new VertexEffectDeform(dVec3, dRad, dCen3, dReg);
230
      VertexEffectDeform effect10= new VertexEffectDeform(dVec4, dRad, dCen4, dReg);
231
      VertexEffectDeform effect11= new VertexEffectDeform(dVec5, dRad, dCen5, dReg);
232
      VertexEffectDeform effect12= new VertexEffectDeform(dVec6, dRad, dCen6, dReg);
233
      VertexEffectDeform effect13= new VertexEffectDeform(dVec7, dRad, dCen7, dReg);
234

    
235
      VertexEffectSink   effect14= new VertexEffectSink( new Static1D(1.5f), center, new Static4D(0,0,0,0.72f) );
236

    
237
      mMesh.apply(effect0);
238
      mMesh.apply(effect1);
239
      mMesh.apply(effect2);
240
      mMesh.apply(effect3);
241
      mMesh.apply(effect4);
242
      mMesh.apply(effect5);
243
      mMesh.apply(effect6);
244
      mMesh.apply(effect7);
245
      mMesh.apply(effect8);
246
      mMesh.apply(effect9);
247
      mMesh.apply(effect10);
248
      mMesh.apply(effect11);
249
      mMesh.apply(effect12);
250
      mMesh.apply(effect13);
251
      mMesh.apply(effect14);
252

    
253
      mMesh.mergeEffComponents();
254
      }
255

    
256
    return mMesh.copy(true);
257
    }
258

    
259
///////////////////////////////////////////////////////////////////////////////////////////////////
260
// PUBLIC API
261

    
262
  public Static3D[] getRotationAxis()
263
    {
264
    return AXIS;
265
    }
266

    
267
///////////////////////////////////////////////////////////////////////////////////////////////////
268

    
269
  public int getBasicAngle()
270
    {
271
    return 4;
272
    }
273

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

    
276
  public float returnMultiplier()
277
    {
278
    return getSize();
279
    }
280

    
281
///////////////////////////////////////////////////////////////////////////////////////////////////
282

    
283
  public float[] getRowChances()
284
    {
285
    int size = getSize();
286
    float[] chances = new float[size];
287

    
288
    for(int i=0; i<size; i++)
289
      {
290
      chances[i] = (i+1.0f) / size;
291
      }
292

    
293
    return chances;
294
    }
295

    
296
///////////////////////////////////////////////////////////////////////////////////////////////////
297

    
298
  public float returnRotationFactor(float offset)
299
    {
300
    return 1.0f;
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 size = getSize();
330
    int len = size*size;
331
    int cubitIndex, row, col;
332
    int color;
333

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

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

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

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

    
353
    for(int i=0; i<len; i++)
354
      {
355
      cubitIndex = 6*size*size - 12*size +7 - i;
356
      color = getCubitFaceColorIndex(cubitIndex,RIGHT);
357
      objectString.append(FACE_NAMES[color]);
358
      }
359

    
360
    for(int i=0; i<len; i++)
361
      {
362
      row = i/size;
363
      col = i%size;
364

    
365
      if( col==size-1 ) cubitIndex = 6*size*size - 11*size + 6 -i;
366
      else if( col==0 ) cubitIndex = size*size - 1 - i;
367
      else
368
        {
369
        if( row==0 ) cubitIndex = size*size + size-1 + 4*(col-1)*(size-1) + 2*(size-2) + size;
370
        else         cubitIndex = size*size + size-1 + 4*(col-1)*(size-1) + 2*(size-1-row);
371
        }
372

    
373
      color = getCubitFaceColorIndex(cubitIndex,FRONT);
374
      objectString.append(FACE_NAMES[color]);
375
      }
376

    
377
    for(int i=0; i<len; i++)
378
      {
379
      row = i/size;
380
      col = i%size;
381

    
382
      cubitIndex = col==0 ? size-1-row : size*size + size-1 + 4*(col-1)*(size-1) - row;
383
      color = getCubitFaceColorIndex(cubitIndex,DOWN);
384
      objectString.append(FACE_NAMES[color]);
385
      }
386

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

    
392
      cubitIndex = (size-1-row)*size + col;
393
      color = getCubitFaceColorIndex(cubitIndex,LEFT);
394
      objectString.append(FACE_NAMES[color]);
395
      }
396

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

    
402
      if( col==size-1 ) cubitIndex = size*(size-1-row);
403
      else if( col==0 ) cubitIndex = 5*size*size - 12*size + 8 + (size-1-row)*size;
404
      else
405
        {
406
        if( row==size-1 ) cubitIndex = size*size + 4*(size-2-col)*(size-1);
407
        else              cubitIndex = size*size + 4*(size-2-col)*(size-1) + size + 2*(size-2-row);
408
        }
409

    
410
      color = getCubitFaceColorIndex(cubitIndex,BACK);
411
      objectString.append(FACE_NAMES[color]);
412
      }
413

    
414
    return objectString.toString();
415
    }
416
}
(2-2/8)