Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / TwistyIvy.java @ b3c9061a

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.helpers.FactoryCubit;
27
import org.distorted.helpers.FactorySticker;
28
import org.distorted.library.effect.MatrixEffectQuaternion;
29
import org.distorted.library.main.DistortedEffects;
30
import org.distorted.library.main.DistortedTexture;
31
import org.distorted.library.mesh.MeshBase;
32
import org.distorted.library.mesh.MeshSquare;
33
import org.distorted.library.type.Static3D;
34
import org.distorted.library.type.Static4D;
35
import org.distorted.main.R;
36
import org.distorted.main.RubikSurfaceView;
37

    
38
import java.util.Random;
39

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

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

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

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

    
62
  // All legal rotation quats of a RubikIvy
63
  private static final Static4D[] QUATS = new Static4D[]
64
         {
65
           new Static4D(  0.0f,  0.0f,  0.0f,  1.0f ),
66
           new Static4D(  1.0f,  0.0f,  0.0f,  0.0f ),
67
           new Static4D(  0.0f,  1.0f,  0.0f,  0.0f ),
68
           new Static4D(  0.0f,  0.0f,  1.0f,  0.0f ),
69

    
70
           new Static4D(  0.5f,  0.5f,  0.5f,  0.5f ),
71
           new Static4D(  0.5f,  0.5f,  0.5f, -0.5f ),
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
         };
79

    
80
  private static final int[][] mFaceMap =
81
         {
82
           {  4, 2, 0, 12,12,12 },
83
           {  5, 2, 1, 12,12,12 },
84
           {  4, 3, 1, 12,12,12 },
85
           {  5, 3, 0, 12,12,12 },
86

    
87
           {  6, 12,12,12,12,12 },
88
           {  7, 12,12,12,12,12 },
89
           {  8, 12,12,12,12,12 },
90
           {  9, 12,12,12,12,12 },
91
           { 10, 12,12,12,12,12 },
92
           { 11, 12,12,12,12,12 },
93
         };
94

    
95
  private static MeshBase mCornerMesh, mFaceMesh;
96

    
97
///////////////////////////////////////////////////////////////////////////////////////////////////
98

    
99
  TwistyIvy(int size, Static4D quat, DistortedTexture texture,
100
            MeshSquare mesh, DistortedEffects effects, int[][] moves, Resources res, int scrWidth)
101
    {
102
    super(size, size, quat, texture, mesh, effects, moves, ObjectList.IVY, res, scrWidth);
103
    }
104

    
105
///////////////////////////////////////////////////////////////////////////////////////////////////
106
// don't use this
107

    
108
  double[][] getVertices(int cubitType)
109
    {
110
    return null;
111
    }
112

    
113
///////////////////////////////////////////////////////////////////////////////////////////////////
114
// don't use this
115

    
116
  int[][] getVertIndexes(int cubitType)
117
    {
118
    return null;
119
    }
120

    
121
///////////////////////////////////////////////////////////////////////////////////////////////////
122

    
123
  int getNumCubitTypes(int numLayers)
124
    {
125
    return 2;
126
    }
127

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

    
130
  float getScreenRatio()
131
    {
132
    return 1.0f;
133
    }
134

    
135
///////////////////////////////////////////////////////////////////////////////////////////////////
136

    
137
  Static4D[] getQuats()
138
    {
139
    return QUATS;
140
    }
141

    
142
///////////////////////////////////////////////////////////////////////////////////////////////////
143

    
144
  int getNumFaces()
145
    {
146
    return FACE_COLORS.length;
147
    }
148

    
149
///////////////////////////////////////////////////////////////////////////////////////////////////
150

    
151
  boolean shouldResetTextureMaps()
152
    {
153
    return false;
154
    }
155

    
156
///////////////////////////////////////////////////////////////////////////////////////////////////
157

    
158
  int getNumStickerTypes(int numLayers)
159
    {
160
    return 2;
161
    }
162

    
163
///////////////////////////////////////////////////////////////////////////////////////////////////
164

    
165
  float[] getCuts(int numLayers)
166
    {
167
    float[] cuts = new float[1];
168
    cuts[0] = 0.0f;
169

    
170
    return cuts;
171
    }
172

    
173
///////////////////////////////////////////////////////////////////////////////////////////////////
174

    
175
  int getNumCubitFaces()
176
    {
177
    return FACES_PER_CUBIT;
178
    }
179

    
180
///////////////////////////////////////////////////////////////////////////////////////////////////
181

    
182
  float[][] getCubitPositions(int numLayers)
