Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / TwistyBandagedAbstract.java @ 538ee7a6

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 TwistyBandagedAbstract 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
  private static final Static4D[] INIT_QUATS = new Static4D[]
89
        {
90
        new Static4D(  0.0f,   0.0f,   0.0f,   1.0f),  // NULL
91
        new Static4D( SQ2/2,   0.0f,   0.0f, -SQ2/2),  // X
92
        new Static4D(  0.0f,  SQ2/2,   0.0f, -SQ2/2),  // Y
93
        new Static4D(  0.0f,   0.0f,  SQ2/2, -SQ2/2),  // Z
94
        new Static4D( -0.5f,  +0.5f,  -0.5f,  +0.5f),  // ZX
95
        new Static4D( +0.5f,  +0.5f,  +0.5f,  -0.5f),  // YX
96
        };
97

    
98
  private static final int[][] mDimensions = new int[][]
99
        {
100
         {1,1,1},  // has to be X>=Z>=Y so that all
101
         {2,1,1},  // the faces are horizontal
102
         {3,1,1},
103
         {2,1,2},
104
         {2,2,2}
105
        };
106

    
107
  private static final int[][] mStickerDimensions = new int[][]
108
        {
109
         {1,1},  // dimensions of the faces of
110
         {2,1},  // the cuboids defined above
111
         {3,1},
112
         {2,2}
113
        };
114

    
115
  private static final int[][] mFaceMap = new int[][] // cubitface=2 when rotated by
116
    {                                                 // quatIndex=1 gets moved to
117
        {0,0,5,2,4,2},                                // position mFaceMap[2][1]
118
        {1,1,4,3,5,3},
119
        {2,4,2,1,1,4},
120
        {3,5,3,0,0,5},
121
        {4,3,0,4,3,0},
122
        {5,2,1,5,2,1}
123
    };
124

    
125
  private static final int[][] mAxisMap = new int[][] // axis=1 when rotated by
126
    {                                                 // quatIndex=2 gets moved to
127
        {0,0,2,1,2,1},                                // axis mAxisMap[1][2]
128
        {1,2,1,0,0,2},
129
        {2,1,0,2,1,0}
130
    };
131

    
132
  private static final int NUM_STICKERS = mStickerDimensions.length;
133

    
134
  private static MeshBase[] mMeshes;
135

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

    
138
  TwistyBandagedAbstract(int size, Static4D quat, DistortedTexture texture, MeshSquare mesh,
139
                         DistortedEffects effects, int[][] moves, ObjectList list, Resources res, int scrWidth)
140
    {
141
    super(size, size, quat, texture, mesh, effects, moves, list, res, scrWidth);
142
    }
143

    
144
///////////////////////////////////////////////////////////////////////////////////////////////////
145

    
146
  abstract int getCubitVariant(int cubit);
147
  abstract int getNumCubits();
148
  abstract int getQuatIndex(int cubit);
149
  abstract float[] getCubitPosition(int cubit);
150

    
151
///////////////////////////////////////////////////////////////////////////////////////////////////
152

    
153
  MeshBase createCubitMesh(int cubit, int numLayers)
154
    {
155
    if( mMeshes==null )
156
      {
157
      int LEN = mDimensions.length;
158
      mMeshes = new MeshBase[LEN];
159

    
160
      for(int i=0; i<LEN; i++)
161
        {
162
        mMeshes[i] = FactoryCubit.getInstance().createCuboidMesh(mDimensions[i]);
163
        }
164
      }
165

    
166
    int variant = getCubitVariant(cubit);
167
    MeshBase mesh = mMeshes[variant].copy(true);
168
    MatrixEffectQuaternion quat = new MatrixEffectQuaternion( INIT_QUATS[getQuatIndex(cubit)], new Static3D(0,0,0) );
169
    mesh.apply(quat,0xffffffff,0);
170

    
171
    return mesh;
172
    }
173

    
174
///////////////////////////////////////////////////////////////////////////////////////////////////
175

    
176
  void createFaceTexture(Canvas canvas, Paint paint, int face, int left, int top)
177
    {
178
    int numFaces = FACE_COLORS.length;
179
    int stickerType = face/numFaces;
180
    int color = face%numFaces;
181
    float X = mStickerDimensions[stickerType][0];
182
    float Y = mStickerDimensions[stickerType][1];
183
    float MAX = Math.max(X,Y);
184
    float R = 0.10f / MAX;
185
    float S = 0.08f / MAX;
186
    X /= (2*MAX);
187
    Y /= (2*MAX);
188

    
189
    float[] vertices = { -X,-Y, +X,-Y, +X,+Y, -X,+Y};
190

    
191
    FactorySticker factory = FactorySticker.getInstance();
192
    factory.drawRoundedPolygon(canvas, paint, left, top, vertices, S, FACE_COLORS[color], R);
193
    }
