Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / RubikCube.java @ 418aa554

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

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

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

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

    
97
  private static MeshBase[] mMeshes;
98

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

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

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

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

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

    
120
///////////////////////////////////////////////////////////////////////////////////////////////////
121

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

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

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

    
138
    return tmp;
139
    }
140

    
141
///////////////////////////////////////////////////////////////////////////////////////////////////
142

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

    
148
///////////////////////////////////////////////////////////////////////////////////////////////////
149

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

    
155
///////////////////////////////////////////////////////////////////////////////////////////////////
156

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

    
162
///////////////////////////////////////////////////////////////////////////////////////////////////
163

    
164
  MeshBase createCubitMesh(int cubit)
165
    {
166
    int size   = getSize();
167
    int ordinal= RubikObjectList.CUBE.ordinal();
168
    int index  = RubikObjectList.getSizeIndex(ordinal,size);
169
    float[] loc;
170

    
171
    switch(size)
172
      {
173
      case 5 : loc = new float[] { -0.5f, 0.05f, 0.1f, 0.35f, 0.35f, 0.1f, 0.05f };
174
               break;
175
      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 };
176
               break;
177
      default: loc = new float[] { -0.5f, 0.04f, 0.06f, 0.25f, 0.30f, 0.25f, 0.06f, 0.04f };
178
      }
179

    
180
    return createCubitMesh(index,loc);
181
    }
182

    
183
///////////////////////////////////////////////////////////////////////////////////////////////////
184

    
185
  MeshBase createCubitMesh(int index, float[] loc)