183
    {
184
    final float DIST_CORNER = (numLayers-1)*0.50f;
185
    final float DIST_CENTER = (numLayers-1)*0.50f;
186

    
187
    final float[][] CENTERS = new float[10][];
188

    
189
    CENTERS[0] = new float[] { DIST_CORNER, DIST_CORNER, DIST_CORNER };
190
    CENTERS[1] = new float[] {-DIST_CORNER, DIST_CORNER,-DIST_CORNER };
191
    CENTERS[2] = new float[] {-DIST_CORNER,-DIST_CORNER, DIST_CORNER };
192
    CENTERS[3] = new float[] { DIST_CORNER,-DIST_CORNER,-DIST_CORNER };
193
    CENTERS[4] = new float[] { DIST_CENTER,           0,           0 };
194
    CENTERS[5] = new float[] {-DIST_CENTER,           0,           0 };
195
    CENTERS[6] = new float[] {           0, DIST_CENTER,           0 };
196
    CENTERS[7] = new float[] {           0,-DIST_CENTER,           0 };
197
    CENTERS[8] = new float[] {           0,           0, DIST_CENTER };
198
    CENTERS[9] = new float[] {           0,           0,-DIST_CENTER };
199

    
200
    return CENTERS;
201
    }
202

    
203
///////////////////////////////////////////////////////////////////////////////////////////////////
204

    
205
  private int getQuat(int cubit)
206
    {
207
    switch(cubit)
208
      {
209
      case  0: return 0;
210
      case  1: return 2;
211
      case  2: return 3;
212
      case  3: return 1;
213

    
214
      case  4: return 8;
215
      case  5: return 11;
216
      case  6: return 10;
217
      case  7: return 9;
218
      case  8: return 0;
219
      case  9: return 2;
220
      }
221

    
222
    return 0;
223
    }
224

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

    
227
  MeshBase createCubitMesh(int cubit, int numLayers)
228
    {
229
    MeshBase mesh;
230

    
231
    if( cubit<4 )
232
      {
233
      if( mCornerMesh==null ) mCornerMesh = FactoryCubit.getInstance().createIvyCornerMesh();
234
      mesh = mCornerMesh.copy(true);
235
      }
236
    else
237
      {
238
      if( mFaceMesh==null ) mFaceMesh = FactoryCubit.getInstance().createIvyFaceMesh();
239
      mesh = mFaceMesh.copy(true);
240
      }
241

    
242
    MatrixEffectQuaternion quat = new MatrixEffectQuaternion( QUATS[getQuat(cubit)], new Static3D(0,0,0) );
243
    mesh.apply(quat,0xffffffff,0);
244

    
245
    return mesh;
246
    }
247

    
248
///////////////////////////////////////////////////////////////////////////////////////////////////
249

    
250
  int getFaceColor(int cubit, int cubitface, int numLayers)
251
    {
252
    return mFaceMap[cubit][cubitface];
253
    }
254

    
255
///////////////////////////////////////////////////////////////////////////////////////////////////
256

    
257
  void createFaceTexture(Canvas canvas, Paint paint, int face, int left, int top)
258
    {
259
    int COLORS = FACE_COLORS.length;
260
    FactorySticker factory = FactorySticker.getInstance();
261
    float S = 0.08f;
262
    float R = 0.12f;
263

    
264
    if( face<COLORS )
265
      {
266
      factory.drawIvyCornerSticker(canvas, paint, left, top, FACE_COLORS[face%COLORS], S, R);
267
      }
268
    else
269
      {
270
      factory.drawIvyCenterSticker(canvas, paint, left, top, FACE_COLORS[face%COLORS], S, R);
271
      }
272
    }
273

    
274
///////////////////////////////////////////////////////////////////////////////////////////////////
275

    
276
  float returnMultiplier()
277
    {
278
    return 2.0f;
279
    }
280

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

    
283
  float[] getRowChances(int numLayers)
284
    {
285
    float[] chances = new float[2];
286
    chances[0] = 0.5f;
287
    chances[1] = 1.0f;
288

    
289
    return chances;
290
    }
291

    
292
///////////////////////////////////////////////////////////////////////////////////////////////////
293
// PUBLIC API
294

    
295
  public Static3D[] getRotationAxis()
296
    {
297
    return ROT_AXIS;
298
    }
299

    
300
///////////////////////////////////////////////////////////////////////////////////////////////////
301

    
302
  public int getBasicAngle()
303
    {
304
    return 3;
305
    }
306

    
307
///////////////////////////////////////////////////////////////////////////////////////////////////
308

    
309
  public void randomizeNewScramble(int[][] scramble, Random rnd, int num)