194

    
195
///////////////////////////////////////////////////////////////////////////////////////////////////
196

    
197
  Static3D[] getCubitPositions(int size)
198
    {
199
    int numCubits = getNumCubits();
200
    Static3D[] tmp = new Static3D[numCubits];
201

    
202
    for(int cubit=0; cubit<numCubits; cubit++)
203
      {
204
      float[] pos = getCubitPosition(cubit);
205
      tmp[cubit] = new Static3D(pos[0],pos[1],pos[2]);
206
      }
207

    
208
    return tmp;
209
    }
210

    
211
///////////////////////////////////////////////////////////////////////////////////////////////////
212

    
213
  Static4D[] getQuats()
214
    {
215
    return QUATS;
216
    }
217

    
218
///////////////////////////////////////////////////////////////////////////////////////////////////
219

    
220
  boolean shouldResetTextureMaps()
221
    {
222
    return false;
223
    }
224

    
225
///////////////////////////////////////////////////////////////////////////////////////////////////
226

    
227
  int getNumFaces()
228
    {
229
    return FACE_COLORS.length;
230
    }
231

    
232
///////////////////////////////////////////////////////////////////////////////////////////////////
233

    
234
  float[] getCuts(int numLayers)
235
    {
236
    float[] cuts = new float[numLayers-1];
237

    
238
    for(int i=0; i<numLayers-1; i++)
239
      {
240
      cuts[i] = (2-numLayers)*0.5f + i;
241
      }
242

    
243
    return cuts;
244
    }
245

    
246
///////////////////////////////////////////////////////////////////////////////////////////////////
247

    
248
  int getNumStickerTypes(int numLayers)
249
    {
250
    return NUM_STICKERS;
251
    }
252

    
253
///////////////////////////////////////////////////////////////////////////////////////////////////
254

    
255
  int getNumCubitFaces()
256
    {
257
    return FACE_COLORS.length;
258
    }
259

    
260
///////////////////////////////////////////////////////////////////////////////////////////////////
261

    
262
  float getScreenRatio()
263
    {
264
    return 0.5f;
265
    }
266

    
267
///////////////////////////////////////////////////////////////////////////////////////////////////
268

    
269
  private int retStickerIndex(int horzSize, int vertSize)
270
    {
271
    switch(horzSize)
272
      {
273
      case 1: return 0;
274
      case 2: return vertSize==1 ? 1:3;
275
      case 3: return 2;
276
      }
277

    
278
    return 0;
279
    }
280

    
281
///////////////////////////////////////////////////////////////////////////////////////////////////
282

    
283
  private int getStickerIndex(int cubitface, int[] dim)
284
    {
285
    switch(cubitface)
286
      {
287
      case 0: case 1: return retStickerIndex(dim[2],dim[1]);
288
      case 2: case 3: return retStickerIndex(dim[0],dim[2]);
289
      case 4: case 5: return retStickerIndex(dim[0],dim[1]);
290
      }
291

    
292
    return 0;
293
    }
294

    
295
///////////////////////////////////////////////////////////////////////////////////////////////////
296

    
297
  int getFaceColor(int cubit, int cubitface, int numLayers)
298
    {
299
    int variant      = getCubitVariant(cubit);
300
    int[] dim        = mDimensions[variant];
301
    float[] pos      = getCubitPosition(cubit);
302
    int stickerIndex = getStickerIndex(cubitface,dim);
303
    int quatIndex    = getQuatIndex(cubit);
304
    int face         = mFaceMap[cubitface][quatIndex];
305
    int multiplier   = (face%2)==0 ? 1:-1;
306
    int posIndex     = face/2;
307
    int dimIndex     = mAxisMap[posIndex][quatIndex];
308
    boolean reaches  = multiplier*pos[posIndex] + dim[dimIndex]*0.5f > (numLayers-1)*0.5f;
309

    
310
    int ret=  reaches ? stickerIndex*NUM_FACES + face : NUM_STICKERS*NUM_FACES;
311

    
312
if( cubit==0 )
313
  {
314
android.util.Log.e("DISTORTED", "cubit="+cubit+" cubitface="+cubitface+" ret="+ret+" stickerIndex="+stickerIndex+" face="+face);
315
android.util.Log.e("DISTORTED", "reaches="+reaches+" border="+((numLayers-1)*0.5f)+" left="+(multiplier*pos[posIndex] + dim[dimIndex]*0.5f));
316
android.util.Log.e("DISTORTED", "posIndex="+posIndex+" dimIndex="+dimIndex);
317

    
318
  }
319
    return ret;
320
    }
