Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / TwistyMegaminx.java @ 3d8237cc

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 static org.distorted.objects.FactoryCubit.COS18;
37
import static org.distorted.objects.FactoryCubit.SIN18;
38

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

    
41
public class TwistyMegaminx extends TwistyMinx
42
{
43
  static final float MEGA_D = 0.05f;
44

    
45
  private static final int NUM_CORNERS = 20;
46
  private static final int NUM_CENTERS = 12;
47
  private static final int NUM_EDGES   = 30;
48

    
49
  // the five vertices that form a given face. Order: the same as colors
50
  // of the faces in TwistyMinx.
51
  private static final int[][] mCenterMap =
52
         {
53
           { 0, 12,  4, 14,  2},
54
           { 0,  2, 18,  6, 16},
55
           { 6, 18, 11, 19,  7},
56
           { 3, 15,  9, 11, 19},
57
           { 4,  5, 15,  9, 14},
58
           { 1, 13,  5, 15,  3},
59
           { 1,  3, 19,  7, 17},
60
           {10, 16,  6,  7, 17},
61
           { 0, 12,  8, 10, 16},
62
           { 8, 13,  5,  4, 12},
63
           { 1, 13,  8, 10, 17},
64
           { 2, 14,  9, 11, 18},
65
         };
66

    
67
  // the quadruple ( vertex1, vertex2, face1, face2 ) defining an edge.
68
  // In fact the 2 vertices already define it, the faces only provide easy
69
  // way to get to know the colors. Order: arbitrary. Face1 arbitrarily on
70
  // the 'left' or right of vector vertex1 --> vertex2, according to Quat.
71
  private static final int[][] mEdgeMap =
72
         {
73
           {  0, 12,  0,  8},
74
           { 12,  4,  0,  9},
75
           {  4, 14,  0,  4},
76
           { 14,  2,  0, 11},
77
           {  2,  0,  0,  1},
78
           { 14,  9,  4, 11},
79
           {  9, 11,  3, 11},
80
           { 11, 18,  2, 11},
81
           { 18,  2,  1, 11},
82
           { 18,  6,  1,  2},
83
           {  6, 16,  1,  7},
84
           { 16,  0,  8,  1},
85
           { 16, 10,  7,  8},
86
           { 10,  8, 10,  8},
87
           {  8, 12,  9,  8},
88
           {  8, 13,  9, 10},
89
           { 13,  5,  9,  5},
90
           {  5,  4,  9,  4},
91
           {  5, 15,  5,  4},
92
           { 15,  9,  3,  4},
93
           { 11, 19,  2,  3},
94
           { 19,  7,  2,  6},
95
           {  7,  6,  2,  7},
96
           {  7, 17,  7,  6},
97
           { 17, 10,  7, 10},
98
           { 17,  1, 10,  6},
99
           {  1,  3,  5,  6},
100
           {  3, 19,  3,  6},
101
           {  1, 13, 10,  5},
102
           {  3, 15,  3,  5},
103
         };
104

    
105
  private static final float[][] mCenterCoords = new float[NUM_CENTERS][3];
106

    
107
  static
108
    {
109
    for(int center=0; center<NUM_CENTERS; center++)
110
      {
111
      int[] map = mCenterMap[center];
112

    
113
      float x = CORNERS[map[0]].get0() +
114
                CORNERS[map[1]].get0() +
115
                CORNERS[map[2]].get0() +
116
                CORNERS[map[3]].get0() +
117
                CORNERS[map[4]].get0() ;
118

    
119
      float y = CORNERS[map[0]].get1() +
120
                CORNERS[map[1]].get1() +
121
                CORNERS[map[2]].get1() +
122
                CORNERS[map[3]].get1() +
123
                CORNERS[map[4]].get1() ;
124

    
125
      float z = CORNERS[map[0]].get2() +
126
                CORNERS[map[1]].get2() +
127
                CORNERS[map[2]].get2() +
128
                CORNERS[map[3]].get2() +
129
                CORNERS[map[4]].get2() ;
130

    
131
      mCenterCoords[center][0] = x/5;
132
      mCenterCoords[center][1] = y/5;
133
      mCenterCoords[center][2] = z/5;
134
      }
135
    }
136

    
137
  private static MeshBase[] mCenterMeshes, mCornerMeshes;
138
  private static MeshBase[][] mEdgeMeshes;
139

    
140
  private static final Static4D[] mBasicCornerV, mCurrCornerV;
141

    
142
  static
143
    {
144
    mBasicCornerV = new Static4D[3];
145
    mCurrCornerV  = new Static4D[3];
146

    
147
    mBasicCornerV[0] = new Static4D( (SQ5+1)*0.125f, (SQ5-1)*0.125f, -0.250f, 0.0f );
148
    mBasicCornerV[1] = new Static4D(-(SQ5+1)*0.125f, (SQ5-1)*0.125f, -0.250f, 0.0f );
149
    mBasicCornerV[2] = new Static4D(              0,        -0.500f,    0.0f, 0.0f );
150
    };
151

    
152
///////////////////////////////////////////////////////////////////////////////////////////////////
153

    
154
  TwistyMegaminx(int size, Static4D quat, DistortedTexture texture, MeshSquare mesh,
155
                 DistortedEffects effects, int[][] moves, Resources res, int scrWidth)
156
    {
157
    super(size, size, quat, texture, mesh, effects, moves, ObjectList.MEGA, res, scrWidth);
158
    }
159

    
160
///////////////////////////////////////////////////////////////////////////////////////////////////
161

    
162
  private int numCubitsPerCorner(int numLayers)
163
    {
164
    return 3*((numLayers-1)/2)*((numLayers-3)/2) + 1;
165
    }
166

    
167
///////////////////////////////////////////////////////////////////////////////////////////////////
168

    
169
  private int numCubitsPerEdge(int numLayers)
170
    {
171
    return numLayers-2;
172
    }
173

    
174
///////////////////////////////////////////////////////////////////////////////////////////////////
175

    
176
  int getNumStickerTypes(int numLayers)
177
    {
178
    return numLayers-1; //numLayers;
179
    }
180

    
181
///////////////////////////////////////////////////////////////////////////////////////////////////
182

    
183
  float[] getCuts(int numLayers)
184
    {
185
    float[] cuts = new float[numLayers-1];
186
    float D = (numLayers/3.0f)*MovementMinx.DIST3D;
187
    float E = 2*C1;           // 2*cos(36 deg)
188
    float X = 2*D*E/(1+2*E);  // height of the 'upper' part of a dodecahedron, i.e. put it on a table,
189
                              // its height is then 2*DIST3D, it has one 'lower' part of height X, one
190
                              // 'middle' part of height Y and one upper part of height X again.
191
                              // It's edge length = numLayers/3.0f.
192
    int num = (numLayers-1)/2;
193
    float G = X*(0.5f-MEGA_D)/num; // height of one Layer
194

    
195
    for(int i=0; i<num; i++)
196
      {
197
      cuts[        i] = -MovementMinx.DIST3D + (i+0.5f)*G;
198
      cuts[2*num-1-i] = -cuts[i];
199
      }
200

    
201
    return cuts;
202
    }
203

    
204
///////////////////////////////////////////////////////////////////////////////////////////////////
205

    
206
  private void computeCenter(Static3D[] array, int center)
207
    {
208
    float[] coords = mCenterCoords[center];
209
    array[center].set( coords[0], coords[1], coords[2]);
210
    }
211

    
212
///////////////////////////////////////////////////////////////////////////////////////////////////
213
// Fill out mCurrCorner{X,Y,Z} by applying appropriate Quat to mBasicCorner{X,Y,Z}
214
// Appropriate one: QUATS[QUAT_INDICES[corner]].
215

    
216
  private void computeBasicCornerVectors(int corner)
217
    {
218
    Static4D quat = QUATS[QUAT_CORNER_INDICES[corner]];
219

    
220
    mCurrCornerV[0] = RubikSurfaceView.rotateVectorByQuat(mBasicCornerV[0],quat);
221
    mCurrCornerV[1] = RubikSurfaceView.rotateVectorByQuat(mBasicCornerV[1],quat);
222
    mCurrCornerV[2] = RubikSurfaceView.rotateVectorByQuat(mBasicCornerV[2],quat);
223
    }
224

    
225
///////////////////////////////////////////////////////////////////////////////////////////////////
226

    
227
  private void computeCorner(Static3D pos, int numCubitsPerCorner, int numLayers, int corner, int part)
228
    {
229
    float D = numLayers/3.0f;
230
    Static3D corn = CORNERS[corner];
231

    
232
    if( part==0 )
233
      {
234
      pos.set( corn.get0()*D, corn.get1()*D, corn.get2()*D );
235
      }
236
    else
237
      {
238
      float E = 2.0f*(numLayers/3.0f)*(0.5f-MEGA_D)/(0.5f*(numLayers-1));
239
      int N = (numCubitsPerCorner-1)/3;
240
      int block = (part-1) % N;
241
      int index = (part-1) / N;
242
      Static4D pri = mCurrCornerV[index];
243
      Static4D sec = mCurrCornerV[(index+2)%3];
244

    
245
      int multP = (block % ((numLayers-3)/2)) + 1;
246
      int multS = (block / ((numLayers-3)/2));
247

    
248
      pos.set( corn.get0()*D + (pri.get0()*multP + sec.get0()*multS)*E,
249
               corn.get1()*D + (pri.get1()*multP + sec.get1()*multS)*E,
250
               corn.get2()*D + (pri.get2()*multP + sec.get2()*multS)*E );
251
      }
252
    }
253

    
254
///////////////////////////////////////////////////////////////////////////////////////////////////
255

    
256
  private int computeEdgeType(int cubit, int numCubitsPerCorner, int numCubitsPerEdge)
257
    {
258
    int part = (cubit - NUM_CORNERS*numCubitsPerCorner) % numCubitsPerEdge;
259
    return (part+1)/2;
260
    }
261

    
262
///////////////////////////////////////////////////////////////////////////////////////////////////
263

    
264
  private void computeEdge(Static3D pos, int numLayers, int edge, int part)
265
    {
266
    float corr = numLayers/3.0f;
267

    
268
    Static3D c1 = CORNERS[ mEdgeMap[edge][0] ];
269
    Static3D c2 = CORNERS[ mEdgeMap[edge][1] ];
270
    float x = corr*(c1.get0() + c2.get0())/2;
271
    float y = corr*(c1.get1() + c2.get1())/2;
272
    float z = corr*(c1.get2() + c2.get2())/2;
273

    
274
    if( part==0 )
275
      {
276
      pos.set(x,y,z);
277
      }
278
    else
279
      {
280
      int mult = (part+1)/2;
281
      int dir  = (part+1)%2;
282
      float[] center = mCenterCoords[ mEdgeMap[edge][dir+2] ];
283

    
284
      float vX = corr*center[0] - x;
285
      float vY = corr*center[1] - y;
286
      float vZ = corr*center[2] - z;
287

    
288
      float len = (float)Math.sqrt(vX*vX+vY*vY+vZ*vZ);
289
      float A = mult*corr*(0.5f-MEGA_D)*COS18/((numLayers-1)*0.5f)/len;
290

    
291
      pos.set( x+A*vX, y+A*vY, z+A*vZ );
292
      }
293
    }
294

    
295
///////////////////////////////////////////////////////////////////////////////////////////////////
296

    
297
  Static3D[] getCubitPositions(int numLayers)
298
    {
299
    int numCubitsPerCorner = numCubitsPerCorner(numLayers);
300
    int numCubitsPerEdge   = numCubitsPerEdge(numLayers);
301
    int numCubits = NUM_CORNERS*numCubitsPerCorner + NUM_EDGES*numCubitsPerEdge;// + NUM_CENTERS;
302
    int index=0;
303

    
304
    final Static3D[] CENTERS = new Static3D[numCubits];
305

    
306
    for(int corner=0; corner<NUM_CORNERS; corner++)
307
      {
308
      computeBasicCornerVectors(corner);
309

    
310
      for(int part=0; part<numCubitsPerCorner; part++, index++)
311
        {
312
        CENTERS[index] = new Static3D(0,0,0);
313
        computeCorner(CENTERS[index],numCubitsPerCorner,numLayers,corner,part);
314
        }
315
      }
316

    
317
    for(int edge=0; edge<NUM_EDGES; edge++)
318
      {
319
      for(int part=0; part<numCubitsPerEdge; part++, index++)
320
        {
321
        CENTERS[index] = new Static3D(0,0,0);
322
        computeEdge(CENTERS[index], numLayers, edge, part );
323
        }
324
      }
325
/*
326
    for(int center=0; center<NUM_CENTERS; center++, index++)
327
      {
328
      computeCenter(CENTERS,index);
329
      }
330
*/
331
    return CENTERS;
332
    }
333

    
334
///////////////////////////////////////////////////////////////////////////////////////////////////
335

    
336
  private int getQuat(int cubit, int numLayers)
337
    {
338
    int numCubitsPerCorner = numCubitsPerCorner(numLayers);
339

    
340
    if( cubit < NUM_CORNERS*numCubitsPerCorner )
341
      {
342
      int corner = cubit/numCubitsPerCorner;
343
      return QUAT_CORNER_INDICES[corner];
344
      }
345

    
346
    int numCubitsPerEdge = numCubitsPerEdge(numLayers);
347

    
348
    if( cubit < NUM_CORNERS*numCubitsPerCorner + NUM_EDGES*numCubitsPerEdge )
349
      {
350
      int edge = (cubit-NUM_CORNERS*numCubitsPerCorner)/numCubitsPerEdge;
351
      return QUAT_EDGE_INDICES[edge];
352
      }
353

    
354
/*
355
    else
356
      {
357
      // TODO: centers
358
      }
359
*/
360

    
361
    return 0;
362
    }
363

    
364
///////////////////////////////////////////////////////////////////////////////////////////////////
365

    
366
  MeshBase createCubitMesh(int cubit, int numLayers)
367
    {
368
    int numCubitsPerCorner = numCubitsPerCorner(numLayers);
369
    int numCubitsPerEdge   = numCubitsPerEdge(numLayers);
370
    int index = (numLayers-3)/2;
371
    int[] sizes = ObjectList.MEGA.getSizes();
372
    int variants = sizes.length;
373
    MeshBase mesh;
374

    
375
    if( mCornerMeshes==null ) mCornerMeshes = new MeshBase[variants];
376
    if( mEdgeMeshes  ==null ) mEdgeMeshes   = new MeshBase[variants][(sizes[variants-1]-1)/2];
377

    
378
    if( cubit < NUM_CORNERS*numCubitsPerCorner )
379
      {
380
      if( mCornerMeshes[index]==null )
381
        {
382
        mCornerMeshes[index] = FactoryCubit.getInstance().createMegaminxCornerMesh(numLayers);
383
        }
384
      mesh = mCornerMeshes[index].copy(true);
385
      }
386
    else //if( cubit<NUM_CORNERS*numCubitsPerCorner + NUM_EDGES*numCubitsPerEdge )
387
      {
388
      int type = computeEdgeType(cubit,numCubitsPerCorner,numCubitsPerEdge);
389

    
390
      if( mEdgeMeshes[index][type]==null )
391
        {
392
        float height= (numLayers/3.0f)*(0.5f-MEGA_D)*COS18/((numLayers-1)*0.5f);
393
        float width = (numLayers/3.0f)*2*MEGA_D + 2*type*height*SIN18/COS18;
394

    
395
        mEdgeMeshes[index][type] = FactoryCubit.getInstance().createMegaminxEdgeMesh(width,height);
396
        }
397

    
398
      mesh = mEdgeMeshes[index][type].copy(true);
399
      }
400
/*
401
    else
402
      {
403
      // TODO: centers
404
      }
405
*/
406
    Static4D q = QUATS[getQuat(cubit,numLayers)];
407
    MatrixEffectQuaternion quat = new MatrixEffectQuaternion( q, new Static3D(0,0,0) );
408
    mesh.apply(quat,0xffffffff,0);
409

    
410
    return mesh;
411
    }
412

    
413
///////////////////////////////////////////////////////////////////////////////////////////////////
414

    
415
  int getCornerColor(int cubit, int cubitface, int numLayers, int numCubitsPerCorner)
416
    {
417
    if( cubitface<0 || cubitface>2 ) return NUM_TEXTURES*NUM_FACES;
418

    
419
    int part  = cubit % numCubitsPerCorner;
420
    int corner= cubit / numCubitsPerCorner;
421

    
422
    if( part==0 )
423
      {
424
      return mCornerFaceMap[corner][cubitface];
425
      }
426
    else
427
      {
428
      int N = (numCubitsPerCorner-1)/3;
429
      int block = (part-1) % N;
430
      int index = (part-1) / N;
431

    
432
      if( block< (numLayers-1)/2 )
433
        {
434
        switch(index)
435
          {
436
          case 0: return cubitface==1 ? NUM_TEXTURES*NUM_FACES : mCornerFaceMap[corner][cubitface];
437
          case 1: return cubitface==0 ? NUM_TEXTURES*NUM_FACES : mCornerFaceMap[corner][cubitface];
438
          case 2: return cubitface==2 ? NUM_TEXTURES*NUM_FACES : mCornerFaceMap[corner][cubitface];
439
          }
440
        }
441
      else
442
        {
443
        switch(index)
444
          {
445
          case 0: return cubitface==0 ? mCornerFaceMap[corner][cubitface] : NUM_TEXTURES*NUM_FACES;
446
          case 1: return cubitface==2 ? mCornerFaceMap[corner][cubitface] : NUM_TEXTURES*NUM_FACES;
447
          case 2: return cubitface==1 ? mCornerFaceMap[corner][cubitface] : NUM_TEXTURES*NUM_FACES;
448
          }
449
        }
450
      }
451

    
452
    return NUM_TEXTURES*NUM_FACES;
453
    }
454

    
455
///////////////////////////////////////////////////////////////////////////////////////////////////
456

    
457
  int getEdgeColor(int cubit, int cubitface, int numLayers, int numCubitsPerCorner, int numCubitsPerEdge)
458
    {
459
    if( cubitface<0 || cubitface>1 ) return NUM_TEXTURES*NUM_FACES;
460

    
461
    int part = (cubit - NUM_CORNERS*numCubitsPerCorner) % numCubitsPerEdge;
462
    int edge = (cubit - NUM_CORNERS*numCubitsPerCorner) / numCubitsPerEdge;
463

    
464
    if( part==0 )
465
      {
466
      return mEdgeMap[edge][cubitface+2];
467
      }
468

    
469
    return cubitface==((part+1)%2) ? mEdgeMap[edge][cubitface+2] : NUM_TEXTURES*NUM_FACES;
470
    }
471

    
472
///////////////////////////////////////////////////////////////////////////////////////////////////
473
// TODO
474

    
475
  int getCenterColor(int cubit, int cubitface, int numLayers)
476
    {
477
    return 0;
478
    }
479

    
480
///////////////////////////////////////////////////////////////////////////////////////////////////
481

    
482
  int getFaceColor(int cubit, int cubitface, int numLayers)
483
    {
484
    int numCubitsPerCorner = numCubitsPerCorner(numLayers);
485
    int numCubitsPerEdge   = numCubitsPerEdge(numLayers);
486

    
487
    if( cubit < NUM_CORNERS*numCubitsPerCorner )
488
      {
489
      return getCornerColor(cubit,cubitface,numLayers,numCubitsPerCorner);
490
      }
491
    else if( cubit<NUM_CORNERS*numCubitsPerCorner + NUM_EDGES*numCubitsPerEdge )
492
      {
493
      return getEdgeColor(cubit,cubitface,numLayers,numCubitsPerCorner,numCubitsPerEdge);
494
      }
495
    else
496
      {
497
      return getCenterColor(cubit,cubitface,numLayers);
498
      }
499
    }
500

    
501
///////////////////////////////////////////////////////////////////////////////////////////////////
502
// TODO
503

    
504
  void createFaceTexture(Canvas canvas, Paint paint, int face, int left, int top)
505
    {
506
    paint.setColor(FACE_COLORS[face%NUM_FACES]);
507
    paint.setStyle(Paint.Style.FILL);
508
    canvas.drawRect(left,top,left+TEXTURE_HEIGHT,top+TEXTURE_HEIGHT,paint);
509
    }
510

    
511
///////////////////////////////////////////////////////////////////////////////////////////////////
512
// PUBLIC API
513

    
514
  public boolean isSolved()
515
    {
516
    int index = CUBITS[0].mQuatIndex;
517

    
518
    for(int i=1; i<NUM_CUBITS; i++)
519
      {
520
      if( !thereIsNoVisibleDifference(CUBITS[i], index) ) return false;
521
      }
522

    
523
    return true;
524
    }
525

    
526
///////////////////////////////////////////////////////////////////////////////////////////////////
527
// return if the Cubit, when rotated with its own mQuatScramble, would have looked any different
528
// then if it were rotated by quaternion 'quat'.
529
// No it is not so simple as the quats need to be the same - imagine a 4x4x4 cube where the two
530
// middle squares get interchanged. No visible difference!
531
//
532
// So: this is true iff the cubit
533
// a) is a corner or edge and the quaternions are the same
534
// b) is inside one of the faces and after rotations by both quats it ends up on the same face.
535

    
536
  private boolean thereIsNoVisibleDifference(Cubit cubit, int quatIndex)
537
    {
538
    if ( cubit.mQuatIndex == quatIndex ) return true;
539

    
540
    int belongsToHowManyFaces = 0;
541
    int lastLayer = getNumLayers()-1;
542
    float row;
543
    final float MAX_ERROR = 0.01f;
544

    
545
    for(int i=0; i<NUM_AXIS; i++)
546
      {
547
      row = cubit.mRotationRow[i];
548
      if( (row          <MAX_ERROR && row          >-MAX_ERROR) ||
549
          (row-lastLayer<MAX_ERROR && row-lastLayer>-MAX_ERROR)  ) belongsToHowManyFaces++;
550
      }
551

    
552
    switch(belongsToHowManyFaces)
553
      {
554
      case 0 : return true ;  // 'inside' cubit that does not lie on any face
555
      case 1 :                // cubit that lies inside one of the faces
556
               Static3D orig = cubit.getOrigPosition();
557
               Static4D quat1 = QUATS[quatIndex];
558
               Static4D quat2 = QUATS[cubit.mQuatIndex];
559

    
560
               Static4D cubitCenter = new Static4D( orig.get0(), orig.get1(), orig.get2(), 0);
561
               Static4D rotated1 = RubikSurfaceView.rotateVectorByQuat( cubitCenter, quat1 );
562
               Static4D rotated2 = RubikSurfaceView.rotateVectorByQuat( cubitCenter, quat2 );
563

    
564
               float row1, row2;
565
               float x1 = rotated1.get0();
566
               float y1 = rotated1.get1();
567
               float z1 = rotated1.get2();
568
               float x2 = rotated2.get0();
569
               float y2 = rotated2.get1();
570
               float z2 = rotated2.get2();
571

    
572
               for(int i=0; i<NUM_AXIS; i++)
573
                 {
574
                 row1 = computeRow(x1,y1,z1,i);
575
                 row2 = computeRow(x2,y2,z2,i);
576

    
577
                 if( (row1==0 && row2==0) || (row1==lastLayer && row2==lastLayer) ) return true;
578
                 }
579
               return false;
580

    
581
      default: return false;  // edge or corner
582
      }
583
    }
584

    
585
///////////////////////////////////////////////////////////////////////////////////////////////////
586

    
587
  public int getObjectName(int numLayers)
588
    {
589
    if( numLayers==3 ) return R.string.minx3;
590
    if( numLayers==5 ) return R.string.minx4;
591

    
592
    return 0;
593
    }
594

    
595
///////////////////////////////////////////////////////////////////////////////////////////////////
596

    
597
  public int getInventor(int numLayers)
598
    {
599
    if( numLayers==3 ) return R.string.minx3_inventor;
600
    if( numLayers==5 ) return R.string.minx4_inventor;
601

    
602
    return 0;
603
    }
604

    
605
///////////////////////////////////////////////////////////////////////////////////////////////////
606

    
607
  public int getComplexity(int numLayers)
608
    {
609
    if( numLayers==3 ) return 4;
610

    
611
    return 5;
612
    }
613
}
(24-24/30)