Project

General

Profile

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

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

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 oldRotAxis, int oldRow,
285
                                   int numScramble, int remScrambles, int remDoubleScrambles)
286
    {
287
    if( numScramble==1 )
288
      {
289
      scramble[0] = rnd.nextInt(ROTATION_AXIS.length);
290
      }
291
    else
292
      {
293
      int newVector = rnd.nextInt(ROTATION_AXIS.length-1);
294
      scramble[0] = (newVector>=oldRotAxis ? newVector+1 : newVector);
295
      }
296

    
297
    float rowFloat = rnd.nextFloat();
298

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

    
308
    int random = rnd.nextInt(remScrambles);
309
    int result = random<remDoubleScrambles ? 2:1;
310
    int sign   = rnd.nextInt(2);
311

    
312
    scramble[2] = sign==0 ? result : -result;
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
}
(27-27/35)