Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / RubikCube.java @ 40ab026e

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.VertexEffectMove;
26
import org.distorted.library.effect.VertexEffectRotate;
27
import org.distorted.library.effect.VertexEffectSink;
28
import org.distorted.library.main.DistortedEffects;
29
import org.distorted.library.main.DistortedTexture;
30
import org.distorted.library.mesh.MeshBase;
31
import org.distorted.library.mesh.MeshJoined;
32
import org.distorted.library.mesh.MeshRectangles;
33
import org.distorted.library.type.Static1D;
34
import org.distorted.library.type.Static3D;
35
import org.distorted.library.type.Static4D;
36

    
37
///////////////////////////////////////////////////////////////////////////////////////////////////
38

    
39
class RubikCube extends RubikObject
40
{
41
  // the three rotation axis of a RubikCube. Must be normalized.
42
  static final Static3D[] AXIS = new Static3D[]
43
         {
44
           new Static3D(1,0,0),
45
           new Static3D(0,1,0),
46
           new Static3D(0,0,1)
47
         };
48

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

    
56
  // All legal rotation quats of a RubikCube of any size must have all four of their components
57
  // equal to either 0, +-1, +-0.5 or +-sqrt(2)/2.
58
  // Here's how to compute this:
59
  // 1) compute how many rotations there are (RubikCube of any size = 24)
60
  // 2) take the AXIS, angles of rotation (90 in RubikCube's case) compute the basic quaternions
61
  // (i.e. rotations of 1 basic angle along each of the axis) and from there start semi-randomly
62
  // multiplying them and eventually you'll find all (24) legal rotations.
63
  // 3) linear scan through those shows that the only floats in those 24 quats are those 7 given
64
  // below.
65
  //
66
  // Example program in C, res/raw/compute_quats.c , is included.
67
  private static final float[] LEGALQUATS = new float[]
68
         {
69
           0.0f ,
70
           0.5f ,
71
          -0.5f ,
72
           1.0f ,
73
          -1.0f ,
74
           0.5f*((float)Math.sqrt(2)) ,
75
          -0.5f*((float)Math.sqrt(2))
76
         };
77

    
78
  private static MeshBase mMesh = null;
79

    
80
///////////////////////////////////////////////////////////////////////////////////////////////////
81

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

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

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

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

    
100
///////////////////////////////////////////////////////////////////////////////////////////////////
101

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

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

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

    
118
    return tmp;
119
    }
120

    
121
///////////////////////////////////////////////////////////////////////////////////////////////////
122

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

    
128
///////////////////////////////////////////////////////////////////////////////////////////////////
129

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

    
135
///////////////////////////////////////////////////////////////////////////////////////////////////
136

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

    
142
///////////////////////////////////////////////////////////////////////////////////////////////////
143

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

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

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

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

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

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

    
181
      mMesh = new MeshJoined(meshes);
182

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

    
190
      VertexEffectMove   effect0 = new VertexEffectMove(new Static3D(0,0,+0.5f));
191
      effect0.setMeshAssociation(63);  // all 6 sides
192
      VertexEffectRotate effect1 = new VertexEffectRotate( angle180, axisX, center );
193
      effect1.setMeshAssociation(32);  // back
194
      VertexEffectRotate effect2 = new VertexEffectRotate( angle90 , axisX, center );
195
      effect2.setMeshAssociation(8);  // bottom
196
      VertexEffectRotate effect3 = new VertexEffectRotate( angle270, axisX, center );
197
      effect3.setMeshAssociation(4);  // top
198
      VertexEffectRotate effect4 = new VertexEffectRotate( angle270, axisY, center );
199
      effect4.setMeshAssociation(2);  // left
200
      VertexEffectRotate effect5 = new VertexEffectRotate( angle90 , axisY, center );
201
      effect5.setMeshAssociation(1);  // right
202

    
203
      mMesh.apply(effect0);
204
      mMesh.apply(effect1);
205
      mMesh.apply(effect2);
206
      mMesh.apply(effect3);
207
      mMesh.apply(effect4);
208
      mMesh.apply(effect5);
209
      }
210

    
211
    return mMesh.copy(false);
212
    }
213

    
214
///////////////////////////////////////////////////////////////////////////////////////////////////
215
// PUBLIC API
216

    
217
  public Static3D[] getRotationAxis()
218
    {
219
    return AXIS;
220
    }
221

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

    
224
  public int getBasicAngle()
225
    {
226
    return 4;
227
    }
228

    
229
///////////////////////////////////////////////////////////////////////////////////////////////////
230

    
231
  public float returnMultiplier()
232
    {
233
    return getSize();
234
    }
235

    
236
///////////////////////////////////////////////////////////////////////////////////////////////////
237

    
238
  public float[] getRowChances()
239
    {
240
    int size = getSize();
241
    float[] chances = new float[size];
242

    
243
    for(int i=0; i<size; i++)
244
      {
245
      chances[i] = (i+1.0f) / size;
246
      }
247

    
248
    return chances;
249
    }