321

    
322
///////////////////////////////////////////////////////////////////////////////////////////////////
323

    
324
  float returnMultiplier()
325
    {
326
    return getNumLayers();
327
    }
328

    
329
///////////////////////////////////////////////////////////////////////////////////////////////////
330

    
331
  float[] getRowChances(int numLayers)
332
    {
333
    float[] chances = new float[numLayers];
334

    
335
    for(int i=0; i<numLayers; i++)
336
      {
337
      chances[i] = (i+1.0f) / numLayers;
338
      }
339

    
340
    return chances;
341
    }
342

    
343
///////////////////////////////////////////////////////////////////////////////////////////////////
344
// PUBLIC API
345

    
346
  public Static3D[] getRotationAxis()
347
    {
348
    return ROT_AXIS;
349
    }
350

    
351
///////////////////////////////////////////////////////////////////////////////////////////////////
352

    
353
  public int getBasicAngle()
354
    {
355
    return 4;
356
    }
357

    
358
///////////////////////////////////////////////////////////////////////////////////////////////////
359
// TODO
360

    
361
  public int randomizeNewRotAxis(Random rnd, int oldRotAxis)
362
    {
363
    int numAxis = ROTATION_AXIS.length;
364

    
365
    if( oldRotAxis == START_AXIS )
366
      {
367
      return rnd.nextInt(numAxis);
368
      }
369
    else
370
      {
371
      int newVector = rnd.nextInt(numAxis-1);
372
      return (newVector>=oldRotAxis ? newVector+1 : newVector);
373
      }
374
    }
375

    
376
///////////////////////////////////////////////////////////////////////////////////////////////////
377
// TODO
378

    
379
  public int randomizeNewRow(Random rnd, int oldRotAxis, int oldRow, int newRotAxis)
380
    {
381
    float rowFloat = rnd.nextFloat();
382

    
383
    for(int row=0; row<mRowChances.length; row++)
384
      {
385
      if( rowFloat<=mRowChances[row] ) return row;
386
      }
387

    
388
    return 0;
389
    }
390

    
391
///////////////////////////////////////////////////////////////////////////////////////////////////
392

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

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

    
402
    return true;
403
    }
404

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

    
415
  private boolean thereIsNoVisibleDifference(Cubit cubit, int quatIndex)
416
    {
417
    if ( cubit.mQuatIndex == quatIndex ) return true;
418

    
419
    int belongsToHowManyFaces = 0;
420
    int lastLayer = getNumLayers()-1;
421
    float row;
422
    final float MAX_ERROR = 0.01f;
423

    
424
    for(int i=0; i<NUM_AXIS; i++)
425
      {
426
      row = cubit.mRotationRow[i];
427
      if( (row          <MAX_ERROR && row          >-MAX_ERROR) ||
428
          (row-lastLayer<MAX_ERROR && row-lastLayer>-MAX_ERROR)  ) belongsToHowManyFaces++;
429
      }
430

    
431
    switch(belongsToHowManyFaces)
432
      {
433
      case 0 : return true ;  // 'inside' cubit that does not lie on any face
434
      case 1 :                // cubit that lies inside one of the faces
435
               Static3D orig = cubit.getOrigPosition();
436
               Static4D quat1 = QUATS[quatIndex];
437
               Static4D quat2 = QUATS[cubit.mQuatIndex];
438

    
439
               Static4D cubitCenter = new Static4D( orig.get0(), orig.get1(), orig.get2(), 0);
440
               Static4D rotated1 = RubikSurfaceView.rotateVectorByQuat( cubitCenter, quat1 );
441
               Static4D rotated2 = RubikSurfaceView.rotateVectorByQuat( cubitCenter, quat2 );
442

    
443
               float row1, row2;
444
               float x1 = rotated1.get0();
445
               float y1 = rotated1.get1();
446
               float z1 = rotated1.get2();
447
               float x2 = rotated2.get0();
448
               float y2 = rotated2.get1();
449
               float z2 = rotated2.get2();
450

    
451
               for(int i=0; i<NUM_AXIS; i++)
452
                 {
453
                 row1 = computeRow(x1,y1,z1,i);
454
                 row2 = computeRow(x2,y2,z2,i);
455

    
456
                 if( (row1==0 && row2==0) || (row1==lastLayer && row2==lastLayer) ) return true;
457
                 }
458
               return false;
459

    
460
      default: return false;  // edge or corner
461
      }
462
    }
463

    
464
///////////////////////////////////////////////////////////////////////////////////////////////////
465
// only needed for solvers - there are no Bandaged solvers ATM)
466

    
467
  public String retObjectString()
468
    {
469
    return "";
470
    }
471
}
(18-18/35)