Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / RubikCube.java @ 5cf34c5f

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.MatrixEffect;
26
import org.distorted.library.effect.MatrixEffectMove;
27
import org.distorted.library.effect.MatrixEffectRotate;
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
///////////////////////////////////////////////////////////////////////////////////////////////////
80

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

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

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

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

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

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

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

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

    
117
    return tmp;
118
    }
119

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

    
122
  float[] getLegalQuats()
123
    {
124
    return LEGALQUATS;
125
    }
126

    
127
///////////////////////////////////////////////////////////////////////////////////////////////////
128

    
129
  int getNumFaces()
130
    {
131
    return FACE_COLORS.length;
132
    }
133

    
134
///////////////////////////////////////////////////////////////////////////////////////////////////
135

    
136
  float getScreenRatio()
137
    {
138
    return 0.5f;
139
    }
140

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

    
143
  VertexEffectSink getSink(int size)
144
    {
145
    Static3D center = new Static3D(0,0,0);
146
    Static4D region = new Static4D(0,0,0,0.72f);
147
    float strength;
148

    
149
    switch(size)
150
      {
151
      case 1 : strength= 1.1f; break;
152
      case 2 : strength= 1.5f; break;
153
      case 3 : strength= 1.8f; break;
154
      case 4 : strength= 2.0f; break;
155
      default: strength= 3.0f - 4.0f/size;
156
      }
157

    
158
    return new VertexEffectSink( new Static1D(strength), center, region );
159
    }
160

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

    
163
  MeshBase createCubitMesh(int cubit, int vertices)
164
    {
165
    final int MESHES=6;
166

    
167
    Static3D axisY  = new Static3D(0,1,0);
168
    Static3D axisX  = new Static3D(1,0,0);
169
    Static3D center = new Static3D(0,0,0);
170
    Static1D angle  = new Static1D(0);
171

    
172
    MatrixEffect[] effectsY = new MatrixEffect[2];
173
    effectsY[0] = new MatrixEffectMove(new Static3D(0,0,+0.5f));
174
    effectsY[1] = new MatrixEffectRotate( angle, axisY, center );
175

    
176
    MeshBase[] meshes = new MeshRectangles[MESHES];
177
    for(int i=0; i<MESHES; i++) meshes[i] = new MeshRectangles(vertices,vertices);
178

    
179
    angle.set(0);
180
    meshes[4].apply(effectsY);  // front
181
    angle.set(90);
182
    meshes[0].apply(effectsY);  // right
183
    angle.set(180);
184
    meshes[5].apply(effectsY);  // back
185
    angle.set(270);
186
    meshes[1].apply(effectsY);  // left
187

    
188
    MatrixEffect[] effectsX = new MatrixEffect[2];
189
    effectsX[0] = new MatrixEffectMove(new Static3D(0,0,+0.5f));
190
    effectsX[1] = new MatrixEffectRotate( angle, axisX, center );
191

    
192
    angle.set( 90);
193
    meshes[3].apply(effectsX);  // bottom
194
    angle.set(-90);
195
    meshes[2].apply(effectsX);  // top
196

    
197
    return new MeshJoined(meshes);
198
    }
199

    
200
///////////////////////////////////////////////////////////////////////////////////////////////////
201
// PUBLIC API
202

    
203
  public Static3D[] getRotationAxis()
204
    {
205
    return AXIS;
206
    }
207

    
208
///////////////////////////////////////////////////////////////////////////////////////////////////
209

    
210
  public int getBasicAngle()
211
    {
212
    return 4;
213
    }
214

    
215
///////////////////////////////////////////////////////////////////////////////////////////////////
216

    
217
  public float returnMultiplier()
218
    {
219
    return getSize();
220
    }
221

    
222
///////////////////////////////////////////////////////////////////////////////////////////////////
223

    
224
  public float[] getRowChances()
225
    {
226
    int size = getSize();
227
    float[] chances = new float[size];
228

    
229
    for(int i=0; i<size; i++)
230
      {
231
      chances[i] = (i+1.0f) / size;
232
      }
233

    
234
    return chances;
235
    }
236

    
237
///////////////////////////////////////////////////////////////////////////////////////////////////
238

    
239
  public float returnRotationFactor(float offset)
240
    {
241
    return 1.0f;
242
    }
