Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / TwistyIvy.java @ 15da2470

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[] BASIC_ANGLE = new int[] { 3,3,3,3 };
67

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

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

    
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
           new Static4D(  0.5f, -0.5f, -0.5f,  0.5f ),
90
           new Static4D(  0.5f, -0.5f, -0.5f, -0.5f )
91
         };
92

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

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

    
108
  private static MeshBase mCornerMesh, mFaceMesh;
109

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

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

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

    
120
  float getScreenRatio()
121
    {
122
    return 1.0f;
123
    }
124

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

    
127
  Static4D[] getQuats()
128
    {
129
    return QUATS;
130
    }
131

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

    
134
  int getNumFaces()
135
    {
136
    return FACE_COLORS.length;
137
    }
138

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

    
141
  boolean shouldResetTextureMaps()
142
    {
143
    return false;
144
    }
145

    
146
///////////////////////////////////////////////////////////////////////////////////////////////////
147

    
148
  int getNumStickerTypes(int numLayers)
149
    {
150
    return 2;
151
    }
152

    
153
///////////////////////////////////////////////////////////////////////////////////////////////////
154

    
155
  float[][] getCuts(int numLayers)
156
    {
157
    float[] cut = new float[] {0.0f};
158
    return new float[][] { cut,cut,cut,cut };
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
// PUBLIC API
421

    
422
  public Static3D[] getRotationAxis()
423
    {
424
    return ROT_AXIS;
425
    }
426

    
427
///////////////////////////////////////////////////////////////////////////////////////////////////
428

    
429
  public int[] getBasicAngle()
430
    {
431
    return BASIC_ANGLE;
432
    }
433

    
434
///////////////////////////////////////////////////////////////////////////////////////////////////
435

    
436
  public void randomizeNewScramble(int[][] scramble, Random rnd, int curr, int total)
437
    {
438
    if( curr==0 )
439
      {
440
      scramble[curr][0] = rnd.nextInt(NUM_AXIS);
441
      }
442
    else
443
      {
444
      int newVector = rnd.nextInt(NUM_AXIS -1);
445
      scramble[curr][0] = (newVector>=scramble[curr-1][0] ? newVector+1 : newVector);
446
      }
447

    
448
    scramble[curr][1] = rnd.nextFloat()<=0.5f ? 0 : 1;
449

    
450
    switch( rnd.nextInt(2) )
451
      {
452
      case 0: scramble[curr][2] = -1; break;
453
      case 1: scramble[curr][2] =  1; break;
454
      }
455
    }
456

    
457
///////////////////////////////////////////////////////////////////////////////////////////////////
458
// The Ivy is solved if and only if:
459
//
460
// 1) all 4 of its corner cubits are rotated with the same quat
461
// 2) all its face cubits are rotated with the same quat like the corner ones,
462
//    and optionally they also might be upside down.
463
//
464
// i.e.
465
// cubits [4] and [5] - might be extra QUAT[1]
466
// cubits [6] and [7] - might be extra QUAT[2]
467
// cubits [8] and [9] - might be extra QUAT[3]
468

    
469
  public boolean isSolved()
470
    {
471
    int q1,q = CUBITS[0].mQuatIndex;
472

    
473
    if( CUBITS[1].mQuatIndex == q &&
474
        CUBITS[2].mQuatIndex == q &&
475
        CUBITS[3].mQuatIndex == q  )
476
      {
477
      q1 = mulQuat(q,1);
478
      if( CUBITS[4].mQuatIndex != q && CUBITS[4].mQuatIndex != q1 ) return false;
479
      if( CUBITS[5].mQuatIndex != q && CUBITS[5].mQuatIndex != q1 ) return false;
480

    
481
      q1 = mulQuat(q,2);
482
      if( CUBITS[6].mQuatIndex != q && CUBITS[6].mQuatIndex != q1 ) return false;
483
      if( CUBITS[7].mQuatIndex != q && CUBITS[7].mQuatIndex != q1 ) return false;
484

    
485
      q1 = mulQuat(q,3);
486
      if( CUBITS[8].mQuatIndex != q && CUBITS[8].mQuatIndex != q1 ) return false;
487
      if( CUBITS[9].mQuatIndex != q && CUBITS[9].mQuatIndex != q1 ) return false;
488

    
489
      return true;
490
      }
491

    
492
    return false;
493
    }
494

    
495
///////////////////////////////////////////////////////////////////////////////////////////////////
496
// only needed for solvers - there are no Ivy solvers ATM)
497

    
498
  public String retObjectString()
499
    {
500
    return "";
501
    }
502

    
503
///////////////////////////////////////////////////////////////////////////////////////////////////
504

    
505
  public int getObjectName(int numLayers)
506
    {
507
    return R.string.ivy2;
508
    }
509

    
510
///////////////////////////////////////////////////////////////////////////////////////////////////
511

    
512
  public int getInventor(int numLayers)
513
    {
514
    return R.string.ivy2_inventor;
515
    }
516

    
517
///////////////////////////////////////////////////////////////////////////////////////////////////
518

    
519
  public int getComplexity(int numLayers)
520
    {
521
    return 1;
522
    }
523
}
(28-28/41)