186
    {
187
    if( mMeshes==null )
188
      {
189
      mMeshes = new MeshBase[RubikObjectList.CUBE.getNumVariants()];
190
      }
191

    
192
    if( mMeshes[index]==null )
193
      {
194
      final int MESHES=6;
195
      int association = 1;
196
      MeshBase[] meshes = new MeshRectangles[MESHES];
197
      meshes[0] = new MeshRectangles(loc,loc);
198
      meshes[0].setEffectAssociation(0,association,0);
199

    
200
      for(int i=1; i<MESHES; i++)
201
        {
202
        association <<=1;
203
        meshes[i] = meshes[0].copy(true);
204
        meshes[i].setEffectAssociation(0,association,0);
205
        }
206

    
207
      mMeshes[index] = new MeshJoined(meshes);
208

    
209
      Static3D axisY   = new Static3D(0,1,0);
210
      Static3D axisX   = new Static3D(1,0,0);
211
      Static3D center  = new Static3D(0,0,0);
212
      Static1D angle90 = new Static1D(90);
213
      Static1D angle180= new Static1D(180);
214
      Static1D angle270= new Static1D(270);
215

    
216
      float d1 = 1.0f;
217
      float d2 =-0.05f;
218
      float d3 = 0.12f;
219

    
220
      Static3D dCen0 = new Static3D( d1*(+0.5f), d1*(+0.5f), d1*(+0.5f) );
221
      Static3D dCen1 = new Static3D( d1*(+0.5f), d1*(+0.5f), d1*(-0.5f) );
222
      Static3D dCen2 = new Static3D( d1*(+0.5f), d1*(-0.5f), d1*(+0.5f) );
223
      Static3D dCen3 = new Static3D( d1*(+0.5f), d1*(-0.5f), d1*(-0.5f) );
224
      Static3D dCen4 = new Static3D( d1*(-0.5f), d1*(+0.5f), d1*(+0.5f) );
225
      Static3D dCen5 = new Static3D( d1*(-0.5f), d1*(+0.5f), d1*(-0.5f) );
226
      Static3D dCen6 = new Static3D( d1*(-0.5f), d1*(-0.5f), d1*(+0.5f) );
227
      Static3D dCen7 = new Static3D( d1*(-0.5f), d1*(-0.5f), d1*(-0.5f) );
228

    
229
      Static3D dVec0 = new Static3D( d2*(+0.5f), d2*(+0.5f), d2*(+0.5f) );
230
      Static3D dVec1 = new Static3D( d2*(+0.5f), d2*(+0.5f), d2*(-0.5f) );
231
      Static3D dVec2 = new Static3D( d2*(+0.5f), d2*(-0.5f), d2*(+0.5f) );
232
      Static3D dVec3 = new Static3D( d2*(+0.5f), d2*(-0.5f), d2*(-0.5f) );
233
      Static3D dVec4 = new Static3D( d2*(-0.5f), d2*(+0.5f), d2*(+0.5f) );
234
      Static3D dVec5 = new Static3D( d2*(-0.5f), d2*(+0.5f), d2*(-0.5f) );
235
      Static3D dVec6 = new Static3D( d2*(-0.5f), d2*(-0.5f), d2*(+0.5f) );
236
      Static3D dVec7 = new Static3D( d2*(-0.5f), d2*(-0.5f), d2*(-0.5f) );
237

    
238
      Static4D dReg  = new Static4D(0,0,0,d3);
239
      Static1D dRad  = new Static1D(1);
240

    
241
      VertexEffectMove   effect0 = new VertexEffectMove(new Static3D(0,0,+0.5f));
242
      effect0.setMeshAssociation(63,-1);  // all 6 sides
243
      VertexEffectRotate effect1 = new VertexEffectRotate( angle180, axisX, center );
244
      effect1.setMeshAssociation(32,-1);  // back
245
      VertexEffectRotate effect2 = new VertexEffectRotate( angle90 , axisX, center );
246
      effect2.setMeshAssociation( 8,-1);  // bottom
247
      VertexEffectRotate effect3 = new VertexEffectRotate( angle270, axisX, center );
248
      effect3.setMeshAssociation( 4,-1);  // top
249
      VertexEffectRotate effect4 = new VertexEffectRotate( angle270, axisY, center );
250
      effect4.setMeshAssociation( 2,-1);  // left
251
      VertexEffectRotate effect5 = new VertexEffectRotate( angle90 , axisY, center );
252
      effect5.setMeshAssociation( 1,-1);  // right
253

    
254
      VertexEffectDeform effect6 = new VertexEffectDeform(dVec0, dRad, dCen0, dReg);
255
      VertexEffectDeform effect7 = new VertexEffectDeform(dVec1, dRad, dCen1, dReg);
256
      VertexEffectDeform effect8 = new VertexEffectDeform(dVec2, dRad, dCen2, dReg);
257
      VertexEffectDeform effect9 = new VertexEffectDeform(dVec3, dRad, dCen3, dReg);
258
      VertexEffectDeform effect10= new VertexEffectDeform(dVec4, dRad, dCen4, dReg);
259
      VertexEffectDeform effect11= new VertexEffectDeform(dVec5, dRad, dCen5, dReg);
260
      VertexEffectDeform effect12= new VertexEffectDeform(dVec6, dRad, dCen6, dReg);
261
      VertexEffectDeform effect13= new VertexEffectDeform(dVec7, dRad, dCen7, dReg);
262

    
263
      VertexEffectSink   effect14= new VertexEffectSink( new Static1D(1.5f), center, new Static4D(0,0,0,0.72f) );
264

    
265
      mMeshes[index].apply(effect0);
266
      mMeshes[index].apply(effect1);
267
      mMeshes[index].apply(effect2);
268
      mMeshes[index].apply(effect3);
269
      mMeshes[index].apply(effect4);
270
      mMeshes[index].apply(effect5);
271
      mMeshes[index].apply(effect6);
272
      mMeshes[index].apply(effect7);
273
      mMeshes[index].apply(effect8);
274
      mMeshes[index].apply(effect9);
275
      mMeshes[index].apply(effect10);
276
      mMeshes[index].apply(effect11);
277
      mMeshes[index].apply(effect12);
278
      mMeshes[index].apply(effect13);
279
      mMeshes[index].apply(effect14);
280

    
281
      mMeshes[index].mergeEffComponents();
282
      }
283

    
284
    return mMeshes[index].copy(true);
285
    }
286

    
287
///////////////////////////////////////////////////////////////////////////////////////////////////
288
// PUBLIC API
289

    
290
  public Static3D[] getRotationAxis()
291
    {
292
    return AXIS;
293
    }
294

    
295
///////////////////////////////////////////////////////////////////////////////////////////////////
296

    
297
  public int getBasicAngle()
298
    {
299
    return 4;
300
    }
301

    
302
///////////////////////////////////////////////////////////////////////////////////////////////////
303

    
304
  public float returnMultiplier()
305
    {
306
    return getSize();
307
    }
308

    
309
///////////////////////////////////////////////////////////////////////////////////////////////////
310

    
311
  public float[] getRowChances()
312
    {
313
    int size = getSize();
314
    float[] chances = new float[size];
315

    
316
    for(int i=0; i<size; i++)
317
      {
318
      chances[i] = (i+1.0f) / size;
319
      }
320

    
321
    return chances;
322
    }
323

    
324
///////////////////////////////////////////////////////////////////////////////////////////////////
325

    
326
  public float returnRotationFactor(float offset)
327
    {
328
    return 1.0f;
329
    }