243

    
244
///////////////////////////////////////////////////////////////////////////////////////////////////
245
// order: Up --> Right --> Front --> Down --> Left --> Back
246
// (because the first implemented Solver - the two-phase Cube3 one - expects such order)
247
//
248
// Solved 3x3x3 Cube maps to "UUUUUUUUURRRRRRRRRFFFFFFFFFDDDDDDDDDLLLLLLLLLBBBBBBBBB"
249
//
250
// s : size of the cube; let index = a*s + b    (i.e. a,b = row,column)
251
//
252
// Up    :   index --> b<s-1 ? (s-1)*(s+4b)+a : 6*s*s -13*s +8 +a
253
// Right :   index --> 6*s*s - 12*s + 7 - index
254
// Front :   index --> if b==0  : s*s - 1 - index
255
//                     if b==s-1: 6*s*s -11*s +6 - index
256
//                     else
257
//                         a==0: s*s + s-1 + 4*(b-1)*(s-1) + 2*(s-2) + s
258
//                         else: s*s + s-1 + 4*(b-1)*(s-1) + 2*(s-1-a)
259
// Down  :   index --> b==0 ? (s-1-a) : s*s + s-1 + 4*(b-1)*(s-1) - a
260
// Left  :   index --> (s-1-a)*s + b
261
// Back  :   index --> if b==s-1: s*(s-1-a)
262
//                     if b==0  : 5*s*s -12*s + 8 + (s-1-a)*s
263
//                     else
264
//                        if a==s-1: s*s + 4*(s-2-b)*(s-1)
265
//                        else     : s*s + 4*(s-2-b)*(s-1) + s + (s-2-a)*2
266

    
267
  public String retObjectString()
268
    {
269
    StringBuilder objectString = new StringBuilder();
270
    int size = getSize();
271
    int len = size*size;
272
    int cubitIndex, row, col;
273
    int color;
274

    
275
    final int RIGHT= 0;
276
    final int LEFT = 1;
277
    final int UP   = 2;
278
    final int DOWN = 3;
279
    final int FRONT= 4;
280
    final int BACK = 5;
281

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

    
284
    for(int i=0; i<len; i++)
285
      {
286
      row = i/size;
287
      col = i%size;
288

    
289
      cubitIndex = col<size-1 ? (size-1)*(size+4*col) + row : 6*size*size - 13*size + 8 + row;
290
      color = getCubitFaceColorIndex(cubitIndex,UP);
291
      objectString.append(FACE_NAMES[color]);
292
      }
293

    
294
    for(int i=0; i<len; i++)
295
      {
296
      cubitIndex = 6*size*size - 12*size +7 - i;
297
      color = getCubitFaceColorIndex(cubitIndex,RIGHT);
298
      objectString.append(FACE_NAMES[color]);
299
      }
300

    
301
    for(int i=0; i<len; i++)
302
      {
303
      row = i/size;
304
      col = i%size;
305

    
306
      if( col==size-1 ) cubitIndex = 6*size*size - 11*size + 6 -i;
307
      else if( col==0 ) cubitIndex = size*size - 1 - i;
308
      else
309
        {
310
        if( row==0 ) cubitIndex = size*size + size-1 + 4*(col-1)*(size-1) + 2*(size-2) + size;
311
        else         cubitIndex = size*size + size-1 + 4*(col-1)*(size-1) + 2*(size-1-row);
312
        }
313

    
314
      color = getCubitFaceColorIndex(cubitIndex,FRONT);
315
      objectString.append(FACE_NAMES[color]);
316
      }
317

    
318
    for(int i=0; i<len; i++)
319
      {
320
      row = i/size;
321
      col = i%size;
322

    
323
      cubitIndex = col==0 ? size-1-row : size*size + size-1 + 4*(col-1)*(size-1) - row;
324
      color = getCubitFaceColorIndex(cubitIndex,DOWN);
325
      objectString.append(FACE_NAMES[color]);
326
      }
327

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

    
333
      cubitIndex = (size-1-row)*size + col;
334
      color = getCubitFaceColorIndex(cubitIndex,LEFT);
335
      objectString.append(FACE_NAMES[color]);
336
      }
337

    
338
    for(int i=0; i<len; i++)
339
      {
340
      row = i/size;
341
      col = i%size;
342

    
343
      if( col==size-1 ) cubitIndex = size*(size-1-row);
344
      else if( col==0 ) cubitIndex = 5*size*size - 12*size + 8 + (size-1-row)*size;
345
      else
346
        {
347
        if( row==size-1 ) cubitIndex = size*size + 4*(size-2-col)*(size-1);
348
        else              cubitIndex = size*size + 4*(size-2-col)*(size-1) + size + 2*(size-2-row);
349
        }
350

    
351
      color = getCubitFaceColorIndex(cubitIndex,BACK);
352
      objectString.append(FACE_NAMES[color]);
353
      }
354

    
355
    return objectString.toString();
356
    }
357
}
(2-2/8)