Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / TwistyBandagedCube.java @ 4c0a6d97

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2021 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.MatrixEffectQuaternion;
27
import org.distorted.library.main.DistortedEffects;
28
import org.distorted.library.main.DistortedTexture;
29
import org.distorted.library.mesh.MeshBase;
30
import org.distorted.library.mesh.MeshSquare;
31
import org.distorted.library.type.Static3D;
32
import org.distorted.library.type.Static4D;
33
import org.distorted.main.RubikSurfaceView;
34

    
35
import java.util.Random;
36

    
37
import static org.distorted.effects.scramble.ScrambleEffect.START_AXIS;
38

    
39
///////////////////////////////////////////////////////////////////////////////////////////////////
40

    
41
abstract class TwistyBandagedCube extends TwistyObject
42
{
43
  // the three rotation axis of a 3x3 Cube. Must be normalized.
44
  static final Static3D[] ROT_AXIS = new Static3D[]
45
         {
46
           new Static3D(1,0,0),
47
           new Static3D(0,1,0),
48
           new Static3D(0,0,1)
49
         };
50

    
51
  private static final int[] FACE_COLORS = new int[]
52
         {
53
           COLOR_YELLOW, COLOR_WHITE,
54
           COLOR_BLUE  , COLOR_GREEN,
55
           COLOR_RED   , COLOR_ORANGE
56
         };
57

    
58
  private static final Static4D[] QUATS = new Static4D[]
59
         {
60
         new Static4D(  0.0f,   0.0f,   0.0f,   1.0f),
61
         new Static4D(  1.0f,   0.0f,   0.0f,   0.0f),
62
         new Static4D(  0.0f,   1.0f,   0.0f,   0.0f),
63
         new Static4D(  0.0f,   0.0f,   1.0f,   0.0f),
64

    
65
         new Static4D( SQ2/2,  SQ2/2,  0.0f ,   0.0f),
66
         new Static4D( SQ2/2, -SQ2/2,  0.0f ,   0.0f),
67
         new Static4D( SQ2/2,   0.0f,  SQ2/2,   0.0f),
68
         new Static4D(-SQ2/2,   0.0f,  SQ2/2,   0.0f),
69
         new Static4D( SQ2/2,   0.0f,   0.0f,  SQ2/2),
70
         new Static4D( SQ2/2,   0.0f,   0.0f, -SQ2/2),
71
         new Static4D(  0.0f,  SQ2/2,  SQ2/2,   0.0f),
72
         new Static4D(  0.0f,  SQ2/2, -SQ2/2,   0.0f),
73
         new Static4D(  0.0f,  SQ2/2,   0.0f,  SQ2/2),
74
         new Static4D(  0.0f,  SQ2/2,   0.0f, -SQ2/2),
75
         new Static4D(  0.0f,   0.0f,  SQ2/2,  SQ2/2),
76
         new Static4D(  0.0f,   0.0f,  SQ2/2, -SQ2/2),
77

    
78
         new Static4D(  0.5f,   0.5f,   0.5f,   0.5f),
79
         new Static4D(  0.5f,   0.5f,  -0.5f,   0.5f),
80
         new Static4D(  0.5f,   0.5f,  -0.5f,  -0.5f),
81
         new Static4D(  0.5f,  -0.5f,   0.5f,  -0.5f),
82
         new Static4D( -0.5f,  -0.5f,  -0.5f,   0.5f),
83
         new Static4D( -0.5f,   0.5f,  -0.5f,  -0.5f),
84
         new Static4D( -0.5f,   0.5f,   0.5f,  -0.5f),
85
         new Static4D( -0.5f,   0.5f,   0.5f,   0.5f)
86
         };
87

    
88
  // possible aspectRatios of cubit faces in case of a bandaged 3x3:
89
  // 1/3, 1/2, 2/3, 1, 3/2, 2, 3. Numerator = (1/3)*3!, (1/2)*3!, ...
90
  private static final int[] mAspectNumerator3 = new int[] {2,3,4,6,9,12,18};
91
  private static final int[] mAspectRatio3     = new int[] {0,0,0,0,0,0,0};
92

    
93
  static final Static4D[] INIT_QUATS = new Static4D[]
94
        {
95
        new Static4D(  0.0f,   0.0f,   0.0f,   1.0f),  // NULL
96
        new Static4D( SQ2/2,   0.0f,   0.0f,  SQ2/2),  // X
97
        new Static4D(  0.0f,  SQ2/2,   0.0f,  SQ2/2),  // Y
98
        new Static4D(  0.0f,   0.0f,  SQ2/2,  SQ2/2),  // Z
99
        new Static4D( -0.5f,  +0.5f,  -0.5f,  -0.5f),  // ZX
100
        new Static4D( +0.5f,  +0.5f,  +0.5f,  +0.5f),  // YX
101
        };
102

    
103
  private static MeshBase[] mMeshes;
104

    
105
///////////////////////////////////////////////////////////////////////////////////////////////////
106

    
107
  TwistyBandagedCube(int size, Static4D quat, DistortedTexture texture, MeshSquare mesh,
108
                     DistortedEffects effects, int[][] moves, ObjectList list, Resources res, int scrWidth)
109
    {
110
    super(size, size, quat, texture, mesh, effects, moves, list, res, scrWidth);
111
    }
112

    
113
///////////////////////////////////////////////////////////////////////////////////////////////////
114

    
115
  abstract int getNumCubitVariants();
116
  abstract int getCubitVariant(int cubit);
117
  abstract int getNumCubits();
118
  abstract int[] getCubitDimensions(int variant);
119
  abstract Static3D getCubitPosition(int cubit);
120
  abstract int getQuatIndex(int cubit);
121

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

    
124
  MeshBase createCubitMesh(int cubit, int numLayers)
125
    {
126
    if( mMeshes==null )
127
      {
128
      mMeshes = new MeshBase[getNumCubitVariants()];
129
      }
130

    
131
    int variant = getCubitVariant(cubit);
132

    
133
    if( mMeshes[variant]==null )
134
      {
135
      int[] dimensions = getCubitDimensions(variant);
136
      mMeshes[variant] = FactoryCubit.getInstance().createCuboidMesh(dimensions);
137
      }
138

    
139
    MeshBase mesh = mMeshes[variant].copy(true);
140
    MatrixEffectQuaternion quat = new MatrixEffectQuaternion( INIT_QUATS[getQuatIndex(cubit)], new Static3D(0,0,0) );
141
    mesh.apply(quat,0xffffffff,0);
142

    
143
    return mesh;
144
    }
145

    
146
///////////////////////////////////////////////////////////////////////////////////////////////////
147

    
148
  private int getAspectNumerator(int stickerType)
149
    {
150
    int type=-1;
151
    int len = mAspectRatio3.length;
152

    
153
    for(int i=0; i<len; i++)
154
      {
155
      if( mAspectRatio3[i] != 0 ) type++;
156
      if( type==stickerType ) return mAspectNumerator3[i];
157
      }
158

    
159
    return 0;
160
    }
161

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

    
164
  void createFaceTexture(Canvas canvas, Paint paint, int face, int left, int top)
165
    {
166
    float R = 0.10f;
167
    float S = 0.08f;
168
    int numFaces = FACE_COLORS.length;
169
    int stickerType = face/numFaces;
170
    float ratio = getAspectNumerator(stickerType)/6.0f;
171
    float X,Y;
172

    
173
    if( ratio<1.0f )
174
      {
175
      X = ratio/2;
176
      Y = 0.5f;
177
      }
178
    else
179
      {
180
      X = 0.5f;
181
      Y = 0.5f/ratio;
182
      }
183

    
184
    float[] vertices = { -X,-Y, +X,-Y, +X,+Y, -X,+Y};
185

    
186
    FactorySticker factory = FactorySticker.getInstance();
187
    factory.drawRoundedPolygon(canvas, paint, left, top, vertices, S, FACE_COLORS[face%numFaces], R);
188
    }
189

    
190
///////////////////////////////////////////////////////////////////////////////////////////////////
191

    
192
  Static3D[] getCubitPositions(int size)
193
    {
194
    int numCubits = getNumCubits();
195
    Static3D[] tmp = new Static3D[numCubits];
196

    
197
    for(int cubit=0; cubit<numCubits; cubit++)
198
      {
199
      tmp[cubit] = getCubitPosition(cubit);
200
      }
201

    
202
    return tmp;
203
    }
204

    
205
///////////////////////////////////////////////////////////////////////////////////////////////////
206

    
207
  Static4D[] getQuats()
208
    {
209
    return QUATS;
210
    }
211

    
212
///////////////////////////////////////////////////////////////////////////////////////////////////
213

    
214
  boolean shouldResetTextureMaps()
215
    {
216
    return false;
217
    }
218

    
219
///////////////////////////////////////////////////////////////////////////////////////////////////
220

    
221
  int getNumFaces()
222
    {
223
    return FACE_COLORS.length;
224
    }
225

    
226
///////////////////////////////////////////////////////////////////////////////////////////////////
227

    
228
  float[] getCuts(int numLayers)
229
    {
230
    float[] cuts = new float[numLayers-1];
231

    
232
    for(int i=0; i<numLayers-1; i++)
233
      {
234
      cuts[i] = (2-numLayers)*0.5f + i;
235
      }
236

    
237
    return cuts;
238
    }
239

    
240
///////////////////////////////////////////////////////////////////////////////////////////////////
241

    
242
  int getNumStickerTypes(int numLayers)
243
    {
244
    if( numLayers==3 )
245
      {
246
      int numVariants = getNumCubitVariants();
247
      int len = mAspectNumerator3.length;
248

    
249
      for(int variant=0; variant<numVariants; variant++)
250
        {
251
        int[] dimensions = getCubitDimensions(variant);
252

    
253
        int ratio0 = 6*dimensions[0]/dimensions[1];
254
        int ratio1 = 6*dimensions[0]/dimensions[2];
255
        int ratio2 = 6*dimensions[2]/dimensions[1];
256

    
257
        for(int i=0; i<len; i++)
258
          {
259
          if( mAspectNumerator3[i]==ratio0 ||
260
              mAspectNumerator3[i]==ratio1 ||
261
              mAspectNumerator3[i]==ratio2  ) mAspectRatio3[i]++;
262
          }
263
        }
264

    
265
      int result=0;
266

    
267
      for(int i=0; i<len; i++)
268
        {
269
        if( mAspectRatio3[i]>0 ) result++;
270
        }
271

    
272
      return result;
273
      }
274

    
275
    return 1;
276
    }
277

    
278
///////////////////////////////////////////////////////////////////////////////////////////////////
279

    
280
  int getNumCubitFaces()
281
    {
282
    return FACE_COLORS.length;
283
    }
284

    
285
///////////////////////////////////////////////////////////////////////////////////////////////////
286

    
287
  float getScreenRatio()
288
    {
289
    return 0.5f;
290
    }
291

    
292
///////////////////////////////////////////////////////////////////////////////////////////////////
293

    
294
  int getFaceColor(int cubit, int cubitface, int numLayers)
295
    {
296
    int X=0,Y=0,Z=0;
297
    int variant = getCubitVariant(cubit);
298
    int[] dim = getCubitDimensions(variant);
299
    Static3D pos = getCubitPosition(cubit);
300

    
301
    switch( getQuatIndex(cubit) )
302
      {
303
      case 0: X= dim[0]; Y=dim[1]; Z=dim[2]; break;
304
      case 1: X= dim[0]; Y=dim[2]; Z=dim[1]; break;
305
      case 2: X= dim[2]; Y=dim[1]; Z=dim[0]; break;
306
      case 3: X= dim[1]; Y=dim[0]; Z=dim[2]; break;
307
      case 4: X= dim[1]; Y=dim[2]; Z=dim[0]; break;
308
      case 5: X= dim[2]; Y=dim[0]; Z=dim[1]; break;
309
      }
310

    
311
    float posX = pos.get0();
312
    float posY = pos.get1();
313
    float posZ = pos.get2();
314
    float border = (numLayers-1)*0.5f;
315
    int ret = NUM_FACES;
316

    
317
    switch(cubitface)
318
      {
319
      case 0: ret = posX + X*0.5f > border ? cubitface : NUM_FACES; break;
320
      case 1: ret = posX - X*0.5f <-border ? cubitface : NUM_FACES; break;
321
      case 2: ret = posY + Y*0.5f > border ? cubitface : NUM_FACES; break;
322
      case 3: ret = posY - Y*0.5f <-border ? cubitface : NUM_FACES; break;
323
      case 4: ret = posZ + Z*0.5f > border ? cubitface : NUM_FACES; break;
324
      case 5: ret = posZ - Z*0.5f <-border ? cubitface : NUM_FACES; break;
325
      }
326

    
327
    return ret;
328
    }
329

    
330
///////////////////////////////////////////////////////////////////////////////////////////////////
331

    
332
  float returnMultiplier()
333
    {
334
    return getNumLayers();
335
    }
336

    
337
///////////////////////////////////////////////////////////////////////////////////////////////////
338

    
339
  float[] getRowChances(int numLayers)
340
    {
341
    float[] chances = new float[numLayers];
342

    
343
    for(int i=0; i<numLayers; i++)
344
      {
345
      chances[i] = (i+1.0f) / numLayers;
346
      }
347

    
348
    return chances;
349
    }
350

    
351
///////////////////////////////////////////////////////////////////////////////////////////////////
352
// PUBLIC API
353

    
354
  public Static3D[] getRotationAxis()
355
    {
356
    return ROT_AXIS;
357
    }
358

    
359
///////////////////////////////////////////////////////////////////////////////////////////////////
360

    
361
  public int getBasicAngle()
362
    {
363
    return 4;
364
    }
365

    
366
///////////////////////////////////////////////////////////////////////////////////////////////////
367
// TODO
368

    
369
  public int randomizeNewRotAxis(Random rnd, int oldRotAxis)
370
    {
371
    int numAxis = ROTATION_AXIS.length;
372

    
373
    if( oldRotAxis == START_AXIS )
374
      {
375
      return rnd.nextInt(numAxis);
376
      }
377
    else
378
      {
379
      int newVector = rnd.nextInt(numAxis-1);
380
      return (newVector>=oldRotAxis ? newVector+1 : newVector);
381
      }
382
    }
383

    
384
///////////////////////////////////////////////////////////////////////////////////////////////////
385
// TODO
386

    
387
  public int randomizeNewRow(Random rnd, int oldRotAxis, int oldRow, int newRotAxis)
388
    {
389
    float rowFloat = rnd.nextFloat();
390

    
391
    for(int row=0; row<mRowChances.length; row++)
392
      {
393
      if( rowFloat<=mRowChances[row] ) return row;
394
      }
395

    
396
    return 0;
397
    }
398

    
399
///////////////////////////////////////////////////////////////////////////////////////////////////
400

    
401
  public boolean isSolved()
402
    {
403
    int index = CUBITS[0].mQuatIndex;
404

    
405
    for(int i=1; i<NUM_CUBITS; i++)
406
      {
407
      if( !thereIsNoVisibleDifference(CUBITS[i], index) ) return false;
408
      }
409

    
410
    return true;
411
    }
412

    
413
///////////////////////////////////////////////////////////////////////////////////////////////////
414
// return if the Cubit, when rotated with its own mQuatScramble, would have looked any different
415
// then if it were rotated by quaternion 'quat'.
416
// No it is not so simple as the quats need to be the same - imagine a 4x4x4 cube where the two
417
// middle squares get interchanged. No visible difference!
418
//
419
// So: this is true iff the cubit
420
// a) is a corner or edge and the quaternions are the same
421
// b) is inside one of the faces and after rotations by both quats it ends up on the same face.
422

    
423
  private boolean thereIsNoVisibleDifference(Cubit cubit, int quatIndex)
424
    {
425
    if ( cubit.mQuatIndex == quatIndex ) return true;
426

    
427
    int belongsToHowManyFaces = 0;
428
    int lastLayer = getNumLayers()-1;
429
    float row;
430
    final float MAX_ERROR = 0.01f;
431

    
432
    for(int i=0; i<NUM_AXIS; i++)
433
      {
434
      row = cubit.mRotationRow[i];
435
      if( (row          <MAX_ERROR && row          >-MAX_ERROR) ||
436
          (row-lastLayer<MAX_ERROR && row-lastLayer>-MAX_ERROR)  ) belongsToHowManyFaces++;
437
      }
438

    
439
    switch(belongsToHowManyFaces)
440
      {
441
      case 0 : return true ;  // 'inside' cubit that does not lie on any face
442
      case 1 :                // cubit that lies inside one of the faces
443
               Static3D orig = cubit.getOrigPosition();
444
               Static4D quat1 = QUATS[quatIndex];
445
               Static4D quat2 = QUATS[cubit.mQuatIndex];
446

    
447
               Static4D cubitCenter = new Static4D( orig.get0(), orig.get1(), orig.get2(), 0);
448
               Static4D rotated1 = RubikSurfaceView.rotateVectorByQuat( cubitCenter, quat1 );
449
               Static4D rotated2 = RubikSurfaceView.rotateVectorByQuat( cubitCenter, quat2 );
450

    
451
               float row1, row2;
452
               float x1 = rotated1.get0();
453
               float y1 = rotated1.get1();
454
               float z1 = rotated1.get2();
455
               float x2 = rotated2.get0();
456
               float y2 = rotated2.get1();
457
               float z2 = rotated2.get2();
458

    
459
               for(int i=0; i<NUM_AXIS; i++)
460
                 {
461
                 row1 = computeRow(x1,y1,z1,i);
462
                 row2 = computeRow(x2,y2,z2,i);
463

    
464
                 if( (row1==0 && row2==0) || (row1==lastLayer && row2==lastLayer) ) return true;
465
                 }
466
               return false;
467

    
468
      default: return false;  // edge or corner
469
      }
470
    }
471

    
472
///////////////////////////////////////////////////////////////////////////////////////////////////
473
// only needed for solvers - there are no Ivy solvers ATM)
474

    
475
  public String retObjectString()
476
    {
477
    return "";
478
    }
479
}
(16-16/32)