Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / TwistyIvy.java @ 886d1ebb

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.RubikSurfaceView;
34

    
35
import java.util.Random;
36

    
37
import static org.distorted.effects.scramble.ScrambleEffect.START_AXIS;
38

    
39
///////////////////////////////////////////////////////////////////////////////////////////////////
40

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

    
45
  // the four rotation axis of a RubikIvy. Must be normalized.
46
  static final Static3D[] ROT_AXIS = new Static3D[]
47
         {
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
           new Static3D(+SQ3/3,-SQ3/3,-SQ3/3)
52
         };
53

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

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

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

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

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

    
94
  private static MeshBase mCornerMesh, mFaceMesh;
95

    
96
///////////////////////////////////////////////////////////////////////////////////////////////////
97

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

    
104
///////////////////////////////////////////////////////////////////////////////////////////////////
105

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

    
111
///////////////////////////////////////////////////////////////////////////////////////////////////
112

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

    
118
///////////////////////////////////////////////////////////////////////////////////////////////////
119

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

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

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

    
132
///////////////////////////////////////////////////////////////////////////////////////////////////
133

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

    
139
///////////////////////////////////////////////////////////////////////////////////////////////////
140

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

    
146
    return cuts;
147
    }
148

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

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

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

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

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

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

    
176
    return CENTERS;
177
    }
178

    
179
///////////////////////////////////////////////////////////////////////////////////////////////////
180

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

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

    
198
    return 0;
199
    }
200

    
201
///////////////////////////////////////////////////////////////////////////////////////////////////
202

    
203
  MeshBase createCubitMesh(int cubit)
204
    {
205
    MeshBase mesh;
206

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

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

    
221
    return mesh;
222
    }
223

    
224
///////////////////////////////////////////////////////////////////////////////////////////////////
225

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

    
231
///////////////////////////////////////////////////////////////////////////////////////////////////
232

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

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

    
250
///////////////////////////////////////////////////////////////////////////////////////////////////
251

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

    
257
///////////////////////////////////////////////////////////////////////////////////////////////////
258

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

    
265
    return chances;
266
    }
267

    
268
///////////////////////////////////////////////////////////////////////////////////////////////////
269
// PUBLIC API
270

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

    
276
///////////////////////////////////////////////////////////////////////////////////////////////////
277

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

    
283
///////////////////////////////////////////////////////////////////////////////////////////////////
284

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

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

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

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

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

    
311
    return 0;
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
}
(20-20/24)