Project

General

Profile

Download (29.5 KB) Statistics
| Branch: | Revision:

distorted-objectlib / src / main / java / org / distorted / objectlib / objects / TwistyBandagedCuboid.java @ 5d09301e

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2021 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Magic Cube.                                                              //
5
//                                                                                               //
6
// Magic Cube is proprietary software licensed under an EULA which you should have received      //
7
// along with the code. If not, check https://distorted.org/magic/License-Magic-Cube.html        //
8
///////////////////////////////////////////////////////////////////////////////////////////////////
9

    
10
package org.distorted.objectlib.objects;
11

    
12
import static org.distorted.objectlib.touchcontrol.TouchControl.TC_CUBOID;
13
import static org.distorted.objectlib.touchcontrol.TouchControl.TYPE_NOT_SPLIT;
14

    
15
import java.io.InputStream;
16

    
17
import org.distorted.library.main.DistortedLibrary;
18
import org.distorted.library.type.Static3D;
19
import org.distorted.library.type.Static4D;
20

    
21
import org.distorted.objectlib.helpers.FactoryBandagedCubit;
22
import org.distorted.objectlib.helpers.ObjectFaceShape;
23
import org.distorted.objectlib.helpers.ObjectSignature;
24
import org.distorted.objectlib.main.InitData;
25
import org.distorted.objectlib.main.ObjectType;
26
import org.distorted.objectlib.touchcontrol.TouchControlHexahedron;
27
import org.distorted.objectlib.helpers.ObjectShape;
28
import org.distorted.objectlib.scrambling.ScrambleState;
29
import org.distorted.objectlib.main.ShapeHexahedron;
30

    
31
///////////////////////////////////////////////////////////////////////////////////////////////////
32

    
33
public class TwistyBandagedCuboid extends ShapeHexahedron
34
{
35
  private static final String OBJECT_NAME = "LOCAL_BANDAGED";
36

    
37
  private static final int CUBIT_111 = 0;
38
  private static final int CUBIT_211 = 1;
39
  private static final int CUBIT_311 = 2;
40
  private static final int CUBIT_221 = 3;
41
  private static final int CUBIT_222 = 4;
42
  private static final int CUBIT_OTH = 5;
43

    
44
  // the three rotation axis of a 3x3 Cube. Must be normalized.
45
  static final Static3D[] ROT_AXIS = new Static3D[]
46
         {
47
           new Static3D(1,0,0),
48
           new Static3D(0,1,0),
49
           new Static3D(0,0,1)
50
         };
51

    
52
  private static final int[][] mDims = new int[][]
53
        {
54
         {1,1,1},  // has to be X>=Z>=Y so that all
55
         {2,1,1},  // the faces are horizontal
56
         {3,1,1},
57
         {2,1,2},
58
         {2,2,2},
59
        };
60

    
61
  public static final float[][] POS_1 = new float[][]
62
        {
63
          {-1.0f, -1.0f, +0.0f,
64
           -1.0f, -1.0f, +1.0f,
65
           -1.0f,  0.0f, +0.0f,
66
           -1.0f,  0.0f, +1.0f,
67
            0.0f, -1.0f, +0.0f,
68
            0.0f, -1.0f, +1.0f,
69
            0.0f,  0.0f, +0.0f,
70
            0.0f,  0.0f, +1.0f},
71
          {-1.0f, +1.0f, +1.0f},
72
          {-1.0f, +1.0f, +0.0f},
73
          {-1.0f, +1.0f, -1.0f},
74
          { 0.0f, +1.0f, +1.0f},
75
          { 0.0f, +1.0f, +0.0f},
76
          { 0.0f, +1.0f, -1.0f},
77
          { 1.0f, +1.0f, +1.0f},
78
          { 1.0f, +1.0f, +0.0f},
79
          { 1.0f, +1.0f, -1.0f},
80
          { 1.0f,  0.0f, +1.0f},
81
          { 1.0f,  0.0f, +0.0f},
82
          { 1.0f,  0.0f, -1.0f},
83
          { 1.0f, -1.0f, +1.0f},
84
          { 1.0f, -1.0f, +0.0f},
85
          { 1.0f, -1.0f, -1.0f},
86
          {-1.0f, -1.0f, -1.0f},
87
          {-1.0f,  0.0f, -1.0f},
88
          { 0.0f, -1.0f, -1.0f},
89
          { 0.0f,  0.0f, -1.0f}
90
        };
91

    
92
  public static final float[][] POS_2 = new float[][]
93
        {
94
          { 0.0f, +1.0f,  1.0f, 0.0f, +1.0f,  0.0f, 0.0f, +1.0f, -1.0f},
95
          {-1.0f, -1.0f,  0.0f, 0.0f, -1.0f,  0.0f, 1.0f, -1.0f,  0.0f},
96
          {-1.0f, +1.0f, +1.0f},
97
          {-1.0f, +1.0f,  0.0f},
98
          {-1.0f, +1.0f, -1.0f},
99
          {-1.0f,  0.0f, +1.0f},
100
          {-1.0f,  0.0f,  0.0f},
101
          {-1.0f,  0.0f, -1.0f},
102
          {-1.0f, -1.0f, +1.0f},
103
          {-1.0f, -1.0f, -1.0f},
104
          {+1.0f, +1.0f, +1.0f},
105
          {+1.0f, +1.0f,  0.0f},
106
          {+1.0f, +1.0f, -1.0f},
107
          {+1.0f,  0.0f, +1.0f},
108
          {+1.0f,  0.0f,  0.0f},
109
          {+1.0f,  0.0f, -1.0f},
110
          {+1.0f, -1.0f, +1.0f},
111
          {+1.0f, -1.0f, -1.0f},
112
          { 0.0f,  0.0f, +1.0f},
113
          { 0.0f, -1.0f, +1.0f},
114
          { 0.0f,  0.0f, -1.0f},
115
          { 0.0f, -1.0f, -1.0f}
116
        };
117

    
118
  public static final float[][] POS_3 = new float[][]
119
        {
120
          {-1.0f,  1.0f,  1.0f, -1.0f,  0.0f,  1.0f,  0.0f,  1.0f,  1.0f,  0.0f,  0.0f,  1.0f},
121
          { 1.0f,  0.0f, -1.0f,  1.0f,  0.0f,  0.0f,  1.0f,  1.0f, -1.0f,  1.0f,  1.0f,  0.0f},
122
          {-1.0f, -1.0f, -1.0f, -1.0f, -1.0f,  0.0f,  0.0f, -1.0f, -1.0f,  0.0f, -1.0f,  0.0f},
123
          { 1.0f,  1.0f,  1.0f},
124
          { 1.0f,  0.0f,  1.0f},
125
          { 1.0f, -1.0f,  1.0f},
126
          {-1.0f, -1.0f,  1.0f},
127
          { 0.0f, -1.0f,  1.0f},
128
          { 1.0f, -1.0f,  0.0f},
129
          { 1.0f, -1.0f, -1.0f},
130
          {-1.0f,  1.0f, -1.0f},
131
          {-1.0f,  1.0f,  0.0f},
132
          { 0.0f,  1.0f, -1.0f},
133
          { 0.0f,  1.0f,  0.0f},
134
          {-1.0f,  0.0f, -1.0f},
135
          {-1.0f,  0.0f,  0.0f},
136
          { 0.0f,  0.0f, -1.0f}
137
        };
138

    
139
  public static final float[][] POS_4 = new float[][]
140
        {
141
          { 1.0f,  1.0f, -1.0f},
142
          {-1.0f, -1.0f,  0.0f, -1.0f,  0.0f,  0.0f, 0.0f, -1.0f,  0.0f,  0.0f,  0.0f,  0.0f},
143
          {-1.0f,  1.0f, -1.0f,  0.0f,  1.0f, -1.0f},
144
          {-1.0f,  0.0f, -1.0f,  0.0f,  0.0f, -1.0f},
145
          {-1.0f, -1.0f, -1.0f,  0.0f, -1.0f, -1.0f},
146
          {-1.0f,  1.0f,  0.0f, -1.0f,  1.0f,  1.0f},
147
          { 0.0f,  1.0f,  0.0f,  0.0f,  1.0f,  1.0f},
148
          { 1.0f,  1.0f,  0.0f,  1.0f,  1.0f,  1.0f},
149
          {-1.0f, -1.0f,  1.0f, -1.0f,  0.0f,  1.0f},
150
          { 0.0f, -1.0f,  1.0f,  0.0f,  0.0f,  1.0f},
151
          { 1.0f, -1.0f,  1.0f,  1.0f,  0.0f,  1.0f},
152
          { 1.0f, -1.0f,  0.0f,  1.0f,  0.0f,  0.0f},
153
          { 1.0f, -1.0f, -1.0f,  1.0f,  0.0f, -1.0f}
154
        };
155

    
156
  private int[][] mBasicAngle;
157
  private Static4D[] mInitQuats;
158
  private float[][] mCuts;
159
  private int[] mCubitVariantMap;
160
  private int[] mTypeVariantMap;
161
  private int[][] mSolvedQuatsAbstract;
162
  private float[][] mPosition;
163
  private ObjectSignature mSignature;
164

    
165
///////////////////////////////////////////////////////////////////////////////////////////////////
166

    
167
  public TwistyBandagedCuboid(InitData data, int meshState, int iconMode, Static4D quat, Static3D move, float scale, InputStream stream)
168
    {
169
    super(data, meshState, iconMode, (data.getNumLayers()[0]+data.getNumLayers()[1]+data.getNumLayers()[2])/3.0f, quat, move, scale, stream);
170
    }
171

    
172
///////////////////////////////////////////////////////////////////////////////////////////////////
173
// return 0 if cubit is 'external' (it has at least two walls which belong to two different faces
174
// of the cuboid, faces which do not both rotate along the same axis! So: it is an edge, a corner,
175
// or a bandaged cubit which 'comes out' in two different, non-opposite, faces.
176
// Otherwise, if the cubit only comes out in one face or in two faces which are opposite to each other,
177
// return the index of the first of the three quats which rotate stuff in this face (so right or left
178
// return 1 because quats 1,2,3 are the ones rotating along the X axis)
179

    
180
  private int cubitIsExternal(float[] pos, float dx, float dy, float dz)
181
    {
182
    int len = pos.length/3;
183
    int x=0, y=0, z=0;
184

    
185
    for(int i=0; i<len; i++)
186
      {
187
      float cx = pos[3*i  ];
188
      float cy = pos[3*i+1];
189
      float cz = pos[3*i+2];
190

    
191
      if( cx>dx || cx<-dx ) x=1;
192
      if( cy>dy || cy<-dy ) y=1;
193
      if( cz>dz || cz<-dz ) z=1;
194
      }
195

    
196
    if( x+y+z>=2 ) return 0;
197

    
198
    if( x==1 ) return 1;
199
    if( y==1 ) return 4;
200
    if( z==1 ) return 7;
201

    
202
    android.util.Log.e("D", "ERROR: unsupported: internal cubit! ");
203
    return 0;
204
    }
205

    
206
///////////////////////////////////////////////////////////////////////////////////////////////////
207
// If we have a flat cuboid than retCubitSolvedStatus() wrongly reports that the internal cubits
208
// are edges (they do have two non-black faces after all!) which leads to wrong solvedQuats and
209
// mis-detection of a solved status. Correct this manually here.
210
//
211
// Note that this is still not completely good in case of bandaged cuboids - there can be a 4x4x2
212
// bandaged cuboid whose 4 'internal' cubits from the 4x4 face are fused with the other 4 internal
213
// cubits from the other 4x4 face - and those would again get mis-detected as edges...
214

    
215
  @Override
216
  public int[][] getSolvedQuats()
217
    {
218
    if( mSolvedQuatsAbstract==null )
219
      {
220
      int[] numLayers = getNumLayers();
221
      float dx = 0.5f*(numLayers[0]-1) - 0.1f;
222
      float dy = 0.5f*(numLayers[1]-1) - 0.1f;
223
      float dz = 0.5f*(numLayers[2]-1) - 0.1f;
224

    
225
      float[][] pos = getPositions();
226
      int numTotal = pos.length;
227
      boolean[] isExternal = new boolean[numTotal];
228
      int[] internalQuat = new int[numTotal];
229
      int numExternal = 0;
230
      int pointer = 0;
231

    
232
      for(int cubit=0; cubit<numTotal; cubit++)
233
        {
234
        int q = cubitIsExternal(pos[cubit],dx,dy,dz);
235

    
236
        if( q<=0 )
237
          {
238
          isExternal[cubit] = true;
239
          numExternal++;
240
          }
241
        else
242
          {
243
          isExternal[cubit] = false;
244
          internalQuat[pointer] = q;
245
          pointer++;
246
          }
247
        }
248

    
249
      int numInternal = numTotal - numExternal;
250

    
251
      mSolvedQuatsAbstract = new int[numInternal+1][];
252
      mSolvedQuatsAbstract[0] = new int[numExternal+1];
253
      mSolvedQuatsAbstract[0][0] = numExternal;
254

    
255
      for(int i=0; i<numInternal; i++)
256
        {
257
        int q = internalQuat[i];
258
        mSolvedQuatsAbstract[i+1] = new int[5];
259
        mSolvedQuatsAbstract[i+1][0] = 1;
260
        mSolvedQuatsAbstract[i+1][2] = q;
261
        mSolvedQuatsAbstract[i+1][3] = q+1;
262
        mSolvedQuatsAbstract[i+1][4] = q+2;
263
        }
264

    
265
      int pointerExternal = 1;
266
      int pointerInternal = 1;
267

    
268
      for(int cubit=0; cubit<numTotal; cubit++)
269
        {
270
        if( isExternal[cubit] ) mSolvedQuatsAbstract[0][pointerExternal++] = cubit;
271
        else                    mSolvedQuatsAbstract[pointerInternal++][1] = cubit;
272
        }
273
      }
274

    
275
    return mSolvedQuatsAbstract;
276
    }
277

    
278
///////////////////////////////////////////////////////////////////////////////////////////////////
279
// Computing scramble states of many a bandaged cubes takes way too long time and too much space.
280
// Return null here and turn to construction of scramble tables just-in-time.
281

    
282
  @Override
283
  public ScrambleState[] getScrambleStates()
284
    {
285
    return null;
286
    }
287

    
288
///////////////////////////////////////////////////////////////////////////////////////////////////
289

    
290
  @Override
291
  public int getScrambleType()
292
    {
293
    return 2;
294
    }
295

    
296
///////////////////////////////////////////////////////////////////////////////////////////////////
297

    
298
  private int getType(float[] pos)
299
    {
300
    switch(pos.length)
301
      {
302
      case  3: return CUBIT_111;
303
      case  6: return CUBIT_211;
304
      case  9: boolean x1 = (pos[0]==pos[3] && pos[0]==pos[6]);
305
               boolean y1 = (pos[1]==pos[4] && pos[1]==pos[7]);
306
               boolean z1 = (pos[2]==pos[5] && pos[2]==pos[8]);
307
               return ( (x1&&y1) || (x1&&z1) || (y1&&z1) ) ? CUBIT_311 : CUBIT_OTH;
308
      case 12: float x = (pos[0]+pos[3]+pos[6]+pos[ 9])/4;
309
               float y = (pos[1]+pos[4]+pos[7]+pos[10])/4;
310
               float z = (pos[2]+pos[5]+pos[8]+pos[11])/4;
311
               float d1 = (pos[0]-x)*(pos[0]-x) + (pos[ 1]-y)*(pos[ 1]-y) + (pos[ 2]-z)*(pos[ 2]-z);
312
               float d2 = (pos[3]-x)*(pos[3]-x) + (pos[ 4]-y)*(pos[ 4]-y) + (pos[ 5]-z)*(pos[ 5]-z);
313
               float d3 = (pos[6]-x)*(pos[6]-x) + (pos[ 7]-y)*(pos[ 7]-y) + (pos[ 8]-z)*(pos[ 8]-z);
314
               float d4 = (pos[9]-x)*(pos[9]-x) + (pos[10]-y)*(pos[10]-y) + (pos[11]-z)*(pos[11]-z);
315
               return ( d1==0.5f && d2==0.5f && d3==0.5f && d4==0.5f ) ? CUBIT_221 : CUBIT_OTH;
316
      case 24: float x3 = pos[0];
317
               float y3 = pos[1];
318
               float z3 = pos[2];
319
               float x4=-10,y4=-10,z4=-10;
320
               int i;
321

    
322
               for(i=0; i<8; i++)
323
                 {
324
                 if( pos[3*i]!=x3 && pos[3*i+1]!=y3 && pos[3*i+2]!=z3 )
325
                   {
326
                   x4 = pos[3*i  ];
327
                   y4 = pos[3*i+1];
328
                   z4 = pos[3*i+2];
329
                   break;
330
                   }
331
                 }
332
               if( i==9 ) return CUBIT_OTH;
333

    
334
               float dX = x4-x3;
335
               float dY = y4-y3;
336
               float dZ = z4-z3;
337

    
338
               if( (dX==1.0f || dX==-1.0f) && (dY==1.0f || dY==-1.0f) && (dZ==1.0f || dZ==-1.0f) )
339
                 {
340
                 for(i=0; i<8; i++)
341
                   {
342
                   if( (pos[3*i  ]!=x3 && pos[3*i  ]!=x4) ||
343
                       (pos[3*i+1]!=y3 && pos[3*i+1]!=y4) ||
344
                       (pos[3*i+2]!=z3 && pos[3*i+2]!=z4)  ) return CUBIT_OTH;
345
                   }
346

    
347
                 return CUBIT_222;
348
                 }
349

    
350
      default: return CUBIT_OTH;
351
      }
352
    }
353

    
354
///////////////////////////////////////////////////////////////////////////////////////////////////
355

    
356
  private int getQuatIndex(int cubit)
357
    {
358
    float[][] positions = getPositions();
359
    int len = positions.length;
360

    
361
    if( cubit>=0 && cubit<len )
362
      {
363
      float[] pos = positions[cubit];
364
      int type = getType(pos);
365

    
366
      switch(type)
367
        {
368
        case CUBIT_222:
369
        case CUBIT_111: return 0;
370
        case CUBIT_211:
371
        case CUBIT_311: return (pos[1]==pos[4]) ? (pos[0]==pos[3] ? 2 : 0) : 3;
372
        case CUBIT_221: if( pos[0]==pos[3] && pos[0]==pos[6] ) return 3;
373
                        if( pos[1]==pos[4] && pos[1]==pos[7] ) return 0;
374
                        if( pos[2]==pos[5] && pos[2]==pos[8] ) return 1;
375
        }
376
      }
377

    
378
    return 0;
379
    }
380

    
381
///////////////////////////////////////////////////////////////////////////////////////////////////
382

    
383
  public ObjectShape getObjectShape(int variant)
384
    {
385
    int type,numTypes = mDims.length;
386
    for(type=0; type<numTypes; type++) if( mTypeVariantMap[type]==variant ) break;
387

    
388
    if( type<numTypes )
389
      {
390
      int X = mDims[type][0];
391
      int Y = mDims[type][1];
392
      int Z = mDims[type][2];
393

    
394
      float[][] vertices =
395
        {
396
          {+0.5f*X,+0.5f*Y,+0.5f*Z},
397
          {+0.5f*X,+0.5f*Y,-0.5f*Z},
398
          {+0.5f*X,-0.5f*Y,+0.5f*Z},
399
          {+0.5f*X,-0.5f*Y,-0.5f*Z},
400
          {-0.5f*X,+0.5f*Y,+0.5f*Z},
401
          {-0.5f*X,+0.5f*Y,-0.5f*Z},
402
          {-0.5f*X,-0.5f*Y,+0.5f*Z},
403
          {-0.5f*X,-0.5f*Y,-0.5f*Z}
404
        };
405

    
406
      int[][] indices =
407
        {
408
          {2,3,1,0},
409
          {7,6,4,5},
410
          {4,0,1,5},
411
          {7,3,2,6},
412
          {6,2,0,4},
413
          {3,7,5,1},
414
        };
415

    
416
      return new ObjectShape(vertices, indices);
417
      }
418

    
419
    float[][] positions = getPositions();
420
    int cubit,numCubits = positions.length;
421

    
422
    for(cubit=0; cubit<numCubits; cubit++)
423
      {
424
      if( mCubitVariantMap[cubit]==variant ) break;
425
      }
426

    
427
    if( cubit>=numCubits )
428
      {
429
      android.util.Log.e("D", "unknown variant: "+variant);
430
      return null;
431
      }
432

    
433
    FactoryBandagedCubit factory = FactoryBandagedCubit.getInstance();
434
    return factory.createIrregularShape(variant,positions[cubit]);
435
    }
436

    
437
///////////////////////////////////////////////////////////////////////////////////////////////////
438

    
439
  public ObjectFaceShape getObjectFaceShape(int variant)
440
    {
441
    int[] numLayers = getNumLayers();
442
    int size = (numLayers[0]+numLayers[1]+numLayers[2])/3;
443
    boolean roundCorners = (DistortedLibrary.fastCompilationTF() && size<=5);
444
    int type,numTypes = mDims.length;
445
    for(type=0; type<numTypes; type++) if( mTypeVariantMap[type]==variant ) break;
446

    
447
    if( type<numTypes )
448
      {
449
      int val = roundCorners ? 0 : -1;
450
      int X = mDims[type][0];
451
      int Y = mDims[type][1];
452
      int Z = mDims[type][2];
453

    
454
      float height        = isInIconMode() ? 0.001f : size<=5 ? 0.048f : 0.020f;
455
      int[] bandIndices   = { 0,0,1,1,2,2 };
456
      float[][] corners   = { {0.04f,0.15f} };
457
      int[] cornerIndices = { val,val,val,val,val,val,val,val };
458
      int[] centerIndices = { 0,1,2,3,4,5,6,7 };
459

    
460
      int maxXY = Math.max(X,Y);
461
      int maxXZ = Math.max(X,Z);
462
      int maxYZ = Math.max(Y,Z);
463

    
464
      int angle = 45;
465
      float R = 0.25f;
466
      float S = 0.50f;
467
      float N = size<=4 ? 5 : size<=5 ? 4 : 3;
468

    
469
      float[][] bands =
470
        {
471
          {height/maxYZ,angle,R,S,N,0,0},
472
          {height/maxXZ,angle,R,S,N,0,0},
473
          {height/maxXY,angle,R,S,N,0,0}
474
        };
475

    
476
      float[][] centers =
477
        {
478
          {+0.5f*(X-1),+0.5f*(Y-1),+0.5f*(Z-1)},
479
          {+0.5f*(X-1),+0.5f*(Y-1),-0.5f*(Z-1)},
480
          {+0.5f*(X-1),-0.5f*(Y-1),+0.5f*(Z-1)},
481
          {+0.5f*(X-1),-0.5f*(Y-1),-0.5f*(Z-1)},
482
          {-0.5f*(X-1),+0.5f*(Y-1),+0.5f*(Z-1)},
483
          {-0.5f*(X-1),+0.5f*(Y-1),-0.5f*(Z-1)},
484
          {-0.5f*(X-1),-0.5f*(Y-1),+0.5f*(Z-1)},
485
          {-0.5f*(X-1),-0.5f*(Y-1),-0.5f*(Z-1)}
486
        };
487

    
488
      return new ObjectFaceShape(bands,bandIndices,corners,cornerIndices,centers,centerIndices,null);
489
      }
490

    
491
    FactoryBandagedCubit factory = FactoryBandagedCubit.getInstance();
492
    return factory.createIrregularFaceShape(variant, isInIconMode(), roundCorners );
493
    }
494

    
495
///////////////////////////////////////////////////////////////////////////////////////////////////
496

    
497
  public float[][] getCubitPositions(int[] numLayers)
498
    {
499
    return getPositions();
500
    }
501

    
502
///////////////////////////////////////////////////////////////////////////////////////////////////
503

    
504
  public Static4D getCubitQuats(int cubit, int[] numLayers)
505
    {
506
    if( mInitQuats ==null )
507
      {
508
      mInitQuats = new Static4D[]
509
        {
510
        new Static4D(  0.0f,   0.0f,   0.0f,   1.0f),  // NULL
511
        new Static4D( SQ2/2,   0.0f,   0.0f, -SQ2/2),  // X
512
        new Static4D(  0.0f,  SQ2/2,   0.0f, -SQ2/2),  // Y
513
        new Static4D(  0.0f,   0.0f,  SQ2/2, -SQ2/2),  // Z
514
        new Static4D( -0.5f,  +0.5f,  -0.5f,  +0.5f),  // ZX
515
        new Static4D( +0.5f,  +0.5f,  +0.5f,  -0.5f),  // YX
516
        };
517
      }
518

    
519
    return mInitQuats[getQuatIndex(cubit)];
520
    }
521

    
522
///////////////////////////////////////////////////////////////////////////////////////////////////
523

    
524
  public int getNumCubitVariants(int[] numLayers)
525
    {
526
    int numVariants = 0;
527
    float[][] positions = getPositions();
528
    boolean C111=false;
529
    boolean C211=false;
530
    boolean C311=false;
531
    boolean C221=false;
532
    boolean C222=false;
533

    
534
    int numCubits = positions.length;
535
    mCubitVariantMap = new int[numCubits];
536

    
537
    int numTypes = mDims.length;
538
    mTypeVariantMap = new int[numTypes];
539
    for(int i=0; i<numTypes; i++) mTypeVariantMap[i] = -1;
540

    
541
    for (int cubit=0; cubit<numCubits; cubit++)
542
      {
543
      int type = getType(positions[cubit]);
544

    
545
      switch (type)
546
        {
547
        case CUBIT_111: if (!C111) { C111 = true; mTypeVariantMap[CUBIT_111]=numVariants++; }
548
                        mCubitVariantMap[cubit]=mTypeVariantMap[CUBIT_111];
549
                        break;
550
        case CUBIT_211: if (!C211) { C211 = true; mTypeVariantMap[CUBIT_211]=numVariants++; }
551
                        mCubitVariantMap[cubit]=mTypeVariantMap[CUBIT_211];
552
                        break;
553
        case CUBIT_311: if (!C311) { C311 = true; mTypeVariantMap[CUBIT_311]=numVariants++; }
554
                        mCubitVariantMap[cubit]=mTypeVariantMap[CUBIT_311];
555
                        break;
556
        case CUBIT_221: if (!C221) { C221 = true; mTypeVariantMap[CUBIT_221]=numVariants++; }
557
                        mCubitVariantMap[cubit]=mTypeVariantMap[CUBIT_221];
558
                        break;
559
        case CUBIT_222: if (!C222) { C222 = true; mTypeVariantMap[CUBIT_222]=numVariants++; }
560
                        mCubitVariantMap[cubit]=mTypeVariantMap[CUBIT_222];
561
                        break;
562
        default       : mCubitVariantMap[cubit] = numVariants++;
563
        }
564
      }
565

    
566
    FactoryBandagedCubit factory = FactoryBandagedCubit.getInstance();
567
    factory.prepare(numVariants,numLayers[0],numLayers[1],numLayers[2]);
568

    
569
    return numVariants;
570
    }
571

    
572
///////////////////////////////////////////////////////////////////////////////////////////////////
573

    
574
  public int getCubitVariant(int cubit, int[] numLayers)
575
    {
576
    return mCubitVariantMap[cubit];
577
    }
578

    
579
///////////////////////////////////////////////////////////////////////////////////////////////////
580

    
581
  public float[][] getCuts(int[] numLayers)
582
    {
583
    if( mCuts==null )
584
      {
585
      mCuts = new float[3][];
586

    
587
      for(int axis=0; axis<3; axis++)
588
        {
589
        int len = numLayers[axis];
590
        float start = (2-len)*0.5f;
591

    
592
        if( len>=2 )
593
          {
594
          mCuts[axis] = new float[len-1];
595
          for(int i=0; i<len-1; i++) mCuts[axis][i] = start+i;
596
          }
597
        }
598
      }
599

    
600
    return mCuts;
601
    }
602

    
603
///////////////////////////////////////////////////////////////////////////////////////////////////
604

    
605
  public boolean[][] getLayerRotatable(int[] numLayers)
606
    {
607
    int numAxis = ROT_AXIS.length;
608
    boolean[][] layerRotatable = new boolean[numAxis][];
609

    
610
    for(int i=0; i<numAxis; i++)
611
      {
612
      layerRotatable[i] = new boolean[numLayers[i]];
613
      for(int j=0; j<numLayers[i]; j++) layerRotatable[i][j] = true;
614
      }
615

    
616
    return layerRotatable;
617
    }
618

    
619
///////////////////////////////////////////////////////////////////////////////////////////////////
620

    
621
  public int getTouchControlType()
622
    {
623
    return TC_CUBOID;
624
    }
625

    
626
///////////////////////////////////////////////////////////////////////////////////////////////////
627

    
628
  public int getTouchControlSplit()
629
    {
630
    return TYPE_NOT_SPLIT;
631
    }
632

    
633
///////////////////////////////////////////////////////////////////////////////////////////////////
634

    
635
  public int[][][] getEnabled()
636
    {
637
    return new int[][][] { {{1,2}},{{1,2}},{{0,2}},{{0,2}},{{0,1}},{{0,1}} };
638
    }
639

    
640
///////////////////////////////////////////////////////////////////////////////////////////////////
641

    
642
  public float[] getDist3D(int[] numLayers)
643
    {
644
    float x = numLayers[0];
645
    float y = numLayers[1];
646
    float z = numLayers[2];
647
    float a = (x+y+z)/1.5f;
648

    
649
    return new float[] {x/a,x/a,y/a,y/a,z/a,z/a};
650
    }
651

    
652
///////////////////////////////////////////////////////////////////////////////////////////////////
653

    
654
  public Static3D[] getFaceAxis()
655
    {
656
    return TouchControlHexahedron.FACE_AXIS;
657
    }
658

    
659
///////////////////////////////////////////////////////////////////////////////////////////////////
660

    
661
  public float getStickerRadius()
662
    {
663
    return 0.10f;
664
    }
665

    
666
///////////////////////////////////////////////////////////////////////////////////////////////////
667

    
668
  public float getStickerStroke()
669
    {
670
    return isInIconMode() ? 0.16f : 0.08f;
671
    }
672

    
673
///////////////////////////////////////////////////////////////////////////////////////////////////
674

    
675
  public float[][] getStickerAngles()
676
    {
677
    return null;
678
    }
679

    
680
///////////////////////////////////////////////////////////////////////////////////////////////////
681
// PUBLIC API
682

    
683
  public Static3D[] getRotationAxis()
684
    {
685
    return ROT_AXIS;
686
    }
687

    
688
///////////////////////////////////////////////////////////////////////////////////////////////////
689

    
690
  public int[][] getBasicAngles()
691
    {
692
     if( mBasicAngle==null )
693
      {
694
      int[] num = getNumLayers();
695
      int numX = num[0];
696
      int numY = num[1];
697
      int numZ = num[2];
698

    
699
      int x = numY==numZ ? 4 : 2;
700
      int y = numX==numZ ? 4 : 2;
701
      int z = numX==numY ? 4 : 2;
702

    
703
      int[] tmpX = new int[numX];
704
      for(int i=0; i<numX; i++) tmpX[i] = x;
705
      int[] tmpY = new int[numY];
706
      for(int i=0; i<numY; i++) tmpY[i] = y;
707
      int[] tmpZ = new int[numZ];
708
      for(int i=0; i<numZ; i++) tmpZ[i] = z;
709

    
710
      mBasicAngle = new int[][] { tmpX,tmpY,tmpZ };
711
      }
712

    
713
    return mBasicAngle;
714
    }
715

    
716
///////////////////////////////////////////////////////////////////////////////////////////////////
717

    
718
  float[][] getPositions()
719
    {
720
    if( mPosition==null ) mPosition = getInitData().getPos();
721
    return mPosition;
722
    }
723

    
724
///////////////////////////////////////////////////////////////////////////////////////////////////
725

    
726
  public static int getType(String shortName, String longName)
727
    {
728
    if( shortName.equals(ObjectType.BAN1_3.name()) ||
729
        shortName.equals(ObjectType.BAN2_3.name()) ||
730
        shortName.equals(ObjectType.BAN3_3.name()) ||
731
        shortName.equals(ObjectType.BAN4_3.name())  ) return 2;
732

    
733
    if( longName.equals(OBJECT_NAME) ) return 1;
734

    
735
    return 0;
736
    }
737

    
738
///////////////////////////////////////////////////////////////////////////////////////////////////
739
// PUBLIC APi
740

    
741
  public String getShortName()
742
    {
743
    if( mPosition==null ) mPosition = getInitData().getPos();
744

    
745
    if( mPosition==POS_1 ) return ObjectType.BAN1_3.name();
746
    if( mPosition==POS_2 ) return ObjectType.BAN2_3.name();
747
    if( mPosition==POS_3 ) return ObjectType.BAN3_3.name();
748
    if( mPosition==POS_4 ) return ObjectType.BAN4_3.name();
749

    
750
    if( mSignature==null ) mSignature = getSignature();
751
    int[] numLayers = getNumLayers();
752
    int number = 100*numLayers[0]+10*numLayers[1]+numLayers[2];
753

    
754
    return number+"_"+mSignature.getString();
755
    }
756

    
757
///////////////////////////////////////////////////////////////////////////////////////////////////
758

    
759
  public ObjectSignature getSignature()
760
    {
761
    if( mSignature==null )
762
      {
763
      int[] numLayers = getNumLayers();
764
      mSignature = new ObjectSignature(numLayers[0],numLayers[1],numLayers[2],mPosition);
765
      }
766
    return mSignature;
767
    }
768

    
769
///////////////////////////////////////////////////////////////////////////////////////////////////
770

    
771
  public String getObjectName()
772
    {
773
    if( mPosition==null ) mPosition = getInitData().getPos();
774

    
775
    if( mPosition==POS_1 ) return "Fused Cube";
776
    if( mPosition==POS_2 ) return "2Bar Cube";
777
    if( mPosition==POS_3 ) return "Bandaged Cube C";
778
    if( mPosition==POS_4 ) return "BiCube";
779

    
780
    return OBJECT_NAME;
781
    }
782

    
783
///////////////////////////////////////////////////////////////////////////////////////////////////
784

    
785
  public String getInventor()
786
    {
787
    if( mPosition==null ) mPosition = getInitData().getPos();
788

    
789
    if( mPosition==POS_1 ) return "Ting Huang";
790
    if( mPosition==POS_2 ) return "Unknown";
791
    if( mPosition==POS_3 ) return "Andreas Nortmann";
792
    if( mPosition==POS_4 ) return "Uwe Meffert";
793

    
794
    return "??";
795
    }
796

    
797
///////////////////////////////////////////////////////////////////////////////////////////////////
798

    
799
  public int getYearOfInvention()
800
    {
801
    if( mPosition==null ) mPosition = getInitData().getPos();
802

    
803
    if( mPosition==POS_1 ) return 2011;
804
    if( mPosition==POS_2 ) return 0;
805
    if( mPosition==POS_3 ) return 2005;
806
    if( mPosition==POS_4 ) return 1999;
807

    
808
    return 0;
809
    }
810

    
811
///////////////////////////////////////////////////////////////////////////////////////////////////
812

    
813
  public int getComplexity()
814
    {
815
    if( mPosition==null ) mPosition = getInitData().getPos();
816

    
817
    if( mPosition==POS_1 ) return 1;
818
    if( mPosition==POS_2 ) return 2;
819
    if( mPosition==POS_3 ) return 2;
820
    if( mPosition==POS_4 ) return 3;
821

    
822
    return 4;
823
    }
824

    
825
///////////////////////////////////////////////////////////////////////////////////////////////////
826

    
827
  public String[][] getTutorials()
828
    {
829
    if( mPosition==null ) mPosition = getInitData().getPos();
830

    
831
    if( mPosition==POS_1 )
832
      {
833
      return new String[][]{
834
                            {"gb","F_iJk_IvpVo","Bandaged Cube","CanChrisSolve"},
835
                            {"es","_lTgw5aEFOg","Tutorial 3x3 Fuse Cube","QBAndo"},
836
                            {"ru","raYDwFEXIq4","Как собрать Fused Cube","Алексей Ярыгин"},
837
                            {"fr","9Cfi4rhKzIw","Tutoriel: résolution du Fused Cube","Skieur Cubb"},
838
                            {"pl","0PcUoGxQa6s","Bandaged 3x3 v.A cube","MrUK"},
839
                            {"kr","1RePOLrzJNE","밴디지 타입 A 해법","듀나메스 큐브 해법연구소"},
840
                            {"vn","vg4J0U0n1oA","Tutorial N.1 - Bandaged VA","Duy Thích Rubik"},
841
                           };
842
      }
843
    if( mPosition==POS_2 )
844
      {
845
      return new String[][]{
846
                            {"ru","lS_EK0PMWI8","Как собрать 2-bar Cube","Алексей Ярыгин"},
847
                            {"pl","tX8ubTLh6p8","Bandaged 3x3 (Two bar)","MrUK"},
848
                            {"kr","NE6XuC1r8xw","밴디지 큐브","Denzel Washington"},
849
                           };
850
      }
851
    if( mPosition==POS_3 )
852
      {
853
      return new String[][]{
854
                            {"gb","7UiCVGygUT4","Bandage Cube C Tutorial","PolyakB"},
855
                            {"ru","gXenRA92Wdc","Как собрать Bandaged 3x3 Type C","YG Cuber"},
856
                            {"pl","sKfdFLm79Zs","Bandaged 3x3 v.C cube","MrUK"},
857
                            {"kr","BcCFgeFy6Ec","밴디지 타입 C 해법","듀나메스 큐브 해법연구소"},
858
                            {"vn","9674LLkPSog","Tutorial N.2 - Bandaged VC","Duy Thích Rubik"},
859
                           };
860
      }
861
    if( mPosition==POS_4 )
862
      {
863
      return new String[][]{
864
                            {"gb","AnpdIKICBpM","Trying to Solve a Bandaged Cube","RedKB"},
865
                            {"es","cUyo5fycrvI","Tutorial Bandaged Cube en español","Rafa Garcia Benacazon"},
866
                            {"ru","-MTzeEJptsg","Как собрать bandaged Cube B","стратегия знаний"},
867
                            {"fr","3rsfIJ3roT0","Tutoriel: résolution du Bicube","Skieur Cubb"},
868
                            {"de","sqWVRwkXX9w","Bandaged Cube - Tutorial","GerCubing"},
869
                            {"pl","XcHzTvVR6Po","Bandaged 3x3 v.B cube","MrUK"},
870
                            {"kr","1gsoijF_5q0","BiCube Tutorial (해법)","듀나메스 큐브 해법연구소"},
871
                            {"vn","ZCJDaF4jEbc","Tutorial N.3 - BiCube","Duy Thích Rubik"},
872
                           };
873
      }
874

    
875
    return null;
876
    }
877
}
(2-2/36)