Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / TwistyCube.java @ 9c2f0c91

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2019 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.VertexEffectDeform;
27
import org.distorted.library.effect.VertexEffectMove;
28
import org.distorted.library.effect.VertexEffectRotate;
29
import org.distorted.library.main.DistortedEffects;
30
import org.distorted.library.main.DistortedTexture;
31
import org.distorted.library.mesh.MeshBase;
32
import org.distorted.library.mesh.MeshJoined;
33
import org.distorted.library.mesh.MeshPolygon;
34
import org.distorted.library.mesh.MeshSquare;
35
import org.distorted.library.type.Static1D;
36
import org.distorted.library.type.Static3D;
37
import org.distorted.library.type.Static4D;
38
import org.distorted.main.RubikSurfaceView;
39

    
40
import java.util.Random;
41

    
42
import static org.distorted.effects.scramble.ScrambleEffect.START_AXIS;
43

    
44
///////////////////////////////////////////////////////////////////////////////////////////////////
45

    
46
class TwistyCube extends TwistyObject
47
{
48
  static final float SQ2 = (float)Math.sqrt(2);
49

    
50
  // the three rotation axis of a RubikCube. Must be normalized.
51
  static final Static3D[] ROT_AXIS = new Static3D[]
52
         {
53
           new Static3D(1,0,0),
54
           new Static3D(0,1,0),
55
           new Static3D(0,0,1)
56
         };
57

    
58
  // the six axis that determine the faces
59
  static final Static3D[] FACE_AXIS = new Static3D[]
60
         {
61
           new Static3D(1,0,0), new Static3D(-1,0,0),
62
           new Static3D(0,1,0), new Static3D(0,-1,0),
63
           new Static3D(0,0,1), new Static3D(0,0,-1)
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_BROWN
71
         };
72

    
73
  // All legal rotation quats of a RubikCube of any size.
74
  // Here's how to compute this:
75
  // 1) compute how many rotations there are (RubikCube of any size = 24)
76
  // 2) take the AXIS, angles of rotation (90 in RubikCube's case) compute the basic quaternions
77
  // (i.e. rotations of 1 basic angle along each of the axis) and from there start semi-randomly
78
  // multiplying them and eventually you'll find all (24) legal rotations.
79
  // Example program in C, res/raw/compute_quats.c , is included.
80
  private static final Static4D[] QUATS = new Static4D[]
81
         {
82
         new Static4D(  0.0f,   0.0f,   0.0f,   1.0f),
83
         new Static4D(  1.0f,   0.0f,   0.0f,   0.0f),
84
         new Static4D(  0.0f,   1.0f,   0.0f,   0.0f),
85
         new Static4D(  0.0f,   0.0f,   1.0f,   0.0f),
86

    
87
         new Static4D( SQ2/2,  SQ2/2,  0.0f ,   0.0f),
88
         new Static4D( SQ2/2, -SQ2/2,  0.0f ,   0.0f),
89
         new Static4D( SQ2/2,   0.0f,  SQ2/2,   0.0f),
90
         new Static4D(-SQ2/2,   0.0f,  SQ2/2,   0.0f),
91
         new Static4D( SQ2/2,   0.0f,   0.0f,  SQ2/2),
92
         new Static4D( SQ2/2,   0.0f,   0.0f, -SQ2/2),
93
         new Static4D(  0.0f,  SQ2/2,  SQ2/2,   0.0f),
94
         new Static4D(  0.0f,  SQ2/2, -SQ2/2,   0.0f),
95
         new Static4D(  0.0f,  SQ2/2,   0.0f,  SQ2/2),
96
         new Static4D(  0.0f,  SQ2/2,   0.0f, -SQ2/2),
97
         new Static4D(  0.0f,   0.0f,  SQ2/2,  SQ2/2),
98
         new Static4D(  0.0f,   0.0f,  SQ2/2, -SQ2/2),
99

    
100
         new Static4D(  0.5f,   0.5f,   0.5f,   0.5f),
101
         new Static4D(  0.5f,   0.5f,  -0.5f,   0.5f),
102
         new Static4D(  0.5f,   0.5f,  -0.5f,  -0.5f),
103
         new Static4D(  0.5f,  -0.5f,   0.5f,  -0.5f),
104
         new Static4D( -0.5f,  -0.5f,  -0.5f,   0.5f),
105
         new Static4D( -0.5f,   0.5f,  -0.5f,  -0.5f),
106
         new Static4D( -0.5f,   0.5f,   0.5f,  -0.5f),
107
         new Static4D( -0.5f,   0.5f,   0.5f,   0.5f)
108
         };
109

    
110
  private static MeshBase[] mMeshes;
111

    
112
///////////////////////////////////////////////////////////////////////////////////////////////////
113

    
114
  TwistyCube(int size, Static4D quat, DistortedTexture texture,
115
             MeshSquare mesh, DistortedEffects effects, int[][] moves, Resources res, int scrWidth)
116
    {
117
    super(size, 60, quat, texture, mesh, effects, moves, ObjectList.CUBE, res, scrWidth);
118
    }
119

    
120
///////////////////////////////////////////////////////////////////////////////////////////////////
121
// paint the square with upper-right corner at (left,top) and side length 'side' with texture
122
// for face 'face'.
123

    
124
  void createFaceTexture(Canvas canvas, Paint paint, int face, int left, int top, int side)
125
    {
126
    final float R = side*0.10f;
127
    final float M = side*0.05f;
128

    
129
    paint.setColor(FACE_COLORS[face]);
130
    canvas.drawRoundRect( left+M, top+M, left+side-M, top+side-M, R, R, paint);
131
    }
132

    
133
///////////////////////////////////////////////////////////////////////////////////////////////////
134

    
135
  Static3D[] getCubitPositions(int size)
136
    {
137
    int numCubits = size>1 ? 6*size*size - 12*size + 8 : 1;
138
    Static3D[] tmp = new Static3D[numCubits];
139

    
140
    float diff = 0.5f*(size-1);
141
    int currentPosition = 0;
142

    
143
    for(int x = 0; x<size; x++)
144
      for(int y = 0; y<size; y++)
145
        for(int z = 0; z<size; z++)
146
          if( x==0 || x==size-1 || y==0 || y==size-1 || z==0 || z==size-1 )
147
            {
148
            tmp[currentPosition++] = new Static3D(x-diff,y-diff,z-diff);
149
            }
150

    
151
    return tmp;
152
    }
153

    
154
///////////////////////////////////////////////////////////////////////////////////////////////////
155

    
156
  Static4D[] getQuats()
157
    {
158
    return QUATS;
159
    }
160

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

    
163
  boolean shouldResetTextureMaps()
164
    {
165
    return false;
166
    }
167

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

    
170
  int getNumFaces()
171
    {
172
    return FACE_COLORS.length;
173
    }
174

    
175
///////////////////////////////////////////////////////////////////////////////////////////////////
176

    
177
  float getBasicStep()
178
    {
179
    return 1.0f;
180
    }
181

    
182
///////////////////////////////////////////////////////////////////////////////////////////////////
183

    
184
  int getNumStickerTypes()
185
    {
186
    return 1;
187
    }
188

    
189
///////////////////////////////////////////////////////////////////////////////////////////////////
190

    
191
  int getNumCubitFaces()
192
    {
193
    return FACE_COLORS.length;
194
    }
195

    
196
///////////////////////////////////////////////////////////////////////////////////////////////////
197

    
198
  float getScreenRatio()
199
    {
200
    return 0.5f;
201
    }
202

    
203
///////////////////////////////////////////////////////////////////////////////////////////////////
204

    
205
  int getFaceColor(int cubit, int cubitface, int size)
206
    {
207
    boolean belongs = isOnFace(cubit, cubitface/2, cubitface%2==0 ? size-1:0 );
208
    return belongs ? cubitface : NUM_FACES;
209
    }
210

    
211
///////////////////////////////////////////////////////////////////////////////////////////////////
212

    
213
  MeshBase createCubitMesh(int cubit)
214
    {
215
    int size   = getSize();
216
    int ordinal= ObjectList.CUBE.ordinal();
217
    int index  = ObjectList.getSizeIndex(ordinal,size);
218
    float[] bands;
219
    float D = 0.027f;
220
    float E = 0.5f-D;
221
    float[] vertices = { -E,-E, +E,-E, +E,+E, -E,+E };
222
    int extraI, extraV;
223

    
224
    switch(size)
225
      {
226
      case 2 : bands = new float[] { 1.0f    ,-D,
227
                                     1.0f-D/2,-D*0.55f,
228
                                     1.0f-D  ,-D*0.25f,
229
                                     1.0f-2*D, 0.0f,
230
                                     0.50f, 0.040f,
231
                                     0.0f, 0.048f };
232
               extraI = 2;
233
               extraV = 2;
234
               break;
235
      case 3 : bands = new float[] { 1.0f    ,-D,
236
                                     1.0f-D*1.2f,-D*0.55f,
237
                                     1.0f-2*D, 0.0f,
238
                                     0.50f, 0.040f,
239
                                     0.0f, 0.048f };
240
               extraI = 2;
241
               extraV = 2;
242
               break;
243
      case 4 : bands = new float[] { 1.0f    ,-D,
244
                                     1.0f-D*1.2f,-D*0.55f,
245
                                     1.0f-2*D, 0.0f,
246
                                     0.50f, 0.040f,
247
                                     0.0f, 0.048f };
248
               extraI = 1;
249
               extraV = 2;
250
               break;
251
      default: bands = new float[] { 1.0f    ,-D,
252
                                     1.0f-2*D, 0.0f,
253
                                     0.50f, 0.025f,
254
                                     0.0f, 0.030f };
255
               extraI = 1;
256
               extraV = 1;
257
               break;
258
      }
259

    
260
    return createCubitMesh(index,vertices,bands,extraI,extraV);
261
    }
262

    
263
///////////////////////////////////////////////////////////////////////////////////////////////////
264

    
265
  MeshBase createCubitMesh(int index, float[] vertices, float[] bands, int extraI, int extraV)
266
    {
267
    if( mMeshes==null )
268
      {
269
      mMeshes = new MeshBase[ObjectList.CUBE.getNumVariants()];
270
      }
271

    
272
    if( mMeshes[index]==null )
273
      {
274
      final int MESHES=6;
275
      int association = 1;
276
      MeshBase[] meshes = new MeshPolygon[MESHES];
277
      meshes[0] = new MeshPolygon(vertices,bands,extraI,extraV);
278
      meshes[0].setEffectAssociation(0,association,0);
279

    
280
      for(int i=1; i<MESHES; i++)
281
        {
282
        association <<=1;
283
        meshes[i] = meshes[0].copy(true);
284
        meshes[i].setEffectAssociation(0,association,0);
285
        }
286

    
287
      mMeshes[index] = new MeshJoined(meshes);
288

    
289
      Static3D axisY   = new Static3D(0,1,0);
290
      Static3D axisX   = new Static3D(1,0,0);
291
      Static3D center  = new Static3D(0,0,0);
292
      Static1D angle90 = new Static1D(90);
293
      Static1D angle180= new Static1D(180);
294
      Static1D angle270= new Static1D(270);
295

    
296
      float d1 = 1.0f;
297
      float d2 =-0.05f;
298
      float d3 = 0.12f;
299

    
300
      Static3D dCen0 = new Static3D( d1*(+0.5f), d1*(+0.5f), d1*(+0.5f) );
301
      Static3D dCen1 = new Static3D( d1*(+0.5f), d1*(+0.5f), d1*(-0.5f) );
302
      Static3D dCen2 = new Static3D( d1*(+0.5f), d1*(-0.5f), d1*(+0.5f) );
303
      Static3D dCen3 = new Static3D( d1*(+0.5f), d1*(-0.5f), d1*(-0.5f) );
304
      Static3D dCen4 = new Static3D( d1*(-0.5f), d1*(+0.5f), d1*(+0.5f) );
305
      Static3D dCen5 = new Static3D( d1*(-0.5f), d1*(+0.5f), d1*(-0.5f) );
306
      Static3D dCen6 = new Static3D( d1*(-0.5f), d1*(-0.5f), d1*(+0.5f) );
307
      Static3D dCen7 = new Static3D( d1*(-0.5f), d1*(-0.5f), d1*(-0.5f) );
308

    
309
      Static3D dVec0 = new Static3D( d2*(+0.5f), d2*(+0.5f), d2*(+0.5f) );
310
      Static3D dVec1 = new Static3D( d2*(+0.5f), d2*(+0.5f), d2*(-0.5f) );
311
      Static3D dVec2 = new Static3D( d2*(+0.5f), d2*(-0.5f), d2*(+0.5f) );
312
      Static3D dVec3 = new Static3D( d2*(+0.5f), d2*(-0.5f), d2*(-0.5f) );
313
      Static3D dVec4 = new Static3D( d2*(-0.5f), d2*(+0.5f), d2*(+0.5f) );
314
      Static3D dVec5 = new Static3D( d2*(-0.5f), d2*(+0.5f), d2*(-0.5f) );
315
      Static3D dVec6 = new Static3D( d2*(-0.5f), d2*(-0.5f), d2*(+0.5f) );
316
      Static3D dVec7 = new Static3D( d2*(-0.5f), d2*(-0.5f), d2*(-0.5f) );
317

    
318
      Static4D dReg  = new Static4D(0,0,0,d3);
319
      Static1D dRad  = new Static1D(1);
320

    
321
      VertexEffectMove   effect0 = new VertexEffectMove(new Static3D(0,0,+0.5f));
322
      effect0.setMeshAssociation(63,-1);  // all 6 sides
323
      VertexEffectRotate effect1 = new VertexEffectRotate( angle180, axisX, center );
324
      effect1.setMeshAssociation(32,-1);  // back
325
      VertexEffectRotate effect2 = new VertexEffectRotate( angle90 , axisX, center );
326
      effect2.setMeshAssociation( 8,-1);  // bottom
327
      VertexEffectRotate effect3 = new VertexEffectRotate( angle270, axisX, center );
328
      effect3.setMeshAssociation( 4,-1);  // top
329
      VertexEffectRotate effect4 = new VertexEffectRotate( angle270, axisY, center );
330
      effect4.setMeshAssociation( 2,-1);  // left
331
      VertexEffectRotate effect5 = new VertexEffectRotate( angle90 , axisY, center );
332
      effect5.setMeshAssociation( 1,-1);  // right
333

    
334
      VertexEffectDeform effect6 = new VertexEffectDeform(dVec0, dRad, dCen0, dReg);
335
      VertexEffectDeform effect7 = new VertexEffectDeform(dVec1, dRad, dCen1, dReg);
336
      VertexEffectDeform effect8 = new VertexEffectDeform(dVec2, dRad, dCen2, dReg);
337
      VertexEffectDeform effect9 = new VertexEffectDeform(dVec3, dRad, dCen3, dReg);
338
      VertexEffectDeform effect10= new VertexEffectDeform(dVec4, dRad, dCen4, dReg);
339
      VertexEffectDeform effect11= new VertexEffectDeform(dVec5, dRad, dCen5, dReg);
340
      VertexEffectDeform effect12= new VertexEffectDeform(dVec6, dRad, dCen6, dReg);
341
      VertexEffectDeform effect13= new VertexEffectDeform(dVec7, dRad, dCen7, dReg);
342

    
343
      mMeshes[index].apply(effect0);
344
      mMeshes[index].apply(effect1);
345
      mMeshes[index].apply(effect2);
346
      mMeshes[index].apply(effect3);
347
      mMeshes[index].apply(effect4);
348
      mMeshes[index].apply(effect5);
349
      mMeshes[index].apply(effect6);
350
      mMeshes[index].apply(effect7);
351
      mMeshes[index].apply(effect8);
352
      mMeshes[index].apply(effect9);
353
      mMeshes[index].apply(effect10);
354
      mMeshes[index].apply(effect11);
355
      mMeshes[index].apply(effect12);
356
      mMeshes[index].apply(effect13);
357

    
358
      mMeshes[index].mergeEffComponents();
359
      }
360

    
361
    return mMeshes[index].copy(true);
362
    }
363

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

    
366
  float returnMultiplier()
367
    {
368
    return getSize();
369
    }
370

    
371
///////////////////////////////////////////////////////////////////////////////////////////////////
372

    
373
  float[] getRowChances()
374
    {
375
    int size = getSize();
376
    float[] chances = new float[size];
377

    
378
    for(int i=0; i<size; i++)
379
      {
380
      chances[i] = (i+1.0f) / size;
381
      }
382

    
383
    return chances;
384
    }
385

    
386
///////////////////////////////////////////////////////////////////////////////////////////////////
387
// PUBLIC API
388

    
389
  public Static3D[] getRotationAxis()
390
    {
391
    return ROT_AXIS;
392
    }
393

    
394
///////////////////////////////////////////////////////////////////////////////////////////////////
395

    
396
  public int getBasicAngle()
397
    {
398
    return 4;
399
    }
400

    
401
///////////////////////////////////////////////////////////////////////////////////////////////////
402

    
403
  public int computeRowFromOffset(float offset)
404
    {
405
    return (int)(getSize()*offset);
406
    }
407

    
408
///////////////////////////////////////////////////////////////////////////////////////////////////
409

    
410
  public float returnRotationFactor(float offset)
411
    {
412
    return 1.0f;
413
    }
414

    
415
///////////////////////////////////////////////////////////////////////////////////////////////////
416

    
417
  public int randomizeNewRotAxis(Random rnd, int oldRotAxis)
418
    {
419
    int numAxis = ROTATION_AXIS.length;
420

    
421
    if( oldRotAxis == START_AXIS )
422
      {
423
      return rnd.nextInt(numAxis);
424
      }
425
    else
426
      {
427
      int newVector = rnd.nextInt(numAxis-1);
428
      return (newVector>=oldRotAxis ? newVector+1 : newVector);
429
      }
430
    }
431

    
432
///////////////////////////////////////////////////////////////////////////////////////////////////
433

    
434
  public int randomizeNewRow(Random rnd, int oldRotAxis, int oldRow, int newRotAxis)
435
    {
436
    float rowFloat = rnd.nextFloat();
437

    
438
    for(int row=0; row<mRowChances.length; row++)
439
      {
440
      if( rowFloat<=mRowChances[row] ) return row;
441
      }
442

    
443
    return 0;
444
    }
445

    
446
///////////////////////////////////////////////////////////////////////////////////////////////////
447

    
448
  public boolean isSolved()
449
    {
450
    int index = CUBITS[0].mQuatIndex;
451

    
452
    for(int i=1; i<NUM_CUBITS; i++)
453
      {
454
      if( !thereIsNoVisibleDifference(CUBITS[i], index) ) return false;
455
      }
456

    
457
    return true;
458
    }
459

    
460
///////////////////////////////////////////////////////////////////////////////////////////////////
461
// return if the Cubit, when rotated with its own mQuatScramble, would have looked any different
462
// then if it were rotated by quaternion 'quat'.
463
// No it is not so simple as the quats need to be the same - imagine a 4x4x4 cube where the two
464
// middle squares get interchanged. No visible difference!
465
//
466
// So: this is true iff the cubit
467
// a) is a corner or edge and the quaternions are the same
468
// b) is inside one of the faces and after rotations by both quats it ends up on the same face.
469

    
470
  private boolean thereIsNoVisibleDifference(Cubit cubit, int quatIndex)
471
    {
472
    if ( cubit.mQuatIndex == quatIndex ) return true;
473

    
474
    int belongsToHowManyFaces = 0;
475
    int size = getSize()-1;
476
    float row;
477
    final float MAX_ERROR = 0.01f;
478

    
479
    for(int i=0; i<NUM_AXIS; i++)
480
      {
481
      row = cubit.mRotationRow[i];
482
      if( (row     <MAX_ERROR && row     >-MAX_ERROR) ||
483
          (row-size<MAX_ERROR && row-size>-MAX_ERROR)  ) belongsToHowManyFaces++;
484
      }
485

    
486
    switch(belongsToHowManyFaces)
487
      {
488
      case 0 : return true ;  // 'inside' cubit that does not lie on any face
489
      case 1 :                // cubit that lies inside one of the faces
490
               Static3D orig = cubit.getOrigPosition();
491
               Static4D quat1 = QUATS[quatIndex];
492
               Static4D quat2 = QUATS[cubit.mQuatIndex];
493

    
494
               Static4D cubitCenter = new Static4D( orig.get0(), orig.get1(), orig.get2(), 0);
495
               Static4D rotated1 = RubikSurfaceView.rotateVectorByQuat( cubitCenter, quat1 );
496
               Static4D rotated2 = RubikSurfaceView.rotateVectorByQuat( cubitCenter, quat2 );
497

    
498
               float row1, row2, row3, row4;
499
               float ax,ay,az;
500
               Static3D axis;
501
               float x1 = rotated1.get0();
502
               float y1 = rotated1.get1();
503
               float z1 = rotated1.get2();
504
               float x2 = rotated2.get0();
505
               float y2 = rotated2.get1();
506
               float z2 = rotated2.get2();
507

    
508
               for(int i=0; i<NUM_AXIS; i++)
509
                 {
510
                 axis = ROTATION_AXIS[i];
511
                 ax = axis.get0();
512
                 ay = axis.get1();
513
                 az = axis.get2();
514

    
515
                 row1 = ((x1*ax + y1*ay + z1*az) - mStart) / mStep;
516
                 row2 = ((x2*ax + y2*ay + z2*az) - mStart) / mStep;
517
                 row3 = row1 - size;
518
                 row4 = row2 - size;
519

    
520
                 if( (row1<MAX_ERROR && row1>-MAX_ERROR && row2<MAX_ERROR && row2>-MAX_ERROR) ||
521
                     (row3<MAX_ERROR && row3>-MAX_ERROR && row4<MAX_ERROR && row4>-MAX_ERROR)  )
522
                   {
523
                   return true;
524
                   }
525
                 }
526
               return false;
527

    
528
      default: return false;  // edge or corner
529
      }
530
    }
531

    
532
///////////////////////////////////////////////////////////////////////////////////////////////////
533
// order: Up --> Right --> Front --> Down --> Left --> Back
534
// (because the first implemented Solver - the two-phase Cube3 one - expects such order)
535
//
536
// Solved 3x3x3 Cube maps to "UUUUUUUUURRRRRRRRRFFFFFFFFFDDDDDDDDDLLLLLLLLLBBBBBBBBB"
537
//
538
// s : size of the cube; let index = a*s + b    (i.e. a,b = row,column)
539
//
540
// Up    :   index --> b<s-1 ? (s-1)*(s+4b)+a : 6*s*s -13*s +8 +a
541
// Right :   index --> 6*s*s - 12*s + 7 - index
542
// Front :   index --> if b==0  : s*s - 1 - index
543
//                     if b==s-1: 6*s*s -11*s +6 - index
544
//                     else
545
//                         a==0: s*s + s-1 + 4*(b-1)*(s-1) + 2*(s-2) + s
546
//                         else: s*s + s-1 + 4*(b-1)*(s-1) + 2*(s-1-a)
547
// Down  :   index --> b==0 ? (s-1-a) : s*s + s-1 + 4*(b-1)*(s-1) - a
548
// Left  :   index --> (s-1-a)*s + b
549
// Back  :   index --> if b==s-1: s*(s-1-a)
550
//                     if b==0  : 5*s*s -12*s + 8 + (s-1-a)*s
551
//                     else
552
//                        if a==s-1: s*s + 4*(s-2-b)*(s-1)
553
//                        else     : s*s + 4*(s-2-b)*(s-1) + s + (s-2-a)*2
554

    
555
  public String retObjectString()
556
    {
557
    StringBuilder objectString = new StringBuilder();
558
    int size = getSize();
559
    int len = size*size;
560
    int cubitIndex=-1, row=-1, col=-1;
561
    int color=-1, face=-1;
562

    
563
    final int RIGHT= 0;
564
    final int LEFT = 1;
565
    final int UP   = 2;
566
    final int DOWN = 3;
567
    final int FRONT= 4;
568
    final int BACK = 5;
569

    
570
    // 'I' - interior, theoretically can happen
571
    final char[] FACE_NAMES = { 'R', 'L', 'U', 'D', 'F', 'B', 'I'};
572

    
573
    face = UP;
574

    
575
    for(int i=0; i<len; i++)
576
      {
577
      row = i/size;
578
      col = i%size;
579

    
580
      cubitIndex = col<size-1 ? (size-1)*(size+4*col) + row : 6*size*size - 13*size + 8 + row;
581
      color = getCubitFaceColorIndex(cubitIndex,face);
582
      objectString.append(FACE_NAMES[color]);
583
      }
584

    
585
    face = RIGHT;
586

    
587
    for(int i=0; i<len; i++)
588
      {
589
      cubitIndex = 6*size*size - 12*size +7 - i;
590
      color = getCubitFaceColorIndex(cubitIndex,face);
591
      objectString.append(FACE_NAMES[color]);
592
      }
593

    
594
     face = FRONT;
595

    
596
    for(int i=0; i<len; i++)
597
      {
598
      row = i/size;
599
      col = i%size;
600

    
601
      if( col==size-1 ) cubitIndex = 6*size*size - 11*size + 6 -i;
602
      else if( col==0 ) cubitIndex = size*size - 1 - i;
603
      else
604
        {
605
        if( row==0 ) cubitIndex = size*size + size-1 + 4*(col-1)*(size-1) + 2*(size-2) + size;
606
        else         cubitIndex = size*size + size-1 + 4*(col-1)*(size-1) + 2*(size-1-row);
607
        }
608

    
609
      color = getCubitFaceColorIndex(cubitIndex,face);
610
      objectString.append(FACE_NAMES[color]);
611
      }
612

    
613
    face = DOWN;
614

    
615
    for(int i=0; i<len; i++)
616
      {
617
      row = i/size;
618
      col = i%size;
619

    
620
      cubitIndex = col==0 ? size-1-row : size*size + size-1 + 4*(col-1)*(size-1) - row;
621
      color = getCubitFaceColorIndex(cubitIndex,face);
622
      objectString.append(FACE_NAMES[color]);
623
      }
624

    
625
    face = LEFT;
626

    
627
    for(int i=0; i<len; i++)
628
      {
629
      row = i/size;
630
      col = i%size;
631

    
632
      cubitIndex = (size-1-row)*size + col;
633
      color = getCubitFaceColorIndex(cubitIndex,face);
634
      objectString.append(FACE_NAMES[color]);
635
      }
636

    
637
    face = BACK;
638

    
639
    for(int i=0; i<len; i++)
640
      {
641
      row = i/size;
642
      col = i%size;
643

    
644
      if( col==size-1 ) cubitIndex = size*(size-1-row);
645
      else if( col==0 ) cubitIndex = 5*size*size - 12*size + 8 + (size-1-row)*size;
646
      else
647
        {
648
        if( row==size-1 ) cubitIndex = size*size + 4*(size-2-col)*(size-1);
649
        else              cubitIndex = size*size + 4*(size-2-col)*(size-1) + size + 2*(size-2-row);
650
        }
651

    
652
      color = getCubitFaceColorIndex(cubitIndex,face);
653
      objectString.append(FACE_NAMES[color]);
654
      }
655

    
656
    return objectString.toString();
657
    }
658
}
(10-10/18)