Project

General

Profile

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

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

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.effect.VertexEffect;
30
import org.distorted.library.effect.VertexEffectMove;
31
import org.distorted.library.effect.VertexEffectRotate;
32
import org.distorted.library.effect.VertexEffectScale;
33
import org.distorted.library.main.DistortedEffects;
34
import org.distorted.library.main.DistortedTexture;
35
import org.distorted.library.mesh.MeshBase;
36
import org.distorted.library.mesh.MeshJoined;
37
import org.distorted.library.mesh.MeshPolygon;
38
import org.distorted.library.mesh.MeshSquare;
39
import org.distorted.library.type.Static1D;
40
import org.distorted.library.type.Static3D;
41
import org.distorted.library.type.Static4D;
42
import org.distorted.main.R;
43

    
44
import java.util.Random;
45

    
46
///////////////////////////////////////////////////////////////////////////////////////////////////
47

    
48
public class TwistyIvy extends TwistyObject
49
{
50
  public static final float IVY_D = 0.003f;
51
  public static final float IVY_C = 0.59f;
52
  public static final float IVY_M = 0.35f;
53
  private static final int IVY_N = 8;
54

    
55
  private static final int FACES_PER_CUBIT =6;
56

    
57
  // the four rotation axis of a RubikIvy. Must be normalized.
58
  static final Static3D[] ROT_AXIS = new Static3D[]
59
         {
60
           new Static3D(+SQ3/3,+SQ3/3,+SQ3/3),
61
           new Static3D(+SQ3/3,+SQ3/3,-SQ3/3),
62
           new Static3D(+SQ3/3,-SQ3/3,+SQ3/3),
63
           new Static3D(+SQ3/3,-SQ3/3,-SQ3/3)
64
         };
65

    
66
  private static final int[] FACE_COLORS = new int[]
67
         {
68
           COLOR_YELLOW, COLOR_WHITE,
69
           COLOR_BLUE  , COLOR_GREEN,
70
           COLOR_RED   , COLOR_ORANGE
71
         };
72

    
73
  // All legal rotation quats of a RubikIvy
74
  private static final Static4D[] QUATS = new Static4D[]
75
         {
76
           new Static4D(  0.0f,  0.0f,  0.0f,  1.0f ),
77
           new Static4D(  1.0f,  0.0f,  0.0f,  0.0f ),
78
           new Static4D(  0.0f,  1.0f,  0.0f,  0.0f ),
79
           new Static4D(  0.0f,  0.0f,  1.0f,  0.0f ),
80

    
81
           new Static4D(  0.5f,  0.5f,  0.5f,  0.5f ),
82
           new Static4D(  0.5f,  0.5f,  0.5f, -0.5f ),
83
           new Static4D(  0.5f,  0.5f, -0.5f,  0.5f ),
84
           new Static4D(  0.5f,  0.5f, -0.5f, -0.5f ),
85
           new Static4D(  0.5f, -0.5f,  0.5f,  0.5f ),
86
           new Static4D(  0.5f, -0.5f,  0.5f, -0.5f ),
87
           new Static4D(  0.5f, -0.5f, -0.5f,  0.5f ),
88
           new Static4D(  0.5f, -0.5f, -0.5f, -0.5f )
89
         };
90

    
91
  private static final int[][] mFaceMap =
92
         {
93
           {  4, 2, 0, 12,12,12 },
94
           {  5, 2, 1, 12,12,12 },
95
           {  4, 3, 1, 12,12,12 },
96
           {  5, 3, 0, 12,12,12 },
97

    
98
           {  6, 12,12,12,12,12 },
99
           {  7, 12,12,12,12,12 },
100
           {  8, 12,12,12,12,12 },
101
           {  9, 12,12,12,12,12 },
102
           { 10, 12,12,12,12,12 },
103
           { 11, 12,12,12,12,12 },
104
         };
105

    
106
  private static MeshBase mCornerMesh, mFaceMesh;
107

    
108
///////////////////////////////////////////////////////////////////////////////////////////////////
109

    
110
  TwistyIvy(int size, Static4D quat, DistortedTexture texture,
111
            MeshSquare mesh, DistortedEffects effects, int[][] moves, Resources res, int scrWidth)
112
    {
113
    super(size, size, quat, texture, mesh, effects, moves, ObjectList.IVY, res, scrWidth);
114
    }
115

    
116
///////////////////////////////////////////////////////////////////////////////////////////////////
117

    
118
  float getScreenRatio()
119
    {
120
    return 1.0f;
121
    }
122

    
123
///////////////////////////////////////////////////////////////////////////////////////////////////
124

    
125
  Static4D[] getQuats()
126
    {
127
    return QUATS;
128
    }
129

    
130
///////////////////////////////////////////////////////////////////////////////////////////////////
131

    
132
  int getNumFaces()
133
    {
134
    return FACE_COLORS.length;
135
    }
136

    
137
///////////////////////////////////////////////////////////////////////////////////////////////////
138

    
139
  boolean shouldResetTextureMaps()
140
    {
141
    return false;
142
    }
143

    
144
///////////////////////////////////////////////////////////////////////////////////////////////////
145

    
146
  int getNumStickerTypes(int numLayers)
147
    {
148
    return 2;
149
    }
150

    
151
///////////////////////////////////////////////////////////////////////////////////////////////////
152

    
153
  float[] getCuts(int numLayers)
154
    {
155
    float[] cuts = new float[1];
156
    cuts[0] = 0.0f;
157

    
158
    return cuts;
159
    }
160

    
161
///////////////////////////////////////////////////////////////////////////////////////////////////
162

    
163
  int getNumCubitFaces()
164
    {
165
    return FACES_PER_CUBIT;
166
    }
167

    
168
///////////////////////////////////////////////////////////////////////////////////////////////////
169

    
170
  float[][] getCubitPositions(int numLayers)
171
    {
172
    final float DIST_CORNER = (numLayers-1)*0.50f;
173
    final float DIST_CENTER = (numLayers-1)*0.50f;
174

    
175
    final float[][] CENTERS = new float[10][];
176

    
177
    CENTERS[0] = new float[] { DIST_CORNER, DIST_CORNER, DIST_CORNER };
178
    CENTERS[1] = new float[] {-DIST_CORNER, DIST_CORNER,-DIST_CORNER };
179
    CENTERS[2] = new float[] {-DIST_CORNER,-DIST_CORNER, DIST_CORNER };
180
    CENTERS[3] = new float[] { DIST_CORNER,-DIST_CORNER,-DIST_CORNER };
181
    CENTERS[4] = new float[] { DIST_CENTER,           0,           0 };
182
    CENTERS[5] = new float[] {-DIST_CENTER,           0,           0 };
183
    CENTERS[6] = new float[] {           0, DIST_CENTER,           0 };
184
    CENTERS[7] = new float[] {           0,-DIST_CENTER,           0 };
185
    CENTERS[8] = new float[] {           0,           0, DIST_CENTER };
186
    CENTERS[9] = new float[] {           0,           0,-DIST_CENTER };
187

    
188
    return CENTERS;
189
    }
190

    
191
///////////////////////////////////////////////////////////////////////////////////////////////////
192

    
193
  private int getQuat(int cubit)
194
    {
195
    switch(cubit)
196
      {
197
      case  0: return 0;
198
      case  1: return 2;
199
      case  2: return 3;
200
      case  3: return 1;
201

    
202
      case  4: return 8;
203
      case  5: return 11;
204
      case  6: return 10;
205
      case  7: return 9;
206
      case  8: return 0;
207
      case  9: return 2;
208
      }
209

    
210
    return 0;
211
    }
212

    
213
///////////////////////////////////////////////////////////////////////////////////////////////////
214

    
215
  MeshBase createFacesIvyCorner()
216
    {
217
    MeshBase[] meshes = new MeshBase[6];
218

    
219
    final float angle = (float)Math.PI/(2*IVY_N);
220
    final float CORR  = 1.0f - 2*IVY_D;
221
    final float DIST  = -0.5f*CORR + IVY_D;
222
    float[] vertices  = new float[2*(IVY_N+1)+6];
223

    
224
    vertices[0] = (0.5f-IVY_M) * IVY_C;
225
    vertices[1] = (DIST-IVY_M) * IVY_C;
226
    vertices[2] = (0.5f-IVY_M) * IVY_C;
227
    vertices[3] = (0.5f-IVY_M) * IVY_C;
228
    vertices[4] = (DIST-IVY_M) * IVY_C;
229
    vertices[5] = (0.5f-IVY_M) * IVY_C;
230

    
231
    for(int i=0; i<=IVY_N; i++)
232
      {
233
      float ang = (IVY_N-i)*angle;
234
      float sin = (float)Math.sin(ang);
235
      float cos = (float)Math.cos(ang);
236

    
237
      vertices[2*i+6] = (CORR*(cos-0.5f)-IVY_M)*IVY_C;
238
      vertices[2*i+7] = (CORR*(sin-0.5f)-IVY_M)*IVY_C;
239
      }
240

    
241
    FactoryCubit factory = FactoryCubit.getInstance();
242
    float[] bands0 = factory.computeBands(+0.012f,20,0.2f,0.5f,7);
243
    float[] bands1 = factory.computeBands(-0.100f,20,0.2f,0.0f,2);
244

    
245
    meshes[0] = new MeshPolygon(vertices,bands0,1,2);
246
    meshes[0].setEffectAssociation(0,1,0);
247
    meshes[1] = meshes[0].copy(true);
248
    meshes[1].setEffectAssociation(0,2,0);
249
    meshes[2] = meshes[0].copy(true);
250
    meshes[2].setEffectAssociation(0,4,0);
251
    meshes[3] = new MeshPolygon(vertices,bands1,1,2);
252
    meshes[3].setEffectAssociation(0,8,0);
253
    meshes[4] = meshes[3].copy(true);
254
    meshes[4].setEffectAssociation(0,16,0);
255
    meshes[5] = meshes[3].copy(true);
256
    meshes[5].setEffectAssociation(0,32,0);
257

    
258
    return new MeshJoined(meshes);
259
    }
260

    
261
///////////////////////////////////////////////////////////////////////////////////////////////////
262

    
263
  private VertexEffect[] createVertexEffectsIvyCorner()
264
    {
265
    Static3D axisX  = new Static3D(1,0,0);
266
    Static3D axisY  = new Static3D(0,1,0);
267
    Static1D angle1 = new Static1D(+90);
268
    Static1D angle2 = new Static1D(-90);
269
    Static3D center = new Static3D(0,0,0);
270
    Static3D move1  = new Static3D(IVY_M-0.5f,IVY_M-0.5f,0);
271

    
272
    VertexEffect[] effect = new VertexEffect[5];
273

    
274
    effect[0] = new VertexEffectScale(1/IVY_C);
275
    effect[1] = new VertexEffectMove(move1);
276
    effect[2] = new VertexEffectScale(new Static3D(1,1,-1));
277
    effect[3] = new VertexEffectRotate(angle1,axisX,center);
278
    effect[4] = new VertexEffectRotate(angle2,axisY,center);
279

    
280
    effect[2].setMeshAssociation(54,-1);  // meshes 1,2,4,5
281
    effect[3].setMeshAssociation(18,-1);  // meshes 1,4
282
    effect[4].setMeshAssociation(36,-1);  // meshes 2,5
283

    
284
    return effect;
285
    }
286

    
287
///////////////////////////////////////////////////////////////////////////////////////////////////
288

    
289
  private MeshBase createFacesIvyFace()
290
    {
291
    MeshBase[] meshes = new MeshBase[2];
292

    
293
    final float angle = (float)Math.PI/(2*IVY_N);
294
    final float CORR  = 1.0f - 2*IVY_D;
295
    float[] vertices = new float[4*IVY_N];
296

    
297
    for(int i=0; i<IVY_N; i++)
298
      {
299
      float sin = (float)Math.sin(i*angle);
300
      float cos = (float)Math.cos(i*angle);
301

    
302
      vertices[2*i          ] = CORR*(0.5f-cos);
303
      vertices[2*i+1        ] = CORR*(0.5f-sin);
304
      vertices[2*i  +2*IVY_N] = CORR*(cos-0.5f);
305
      vertices[2*i+1+2*IVY_N] = CORR*(sin-0.5f);
306
      }
307

    
308
    FactoryCubit factory = FactoryCubit.getInstance();
309
    float[] bands0 = factory.computeBands(+0.03f,35,0.5f,0.5f,5);
310
    float[] bands1 = factory.computeBands(-0.10f,45,0.5f,0.0f,2);
311

    
312
    meshes[0] = new MeshPolygon(vertices,bands0,0,0);
313
    meshes[0].setEffectAssociation(0,1,0);
314
    meshes[1] = new MeshPolygon(vertices,bands1,0,0);
315
    meshes[1].setEffectAssociation(0,2,0);
316

    
317
    return new MeshJoined(meshes);
318
    }
319

    
320
///////////////////////////////////////////////////////////////////////////////////////////////////
321

    
322
  private MeshBase createIvyFaceMesh()
323
    {
324
    MeshBase mesh = createFacesIvyFace();
325

    
326
    Static3D center = new Static3D(-0.0f,-0.0f,-0.5f);
327
    Static3D[] vertices = new Static3D[2];
328
    vertices[0] = new Static3D(-0.5f,+0.5f,+0.0f);
329
    vertices[1] = new Static3D(+0.5f,-0.5f,+0.0f);
330

    
331
    FactoryCubit.getInstance().roundCorners(mesh,center,vertices,0.03f,0.10f);
332

    
333
    mesh.mergeEffComponents();
334
    mesh.addEmptyTexComponent();
335
    mesh.addEmptyTexComponent();
336
    mesh.addEmptyTexComponent();
337
    mesh.addEmptyTexComponent();
338

    
339
    return mesh;
340
    }
341
///////////////////////////////////////////////////////////////////////////////////////////////////
342

    
343
  private MeshBase createIvyCornerMesh()
344
    {
345
    MeshBase mesh = createFacesIvyCorner();
346
    VertexEffect[] effects = createVertexEffectsIvyCorner();
347
    for( VertexEffect effect : effects ) mesh.apply(effect);
348

    
349
    Static3D center = new Static3D(-0.5f,-0.5f,-0.5f);
350
    Static3D[] vertices = new Static3D[4];
351
    vertices[0] = new Static3D(+0.0f,+0.0f,+0.0f);
352
    vertices[1] = new Static3D(-1.0f,+0.0f,+0.0f);
353
    vertices[2] = new Static3D(+0.0f,-1.0f,+0.0f);
354
    vertices[3] = new Static3D(+0.0f,+0.0f,-1.0f);
355

    
356
    FactoryCubit.getInstance().roundCorners(mesh,center,vertices,0.03f,0.10f);
357

    
358
    mesh.mergeEffComponents();
359

    
360
    return mesh;
361
    }
362

    
363
///////////////////////////////////////////////////////////////////////////////////////////////////
364

    
365
  MeshBase createCubitMesh(int cubit, int numLayers)
366
    {
367
    MeshBase mesh;
368

    
369
    if( cubit<4 )
370
      {
371
      if( mCornerMesh==null ) mCornerMesh = createIvyCornerMesh();
372
      mesh = mCornerMesh.copy(true);
373
      }
374
    else
375
      {
376
      if( mFaceMesh==null ) mFaceMesh = createIvyFaceMesh();
377
      mesh = mFaceMesh.copy(true);
378
      }
379

    
380
    MatrixEffectQuaternion quat = new MatrixEffectQuaternion( QUATS[getQuat(cubit)], new Static3D(0,0,0) );
381
    mesh.apply(quat,0xffffffff,0);
382

    
383
    return mesh;
384
    }
385

    
386
///////////////////////////////////////////////////////////////////////////////////////////////////
387

    
388
  int getFaceColor(int cubit, int cubitface, int numLayers)
389
    {
390
    return mFaceMap[cubit][cubitface];
391
    }
392

    
393
///////////////////////////////////////////////////////////////////////////////////////////////////
394

    
395
  void createFaceTexture(Canvas canvas, Paint paint, int face, int left, int top)
396
    {
397
    int COLORS = FACE_COLORS.length;
398
    FactorySticker factory = FactorySticker.getInstance();
399
    float S = 0.08f;
400
    float R = 0.12f;
401

    
402
    if( face<COLORS )
403
      {
404
      factory.drawIvyCornerSticker(canvas, paint, left, top, FACE_COLORS[face%COLORS], S, R);
405
      }
406
    else
407
      {
408
      factory.drawIvyCenterSticker(canvas, paint, left, top, FACE_COLORS[face%COLORS], S, R);
409
      }
410
    }
411

    
412
///////////////////////////////////////////////////////////////////////////////////////////////////
413

    
414
  float returnMultiplier()
415
    {
416
    return 2.0f;
417
    }
418

    
419
///////////////////////////////////////////////////////////////////////////////////////////////////
420

    
421
  float[] getRowChances(int numLayers)
422
    {
423
    float[] chances = new float[2];
424
    chances[0] = 0.5f;
425
    chances[1] = 1.0f;
426

    
427
    return chances;
428
    }
429

    
430
///////////////////////////////////////////////////////////////////////////////////////////////////
431
// PUBLIC API
432

    
433
  public Static3D[] getRotationAxis()
434
    {
435
    return ROT_AXIS;
436
    }
437

    
438
///////////////////////////////////////////////////////////////////////////////////////////////////
439

    
440
  public int getBasicAngle()
441
    {
442
    return 3;
443
    }
444

    
445
///////////////////////////////////////////////////////////////////////////////////////////////////
446

    
447
  public void randomizeNewScramble(int[][] scramble, Random rnd, int num)
448
    {
449
    if( num==0 )
450
      {
451
      scramble[num][0] = rnd.nextInt(ROTATION_AXIS.length);
452
      }
453
    else
454
      {
455
      int newVector = rnd.nextInt(ROTATION_AXIS.length-1);
456
      scramble[num][0] = (newVector>=scramble[num-1][0] ? newVector+1 : newVector);
457
      }
458

    
459
    float rowFloat = rnd.nextFloat();
460

    
461
    for(int row=0; row<mRowChances.length; row++)
462
      {
463
      if( rowFloat<=mRowChances[row] )
464
        {
465
        scramble[num][1] = row;
466
        break;
467
        }
468
      }
469

    
470
    switch( rnd.nextInt(2) )
471
      {
472
      case 0: scramble[num][2] = -1; break;
473
      case 1: scramble[num][2] =  1; break;
474
      }
475
    }
476

    
477
///////////////////////////////////////////////////////////////////////////////////////////////////
478
// The Ivy is solved if and only if:
479
//
480
// 1) all 4 of its corner cubits are rotated with the same quat
481
// 2) all its face cubits are rotated with the same quat like the corner ones,
482
//    and optionally they also might be upside down.
483
//
484
// i.e.
485
// cubits [4] and [5] - might be extra QUAT[1]
486
// cubits [6] and [7] - might be extra QUAT[2]
487
// cubits [8] and [9] - might be extra QUAT[3]
488

    
489
  public boolean isSolved()
490
    {
491
    int q1,q = CUBITS[0].mQuatIndex;
492

    
493
    if( CUBITS[1].mQuatIndex == q &&
494
        CUBITS[2].mQuatIndex == q &&
495
        CUBITS[3].mQuatIndex == q  )
496
      {
497
      q1 = mulQuat(q,1);
498
      if( CUBITS[4].mQuatIndex != q && CUBITS[4].mQuatIndex != q1 ) return false;
499
      if( CUBITS[5].mQuatIndex != q && CUBITS[5].mQuatIndex != q1 ) return false;
500

    
501
      q1 = mulQuat(q,2);
502
      if( CUBITS[6].mQuatIndex != q && CUBITS[6].mQuatIndex != q1 ) return false;
503
      if( CUBITS[7].mQuatIndex != q && CUBITS[7].mQuatIndex != q1 ) return false;
504

    
505
      q1 = mulQuat(q,3);
506
      if( CUBITS[8].mQuatIndex != q && CUBITS[8].mQuatIndex != q1 ) return false;
507
      if( CUBITS[9].mQuatIndex != q && CUBITS[9].mQuatIndex != q1 ) return false;
508

    
509
      return true;
510
      }
511

    
512
    return false;
513
    }
514

    
515
///////////////////////////////////////////////////////////////////////////////////////////////////
516
// only needed for solvers - there are no Ivy solvers ATM)
517

    
518
  public String retObjectString()
519
    {
520
    return "";
521
    }
522

    
523
///////////////////////////////////////////////////////////////////////////////////////////////////
524

    
525
  public int getObjectName(int numLayers)
526
    {
527
    return R.string.ivy2;
528
    }
529

    
530
///////////////////////////////////////////////////////////////////////////////////////////////////
531

    
532
  public int getInventor(int numLayers)
533
    {
534
    return R.string.ivy2_inventor;
535
    }
536

    
537
///////////////////////////////////////////////////////////////////////////////////////////////////
538

    
539
  public int getComplexity(int numLayers)
540
    {
541
    return 1;
542
    }
543
}
(25-25/33)