Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / TwistyDiamond.java @ a64e07d0

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
import static org.distorted.effects.scramble.ScrambleEffect.START_AXIS;
39

    
40
///////////////////////////////////////////////////////////////////////////////////////////////////
41

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

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

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

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

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

    
81
  private static final float DIST = 0.50f;
82

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

    
93
           new Static3D(    0, DIST*SQ2/2, DIST ),
94
           new Static3D( DIST, DIST*SQ2/2,    0 ),
95
           new Static3D(    0, DIST*SQ2/2,-DIST ),
96
           new Static3D(-DIST, DIST*SQ2/2,    0 ),
97
           new Static3D(    0,-DIST*SQ2/2, DIST ),
98
           new Static3D( DIST,-DIST*SQ2/2,    0 ),
99
           new Static3D(    0,-DIST*SQ2/2,-DIST ),
100
           new Static3D(-DIST,-DIST*SQ2/2,    0 )
101
         };
102

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

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

    
123
  private static MeshBase mOctaMesh, mTetraMesh;
124

    
125
///////////////////////////////////////////////////////////////////////////////////////////////////
126

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

    
133
///////////////////////////////////////////////////////////////////////////////////////////////////
134

    
135
  float getScreenRatio()
136
    {
137
    return 0.65f;
138
    }
139

    
140
///////////////////////////////////////////////////////////////////////////////////////////////////
141

    
142
  Static4D[] getQuats()
143
    {
144
    return QUATS;
145
    }
146

    
147
///////////////////////////////////////////////////////////////////////////////////////////////////
148

    
149
  int getNumFaces()
150
    {
151
    return FACE_COLORS.length;
152
    }
153

    
154
///////////////////////////////////////////////////////////////////////////////////////////////////
155

    
156
  boolean shouldResetTextureMaps()
157
    {
158
    return false;
159
    }
160

    
161
///////////////////////////////////////////////////////////////////////////////////////////////////
162

    
163
  int getNumStickerTypes(int numLayers)
164
    {
165
    return 1;
166
    }
167

    
168
///////////////////////////////////////////////////////////////////////////////////////////////////
169

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

    
177
///////////////////////////////////////////////////////////////////////////////////////////////////
178

    
179
  int getNumCubitFaces()
180
    {
181
    return FACES_PER_CUBIT;
182
    }
183

    
184
///////////////////////////////////////////////////////////////////////////////////////////////////
185

    
186
  Static3D[] getCubitPositions(int size)
187
    {
188
    return CENTERS;
189
    }
190

    
191
///////////////////////////////////////////////////////////////////////////////////////////////////
192

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

    
213
    return null;
214
    }
215

    
216
///////////////////////////////////////////////////////////////////////////////////////////////////
217

    
218
  MeshBase createCubitMesh(int cubit, int numLayers)
219
    {
220
    MeshBase mesh;
221

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

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

    
236
    return mesh;
237
    }
238

    
239
///////////////////////////////////////////////////////////////////////////////////////////////////
240

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

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

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

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

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

    
262
  float returnMultiplier()
263
    {
264
    return 1.5f;
265
    }
266

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

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

    
273
    chances[0] = 0.5f;
274
    chances[1] = 1.0f;
275

    
276
    return chances;
277
    }
278

    
279
///////////////////////////////////////////////////////////////////////////////////////////////////
280
// PUBLIC API
281

    
282
  public Static3D[] getRotationAxis()
283
    {
284
    return ROT_AXIS;
285
    }
286

    
287
///////////////////////////////////////////////////////////////////////////////////////////////////
288

    
289
  public int getBasicAngle()
290
    {
291
    return 3;
292
    }
293

    
294
///////////////////////////////////////////////////////////////////////////////////////////////////
295

    
296
  public int randomizeNewRotAxis(Random rnd, int oldRotAxis)
297
    {
298
    int numAxis = ROTATION_AXIS.length;
299

    
300
    if( oldRotAxis == START_AXIS )
301
      {
302
      return rnd.nextInt(numAxis);
303
      }
304
    else
305
      {
306
      int newVector = rnd.nextInt(numAxis-1);
307
      return (newVector>=oldRotAxis ? newVector+1 : newVector);
308
      }
309
    }
310

    
311
///////////////////////////////////////////////////////////////////////////////////////////////////
312

    
313
  public int randomizeNewRow(Random rnd, int oldRotAxis, int oldRow, int newRotAxis)
314
    {
315
    float rowFloat = rnd.nextFloat();
316

    
317
    for(int row=0; row<mRowChances.length; row++)
318
      {
319
      if( rowFloat<=mRowChances[row] ) return row;
320
      }
321

    
322
    return 0;
323
    }
324

    
325
///////////////////////////////////////////////////////////////////////////////////////////////////
326

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

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

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

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

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

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

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

    
362
    return -1;
363
    }
364

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

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

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

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

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

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

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

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

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

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

    
412
      return true;
413
      }
414

    
415
    return false;
416
    }
417

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

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

    
426
///////////////////////////////////////////////////////////////////////////////////////////////////
427

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

    
433
///////////////////////////////////////////////////////////////////////////////////////////////////
434

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

    
440
///////////////////////////////////////////////////////////////////////////////////////////////////
441

    
442
  public int getComplexity(int numLayers)
443
    {
444
    return 5;
445
    }
446
}
(17-17/30)