Project

General

Profile

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

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

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 TwistyIvy extends TwistyObject
41
{
42
  private static final int FACES_PER_CUBIT =6;
43

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

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

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

    
68
           new Static4D(  0.5f,  0.5f,  0.5f,  0.5f ),
69
           new Static4D(  0.5f,  0.5f,  0.5f, -0.5f ),
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
         };
77

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

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

    
93
  private static MeshBase mCornerMesh, mFaceMesh;
94

    
95
///////////////////////////////////////////////////////////////////////////////////////////////////
96

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

    
103
///////////////////////////////////////////////////////////////////////////////////////////////////
104

    
105
  float getScreenRatio()
106
    {
107
    return 1.0f;
108
    }
109

    
110
///////////////////////////////////////////////////////////////////////////////////////////////////
111

    
112
  Static4D[] getQuats()
113
    {
114
    return QUATS;
115
    }
116

    
117
///////////////////////////////////////////////////////////////////////////////////////////////////
118

    
119
  int getNumFaces()
120
    {
121
    return FACE_COLORS.length;
122
    }
123

    
124
///////////////////////////////////////////////////////////////////////////////////////////////////
125

    
126
  boolean shouldResetTextureMaps()
127
    {
128
    return false;
129
    }
130

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

    
133
  int getNumStickerTypes(int numLayers)
134
    {
135
    return 2;
136
    }
137

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

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

    
145
    return cuts;
146
    }
147

    
148
///////////////////////////////////////////////////////////////////////////////////////////////////
149

    
150
  int getNumCubitFaces()
151
    {
152
    return FACES_PER_CUBIT;
153
    }
154

    
155
///////////////////////////////////////////////////////////////////////////////////////////////////
156

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

    
162
    final float[][] CENTERS = new float[10][];
163

    
164
    CENTERS[0] = new float[] { DIST_CORNER, DIST_CORNER, DIST_CORNER };
165
    CENTERS[1] = new float[] {-DIST_CORNER, DIST_CORNER,-DIST_CORNER };
166
    CENTERS[2] = new float[] {-DIST_CORNER,-DIST_CORNER, DIST_CORNER };
167
    CENTERS[3] = new float[] { DIST_CORNER,-DIST_CORNER,-DIST_CORNER };
168
    CENTERS[4] = new float[] { DIST_CENTER,           0,           0 };
169
    CENTERS[5] = new float[] {-DIST_CENTER,           0,           0 };
170
    CENTERS[6] = new float[] {           0, DIST_CENTER,           0 };
171
    CENTERS[7] = new float[] {           0,-DIST_CENTER,           0 };
172
    CENTERS[8] = new float[] {           0,           0, DIST_CENTER };
173
    CENTERS[9] = new float[] {           0,           0,-DIST_CENTER };
174

    
175
    return CENTERS;
176
    }
177

    
178
///////////////////////////////////////////////////////////////////////////////////////////////////
179

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

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

    
197
    return 0;
198
    }
199

    
200
///////////////////////////////////////////////////////////////////////////////////////////////////
201

    
202
  MeshBase createCubitMesh(int cubit, int numLayers)
203
    {
204
    MeshBase mesh;
205

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

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

    
220
    return mesh;
221
    }
222

    
223
///////////////////////////////////////////////////////////////////////////////////////////////////
224

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

    
230
///////////////////////////////////////////////////////////////////////////////////////////////////
231

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

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

    
249
///////////////////////////////////////////////////////////////////////////////////////////////////
250

    
251
  float returnMultiplier()
252
    {
253
    return 2.0f;
254
    }
255

    
256
///////////////////////////////////////////////////////////////////////////////////////////////////
257

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

    
264
    return chances;
265
    }
266

    
267
///////////////////////////////////////////////////////////////////////////////////////////////////
268
// PUBLIC API
269

    
270
  public Static3D[] getRotationAxis()
271
    {
272
    return ROT_AXIS;
273
    }
274

    
275
///////////////////////////////////////////////////////////////////////////////////////////////////
276

    
277
  public int getBasicAngle()
278
    {
279
    return 3;
280
    }
281

    
282
///////////////////////////////////////////////////////////////////////////////////////////////////
283

    
284
  public void randomizeNewScramble(int[][] scramble, Random rnd, int num)
285
    {
286
    if( num==0 )
287
      {
288
      scramble[num][0] = rnd.nextInt(ROTATION_AXIS.length);
289
      }
290
    else
291
      {
292
      int newVector = rnd.nextInt(ROTATION_AXIS.length-1);
293
      scramble[num][0] = (newVector>=scramble[num-1][0] ? newVector+1 : newVector);
294
      }
295

    
296
    float rowFloat = rnd.nextFloat();
297

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

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

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

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

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

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

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

    
336
      if( dX<MAX_ERROR && dX>-MAX_ERROR &&
337
          dY<MAX_ERROR && dY>-MAX_ERROR &&
338
          dZ<MAX_ERROR && dZ>-MAX_ERROR &&
339
          dW<MAX_ERROR && dW>-MAX_ERROR  ) return 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

    
352
    return -1;
353
    }
354

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

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

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

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

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

    
387
      return true;
388
      }
389

    
390
    return false;
391
    }
392

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

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

    
401
///////////////////////////////////////////////////////////////////////////////////////////////////
402

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

    
408
///////////////////////////////////////////////////////////////////////////////////////////////////
409

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

    
415
///////////////////////////////////////////////////////////////////////////////////////////////////
416

    
417
  public int getComplexity(int numLayers)
418
    {
419
    return 1;
420
    }
421
}
(27-27/35)