Project

General

Profile

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

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

1
///////////////////////////////////////////////////////////////////////////////////////////////////
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
public class TwistySkewb extends TwistyObject
42
{
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
           COLOR_YELLOW, COLOR_WHITE,
60
           COLOR_BLUE  , COLOR_GREEN,
61
           COLOR_RED   , COLOR_BROWN
62
         };
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
  private static final float DIST_CORNER = 0.50f;
83
  private static final float DIST_CENTER = 0.49f;
84

    
85
  // centers of the 8 corners + 6 sides ( i.e. of the all 14 cubits)
86
  private static final Static3D[] CENTERS = new Static3D[]
87
         {
88
           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
         };
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
           { 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
         };
125

    
126
  private static MeshBase mCornerMesh, mFaceMesh;
127

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

    
130
  TwistySkewb(int size, Static4D quat, DistortedTexture texture,
131
              MeshSquare mesh, DistortedEffects effects, int[][] moves, Resources res, int scrWidth)
132
    {
133
    super(size, 60, quat, texture, mesh, effects, moves, ObjectList.SKEW, res, scrWidth);
134
    }
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
///////////////////////////////////////////////////////////////////////////////////////////////////
158

    
159
  boolean shouldResetTextureMaps()
160
    {
161
    return false;
162
    }
163

    
164
///////////////////////////////////////////////////////////////////////////////////////////////////
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
///////////////////////////////////////////////////////////////////////////////////////////////////
173

    
174
  float getBasicStep()
175
    {
176
    return SQ3;
177
    }
178

    
179
///////////////////////////////////////////////////////////////////////////////////////////////////
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
      if( mCornerMesh==null ) mCornerMesh = CubitFactory.getInstance().createSkewbCornerMesh();
227
      mesh = mCornerMesh.copy(true);
228
      }
229
    else
230
      {
231
      if( mFaceMesh==null ) mFaceMesh = CubitFactory.getInstance().createSkewbFaceMesh();
232
      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
    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
    }
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
// only needed for solvers - there are no Skewb solvers ATM)
446

    
447
  public String retObjectString()
448
    {
449
    return "";
450
    }
451

    
452
}
(19-19/19)