Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / TwistyDiamond.java @ 5043d5d0

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.R;
34
import org.distorted.main.RubikSurfaceView;
35

    
36
import java.util.Random;
37

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

    
40
public class TwistyDiamond extends TwistyObject
41
{
42
  private static final int FACES_PER_CUBIT =8;
43

    
44
  // the four rotation axis of a Diamond. Must be normalized.
45
  static final Static3D[] ROT_AXIS = new Static3D[]
46
         {
47
           new Static3D(+SQ6/3,+SQ3/3,     0),
48
           new Static3D(-SQ6/3,+SQ3/3,     0),
49
           new Static3D(     0,-SQ3/3,-SQ6/3),
50
           new Static3D(     0,-SQ3/3,+SQ6/3)
51
         };
52

    
53
  private static final int[] FACE_COLORS = new int[]
54
         {
55
           COLOR_GREY  , COLOR_VIOLET,
56
           COLOR_YELLOW, COLOR_WHITE ,
57
           COLOR_BLUE  , COLOR_RED   ,
58
           COLOR_ORANGE, COLOR_GREEN
59
         };
60

    
61
  // All legal rotation quats of a Diamond: unit + three 180 deg turns + 8 generators
62
  private static final Static4D[] QUATS = new Static4D[]
63
         {
64
           new Static4D(  0.0f,  0.0f,   0.0f,  1.0f ),
65
           new Static4D(  0.0f,  1.0f,   0.0f,  0.0f ),
66
           new Static4D(+SQ2/2,  0.0f, -SQ2/2,  0.0f ),
67
           new Static4D(-SQ2/2,  0.0f, -SQ2/2,  0.0f ),
68

    
69
           new Static4D(+SQ2/2,  0.5f,   0.0f,  0.5f ),
70
           new Static4D(-SQ2/2,  0.5f,   0.0f,  0.5f ),
71
           new Static4D(  0.0f,  0.5f, +SQ2/2,  0.5f ),
72
           new Static4D(  0.0f,  0.5f, -SQ2/2,  0.5f ),
73
           new Static4D(+SQ2/2,  0.5f,   0.0f, -0.5f ),
74
           new Static4D(-SQ2/2,  0.5f,   0.0f, -0.5f ),
75
           new Static4D(  0.0f,  0.5f, +SQ2/2, -0.5f ),
76
           new Static4D(  0.0f,  0.5f, -SQ2/2, -0.5f )
77
         };
78

    
79
  private static final float DIST = 0.50f;
80

    
81
  // centers of the 6 octahedrons + 8 tetrahedrons ( i.e. of the all 14 cubits)
82
  private static final float[][] CENTERS = new float[][]
83
         {
84
             { DIST,          0, DIST },
85
             { DIST,          0,-DIST },
86
             {-DIST,          0,-DIST },
87
             {-DIST,          0, DIST },
88
             {    0, DIST*SQ2  ,    0 },
89
             {    0,-DIST*SQ2  ,    0 },
90

    
91
             {    0, DIST*SQ2/2, DIST },
92
             { DIST, DIST*SQ2/2,    0 },
93
             {    0, DIST*SQ2/2,-DIST },
94
             {-DIST, DIST*SQ2/2,    0 },
95
             {    0,-DIST*SQ2/2, DIST },
96
             { DIST,-DIST*SQ2/2,    0 },
97
             {    0,-DIST*SQ2/2,-DIST },
98
             {-DIST,-DIST*SQ2/2,    0 }
99
         };
100

    
101
  // Colors of the faces of cubits. Each cubit has 8 faces
102
  private static final int[][] mFaceMap = new int[][]
103
         {
104
           { 6,1,8,8, 2,5,8,8 },
105
           { 8,1,3,8, 8,5,7,8 },
106
           { 8,8,3,4, 8,8,7,0 },
107
           { 6,8,8,4, 2,8,8,0 },
108
           { 6,1,3,4, 8,8,8,8 },
109
           { 8,8,8,8, 2,5,7,0 },
110

    
111
           { 6,8,8,8, 8,8,8,8 },
112
           { 1,8,8,8, 8,8,8,8 },
113
           { 3,8,8,8, 8,8,8,8 },
114
           { 4,8,8,8, 8,8,8,8 },
115
           { 2,8,8,8, 8,8,8,8 },
116
           { 5,8,8,8, 8,8,8,8 },
117
           { 7,8,8,8, 8,8,8,8 },
118
           { 0,8,8,8, 8,8,8,8 }
119
         };
120

    
121
  private static MeshBase mOctaMesh, mTetraMesh;
122

    
123
///////////////////////////////////////////////////////////////////////////////////////////////////
124

    
125
  TwistyDiamond(int size, Static4D quat, DistortedTexture texture,
126
                MeshSquare mesh, DistortedEffects effects, int[][] moves, Resources res, int scrWidth)
127
    {
128
    super(size, size, quat, texture, mesh, effects, moves, ObjectList.DIAM, res, scrWidth);
129
    }
130

    
131
///////////////////////////////////////////////////////////////////////////////////////////////////
132

    
133
  float getScreenRatio()
134
    {
135
    return 0.65f;
136
    }
137

    
138
///////////////////////////////////////////////////////////////////////////////////////////////////
139

    
140
  Static4D[] getQuats()
141
    {
142
    return QUATS;
143
    }
144

    
145
///////////////////////////////////////////////////////////////////////////////////////////////////
146

    
147
  int getNumFaces()
148
    {
149
    return FACE_COLORS.length;
150
    }
151

    
152
///////////////////////////////////////////////////////////////////////////////////////////////////
153

    
154
  boolean shouldResetTextureMaps()
155
    {
156
    return false;
157
    }
158

    
159
///////////////////////////////////////////////////////////////////////////////////////////////////
160

    
161
  int getNumStickerTypes(int numLayers)
162
    {
163
    return 1;
164
    }
165

    
166
///////////////////////////////////////////////////////////////////////////////////////////////////
167

    
168
  float[] getCuts(int size)
169
    {
170
    float[] cuts = new float[1];
171
    cuts[0] = 0.0f;
172
    return cuts;
173
    }
174

    
175
///////////////////////////////////////////////////////////////////////////////////////////////////
176

    
177
  int getNumCubitFaces()
178
    {
179
    return FACES_PER_CUBIT;
180
    }
181

    
182
///////////////////////////////////////////////////////////////////////////////////////////////////
183

    
184
  float[][] getCubitPositions(int size)
185
    {
186
    return CENTERS;
187
    }
188

    
189
///////////////////////////////////////////////////////////////////////////////////////////////////
190

    
191
  private Static4D getQuat(int cubit)
192
    {
193
    switch(cubit)
194
      {
195
      case  0:
196
      case  1:
197
      case  2:
198
      case  3:
199
      case  4:
200
      case  5:
201
      case  6: return QUATS[0];                          // unit quat
202
      case  7: return new Static4D(0,-SQ2/2,0,SQ2/2);    //  90 along Y
203
      case  8: return QUATS[1];                          // 180 along Y
204
      case  9: return new Static4D(0,+SQ2/2,0,SQ2/2);    //  90 along Y
205
      case 10: return new Static4D(0,     0,1,    0);    // 180 along Z
206
      case 11: return new Static4D(SQ2/2, 0,SQ2/2,0);    //
207
      case 12: return new Static4D(     1,0,0,    0);    // 180 along X
208
      case 13: return new Static4D(-SQ2/2,0,SQ2/2,0);    //
209
      }
210

    
211
    return null;
212
    }
213

    
214
///////////////////////////////////////////////////////////////////////////////////////////////////
215

    
216
  MeshBase createCubitMesh(int cubit, int numLayers)
217
    {
218
    MeshBase mesh;
219

    
220
    if( cubit<6 )
221
      {
222
      if( mOctaMesh==null ) mOctaMesh = FactoryCubit.getInstance().createOctaMesh();
223
      mesh = mOctaMesh.copy(true);
224
      }
225
    else
226
      {
227
      if( mTetraMesh==null ) mTetraMesh = FactoryCubit.getInstance().createTetraMesh();
228
      mesh = mTetraMesh.copy(true);
229
      }
230

    
231
    MatrixEffectQuaternion quat = new MatrixEffectQuaternion( getQuat(cubit), new Static3D(0,0,0) );
232
    mesh.apply(quat,0xffffffff,0);
233

    
234
    return mesh;
235
    }
236

    
237
///////////////////////////////////////////////////////////////////////////////////////////////////
238

    
239
  int getFaceColor(int cubit, int cubitface, int size)
240
    {
241
    return mFaceMap[cubit][cubitface];
242
    }
243

    
244
///////////////////////////////////////////////////////////////////////////////////////////////////
245

    
246
  void createFaceTexture(Canvas canvas, Paint paint, int face, int left, int top)
247
    {
248
    float E = 0.75f;
249
    float F = 0.50f;
250
    float R = 0.06f;
251
    float S = 0.07f;
252
    float[] vertices = { -F,-E/3, +F,-E/3, 0.0f,2*E/3};
253

    
254
    FactorySticker factory = FactorySticker.getInstance();
255
    factory.drawRoundedPolygon(canvas, paint, left, top, vertices, S, FACE_COLORS[face], R);
256
    }
257

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

    
260
  float returnMultiplier()
261
    {
262
    return 1.5f;
263
    }
264

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

    
267
  float[] getRowChances(int numLayers)
268
    {
269
    float[] chances = new float[2];
270

    
271
    chances[0] = 0.5f;
272
    chances[1] = 1.0f;
273

    
274
    return chances;
275
    }
276

    
277
///////////////////////////////////////////////////////////////////////////////////////////////////
278
// PUBLIC API
279

    
280
  public Static3D[] getRotationAxis()
281
    {
282
    return ROT_AXIS;
283
    }
284

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

    
287
  public int getBasicAngle()
288
    {
289
    return 3;
290
    }
291

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

    
294
  public void randomizeNewScramble(int[][] scramble, Random rnd, int num)
295
    {
296
    if( num==0 )
297
      {
298
      scramble[num][0] = rnd.nextInt(ROTATION_AXIS.length);
299
      }
300
    else
301
      {
302
      int newVector = rnd.nextInt(ROTATION_AXIS.length-1);
303
      scramble[num][0] = (newVector>=scramble[num-1][0] ? newVector+1 : newVector);
304
      }
305

    
306
    float rowFloat = rnd.nextFloat();
307

    
308
    for(int row=0; row<mRowChances.length; row++)
309
      {
310
      if( rowFloat<=mRowChances[row] )
311
        {
312
        scramble[num][1] = row;
313
        break;
314
        }
315
      }
316

    
317
    switch( rnd.nextInt(2) )
318
      {
319
      case 0: scramble[num][2] = -1; break;
320
      case 1: scramble[num][2] =  1; break;
321
      }
322
    }
323

    
324
///////////////////////////////////////////////////////////////////////////////////////////////////
325

    
326
  int mulQuat(int q1, int q2)
327
    {
328
    Static4D result = RubikSurfaceView.quatMultiply(QUATS[q1],QUATS[q2]);
329

    
330
    float rX = result.get0();
331
    float rY = result.get1();
332
    float rZ = result.get2();
333
    float rW = result.get3();
334

    
335
    final float MAX_ERROR = 0.1f;
336
    float dX,dY,dZ,dW;
337

    
338
    for(int i=0; i<QUATS.length; i++)
339
      {
340
      dX = QUATS[i].get0() - rX;
341
      dY = QUATS[i].get1() - rY;
342
      dZ = QUATS[i].get2() - rZ;
343
      dW = QUATS[i].get3() - rW;
344

    
345
      if( dX<MAX_ERROR && dX>-MAX_ERROR &&
346
          dY<MAX_ERROR && dY>-MAX_ERROR &&
347
          dZ<MAX_ERROR && dZ>-MAX_ERROR &&
348
          dW<MAX_ERROR && dW>-MAX_ERROR  ) return i;
349

    
350
      dX = QUATS[i].get0() + rX;
351
      dY = QUATS[i].get1() + rY;
352
      dZ = QUATS[i].get2() + rZ;
353
      dW = QUATS[i].get3() + rW;
354

    
355
      if( dX<MAX_ERROR && dX>-MAX_ERROR &&
356
          dY<MAX_ERROR && dY>-MAX_ERROR &&
357
          dZ<MAX_ERROR && dZ>-MAX_ERROR &&
358
          dW<MAX_ERROR && dW>-MAX_ERROR  ) return i;
359
      }
360

    
361
    return -1;
362
    }
363

    
364
///////////////////////////////////////////////////////////////////////////////////////////////////
365
// The Diamond is solved if and only if:
366
//
367
// 1) all 6 octahedrons are rotated with the same quat
368
// 2) the 8 tetrahedrons are rotated with the quat and, optionally, the can also be rotated
369
//    by multitudes of 120 degrees along the face they are the center of.
370
//
371
// so:
372
// 1) cubits 6,12: can also be QUAT 6,10
373
// 2) cubits 7,13: can also be QUAT 4,8
374
// 3) cubits 8,10: can also be QUAT 7,11
375
// 4) cubits 9,11: can also be QUAT 5,9
376

    
377
  public boolean isSolved()
378
    {
379
    int q = CUBITS[0].mQuatIndex;
380

    
381
    if ( CUBITS[ 1].mQuatIndex == q &&
382
         CUBITS[ 2].mQuatIndex == q &&
383
         CUBITS[ 3].mQuatIndex == q &&
384
         CUBITS[ 4].mQuatIndex == q &&
385
         CUBITS[ 5].mQuatIndex == q  )
386
      {
387
      int q1 = mulQuat(q,5);
388
      int q2 = mulQuat(q,9);
389

    
390
      if( CUBITS[ 9].mQuatIndex != q && CUBITS[ 9].mQuatIndex != q1 && CUBITS[ 9].mQuatIndex != q2 ) return false;
391
      if( CUBITS[11].mQuatIndex != q && CUBITS[11].mQuatIndex != q1 && CUBITS[11].mQuatIndex != q2 ) return false;
392

    
393
      q1 = mulQuat(q,4);
394
      q2 = mulQuat(q,8);
395

    
396
      if( CUBITS[ 7].mQuatIndex != q && CUBITS[ 7].mQuatIndex != q1 && CUBITS[ 7].mQuatIndex != q2 ) return false;
397
      if( CUBITS[13].mQuatIndex != q && CUBITS[13].mQuatIndex != q1 && CUBITS[13].mQuatIndex != q2 ) return false;
398

    
399
      q1 = mulQuat(q,6);
400
      q2 = mulQuat(q,10);
401

    
402
      if( CUBITS[ 6].mQuatIndex != q && CUBITS[ 6].mQuatIndex != q1 && CUBITS[ 6].mQuatIndex != q2 ) return false;
403
      if( CUBITS[12].mQuatIndex != q && CUBITS[12].mQuatIndex != q1 && CUBITS[12].mQuatIndex != q2 ) return false;
404

    
405
      q1 = mulQuat(q,7);
406
      q2 = mulQuat(q,11);
407

    
408
      if( CUBITS[ 8].mQuatIndex != q && CUBITS[ 8].mQuatIndex != q1 && CUBITS[ 8].mQuatIndex != q2 ) return false;
409
      if( CUBITS[10].mQuatIndex != q && CUBITS[10].mQuatIndex != q1 && CUBITS[10].mQuatIndex != q2 ) return false;
410

    
411
      return true;
412
      }
413

    
414
    return false;
415
    }
416

    
417
///////////////////////////////////////////////////////////////////////////////////////////////////
418
// only needed for solvers - there are no Diamond solvers ATM
419

    
420
  public String retObjectString()
421
    {
422
    return "";
423
    }
424

    
425
///////////////////////////////////////////////////////////////////////////////////////////////////
426

    
427
  public int getObjectName(int numLayers)
428
    {
429
    return R.string.diam2;
430
    }
431

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

    
434
  public int getInventor(int numLayers)
435
    {
436
    return R.string.diam2_inventor;
437
    }
438

    
439
///////////////////////////////////////////////////////////////////////////////////////////////////
440

    
441
  public int getComplexity(int numLayers)
442
    {
443
    return 5;
444
    }
445
}
(22-22/35)