330

    
331
///////////////////////////////////////////////////////////////////////////////////////////////////
332
// order: Up --> Right --> Front --> Down --> Left --> Back
333
// (because the first implemented Solver - the two-phase Cube3 one - expects such order)
334
//
335
// Solved 3x3x3 Cube maps to "UUUUUUUUURRRRRRRRRFFFFFFFFFDDDDDDDDDLLLLLLLLLBBBBBBBBB"
336
//
337
// s : size of the cube; let index = a*s + b    (i.e. a,b = row,column)
338
//
339
// Up    :   index --> b<s-1 ? (s-1)*(s+4b)+a : 6*s*s -13*s +8 +a
340
// Right :   index --> 6*s*s - 12*s + 7 - index
341
// Front :   index --> if b==0  : s*s - 1 - index
342
//                     if b==s-1: 6*s*s -11*s +6 - index
343
//                     else
344
//                         a==0: s*s + s-1 + 4*(b-1)*(s-1) + 2*(s-2) + s
345
//                         else: s*s + s-1 + 4*(b-1)*(s-1) + 2*(s-1-a)
346
// Down  :   index --> b==0 ? (s-1-a) : s*s + s-1 + 4*(b-1)*(s-1) - a
347
// Left  :   index --> (s-1-a)*s + b
348
// Back  :   index --> if b==s-1: s*(s-1-a)
349
//                     if b==0  : 5*s*s -12*s + 8 + (s-1-a)*s
350
//                     else
351
//                        if a==s-1: s*s + 4*(s-2-b)*(s-1)
352
//                        else     : s*s + 4*(s-2-b)*(s-1) + s + (s-2-a)*2
353

    
354
  public String retObjectString()
355
    {
356
    StringBuilder objectString = new StringBuilder();
357
    int size = getSize();
358
    int len = size*size;
359
    int cubitIndex, row, col;
360
    int color;
361

    
362
    final int RIGHT= 0;
363
    final int LEFT = 1;
364
    final int UP   = 2;
365
    final int DOWN = 3;
366
    final int FRONT= 4;
367
    final int BACK = 5;
368

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

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

    
376
      cubitIndex = col<size-1 ? (size-1)*(size+4*col) + row : 6*size*size - 13*size + 8 + row;
377
      color = getCubitFaceColorIndex(cubitIndex,UP);
378
      objectString.append(FACE_NAMES[color]);
379
      }
380

    
381
    for(int i=0; i<len; i++)
382
      {
383
      cubitIndex = 6*size*size - 12*size +7 - i;
384
      color = getCubitFaceColorIndex(cubitIndex,RIGHT);
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
      if( col==size-1 ) cubitIndex = 6*size*size - 11*size + 6 -i;
394
      else if( col==0 ) cubitIndex = size*size - 1 - i;
395
      else
396
        {
397
        if( row==0 ) cubitIndex = size*size + size-1 + 4*(col-1)*(size-1) + 2*(size-2) + size;
398
        else         cubitIndex = size*size + size-1 + 4*(col-1)*(size-1) + 2*(size-1-row);
399
        }
400

    
401
      color = getCubitFaceColorIndex(cubitIndex,FRONT);
402
      objectString.append(FACE_NAMES[color]);
403
      }
404

    
405
    for(int i=0; i<len; i++)
406
      {
407
      row = i/size;
408
      col = i%size;
409

    
410
      cubitIndex = col==0 ? size-1-row : size*size + size-1 + 4*(col-1)*(size-1) - row;
411
      color = getCubitFaceColorIndex(cubitIndex,DOWN);
412
      objectString.append(FACE_NAMES[color]);
413
      }
414

    
415
    for(int i=0; i<len; i++)
416
      {
417
      row = i/size;
418
      col = i%size;
419

    
420
      cubitIndex = (size-1-row)*size + col;
421
      color = getCubitFaceColorIndex(cubitIndex,LEFT);
422
      objectString.append(FACE_NAMES[color]);
423
      }
424

    
425
    for(int i=0; i<len; i++)
426
      {
427
      row = i/size;
428
      col = i%size;
429

    
430
      if( col==size-1 ) cubitIndex = size*(size-1-row);
431
      else if( col==0 ) cubitIndex = 5*size*size - 12*size + 8 + (size-1-row)*size;
432
      else
433
        {
434
        if( row==size-1 ) cubitIndex = size*size + 4*(size-2-col)*(size-1);
435
        else              cubitIndex = size*size + 4*(size-2-col)*(size-1) + size + 2*(size-2-row);
436
        }
437

    
438
      color = getCubitFaceColorIndex(cubitIndex,BACK);
439
      objectString.append(FACE_NAMES[color]);
440
      }
441

    
442
    return objectString.toString();
443
    }
444
}
(2-2/10)