250

    
251
///////////////////////////////////////////////////////////////////////////////////////////////////
252

    
253
  public float returnRotationFactor(float offset)
254
    {
255
    return 1.0f;
256
    }
257

    
258
///////////////////////////////////////////////////////////////////////////////////////////////////
259
// order: Up --> Right --> Front --> Down --> Left --> Back
260
// (because the first implemented Solver - the two-phase Cube3 one - expects such order)
261
//
262
// Solved 3x3x3 Cube maps to "UUUUUUUUURRRRRRRRRFFFFFFFFFDDDDDDDDDLLLLLLLLLBBBBBBBBB"
263
//
264
// s : size of the cube; let index = a*s + b    (i.e. a,b = row,column)
265
//
266
// Up    :   index --> b<s-1 ? (s-1)*(s+4b)+a : 6*s*s -13*s +8 +a
267
// Right :   index --> 6*s*s - 12*s + 7 - index
268
// Front :   index --> if b==0  : s*s - 1 - index
269
//                     if b==s-1: 6*s*s -11*s +6 - index
270
//                     else
271
//                         a==0: s*s + s-1 + 4*(b-1)*(s-1) + 2*(s-2) + s
272
//                         else: s*s + s-1 + 4*(b-1)*(s-1) + 2*(s-1-a)
273
// Down  :   index --> b==0 ? (s-1-a) : s*s + s-1 + 4*(b-1)*(s-1) - a
274
// Left  :   index --> (s-1-a)*s + b
275
// Back  :   index --> if b==s-1: s*(s-1-a)
276
//                     if b==0  : 5*s*s -12*s + 8 + (s-1-a)*s
277
//                     else
278
//                        if a==s-1: s*s + 4*(s-2-b)*(s-1)
279
//                        else     : s*s + 4*(s-2-b)*(s-1) + s + (s-2-a)*2
280

    
281
  public String retObjectString()
282
    {
283
    StringBuilder objectString = new StringBuilder();
284
    int size = getSize();
285
    int len = size*size;
286
    int cubitIndex, row, col;
287
    int color;
288

    
289
    final int RIGHT= 0;
290
    final int LEFT = 1;
291
    final int UP   = 2;
292
    final int DOWN = 3;
293
    final int FRONT= 4;
294
    final int BACK = 5;
295

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

    
298
    for(int i=0; i<len; i++)
299
      {
300
      row = i/size;
301
      col = i%size;
302

    
303
      cubitIndex = col<size-1 ? (size-1)*(size+4*col) + row : 6*size*size - 13*size + 8 + row;
304
      color = getCubitFaceColorIndex(cubitIndex,UP);
305
      objectString.append(FACE_NAMES[color]);
306
      }
307

    
308
    for(int i=0; i<len; i++)
309
      {
310
      cubitIndex = 6*size*size - 12*size +7 - i;
311
      color = getCubitFaceColorIndex(cubitIndex,RIGHT);
312
      objectString.append(FACE_NAMES[color]);
313
      }
314

    
315
    for(int i=0; i<len; i++)
316
      {
317
      row = i/size;
318
      col = i%size;
319

    
320
      if( col==size-1 ) cubitIndex = 6*size*size - 11*size + 6 -i;
321
      else if( col==0 ) cubitIndex = size*size - 1 - i;
322
      else
323
        {
324
        if( row==0 ) cubitIndex = size*size + size-1 + 4*(col-1)*(size-1) + 2*(size-2) + size;
325
        else         cubitIndex = size*size + size-1 + 4*(col-1)*(size-1) + 2*(size-1-row);
326
        }
327

    
328
      color = getCubitFaceColorIndex(cubitIndex,FRONT);
329
      objectString.append(FACE_NAMES[color]);
330
      }
331

    
332
    for(int i=0; i<len; i++)
333
      {
334
      row = i/size;
335
      col = i%size;
336

    
337
      cubitIndex = col==0 ? size-1-row : size*size + size-1 + 4*(col-1)*(size-1) - row;
338
      color = getCubitFaceColorIndex(cubitIndex,DOWN);
339
      objectString.append(FACE_NAMES[color]);
340
      }
341

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

    
347
      cubitIndex = (size-1-row)*size + col;
348
      color = getCubitFaceColorIndex(cubitIndex,LEFT);
349
      objectString.append(FACE_NAMES[color]);
350
      }
351

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

    
357
      if( col==size-1 ) cubitIndex = size*(size-1-row);
358
      else if( col==0 ) cubitIndex = 5*size*size - 12*size + 8 + (size-1-row)*size;
359
      else
360
        {
361
        if( row==size-1 ) cubitIndex = size*size + 4*(size-2-col)*(size-1);
362
        else              cubitIndex = size*size + 4*(size-2-col)*(size-1) + size + 2*(size-2-row);
363
        }
364

    
365
      color = getCubitFaceColorIndex(cubitIndex,BACK);
366
      objectString.append(FACE_NAMES[color]);
367
      }
368

    
369
    return objectString.toString();
370
    }
371
}
(2-2/8)