Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / TwistyIvy.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 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, 60, quat, texture, mesh, effects, moves, ObjectList.IVY, res, scrWidth);
103
    }
104

    
105
///////////////////////////////////////////////////////////////////////////////////////////////////
106

    
107
  float getScreenRatio()
108
    {
109
    return 1.0f;
110
    }
111

    
112
///////////////////////////////////////////////////////////////////////////////////////////////////
113

    
114
  Static4D[] getQuats()
115
    {
116
    return QUATS;
117
    }
118

    
119
///////////////////////////////////////////////////////////////////////////////////////////////////
120

    
121
  int getNumFaces()
122
    {
123
    return FACE_COLORS.length;
124
    }
125

    
126
///////////////////////////////////////////////////////////////////////////////////////////////////
127

    
128
  boolean shouldResetTextureMaps()
129
    {
130
    return false;
131
    }
132

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

    
135
  int getNumStickerTypes(int numLayers)
136
    {
137
    return 2;
138
    }
139

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

    
142
  float[] getCuts(int numLayers)
143
    {
144
    float[] cuts = new float[1];
145
    cuts[0] = 0.0f;
146

    
147
    return cuts;
148
    }
149

    
150
///////////////////////////////////////////////////////////////////////////////////////////////////
151

    
152
  int getNumCubitFaces()
153
    {
154
    return FACES_PER_CUBIT;
155
    }
156

    
157
///////////////////////////////////////////////////////////////////////////////////////////////////
158

    
159
  Static3D[] getCubitPositions(int numLayers)
160
    {
161
    final float DIST_CORNER = (numLayers-1)*0.50f;
162
    final float DIST_CENTER = (numLayers-1)*0.50f;
163

    
164
    final Static3D[] CENTERS = new Static3D[10];
165

    
166
    CENTERS[0] = new Static3D( DIST_CORNER, DIST_CORNER, DIST_CORNER );
167
    CENTERS[1] = new Static3D(-DIST_CORNER, DIST_CORNER,-DIST_CORNER );
168
    CENTERS[2] = new Static3D(-DIST_CORNER,-DIST_CORNER, DIST_CORNER );
169
    CENTERS[3] = new Static3D( DIST_CORNER,-DIST_CORNER,-DIST_CORNER );
170
    CENTERS[4] = new Static3D( DIST_CENTER,           0,           0 );
171
    CENTERS[5] = new Static3D(-DIST_CENTER,           0,           0 );
172
    CENTERS[6] = new Static3D(           0, DIST_CENTER,           0 );
173
    CENTERS[7] = new Static3D(           0,-DIST_CENTER,           0 );
174
    CENTERS[8] = new Static3D(           0,           0, DIST_CENTER );
175
    CENTERS[9] = new Static3D(           0,           0,-DIST_CENTER );
176

    
177
    return CENTERS;
178
    }
179

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

    
182
  private int getQuat(int cubit)
183
    {
184
    switch(cubit)
185
      {
186
      case  0: return 0;
187
      case  1: return 2;
188
      case  2: return 3;
189
      case  3: return 1;
190

    
191
      case  4: return 8;
192
      case  5: return 11;
193
      case  6: return 10;
194
      case  7: return 9;
195
      case  8: return 0;
196
      case  9: return 2;
197
      }
198

    
199
    return 0;
200
    }
201

    
202
///////////////////////////////////////////////////////////////////////////////////////////////////
203

    
204
  MeshBase createCubitMesh(int cubit, int numLayers)
205
    {
206
    MeshBase mesh;
207

    
208
    if( cubit<4 )
209
      {
210
      if( mCornerMesh==null ) mCornerMesh = FactoryCubit.getInstance().createIvyCornerMesh();
211
      mesh = mCornerMesh.copy(true);
212
      }
213
    else
214
      {
215
      if( mFaceMesh==null ) mFaceMesh = FactoryCubit.getInstance().createIvyFaceMesh();
216
      mesh = mFaceMesh.copy(true);
217
      }
218

    
219
    MatrixEffectQuaternion quat = new MatrixEffectQuaternion( QUATS[getQuat(cubit)], new Static3D(0,0,0) );
220
    mesh.apply(quat,0xffffffff,0);
221

    
222
    return mesh;
223
    }
224

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

    
227
  int getFaceColor(int cubit, int cubitface, int numLayers)
228
    {
229
    return mFaceMap[cubit][cubitface];
230
    }
231

    
232
///////////////////////////////////////////////////////////////////////////////////////////////////
233

    
234
  void createFaceTexture(Canvas canvas, Paint paint, int face, int left, int top)
235
    {
236
    int COLORS = FACE_COLORS.length;
237
    FactorySticker factory = FactorySticker.getInstance();
238
    float S = 0.08f;
239
    float R = 0.12f;
240

    
241
    if( face<COLORS )
242
      {
243
      factory.drawIvyCornerSticker(canvas, paint, left, top, FACE_COLORS[face%COLORS], S, R);
244
      }
245
    else
246
      {
247
      factory.drawIvyCenterSticker(canvas, paint, left, top, FACE_COLORS[face%COLORS], S, R);
248
      }
249
    }
250

    
251
///////////////////////////////////////////////////////////////////////////////////////////////////
252

    
253
  float returnMultiplier()
254
    {
255
    return 2.0f;
256
    }
257

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

    
260
  float[] getRowChances(int numLayers)
261
    {
262
    float[] chances = new float[2];
263
    chances[0] = 0.5f;
264
    chances[1] = 1.0f;
265

    
266
    return chances;
267
    }
