Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / RubikCube.java @ 470820a7

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
  // the three rotation axis of a RubikCube. Must be normalized.
43
  static final Static3D[] AXIS = new Static3D[]
44
         {
45
           new Static3D(1,0,0),
46
           new Static3D(0,1,0),
47
           new Static3D(0,0,1)
48
         };
49

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

    
57
  // All legal rotation quats of a RubikCube of any size must have all four of their components
58
  // equal to either 0, +-1, +-0.5 or +-sqrt(2)/2.
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
  // 3) linear scan through those shows that the only floats in those 24 quats are those 7 given
65
  // below.
66
  //
67
  // Example program in C, res/raw/compute_quats.c , is included.
68
  private static final float[] LEGALQUATS = new float[]
69
         {
70
           0.0f ,
71
           0.5f ,
72
          -0.5f ,
73
           1.0f ,
74
          -1.0f ,
75
           0.5f*((float)Math.sqrt(2)) ,
76
          -0.5f*((float)Math.sqrt(2))
77
         };
78

    
79
  private static MeshBase mMesh = null;
80

    
81
///////////////////////////////////////////////////////////////////////////////////////////////////
82

    
83
  RubikCube(int size, Static4D quatCur, Static4D quatAcc, DistortedTexture texture, MeshRectangles mesh, DistortedEffects effects, int[][] moves)
84
    {
85
    super(size, 60, quatCur,quatAcc,texture,mesh,effects,moves, RubikObjectList.CUBE);
86
    }
87

    
88
///////////////////////////////////////////////////////////////////////////////////////////////////
89
// paint the square with upper-right cornder at (left,top) and side length 'side' with texture
90
// for face 'face'.
91

    
92
  void createFaceTexture(Canvas canvas, Paint paint, int face, int left, int top, int side)
93
    {
94
    final float R = side*0.10f;
95
    final float M = side*0.05f;
96

    
97
    paint.setColor(FACE_COLORS[face]);
98
    canvas.drawRoundRect( left+M, top+M, left+side-M, top+side-M, R, R, paint);
99
    }
100

    
101
///////////////////////////////////////////////////////////////////////////////////////////////////
102

    
103
  Static3D[] getCubitPositions(int size)
104
    {
105
    int numCubits = size>1 ? 6*size*size - 12*size + 8 : 1;
106
    Static3D[] tmp = new Static3D[numCubits];
107

    
108
    float diff = 0.5f*(size-1);
109
    int currentPosition = 0;
110

    
111
    for(int x = 0; x<size; x++)
112
      for(int y = 0; y<size; y++)
113
        for(int z = 0; z<size; z++)
114
          if( x==0 || x==size-1 || y==0 || y==size-1 || z==0 || z==size-1 )
115
            {
116
            tmp[currentPosition++] = new Static3D(x-diff,y-diff,z-diff);
117
            }
118

    
119
    return tmp;
120
    }
121

    
122
///////////////////////////////////////////////////////////////////////////////////////////////////
123

    
124
  float[] getLegalQuats()
125
    {
126
    return LEGALQUATS;
127
    }
128

    
129
///////////////////////////////////////////////////////////////////////////////////////////////////
130

    
131
  int getNumFaces()
132
    {
133
    return FACE_COLORS.length;
134
    }
135

    
136
///////////////////////////////////////////////////////////////////////////////////////////////////
137

    
138
  float getScreenRatio()
139
    {
140
    return 0.5f;
141
    }
142

    
143
///////////////////////////////////////////////////////////////////////////////////////////////////
144

    
145
  MeshBase createCubitMesh(int cubit)
