Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / TwistySkewb.java @ eb376d3a

1 fb52fae9 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2020 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 9c2f0c91 Leszek Koltunski
public class TwistySkewb extends TwistyObject
42 fb52fae9 Leszek Koltunski
{
43
  private static final float SQ2 = (float)Math.sqrt(2);
44
  private static final float SQ3 = (float)Math.sqrt(3);
45
46
  private static final int FACES_PER_CUBIT =6;
47
48
  // the four rotation axis of a RubikSkewb. Must be normalized.
49
  static final Static3D[] ROT_AXIS = new Static3D[]
50
         {
51
           new Static3D(+SQ3/3,+SQ3/3,+SQ3/3),
52
           new Static3D(+SQ3/3,+SQ3/3,-SQ3/3),
53
           new Static3D(+SQ3/3,-SQ3/3,+SQ3/3),
54
           new Static3D(+SQ3/3,-SQ3/3,-SQ3/3)
55
         };
56
57
  private static final int[] FACE_COLORS = new int[]
58
         {
59 ece1b58d Leszek Koltunski
           COLOR_YELLOW, COLOR_WHITE,
60
           COLOR_BLUE  , COLOR_GREEN,
61
           COLOR_RED   , COLOR_BROWN
62 fb52fae9 Leszek Koltunski
         };
63
64
  // All legal rotation quats of a RubikSkewb
65
  private static final Static4D[] QUATS = new Static4D[]
66
         {
67
           new Static4D(  0.0f,  0.0f,  0.0f,  1.0f ),
68
           new Static4D(  1.0f,  0.0f,  0.0f,  0.0f ),
69
           new Static4D(  0.0f,  1.0f,  0.0f,  0.0f ),
70
           new Static4D(  0.0f,  0.0f,  1.0f,  0.0f ),
71
72
           new Static4D(  0.5f,  0.5f,  0.5f,  0.5f ),
73
           new Static4D(  0.5f,  0.5f,  0.5f, -0.5f ),
74
           new Static4D(  0.5f,  0.5f, -0.5f,  0.5f ),
75
           new Static4D(  0.5f,  0.5f, -0.5f, -0.5f ),
76
           new Static4D(  0.5f, -0.5f,  0.5f,  0.5f ),
77
           new Static4D(  0.5f, -0.5f,  0.5f, -0.5f ),
78
           new Static4D(  0.5f, -0.5f, -0.5f,  0.5f ),
79
           new Static4D(  0.5f, -0.5f, -0.5f, -0.5f )
80
         };
81
82 63002261 Leszek Koltunski
  private static final float DIST_CORNER = 0.50f;
83
  private static final float DIST_CENTER = 0.49f;
84
85 fb52fae9 Leszek Koltunski
  // centers of the 8 corners + 6 sides ( i.e. of the all 14 cubits)
86
  private static final Static3D[] CENTERS = new Static3D[]
87
         {
88 63002261 Leszek Koltunski
           new Static3D( DIST_CORNER, DIST_CORNER, DIST_CORNER ),
89
           new Static3D( DIST_CORNER, DIST_CORNER,-DIST_CORNER ),
90
           new Static3D( DIST_CORNER,-DIST_CORNER, DIST_CORNER ),
91
           new Static3D( DIST_CORNER,-DIST_CORNER,-DIST_CORNER ),
92
           new Static3D(-DIST_CORNER, DIST_CORNER, DIST_CORNER ),
93
           new Static3D(-DIST_CORNER, DIST_CORNER,-DIST_CORNER ),
94
           new Static3D(-DIST_CORNER,-DIST_CORNER, DIST_CORNER ),
95
           new Static3D(-DIST_CORNER,-DIST_CORNER,-DIST_CORNER ),
96
97
           new Static3D( DIST_CENTER,        0.0f,        0.0f ),
98
           new Static3D(-DIST_CENTER,        0.0f,        0.0f ),
99
           new Static3D(        0.0f, DIST_CENTER,        0.0f ),
100
           new Static3D(        0.0f,-DIST_CENTER,        0.0f ),
101
           new Static3D(        0.0f,        0.0f, DIST_CENTER ),
102
           new Static3D(        0.0f,        0.0f,-DIST_CENTER ),
103 fb52fae9 Leszek Koltunski
         };
104
105
  // Colors of the faces of cubits. Each cubit, even the face pyramid, has 6 faces
106
  // (the face has one extra 'fake' face so that everything would have the same number)
107
  private static final int[][] mFaceMap = new int[][]
108
         {
109 eab9d8f8 Leszek Koltunski
           { 4,2,0, 12,12,12 },
110
           { 2,5,0, 12,12,12 },
111
           { 3,4,0, 12,12,12 },
112
           { 5,3,0, 12,12,12 },
113
           { 1,2,4, 12,12,12 },
114
           { 5,2,1, 12,12,12 },
115
           { 4,3,1, 12,12,12 },
116
           { 1,3,5, 12,12,12 },
117
118
           { 6 , 12,12,12,12,12 },
119
           { 7 , 12,12,12,12,12 },
120
           { 8 , 12,12,12,12,12 },
121
           { 9 , 12,12,12,12,12 },
122
           { 10, 12,12,12,12,12 },
123
           { 11, 12,12,12,12,12 },
124 fb52fae9 Leszek Koltunski
         };
125
126
  private static MeshBase mCornerMesh, mFaceMesh;
127
128
///////////////////////////////////////////////////////////////////////////////////////////////////
129
130 9c2f0c91 Leszek Koltunski
  TwistySkewb(int size, Static4D quat, DistortedTexture texture,
131
              MeshSquare mesh, DistortedEffects effects, int[][] moves, Resources res, int scrWidth)
132 fb52fae9 Leszek Koltunski
    {
133 9c2f0c91 Leszek Koltunski
    super(size, 60, quat, texture, mesh, effects, moves, ObjectList.SKEW, res, scrWidth);
134 fb52fae9 Leszek Koltunski
    }
135
136
///////////////////////////////////////////////////////////////////////////////////////////////////
137
138
  float getScreenRatio()
139
    {
140
    return 1.0f;
141
    }
142
143
///////////////////////////////////////////////////////////////////////////////////////////////////
144
145
  Static4D[] getQuats()
146
    {
147
    return QUATS;
148
    }
149
150
///////////////////////////////////////////////////////////////////////////////////////////////////
151
152
  int getNumFaces()
153
    {
154
    return FACE_COLORS.length;
155
    }
156
157 eaee1ddc Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
158
159
  boolean shouldResetTextureMaps()
160
    {
161
    return false;
162
    }
163
164 eab9d8f8 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
165
// Each face has two types of a texture: the central square and the triangle in the corner.
166
167
  int getNumStickerTypes()
168
    {
169
    return 2;
170
    }
171
172 7403cdfa Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
173
174
  float getBasicStep()
175
    {
176
    return SQ3;
177
    }
178
179 fb52fae9 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
180
181
  int getNumCubitFaces()
182
    {
183
    return FACES_PER_CUBIT;
184
    }
185
186
///////////////////////////////////////////////////////////////////////////////////////////////////
187
188
  Static3D[] getCubitPositions(int size)
189
    {
190
    return CENTERS;
191
    }
192
193
///////////////////////////////////////////////////////////////////////////////////////////////////
194
195
  private Static4D getQuat(int cubit)
196
    {
197
    switch(cubit)
198
      {
199
      case  0: return QUATS[0];                          //  unit quat
200
      case  1: return new Static4D( SQ2/2,0,0,SQ2/2);    //  90 along X
201
      case  2: return new Static4D(-SQ2/2,0,0,SQ2/2);    // -90 along X
202
      case  3: return QUATS[1];                          // 180 along X
203
      case  4: return new Static4D(0, SQ2/2,0,SQ2/2);    //  90 along Y
204
      case  5: return QUATS[2];                          // 180 along Y
205
      case  6: return QUATS[3];                          // 180 along Z
206
      case  7: return new Static4D(SQ2/2,0,-SQ2/2,0);    // 180 along (SQ2/2,0,-SQ2/2)
207
      case  8: return new Static4D(0,-SQ2/2,0,SQ2/2);    // -90 along Y
208
      case  9: return new Static4D(0, SQ2/2,0,SQ2/2);    //  90 along Y
209
      case 10: return new Static4D( SQ2/2,0,0,SQ2/2);    //  90 along X
210
      case 11: return new Static4D(-SQ2/2,0,0,SQ2/2);    // -90 along X
211
      case 12: return QUATS[0];                          //  unit quaternion
212
      case 13: return QUATS[1];                          // 180 along X
213
      }
214
215
    return null;
216
    }
217
218
///////////////////////////////////////////////////////////////////////////////////////////////////
219
220
  MeshBase createCubitMesh(int cubit)
221
    {
222
    MeshBase mesh;
223
224
    if( cubit<8 )
225
      {
226 ac940e24 Leszek Koltunski
      if( mCornerMesh==null ) mCornerMesh = CubitFactory.getInstance().createSkewbCornerMesh();
227 fb52fae9 Leszek Koltunski
      mesh = mCornerMesh.copy(true);
228
      }
229
    else
230
      {
231 ac940e24 Leszek Koltunski
      if( mFaceMesh==null ) mFaceMesh = CubitFactory.getInstance().createSkewbFaceMesh();
232 fb52fae9 Leszek Koltunski
      mesh = mFaceMesh.copy(true);
233
      }
234
235
    MatrixEffectQuaternion quat = new MatrixEffectQuaternion( getQuat(cubit), new Static3D(0,0,0) );
236
    mesh.apply(quat,0xffffffff,0);
237
238
    return mesh;
239
    }
240
241
///////////////////////////////////////////////////////////////////////////////////////////////////
242
243
  int getFaceColor(int cubit, int cubitface, int size)
244
    {
245
    return mFaceMap[cubit][cubitface];
246
    }
247
248
///////////////////////////////////////////////////////////////////////////////////////////////////
249
250
  void createFaceTexture(Canvas canvas, Paint paint, int face, int left, int top, int side)
251
    {
252 eab9d8f8 Leszek Koltunski
    int COLORS = FACE_COLORS.length;
253
254
    if( face<COLORS )
255
      {
256
      float STROKE = 0.035f*side;
257
      float L= left+0.125f*side;
258
      float H= 0.375f*side;
259
      float LEN = 0.5f*side;
260
261
      paint.setAntiAlias(true);
262
      paint.setStrokeWidth(STROKE);
263
      paint.setColor(FACE_COLORS[face]);
264
      paint.setStyle(Paint.Style.FILL);
265
266
      canvas.drawRect(left,top,left+side,top+side,paint);
267
268
      paint.setColor(INTERIOR_COLOR);
269
      paint.setStyle(Paint.Style.STROKE);
270
271
      canvas.drawLine( L    , H,  L+LEN, H    , paint);
272
      canvas.drawLine( L    , H,  L+LEN, H+LEN, paint);
273
      canvas.drawLine( L+LEN, H,  L+LEN, H+LEN, paint);
274
275
      float S1 = 0.125f*side;
276
      float S2 = 0.070f*side;
277
      float X  = 0.7f*S2;
278
279
      float LA = left+0.625f*side;
280
      float RA = left+0.125f*side;
281
      float TA = 0.375f*side;
282
      float BA = 0.875f*side;
283
284
      canvas.drawArc( LA-S1, TA     , LA     , TA+S1, 270, 90, false, paint);
285
      canvas.drawArc( RA+X , TA     , RA+X+S2, TA+S2, 135,135, false, paint);
286
      canvas.drawArc( LA-S2, BA-X-S2, LA     , BA-X ,   0,135, false, paint);
287
      }
288
    else
289
      {
290
      final float R = (SQ2/2)*side*0.10f;
291
      final float M = side*(0.5f-SQ2/4+0.018f);
292
293
      paint.setColor(FACE_COLORS[face-COLORS]);
294
      paint.setStyle(Paint.Style.FILL);
295
      canvas.drawRoundRect( left+M, top+M, left+side-M, top+side-M, R, R, paint);
296
      }
297 fb52fae9 Leszek Koltunski
    }
298
299
///////////////////////////////////////////////////////////////////////////////////////////////////
300
301
  float returnMultiplier()
302
    {
303
    return 2.0f;
304
    }
305
306
///////////////////////////////////////////////////////////////////////////////////////////////////
307
308
  float[] getRowChances()
309
    {
310
    float[] chances = new float[2];
311
312
    chances[0] = 0.5f;
313
    chances[1] = 1.0f;
314
315
    return chances;
316
    }
317
318
///////////////////////////////////////////////////////////////////////////////////////////////////
319
// PUBLIC API
320
321
  public Static3D[] getRotationAxis()
322
    {
323
    return ROT_AXIS;
324
    }
325
326
///////////////////////////////////////////////////////////////////////////////////////////////////
327
328
  public int getBasicAngle()
329
    {
330
    return 3;
331
    }
332
333
///////////////////////////////////////////////////////////////////////////////////////////////////
334
335
  public int randomizeNewRotAxis(Random rnd, int oldRotAxis)
336
    {
337
    int numAxis = ROTATION_AXIS.length;
338
339
    if( oldRotAxis == START_AXIS )
340
      {
341
      return rnd.nextInt(numAxis);
342
      }
343
    else
344
      {
345
      int newVector = rnd.nextInt(numAxis-1);
346
      return (newVector>=oldRotAxis ? newVector+1 : newVector);
347
      }
348
    }
349
350
///////////////////////////////////////////////////////////////////////////////////////////////////
351
352
  public int randomizeNewRow(Random rnd, int oldRotAxis, int oldRow, int newRotAxis)
353
    {
354
    float rowFloat = rnd.nextFloat();
355
356
    for(int row=0; row<mRowChances.length; row++)
357
      {
358
      if( rowFloat<=mRowChances[row] ) return row;
359
      }
360
361
    return 0;
362
    }
363
364
///////////////////////////////////////////////////////////////////////////////////////////////////
365
// remember about the double cover or unit quaternions!
366
367
  private int mulQuat(int q1, int q2)
368
    {
369
    Static4D result = RubikSurfaceView.quatMultiply(QUATS[q1],QUATS[q2]);
370
371
    float rX = result.get0();
372
    float rY = result.get1();
373
    float rZ = result.get2();
374
    float rW = result.get3();
375
376
    final float MAX_ERROR = 0.1f;
377
    float dX,dY,dZ,dW;
378
379
    for(int i=0; i<QUATS.length; i++)
380
      {
381
      dX = QUATS[i].get0() - rX;
382
      dY = QUATS[i].get1() - rY;
383
      dZ = QUATS[i].get2() - rZ;
384
      dW = QUATS[i].get3() - rW;
385
386
      if( dX<MAX_ERROR && dX>-MAX_ERROR &&
387
          dY<MAX_ERROR && dY>-MAX_ERROR &&
388
          dZ<MAX_ERROR && dZ>-MAX_ERROR &&
389
          dW<MAX_ERROR && dW>-MAX_ERROR  ) return i;
390
391
      dX = QUATS[i].get0() + rX;
392
      dY = QUATS[i].get1() + rY;
393
      dZ = QUATS[i].get2() + rZ;
394
      dW = QUATS[i].get3() + rW;
395
396
      if( dX<MAX_ERROR && dX>-MAX_ERROR &&
397
          dY<MAX_ERROR && dY>-MAX_ERROR &&
398
          dZ<MAX_ERROR && dZ>-MAX_ERROR &&
399
          dW<MAX_ERROR && dW>-MAX_ERROR  ) return i;
400
      }
401
402
    return -1;
403
    }
404
405
///////////////////////////////////////////////////////////////////////////////////////////////////
406
// The Skewb is solved if and only if:
407
//
408
// 1) all of its corner cubits are rotated with the same quat
409
// 2) all its face cubits are rotated with the same quat like the corner ones,
410
//    and optionally they also might be upside down.
411
//
412
// i.e.
413
// cubits [ 8] and [ 9] - might be extra QUAT[1]
414
// cubits [10] and [11] - might be extra QUAT[2]
415
// cubits [12] and [13] - might be extra QUAT[3]
416
417
  public boolean isSolved()
418
    {
419
    int q = CUBITS[0].mQuatIndex;
420
421
    if ( CUBITS[1].mQuatIndex == q &&
422
         CUBITS[2].mQuatIndex == q &&
423
         CUBITS[3].mQuatIndex == q &&
424
         CUBITS[4].mQuatIndex == q &&
425
         CUBITS[5].mQuatIndex == q &&
426
         CUBITS[6].mQuatIndex == q &&
427
         CUBITS[7].mQuatIndex == q  )
428
      {
429
      int q1 = mulQuat(q,1);
430
      int q2 = mulQuat(q,2);
431
      int q3 = mulQuat(q,3);
432
433
      return (CUBITS[ 8].mQuatIndex == q || CUBITS[ 8].mQuatIndex == q1) &&
434
             (CUBITS[ 9].mQuatIndex == q || CUBITS[ 9].mQuatIndex == q1) &&
435
             (CUBITS[10].mQuatIndex == q || CUBITS[10].mQuatIndex == q2) &&
436
             (CUBITS[11].mQuatIndex == q || CUBITS[11].mQuatIndex == q2) &&
437
             (CUBITS[12].mQuatIndex == q || CUBITS[12].mQuatIndex == q3) &&
438
             (CUBITS[13].mQuatIndex == q || CUBITS[13].mQuatIndex == q3)  ;
439
      }
440
441
    return false;
442
    }
443
444
///////////////////////////////////////////////////////////////////////////////////////////////////
445 ee35e63c Leszek Koltunski
// only needed for solvers - there are no Skewb solvers ATM)
446 fb52fae9 Leszek Koltunski
447
  public String retObjectString()
448
    {
449
    return "";
450
    }
451
452
}