Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / TwistyCube.java @ acf165d9

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

    
24
import org.distorted.helpers.FactoryCubit;
25
import org.distorted.helpers.ObjectShape;
26
import org.distorted.helpers.ObjectSticker;
27
import org.distorted.library.effect.MatrixEffectQuaternion;
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.MeshSquare;
32
import org.distorted.library.type.Static3D;
33
import org.distorted.library.type.Static4D;
34
import org.distorted.main.R;
35

    
36
import java.util.Random;
37

    
38
///////////////////////////////////////////////////////////////////////////////////////////////////
39

    
40
class TwistyCube extends TwistyObject
41
{
42
  // the three rotation axis of a RubikCube. Must be normalized.
43
  static final Static3D[] ROT_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[] BASIC_ANGLE = new int[] { 4,4,4 };
51

    
52
  private static final int[] FACE_COLORS = new int[]
53
         {
54
           COLOR_YELLOW, COLOR_WHITE,
55
           COLOR_BLUE  , COLOR_GREEN,
56
           COLOR_RED   , COLOR_ORANGE
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 final double[][] VERTICES = new double[][]
97
          {
98
              { 0.5, 0.5, 0.5 },
99
              { 0.5, 0.5,-0.5 },
100
              { 0.5,-0.5, 0.5 },
101
              { 0.5,-0.5,-0.5 },
102
              {-0.5, 0.5, 0.5 },
103
              {-0.5, 0.5,-0.5 },
104
              {-0.5,-0.5, 0.5 },
105
              {-0.5,-0.5,-0.5 },
106
          };
107

    
108
  private static final int[][] VERT_INDEXES = new int[][]
109
          {
110
              {2,3,1,0},   // counterclockwise!
111
              {7,6,4,5},
112
              {4,0,1,5},
113
              {7,3,2,6},
114
              {6,2,0,4},
115
              {3,7,5,1}
116
          };
117

    
118
  private static final float[][] STICKERS = new float[][]
119
          {
120
              { -0.5f, -0.5f, 0.5f, -0.5f, 0.5f, 0.5f, -0.5f, 0.5f }
121
          };
122

    
123
  private static final ObjectSticker[] mStickers;
124

    
125
  static
126
    {
127
    final float radius = 0.10f;
128
    final float stroke = 0.08f;
129
    final float[] radii = {radius,radius,radius,radius};
130
    mStickers = new ObjectSticker[STICKERS.length];
131
    mStickers[0] = new ObjectSticker(STICKERS[0],null,radii,stroke );
132
    }
133

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

    
136
  TwistyCube(int size, Static4D quat, DistortedTexture texture,
137
             MeshSquare mesh, DistortedEffects effects, int[][] moves, Resources res, int scrWidth)
138
    {
139
    super(size, size, quat, texture, mesh, effects, moves, ObjectList.CUBE, res, scrWidth);
140
    }
141

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

    
144
  private Static4D getQuat(int cubit, int numLayers)
145
    {
146
    return QUATS[0];
147
    }
148

    
149
///////////////////////////////////////////////////////////////////////////////////////////////////
150

    
151
  private int getNumCubitVariants(int numLayers)
152
    {
153
    return 1;
154
    }
155

    
156
///////////////////////////////////////////////////////////////////////////////////////////////////
157

    
158
  int getCubitVariant(int cubit, int numLayers)
159
    {
160
    return 0;
161
    }
162

    
163
///////////////////////////////////////////////////////////////////////////////////////////////////
164

    
165
  ObjectShape getObjectShape(int cubit, int numLayers)
166
    {
167
    int extraI, extraV, num;
168
    float height;
169

    
170
    switch(numLayers)
171
      {
172
      case 2 : num = 6; extraI = 2; extraV = 2; height = 0.045f; break;
173
      case 3 : num = 5; extraI = 2; extraV = 2; height = 0.045f; break;
174
      case 4 : num = 5; extraI = 1; extraV = 1; height = 0.045f; break;
175
      default: num = 5; extraI = 0; extraV = 0; height = 0.045f; break;
176
      }
177

    
178
    float[][] bands     = new float[][] { {height,35,0.5f,0.7f,num,extraI,extraV} };
179
    int[] bandIndices   = new int[] { 0,0,0,0,0,0};
180
    float[][] corners   = new float[][] { {0.036f,0.12f} };
181
    int[] cornerIndices = new int[] { 0,0,0,0,0,0,0,0 };
182
    float[][] centers   = new float[][] { {0.0f, 0.0f, 0.0f} };
183
    int[] centerIndices = new int[] { 0,0,0,0,0,0,0,0 };
184

    
185
    return new ObjectShape(VERTICES,VERT_INDEXES,bands,bandIndices,corners,cornerIndices,centers,centerIndices,getNumCubitFaces(), null);
186
    }
187

    
188
///////////////////////////////////////////////////////////////////////////////////////////////////
189

    
190
  MeshBase createCubitMesh(int cubit, int numLayers)
191
    {
192
    int variant = getCubitVariant(cubit,numLayers);
193

    
194
    if( mMeshes==null )
195
      {
196
      FactoryCubit factory = FactoryCubit.getInstance();
197
      factory.clear();
198
      mMeshes = new MeshBase[getNumCubitVariants(numLayers)];
199
      }
200

    
201
    if( mMeshes[variant]==null )
202
      {
203
      ObjectShape shape = getObjectShape(cubit,numLayers);
204
      FactoryCubit factory = FactoryCubit.getInstance();
205
      factory.createNewFaceTransform(shape);
206
      mMeshes[variant] = factory.createRoundedSolid(shape);
207
      }
208

    
209
    MeshBase mesh = mMeshes[variant].copy(true);
210
    MatrixEffectQuaternion quat = new MatrixEffectQuaternion( getQuat(cubit,numLayers), new Static3D(0,0,0) );
211
    mesh.apply(quat,0xffffffff,0);
212

    
213
    return mesh;
214
    }
215

    
216
///////////////////////////////////////////////////////////////////////////////////////////////////
217

    
218
  int getColor(int face)
219
    {
220
    return FACE_COLORS[face];
221
    }
222

    
223
///////////////////////////////////////////////////////////////////////////////////////////////////
224

    
225
  ObjectSticker retSticker(int face)
226
    {
227
    return mStickers[face/NUM_FACES];
228
    }
229

    
230
///////////////////////////////////////////////////////////////////////////////////////////////////
231

    
232
  float[][] getCubitPositions(int numLayers)
233
    {
234
    int numCubits = numLayers>1 ? 6*numLayers*numLayers - 12*numLayers + 8 : 1;
235
    float[][] tmp = new float[numCubits][];
236

    
237
    float diff = 0.5f*(numLayers-1);
238
    int currentPosition = 0;
239

    
240
    for(int x = 0; x<numLayers; x++)
241
      for(int y = 0; y<numLayers; y++)
242
        for(int z = 0; z<numLayers; z++)
243
          if( x==0 || x==numLayers-1 || y==0 || y==numLayers-1 || z==0 || z==numLayers-1 )
244
            {
245
            tmp[currentPosition++] = new float[] {x-diff,y-diff,z-diff};
246
            }
247

    
248
    return tmp;
249
    }
250

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

    
253
  Static4D[] getQuats()
254
    {
255
    return QUATS;
256
    }
257

    
258
///////////////////////////////////////////////////////////////////////////////////////////////////
259

    
260
  boolean shouldResetTextureMaps()
261
    {
262
    return false;
263
    }
264

    
265
///////////////////////////////////////////////////////////////////////////////////////////////////
266

    
267
  int getNumFaces()
268
    {
269
    return FACE_COLORS.length;
270
    }
271

    
272
///////////////////////////////////////////////////////////////////////////////////////////////////
273

    
274
  float[][] getCuts(int numLayers)
275
    {
276
    float[][] cuts = new float[3][numLayers-1];
277

    
278
    for(int i=0; i<numLayers-1; i++)
279
      {
280
      float cut = (2-numLayers)*0.5f + i;
281
      cuts[0][i] = cut;
282
      cuts[1][i] = cut;
283
      cuts[2][i] = cut;
284
      }
285

    
286
    return cuts;
287
    }
288

    
289
///////////////////////////////////////////////////////////////////////////////////////////////////
290

    
291
  int getNumStickerTypes(int numLayers)
292
    {
293
    return STICKERS.length;
294
    }
295

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

    
298
  int getNumCubitFaces()
299
    {
300
    return FACE_COLORS.length;
301
    }
302

    
303
///////////////////////////////////////////////////////////////////////////////////////////////////
304

    
305
  float getScreenRatio()
306
    {
307
    return 0.5f;
308
    }
309

    
310
///////////////////////////////////////////////////////////////////////////////////////////////////
311

    
312
  int getFaceColor(int cubit, int cubitface, int numLayers)
313
    {
314
    return CUBITS[cubit].mRotationRow[cubitface/2] == (cubitface%2==0 ? (1<<(numLayers-1)):1) ? cubitface : NUM_FACES;
315
    }
316

    
317
///////////////////////////////////////////////////////////////////////////////////////////////////
318

    
319
  float returnMultiplier()
320
    {
321
    return getNumLayers();
322
    }
323

    
324
///////////////////////////////////////////////////////////////////////////////////////////////////
325
// PUBLIC API
326

    
327
  public Static3D[] getRotationAxis()
328
    {
329
    return ROT_AXIS;
330
    }
331

    
332
///////////////////////////////////////////////////////////////////////////////////////////////////
333

    
334
  public int[] getBasicAngle()
335
    {
336
    return BASIC_ANGLE;
337
    }
338

    
339
///////////////////////////////////////////////////////////////////////////////////////////////////
340

    
341
  public void randomizeNewScramble(int[][] scramble, Random rnd, int curr, int total)
342
    {
343
    if( curr==0 )
344
      {
345
      scramble[curr][0] = rnd.nextInt(NUM_AXIS);
346
      }
347
    else
348
      {
349
      int newVector = rnd.nextInt(NUM_AXIS-1);
350
      scramble[curr][0] = (newVector>=scramble[curr-1][0] ? newVector+1 : newVector);
351

    
352
      // All three axis must be present among every four consecutive rotations.
353
      // Otherwise in case of odd-sized cubes we can get four consecutive rotations
354
      // that collapse to a NOP
355
      // (X,midLayer,180)->(Y,midLayer,180)->(X,midLayer,180)->(Y,midLayer,180) = NOP
356
      if( curr>=3 && scramble[curr-1][0]==scramble[curr-3][0] )
357
        {
358
        for( int ax=0; ax<NUM_AXIS; ax++)
359
          {
360
          if( scramble[curr-1][0]!=ax && scramble[curr-2][0]!=ax )
361
            {
362
            scramble[curr][0] = ax;
363
            break;
364
            }
365
          }
366
        }
367
      }
368

    
369
    float rowFloat = rnd.nextFloat();
370
    int numLayers = getNumLayers();
371

    
372
    for(int row=0; row<numLayers; row++)
373
      {
374
      if( rowFloat*numLayers <= row+1 )
375
        {
376
        scramble[curr][1] = row;
377
        break;
378
        }
379
      }
380

    
381
    switch( rnd.nextInt(4) )
382
      {
383
      case 0: scramble[curr][2] = -2; break;
384
      case 1: scramble[curr][2] = -1; break;
385
      case 2: scramble[curr][2] =  1; break;
386
      case 3: scramble[curr][2] =  2; break;
387
      }
388
    }
389

    
390
///////////////////////////////////////////////////////////////////////////////////////////////////
391

    
392
  public boolean isSolved()
393
    {
394
    int index = CUBITS[0].mQuatIndex;
395

    
396
    for(int i=1; i<NUM_CUBITS; i++)
397
      {
398
      if( thereIsVisibleDifference(CUBITS[i], index) ) return false;
399
      }
400

    
401
    return true;
402
    }
403

    
404
///////////////////////////////////////////////////////////////////////////////////////////////////
405

    
406
  public int getObjectName(int numLayers)
407
    {
408
    switch(numLayers)
409
      {
410
      case 2: return R.string.cube2;
411
      case 3: return R.string.cube3;
412
      case 4: return R.string.cube4;
413
      case 5: return R.string.cube5;
414
      }
415
    return R.string.cube3;
416
    }
417

    
418
///////////////////////////////////////////////////////////////////////////////////////////////////
419

    
420
  public int getInventor(int numLayers)
421
    {
422
    switch(numLayers)
423
      {
424
      case 2: return R.string.cube2_inventor;
425
      case 3: return R.string.cube3_inventor;
426
      case 4: return R.string.cube4_inventor;
427
      case 5: return R.string.cube5_inventor;
428
      }
429
    return R.string.cube3_inventor;
430
    }
431

    
432
///////////////////////////////////////////////////////////////////////////////////////////////////
433

    
434
  public int getComplexity(int numLayers)
435
    {
436
    switch(numLayers)
437
      {
438
      case 2: return 4;
439
      case 3: return 6;
440
      case 4: return 8;
441
      case 5: return 10;
442
      }
443
    return 6;
444
    }
445
}
(22-22/41)