146
    {
147
    if( mMesh==null )
148
      {
149
      final int MESHES=6;
150
      int association = 1;
151
      MeshBase[] meshes = new MeshRectangles[MESHES];
152
      meshes[0] = new MeshRectangles(14,14);
153
      meshes[0].setEffectAssociation(0,association,0);
154

    
155
      for(int i=1; i<MESHES; i++)
156
        {
157
        association <<=1;
158
        meshes[i] = meshes[0].copy(true);
159
        meshes[i].setEffectAssociation(0,association,0);
160
        }
161

    
162
      mMesh = new MeshJoined(meshes);
163

    
164
      Static3D axisY   = new Static3D(0,1,0);
165
      Static3D axisX   = new Static3D(1,0,0);
166
      Static3D center  = new Static3D(0,0,0);
167
      Static1D angle90 = new Static1D(90);
168
      Static1D angle180= new Static1D(180);
169
      Static1D angle270= new Static1D(270);
170

    
171
      float d1 = 1.0f;
172
      float d2 =-0.05f;
173
      float d3 = 0.12f;
174

    
175
      Static3D dCen0 = new Static3D( d1*(+0.5f), d1*(+0.5f), d1*(+0.5f) );
176
      Static3D dCen1 = new Static3D( d1*(+0.5f), d1*(+0.5f), d1*(-0.5f) );
177
      Static3D dCen2 = new Static3D( d1*(+0.5f), d1*(-0.5f), d1*(+0.5f) );
178
      Static3D dCen3 = new Static3D( d1*(+0.5f), d1*(-0.5f), d1*(-0.5f) );
179
      Static3D dCen4 = new Static3D( d1*(-0.5f), d1*(+0.5f), d1*(+0.5f) );
180
      Static3D dCen5 = new Static3D( d1*(-0.5f), d1*(+0.5f), d1*(-0.5f) );
181
      Static3D dCen6 = new Static3D( d1*(-0.5f), d1*(-0.5f), d1*(+0.5f) );
182
      Static3D dCen7 = new Static3D( d1*(-0.5f), d1*(-0.5f), d1*(-0.5f) );
183

    
184
      Static3D dVec0 = new Static3D( d2*(+0.5f), d2*(+0.5f), d2*(+0.5f) );
185
      Static3D dVec1 = new Static3D( d2*(+0.5f), d2*(+0.5f), d2*(-0.5f) );
186
      Static3D dVec2 = new Static3D( d2*(+0.5f), d2*(-0.5f), d2*(+0.5f) );
187
      Static3D dVec3 = new Static3D( d2*(+0.5f), d2*(-0.5f), d2*(-0.5f) );
188
      Static3D dVec4 = new Static3D( d2*(-0.5f), d2*(+0.5f), d2*(+0.5f) );
189
      Static3D dVec5 = new Static3D( d2*(-0.5f), d2*(+0.5f), d2*(-0.5f) );
190
      Static3D dVec6 = new Static3D( d2*(-0.5f), d2*(-0.5f), d2*(+0.5f) );
191
      Static3D dVec7 = new Static3D( d2*(-0.5f), d2*(-0.5f), d2*(-0.5f) );
192

    
193
      Static4D dReg  = new Static4D(0,0,0,d3);
194
      Static1D dRad  = new Static1D(1);
195

    
196
      VertexEffectMove   effect0 = new VertexEffectMove(new Static3D(0,0,+0.5f));
197
      effect0.setMeshAssociation(63,-1);  // all 6 sides
198
      VertexEffectRotate effect1 = new VertexEffectRotate( angle180, axisX, center );
199
      effect1.setMeshAssociation(32,-1);  // back
200
      VertexEffectRotate effect2 = new VertexEffectRotate( angle90 , axisX, center );
201
      effect2.setMeshAssociation( 8,-1);  // bottom
202
      VertexEffectRotate effect3 = new VertexEffectRotate( angle270, axisX, center );
203
      effect3.setMeshAssociation( 4,-1);  // top
204
      VertexEffectRotate effect4 = new VertexEffectRotate( angle270, axisY, center );
205
      effect4.setMeshAssociation( 2,-1);  // left
206
      VertexEffectRotate effect5 = new VertexEffectRotate( angle90 , axisY, center );
207
      effect5.setMeshAssociation( 1,-1);  // right
208

    
209
      VertexEffectDeform effect6 = new VertexEffectDeform(dVec0, dRad, dCen0, dReg);
210
      VertexEffectDeform effect7 = new VertexEffectDeform(dVec1, dRad, dCen1, dReg);
211
      VertexEffectDeform effect8 = new VertexEffectDeform(dVec2, dRad, dCen2, dReg);
212
      VertexEffectDeform effect9 = new VertexEffectDeform(dVec3, dRad, dCen3, dReg);
213
      VertexEffectDeform effect10= new VertexEffectDeform(dVec4, dRad, dCen4, dReg);
214
      VertexEffectDeform effect11= new VertexEffectDeform(dVec5, dRad, dCen5, dReg);
215
      VertexEffectDeform effect12= new VertexEffectDeform(dVec6, dRad, dCen6, dReg);
216
      VertexEffectDeform effect13= new VertexEffectDeform(dVec7, dRad, dCen7, dReg);
217

    
218
      VertexEffectSink   effect14= new VertexEffectSink( new Static1D(1.5f), center, new Static4D(0,0,0,0.72f) );
219

    
220
      mMesh.apply(effect0);
221
      mMesh.apply(effect1);
222
      mMesh.apply(effect2);
223
      mMesh.apply(effect3);
224
      mMesh.apply(effect4);
225
      mMesh.apply(effect5);
226
      mMesh.apply(effect6);
227
      mMesh.apply(effect7);
228
      mMesh.apply(effect8);
229
      mMesh.apply(effect9);
230
      mMesh.apply(effect10);
231
      mMesh.apply(effect11);
232
      mMesh.apply(effect12);
233
      mMesh.apply(effect13);
234
      mMesh.apply(effect14);
235

    
236
      mMesh.mergeEffComponents();
237
      }
238

    
239
    return mMesh.copy(true);
240
    }
241

    
242
///////////////////////////////////////////////////////////////////////////////////////////////////
243
// PUBLIC API
244

    
245
  public Static3D[] getRotationAxis()
246
    {
247
    return AXIS;
248
    }
249

    
250
///////////////////////////////////////////////////////////////////////////////////////////////////
251

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

    
257
///////////////////////////////////////////////////////////////////////////////////////////////////
258

    
259
  public float returnMultiplier()
260
    {
261
    return getSize();
262
    }
263

    
264
///////////////////////////////////////////////////////////////////////////////////////////////////
265

    
266
  public float[] getRowChances()
