Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / TwistyIvy.java @ 749ef882

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

    
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
  float[][] 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 float[][] CENTERS = new float[10][];
165

    
166
    CENTERS[0] = new float[] { DIST_CORNER, DIST_CORNER, DIST_CORNER };
167
    CENTERS[1] = new float[] {-DIST_CORNER, DIST_CORNER,-DIST_CORNER };
168
    CENTERS[2] = new float[] {-DIST_CORNER,-DIST_CORNER, DIST_CORNER };
169
    CENTERS[3] = new float[] { DIST_CORNER,-DIST_CORNER,-DIST_CORNER };
170
    CENTERS[4] = new float[] { DIST_CENTER,           0,           0 };
171
    CENTERS[5] = new float[] {-DIST_CENTER,           0,           0 };
172
    CENTERS[6] = new float[] {           0, DIST_CENTER,           0 };
173
    CENTERS[7] = new float[] {           0,-DIST_CENTER,           0 };
174
    CENTERS[8] = new float[] {           0,           0, DIST_CENTER };
175
    CENTERS[9] = new float[] {           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 void randomizeNewScramble(int[][] scramble, Random rnd, int num)
287
    {
288
    if( num==0 )
289
      {
290
      scramble[num][0] = rnd.nextInt(ROTATION_AXIS.length);
291
      }
292
    else
293
      {
294
      int newVector = rnd.nextInt(ROTATION_AXIS.length-1);
295
      scramble[num][0] = (newVector>=scramble[num-1][0] ? newVector+1 : newVector);
296
      }
297

    
298
    float rowFloat = rnd.nextFloat();
299

    
300
    for(int row=0; row<mRowChances.length; row++)
301
      {
302
      if( rowFloat<=mRowChances[row] )
303
        {
304
        scramble[num][1] = row;
305
        break;
306
        }
307
      }
308

    
309
    switch( rnd.nextInt(2) )
310
      {
311
      case 0: scramble[num][2] = -1; break;
312
      case 1: scramble[num][2] =  1; break;
313
      }
314
    }
315

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

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

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

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

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

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

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

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

    
354
    return -1;
355
    }
356

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

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

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

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

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

    
389
      return true;
390
      }
391

    
392
    return false;
393
    }
394

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

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

    
403
///////////////////////////////////////////////////////////////////////////////////////////////////
404

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

    
410
///////////////////////////////////////////////////////////////////////////////////////////////////
411

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

    
417
///////////////////////////////////////////////////////////////////////////////////////////////////
418

    
419
  public int getComplexity(int numLayers)
420
    {
421
    return 1;
422
    }
423
}
(25-25/33)