268

    
269
///////////////////////////////////////////////////////////////////////////////////////////////////
270
// PUBLIC API
271

    
272
  public Static3D[] getRotationAxis()
273
    {
274
    return ROT_AXIS;
275
    }
276

    
277
///////////////////////////////////////////////////////////////////////////////////////////////////
278

    
279
  public int getBasicAngle()
280
    {
281
    return 3;
282
    }
283

    
284
///////////////////////////////////////////////////////////////////////////////////////////////////
285

    
286
  public int randomizeNewRotAxis(Random rnd, int oldRotAxis)
287
    {
288
    int numAxis = ROTATION_AXIS.length;
289

    
290
    if( oldRotAxis == START_AXIS )
291
      {
292
      return rnd.nextInt(numAxis);
293
      }
294
    else
295
      {
296
      int newVector = rnd.nextInt(numAxis-1);
297
      return (newVector>=oldRotAxis ? newVector+1 : newVector);
298
      }
299
    }
300

    
301
///////////////////////////////////////////////////////////////////////////////////////////////////
302

    
303
  public int randomizeNewRow(Random rnd, int oldRotAxis, int oldRow, int newRotAxis)
304
    {
305
    float rowFloat = rnd.nextFloat();
306

    
307
    for(int row=0; row<mRowChances.length; row++)
308
      {
309
      if( rowFloat<=mRowChances[row] ) return row;
310
      }
311

    
312
    return 0;
313
    }
314

    
315
///////////////////////////////////////////////////////////////////////////////////////////////////
316
// remember about the double cover or unit quaternions!
317

    
318
  private int mulQuat(int q1, int q2)
319
    {
320
    Static4D result = RubikSurfaceView.quatMultiply(QUATS[q1],QUATS[q2]);
321

    
322
    float rX = result.get0();
323
    float rY = result.get1();
324
    float rZ = result.get2();
325
    float rW = result.get3();
326

    
327
    final float MAX_ERROR = 0.1f;
328
    float dX,dY,dZ,dW;
329

    
330
    for(int i=0; i<QUATS.length; i++)
331
      {
332
      dX = QUATS[i].get0() - rX;
333
      dY = QUATS[i].get1() - rY;
334
      dZ = QUATS[i].get2() - rZ;
335
      dW = QUATS[i].get3() - rW;
336

    
337
      if( dX<MAX_ERROR && dX>-MAX_ERROR &&
338
          dY<MAX_ERROR && dY>-MAX_ERROR &&
339
          dZ<MAX_ERROR && dZ>-MAX_ERROR &&
340
          dW<MAX_ERROR && dW>-MAX_ERROR  ) return i;
341

    
342
      dX = QUATS[i].get0() + rX;
343
      dY = QUATS[i].get1() + rY;
344
      dZ = QUATS[i].get2() + rZ;
345
      dW = QUATS[i].get3() + rW;
346

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

    
353
    return -1;
354
    }
355

    
356
///////////////////////////////////////////////////////////////////////////////////////////////////
357
// The Ivy is solved if and only if:
358
//
359
// 1) all 4 of its corner cubits are rotated with the same quat
360
// 2) all its face cubits are rotated with the same quat like the corner ones,
361
//    and optionally they also might be upside down.
362
//
363
// i.e.
364
// cubits [4] and [5] - might be extra QUAT[1]
365
// cubits [6] and [7] - might be extra QUAT[2]
366
// cubits [8] and [9] - might be extra QUAT[3]
367

    
368
  public boolean isSolved()
369
    {
370
    int q1,q = CUBITS[0].mQuatIndex;
371

    
372
    if( CUBITS[1].mQuatIndex == q &&
373
        CUBITS[2].mQuatIndex == q &&
374
        CUBITS[3].mQuatIndex == q  )
375
      {
376
      q1 = mulQuat(q,1);
377
      if( CUBITS[4].mQuatIndex != q && CUBITS[4].mQuatIndex != q1 ) return false;
378
      if( CUBITS[5].mQuatIndex != q && CUBITS[5].mQuatIndex != q1 ) return false;
379

    
380
      q1 = mulQuat(q,2);
381
      if( CUBITS[6].mQuatIndex != q && CUBITS[6].mQuatIndex != q1 ) return false;
382
      if( CUBITS[7].mQuatIndex != q && CUBITS[7].mQuatIndex != q1 ) return false;
383

    
384
      q1 = mulQuat(q,3);
385
      if( CUBITS[8].mQuatIndex != q && CUBITS[8].mQuatIndex != q1 ) return false;
386
      if( CUBITS[9].mQuatIndex != q && CUBITS[9].mQuatIndex != q1 ) return false;
387

    
388
      return true;
389
      }
390

    
391
    return false;
392
    }
393

    
394
///////////////////////////////////////////////////////////////////////////////////////////////////
395
// only needed for solvers - there are no Ivy solvers ATM)
396

    
397
  public String retObjectString()
398
    {
399
    return "";
400
    }
401

    
402
///////////////////////////////////////////////////////////////////////////////////////////////////
403

    
404
  public int getObjectName(int numLayers)
405
    {
406
    return R.string.ivy2;
407
    }
408

    
409
///////////////////////////////////////////////////////////////////////////////////////////////////
410

    
411
  public int getInventor(int numLayers)
412
    {
413
    return R.string.ivy2_inventor;
414
    }
415

    
416
///////////////////////////////////////////////////////////////////////////////////////////////////
417

    
418
  public int getComplexity(int numLayers)
419
    {
420
    return 1;
421
    }
422
}
(22-22/30)