267
    {
268
    int size = getSize();
269
    float[] chances = new float[size];
270

    
271
    for(int i=0; i<size; i++)
272
      {
273
      chances[i] = (i+1.0f) / size;
274
      }
275

    
276
    return chances;
277
    }
278

    
279
///////////////////////////////////////////////////////////////////////////////////////////////////
280

    
281
  public float returnRotationFactor(float offset)
282
    {
283
    return 1.0f;
284
    }
285

    
286
///////////////////////////////////////////////////////////////////////////////////////////////////
287
// order: Up --> Right --> Front --> Down --> Left --> Back
288
// (because the first implemented Solver - the two-phase Cube3 one - expects such order)
289
//
290
// Solved 3x3x3 Cube maps to "UUUUUUUUURRRRRRRRRFFFFFFFFFDDDDDDDDDLLLLLLLLLBBBBBBBBB"
291
//
292
// s : size of the cube; let index = a*s + b    (i.e. a,b = row,column)
293
//
294
// Up    :   index --> b<s-1 ? (s-1)*(s+4b)+a : 6*s*s -13*s +8 +a
295
// Right :   index --> 6*s*s - 12*s + 7 - index
296
// Front :   index --> if b==0  : s*s - 1 - index
297
//                     if b==s-1: 6*s*s -11*s +6 - index
298
//                     else
299
//                         a==0: s*s + s-1 + 4*(b-1)*(s-1) + 2*(s-2) + s
300
//                         else: s*s + s-1 + 4*(b-1)*(s-1) + 2*(s-1-a)
301
// Down  :   index --> b==0 ? (s-1-a) : s*s + s-1 + 4*(b-1)*(s-1) - a
302
// Left  :   index --> (s-1-a)*s + b
303
// Back  :   index --> if b==s-1: s*(s-1-a)
304
//                     if b==0  : 5*s*s -12*s + 8 + (s-1-a)*s
305
//                     else
306
//                        if a==s-1: s*s + 4*(s-2-b)*(s-1)
307
//                        else     : s*s + 4*(s-2-b)*(s-1) + s + (s-2-a)*2
308

    
309
  public String retObjectString()
310
    {
311
    StringBuilder objectString = new StringBuilder();
312
    int size = getSize();
313
    int len = size*size;
314
    int cubitIndex, row, col;
315
    int color;
316

    
317
    final int RIGHT= 0;
318
    final int LEFT = 1;
319
    final int UP   = 2;
320
    final int DOWN = 3;
321
    final int FRONT= 4;
322
    final int BACK = 5;
323

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

    
326
    for(int i=0; i<len; i++)
327
      {
328
      row = i/size;
329
      col = i%size;
330

    
331
      cubitIndex = col<size-1 ? (size-1)*(size+4*col) + row : 6*size*size - 13*size + 8 + row;
332
      color = getCubitFaceColorIndex(cubitIndex,UP);
333
      objectString.append(FACE_NAMES[color]);
334
      }
335

    
336
    for(int i=0; i<len; i++)
337
      {
338
      cubitIndex = 6*size*size - 12*size +7 - i;
339
      color = getCubitFaceColorIndex(cubitIndex,RIGHT);
340
      objectString.append(FACE_NAMES[color]);
341
      }
342

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

    
348
      if( col==size-1 ) cubitIndex = 6*size*size - 11*size + 6 -i;
349
      else if( col==0 ) cubitIndex = size*size - 1 - i;
350
      else
351
        {
352
        if( row==0 ) cubitIndex = size*size + size-1 + 4*(col-1)*(size-1) + 2*(size-2) + size;
353
        else         cubitIndex = size*size + size-1 + 4*(col-1)*(size-1) + 2*(size-1-row);
354
        }
355

    
356
      color = getCubitFaceColorIndex(cubitIndex,FRONT);
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
      cubitIndex = col==0 ? size-1-row : size*size + size-1 + 4*(col-1)*(size-1) - row;
366
      color = getCubitFaceColorIndex(cubitIndex,DOWN);
367
      objectString.append(FACE_NAMES[color]);
368
      }
369

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

    
375
      cubitIndex = (size-1-row)*size + col;
376
      color = getCubitFaceColorIndex(cubitIndex,LEFT);
377
      objectString.append(FACE_NAMES[color]);
378
      }
379

    
380
    for(int i=0; i<len; i++)
381
      {
382
      row = i/size;
383
      col = i%size;
384

    
385
      if( col==size-1 ) cubitIndex = size*(size-1-row);
386
      else if( col==0 ) cubitIndex = 5*size*size - 12*size + 8 + (size-1-row)*size;
387
      else
388
        {
389
        if( row==size-1 ) cubitIndex = size*size + 4*(size-2-col)*(size-1);
390
        else              cubitIndex = size*size + 4*(size-2-col)*(size-1) + size + 2*(size-2-row);
391
        }
392

    
393
      color = getCubitFaceColorIndex(cubitIndex,BACK);
394
      objectString.append(FACE_NAMES[color]);
395
      }
396

    
397
    return objectString.toString();
398
    }
399
}
(2-2/8)