310
    {
311
    if( num==0 )
312
      {
313
      scramble[num][0] = rnd.nextInt(ROTATION_AXIS.length);
314
      }
315
    else
316
      {
317
      int newVector = rnd.nextInt(ROTATION_AXIS.length-1);
318
      scramble[num][0] = (newVector>=scramble[num-1][0] ? newVector+1 : newVector);
319
      }
320

    
321
    float rowFloat = rnd.nextFloat();
322

    
323
    for(int row=0; row<mRowChances.length; row++)
324
      {
325
      if( rowFloat<=mRowChances[row] )
326
        {
327
        scramble[num][1] = row;
328
        break;
329
        }
330
      }
331

    
332
    switch( rnd.nextInt(2) )
333
      {
334
      case 0: scramble[num][2] = -1; break;
335
      case 1: scramble[num][2] =  1; break;
336
      }
337
    }
338

    
339
///////////////////////////////////////////////////////////////////////////////////////////////////
340
// remember about the double cover or unit quaternions!
341

    
342
  private int mulQuat(int q1, int q2)
343
    {
344
    Static4D result = RubikSurfaceView.quatMultiply(QUATS[q1],QUATS[q2]);
345

    
346
    float rX = result.get0();
347
    float rY = result.get1();
348
    float rZ = result.get2();
349
    float rW = result.get3();
350

    
351
    final float MAX_ERROR = 0.1f;
352
    float dX,dY,dZ,dW;
353

    
354
    for(int i=0; i<QUATS.length; i++)
355
      {
356
      dX = QUATS[i].get0() - rX;
357
      dY = QUATS[i].get1() - rY;
358
      dZ = QUATS[i].get2() - rZ;
359
      dW = QUATS[i].get3() - rW;
360

    
361
      if( dX<MAX_ERROR && dX>-MAX_ERROR &&
362
          dY<MAX_ERROR && dY>-MAX_ERROR &&
363
          dZ<MAX_ERROR && dZ>-MAX_ERROR &&
364
          dW<MAX_ERROR && dW>-MAX_ERROR  ) return i;
365

    
366
      dX = QUATS[i].get0() + rX;
367
      dY = QUATS[i].get1() + rY;
368
      dZ = QUATS[i].get2() + rZ;
369
      dW = QUATS[i].get3() + rW;
370

    
371
      if( dX<MAX_ERROR && dX>-MAX_ERROR &&
372
          dY<MAX_ERROR && dY>-MAX_ERROR &&
373
          dZ<MAX_ERROR && dZ>-MAX_ERROR &&
374
          dW<MAX_ERROR && dW>-MAX_ERROR  ) return i;
375
      }
376

    
377
    return -1;
378
    }
379

    
380
///////////////////////////////////////////////////////////////////////////////////////////////////
381
// The Ivy is solved if and only if:
382
//
383
// 1) all 4 of its corner cubits are rotated with the same quat
384
// 2) all its face cubits are rotated with the same quat like the corner ones,
385
//    and optionally they also might be upside down.
386
//
387
// i.e.
388
// cubits [4] and [5] - might be extra QUAT[1]
389
// cubits [6] and [7] - might be extra QUAT[2]
390
// cubits [8] and [9] - might be extra QUAT[3]
391

    
392
  public boolean isSolved()
393
    {
394
    int q1,q = CUBITS[0].mQuatIndex;
395

    
396
    if( CUBITS[1].mQuatIndex == q &&
397
        CUBITS[2].mQuatIndex == q &&
398
        CUBITS[3].mQuatIndex == q  )
399
      {
400
      q1 = mulQuat(q,1);
401
      if( CUBITS[4].mQuatIndex != q && CUBITS[4].mQuatIndex != q1 ) return false;
402
      if( CUBITS[5].mQuatIndex != q && CUBITS[5].mQuatIndex != q1 ) return false;
403

    
404
      q1 = mulQuat(q,2);
405
      if( CUBITS[6].mQuatIndex != q && CUBITS[6].mQuatIndex != q1 ) return false;
406
      if( CUBITS[7].mQuatIndex != q && CUBITS[7].mQuatIndex != q1 ) return false;
407

    
408
      q1 = mulQuat(q,3);
409
      if( CUBITS[8].mQuatIndex != q && CUBITS[8].mQuatIndex != q1 ) return false;
410
      if( CUBITS[9].mQuatIndex != q && CUBITS[9].mQuatIndex != q1 ) return false;
411

    
412
      return true;
413
      }
414

    
415
    return false;
416
    }
417

    
418
///////////////////////////////////////////////////////////////////////////////////////////////////
419
// only needed for solvers - there are no Ivy 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.ivy2;
431
    }
432

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

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

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

    
442
  public int getComplexity(int numLayers)
443
    {
444
    return 1;
445
    }
446
}
(25-25/33)