Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / RubikCube.java @ 6b6504fe

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.effect.VertexEffectSink;
30
import org.distorted.library.main.DistortedEffects;
31
import org.distorted.library.main.DistortedTexture;
32
import org.distorted.library.mesh.MeshBase;
33
import org.distorted.library.mesh.MeshJoined;
34
import org.distorted.library.mesh.MeshRectangles;
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 RubikCube extends RubikObject
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
           0xffffff00, 0xffffffff,   // FACE_AXIS[0] (right-YELLOW) FACE_AXIS[1] (left  -WHITE)
69
           0xff0000ff, 0xff00ff00,   // FACE_AXIS[2] (top  -BLUE  ) FACE_AXIS[3] (bottom-GREEN)
70
           0xffff0000, 0xffb5651d    // FACE_AXIS[4] (front-RED   ) FACE_AXIS[5] (back  -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
  RubikCube(int size, Static4D quat, DistortedTexture texture,
115
            MeshRectangles mesh, DistortedEffects effects, int[][] moves, Resources res, int scrWidth)
116
    {
117
    super(size, 60, quat, texture, mesh, effects, moves, RubikObjectList.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
  int getNumFaces()
164
    {
165
    return FACE_COLORS.length;
166
    }
167

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

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

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

    
177
  float getScreenRatio()
178
    {
179
    return 0.5f;
180
    }
181

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

    
184
  int getFaceColor(int cubit, int cubitface, int size)
185
    {
186
    boolean belongs = isOnFace(cubit, cubitface/2, cubitface%2==0 ? size-1:0 );
187
    return belongs ? cubitface : NUM_FACES;
188
    }
189

    
190
///////////////////////////////////////////////////////////////////////////////////////////////////
191

    
192
  MeshBase createCubitMesh(int cubit)
193
    {
194
    int size   = getSize();
195
    int ordinal= RubikObjectList.CUBE.ordinal();
196
    int index  = RubikObjectList.getSizeIndex(ordinal,size);
197
    float[] loc;
198

    
199
    switch(size)
200
      {
201
      case 5 : loc = new float[] { -0.5f, 0.05f, 0.1f, 0.35f, 0.35f, 0.1f, 0.05f };
202
               break;
203
      case 2 : loc = new float[] { -0.5f, 0.03f, 0.05f, 0.07f, 0.20f, 0.30f, 0.20f, 0.07f, 0.05f, 0.03f };
204
               break;
205
      default: loc = new float[] { -0.5f, 0.04f, 0.06f, 0.25f, 0.30f, 0.25f, 0.06f, 0.04f };
206
      }
207

    
208
    return createCubitMesh(index,loc);
209
    }
210

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

    
213
  MeshBase createCubitMesh(int index, float[] loc)
214
    {
215
    if( mMeshes==null )
216
      {
217
      mMeshes = new MeshBase[RubikObjectList.CUBE.getNumVariants()];
218
      }
219

    
220
    if( mMeshes[index]==null )
221
      {
222
      final int MESHES=6;
223
      int association = 1;
224
      MeshBase[] meshes = new MeshRectangles[MESHES];
225
      meshes[0] = new MeshRectangles(loc,loc);
226
      meshes[0].setEffectAssociation(0,association,0);
227

    
228
      for(int i=1; i<MESHES; i++)
229
        {
230
        association <<=1;
231
        meshes[i] = meshes[0].copy(true);
232
        meshes[i].setEffectAssociation(0,association,0);
233
        }
234

    
235
      mMeshes[index] = new MeshJoined(meshes);
236

    
237
      Static3D axisY   = new Static3D(0,1,0);
238
      Static3D axisX   = new Static3D(1,0,0);
239
      Static3D center  = new Static3D(0,0,0);
240
      Static1D angle90 = new Static1D(90);
241
      Static1D angle180= new Static1D(180);
242
      Static1D angle270= new Static1D(270);
243

    
244
      float d1 = 1.0f;
245
      float d2 =-0.05f;
246
      float d3 = 0.12f;
247

    
248
      Static3D dCen0 = new Static3D( d1*(+0.5f), d1*(+0.5f), d1*(+0.5f) );
249
      Static3D dCen1 = new Static3D( d1*(+0.5f), d1*(+0.5f), d1*(-0.5f) );
250
      Static3D dCen2 = new Static3D( d1*(+0.5f), d1*(-0.5f), d1*(+0.5f) );
251
      Static3D dCen3 = new Static3D( d1*(+0.5f), d1*(-0.5f), d1*(-0.5f) );
252
      Static3D dCen4 = new Static3D( d1*(-0.5f), d1*(+0.5f), d1*(+0.5f) );
253
      Static3D dCen5 = new Static3D( d1*(-0.5f), d1*(+0.5f), d1*(-0.5f) );
254
      Static3D dCen6 = new Static3D( d1*(-0.5f), d1*(-0.5f), d1*(+0.5f) );
255
      Static3D dCen7 = new Static3D( d1*(-0.5f), d1*(-0.5f), d1*(-0.5f) );
256

    
257
      Static3D dVec0 = new Static3D( d2*(+0.5f), d2*(+0.5f), d2*(+0.5f) );
258
      Static3D dVec1 = new Static3D( d2*(+0.5f), d2*(+0.5f), d2*(-0.5f) );
259
      Static3D dVec2 = new Static3D( d2*(+0.5f), d2*(-0.5f), d2*(+0.5f) );
260
      Static3D dVec3 = new Static3D( d2*(+0.5f), d2*(-0.5f), d2*(-0.5f) );
261
      Static3D dVec4 = new Static3D( d2*(-0.5f), d2*(+0.5f), d2*(+0.5f) );
262
      Static3D dVec5 = new Static3D( d2*(-0.5f), d2*(+0.5f), d2*(-0.5f) );
263
      Static3D dVec6 = new Static3D( d2*(-0.5f), d2*(-0.5f), d2*(+0.5f) );
264
      Static3D dVec7 = new Static3D( d2*(-0.5f), d2*(-0.5f), d2*(-0.5f) );
265

    
266
      Static4D dReg  = new Static4D(0,0,0,d3);
267
      Static1D dRad  = new Static1D(1);
268

    
269
      VertexEffectMove   effect0 = new VertexEffectMove(new Static3D(0,0,+0.5f));
270
      effect0.setMeshAssociation(63,-1);  // all 6 sides
271
      VertexEffectRotate effect1 = new VertexEffectRotate( angle180, axisX, center );
272
      effect1.setMeshAssociation(32,-1);  // back
273
      VertexEffectRotate effect2 = new VertexEffectRotate( angle90 , axisX, center );
274
      effect2.setMeshAssociation( 8,-1);  // bottom
275
      VertexEffectRotate effect3 = new VertexEffectRotate( angle270, axisX, center );
276
      effect3.setMeshAssociation( 4,-1);  // top
277
      VertexEffectRotate effect4 = new VertexEffectRotate( angle270, axisY, center );
278
      effect4.setMeshAssociation( 2,-1);  // left
279
      VertexEffectRotate effect5 = new VertexEffectRotate( angle90 , axisY, center );
280
      effect5.setMeshAssociation( 1,-1);  // right
281

    
282
      VertexEffectDeform effect6 = new VertexEffectDeform(dVec0, dRad, dCen0, dReg);
283
      VertexEffectDeform effect7 = new VertexEffectDeform(dVec1, dRad, dCen1, dReg);
284
      VertexEffectDeform effect8 = new VertexEffectDeform(dVec2, dRad, dCen2, dReg);
285
      VertexEffectDeform effect9 = new VertexEffectDeform(dVec3, dRad, dCen3, dReg);
286
      VertexEffectDeform effect10= new VertexEffectDeform(dVec4, dRad, dCen4, dReg);
287
      VertexEffectDeform effect11= new VertexEffectDeform(dVec5, dRad, dCen5, dReg);
288
      VertexEffectDeform effect12= new VertexEffectDeform(dVec6, dRad, dCen6, dReg);
289
      VertexEffectDeform effect13= new VertexEffectDeform(dVec7, dRad, dCen7, dReg);
290

    
291
      VertexEffectSink   effect14= new VertexEffectSink( new Static1D(1.5f), center, new Static4D(0,0,0,0.72f) );
292

    
293
      mMeshes[index].apply(effect0);
294
      mMeshes[index].apply(effect1);
295
      mMeshes[index].apply(effect2);
296
      mMeshes[index].apply(effect3);
297
      mMeshes[index].apply(effect4);
298
      mMeshes[index].apply(effect5);
299
      mMeshes[index].apply(effect6);
300
      mMeshes[index].apply(effect7);
301
      mMeshes[index].apply(effect8);
302
      mMeshes[index].apply(effect9);
303
      mMeshes[index].apply(effect10);
304
      mMeshes[index].apply(effect11);
305
      mMeshes[index].apply(effect12);
306
      mMeshes[index].apply(effect13);
307
      mMeshes[index].apply(effect14);
308

    
309
      mMeshes[index].mergeEffComponents();
310
      }
311

    
312
    return mMeshes[index].copy(true);
313
    }
314

    
315
///////////////////////////////////////////////////////////////////////////////////////////////////
316

    
317
  float returnMultiplier()
318
    {
319
    return getSize();
320
    }
321

    
322
///////////////////////////////////////////////////////////////////////////////////////////////////
323

    
324
  float[] getRowChances()
325
    {
326
    int size = getSize();
327
    float[] chances = new float[size];
328

    
329
    for(int i=0; i<size; i++)
330
      {
331
      chances[i] = (i+1.0f) / size;
332
      }
333

    
334
    return chances;
335
    }
336

    
337
///////////////////////////////////////////////////////////////////////////////////////////////////
338
// PUBLIC API
339

    
340
  public Static3D[] getRotationAxis()
341
    {
342
    return ROT_AXIS;
343
    }
344

    
345
///////////////////////////////////////////////////////////////////////////////////////////////////
346

    
347
  public int getBasicAngle()
348
    {
349
    return 4;
350
    }
351

    
352
///////////////////////////////////////////////////////////////////////////////////////////////////
353

    
354
  public int computeRowFromOffset(float offset)
355
    {
356
    return (int)(getSize()*offset);
357
    }
358

    
359
///////////////////////////////////////////////////////////////////////////////////////////////////
360

    
361
  public float returnRotationFactor(float offset)
362
    {
363
    return 1.0f;
364
    }
365

    
366
///////////////////////////////////////////////////////////////////////////////////////////////////
367

    
368
  public int randomizeNewRotAxis(Random rnd, int oldRotAxis)
369
    {
370
    int numAxis = ROTATION_AXIS.length;
371

    
372
    if( oldRotAxis == START_AXIS )
373
      {
374
      return rnd.nextInt(numAxis);
375
      }
376
    else
377
      {
378
      int newVector = rnd.nextInt(numAxis-1);
379
      return (newVector>=oldRotAxis ? newVector+1 : newVector);
380
      }
381
    }
382

    
383
///////////////////////////////////////////////////////////////////////////////////////////////////
384

    
385
  public int randomizeNewRow(Random rnd, int oldRotAxis, int oldRow, int newRotAxis)
386
    {
387
    float rowFloat = rnd.nextFloat();
388

    
389
    for(int row=0; row<mRowChances.length; row++)
390
      {
391
      if( rowFloat<=mRowChances[row] ) return row;
392
      }
393

    
394
    return 0;
395
    }
396

    
397
///////////////////////////////////////////////////////////////////////////////////////////////////
398

    
399
  public boolean isSolved()
400
    {
401
    int index = CUBITS[0].mQuatIndex;
402

    
403
    for(int i=1; i<NUM_CUBITS; i++)
404
      {
405
      if( !thereIsNoVisibleDifference(CUBITS[i], index) ) return false;
406
      }
407

    
408
    return true;
409
    }
410

    
411
///////////////////////////////////////////////////////////////////////////////////////////////////
412
// return if the Cubit, when rotated with its own mQuatScramble, would have looked any different
413
// then if it were rotated by quaternion 'quat'.
414
// No it is not so simple as the quats need to be the same - imagine a 4x4x4 cube where the two
415
// middle squares get interchanged. No visible difference!
416
//
417
// So: this is true iff the cubit
418
// a) is a corner or edge and the quaternions are the same
419
// b) is inside one of the faces and after rotations by both quats it ends up on the same face.
420

    
421
  private boolean thereIsNoVisibleDifference(Cubit cubit, int quatIndex)
422
    {
423
    if ( cubit.mQuatIndex == quatIndex ) return true;
424

    
425
    int belongsToHowManyFaces = 0;
426
    int size = getSize()-1;
427
    float row;
428
    final float MAX_ERROR = 0.01f;
429

    
430
    for(int i=0; i<NUM_AXIS; i++)
431
      {
432
      row = cubit.mRotationRow[i];
433
      if( (row     <MAX_ERROR && row     >-MAX_ERROR) ||
434
          (row-size<MAX_ERROR && row-size>-MAX_ERROR)  ) belongsToHowManyFaces++;
435
      }
436

    
437
    switch(belongsToHowManyFaces)
438
      {
439
      case 0 : return true ;  // 'inside' cubit that does not lie on any face
440
      case 1 :                // cubit that lies inside one of the faces
441
               Static3D orig = cubit.getOrigPosition();
442
               Static4D quat1 = QUATS[quatIndex];
443
               Static4D quat2 = QUATS[cubit.mQuatIndex];
444

    
445
               Static4D cubitCenter = new Static4D( orig.get0(), orig.get1(), orig.get2(), 0);
446
               Static4D rotated1 = RubikSurfaceView.rotateVectorByQuat( cubitCenter, quat1 );
447
               Static4D rotated2 = RubikSurfaceView.rotateVectorByQuat( cubitCenter, quat2 );
448

    
449
               float row1, row2, row3, row4;
450
               float ax,ay,az;
451
               Static3D axis;
452
               float x1 = rotated1.get0();
453
               float y1 = rotated1.get1();
454
               float z1 = rotated1.get2();
455
               float x2 = rotated2.get0();
456
               float y2 = rotated2.get1();
457
               float z2 = rotated2.get2();
458

    
459
               for(int i=0; i<NUM_AXIS; i++)
460
                 {
461
                 axis = ROTATION_AXIS[i];
462
                 ax = axis.get0();
463
                 ay = axis.get1();
464
                 az = axis.get2();
465

    
466
                 row1 = ((x1*ax + y1*ay + z1*az) - mStart) / mStep;
467
                 row2 = ((x2*ax + y2*ay + z2*az) - mStart) / mStep;
468
                 row3 = row1 - size;
469
                 row4 = row2 - size;
470

    
471
                 if( (row1<MAX_ERROR && row1>-MAX_ERROR && row2<MAX_ERROR && row2>-MAX_ERROR) ||
472
                     (row3<MAX_ERROR && row3>-MAX_ERROR && row4<MAX_ERROR && row4>-MAX_ERROR)  )
473
                   {
474
                   return true;
475
                   }
476
                 }
477
               return false;
478

    
479
      default: return false;  // edge or corner
480
      }
481
    }
482

    
483
///////////////////////////////////////////////////////////////////////////////////////////////////
484
// order: Up --> Right --> Front --> Down --> Left --> Back
485
// (because the first implemented Solver - the two-phase Cube3 one - expects such order)
486
//
487
// Solved 3x3x3 Cube maps to "UUUUUUUUURRRRRRRRRFFFFFFFFFDDDDDDDDDLLLLLLLLLBBBBBBBBB"
488
//
489
// s : size of the cube; let index = a*s + b    (i.e. a,b = row,column)
490
//
491
// Up    :   index --> b<s-1 ? (s-1)*(s+4b)+a : 6*s*s -13*s +8 +a
492
// Right :   index --> 6*s*s - 12*s + 7 - index
493
// Front :   index --> if b==0  : s*s - 1 - index
494
//                     if b==s-1: 6*s*s -11*s +6 - index
495
//                     else
496
//                         a==0: s*s + s-1 + 4*(b-1)*(s-1) + 2*(s-2) + s
497
//                         else: s*s + s-1 + 4*(b-1)*(s-1) + 2*(s-1-a)
498
// Down  :   index --> b==0 ? (s-1-a) : s*s + s-1 + 4*(b-1)*(s-1) - a
499
// Left  :   index --> (s-1-a)*s + b
500
// Back  :   index --> if b==s-1: s*(s-1-a)
501
//                     if b==0  : 5*s*s -12*s + 8 + (s-1-a)*s
502
//                     else
503
//                        if a==s-1: s*s + 4*(s-2-b)*(s-1)
504
//                        else     : s*s + 4*(s-2-b)*(s-1) + s + (s-2-a)*2
505

    
506
  public String retObjectString()
507
    {
508
    StringBuilder objectString = new StringBuilder();
509
    int size = getSize();
510
    int len = size*size;
511
    int cubitIndex, row, col;
512
    int color;
513

    
514
    final int RIGHT= 0;
515
    final int LEFT = 1;
516
    final int UP   = 2;
517
    final int DOWN = 3;
518
    final int FRONT= 4;
519
    final int BACK = 5;
520

    
521
    final char[] FACE_NAMES = { 'R', 'L', 'U', 'D', 'F', 'B'};
522

    
523
    for(int i=0; i<len; i++)
524
      {
525
      row = i/size;
526
      col = i%size;
527

    
528
      cubitIndex = col<size-1 ? (size-1)*(size+4*col) + row : 6*size*size - 13*size + 8 + row;
529
      color = getCubitFaceColorIndex(cubitIndex,UP);
530
      objectString.append(FACE_NAMES[color]);
531
      }
532

    
533
    for(int i=0; i<len; i++)
534
      {
535
      cubitIndex = 6*size*size - 12*size +7 - i;
536
      color = getCubitFaceColorIndex(cubitIndex,RIGHT);
537
      objectString.append(FACE_NAMES[color]);
538
      }
539

    
540
    for(int i=0; i<len; i++)
541
      {
542
      row = i/size;
543
      col = i%size;
544

    
545
      if( col==size-1 ) cubitIndex = 6*size*size - 11*size + 6 -i;
546
      else if( col==0 ) cubitIndex = size*size - 1 - i;
547
      else
548
        {
549
        if( row==0 ) cubitIndex = size*size + size-1 + 4*(col-1)*(size-1) + 2*(size-2) + size;
550
        else         cubitIndex = size*size + size-1 + 4*(col-1)*(size-1) + 2*(size-1-row);
551
        }
552

    
553
      color = getCubitFaceColorIndex(cubitIndex,FRONT);
554
      objectString.append(FACE_NAMES[color]);
555
      }
556

    
557
    for(int i=0; i<len; i++)
558
      {
559
      row = i/size;
560
      col = i%size;
561

    
562
      cubitIndex = col==0 ? size-1-row : size*size + size-1 + 4*(col-1)*(size-1) - row;
563
      color = getCubitFaceColorIndex(cubitIndex,DOWN);
564
      objectString.append(FACE_NAMES[color]);
565
      }
566

    
567
    for(int i=0; i<len; i++)
568
      {
569
      row = i/size;
570
      col = i%size;
571

    
572
      cubitIndex = (size-1-row)*size + col;
573
      color = getCubitFaceColorIndex(cubitIndex,LEFT);
574
      objectString.append(FACE_NAMES[color]);
575
      }
576

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

    
582
      if( col==size-1 ) cubitIndex = size*(size-1-row);
583
      else if( col==0 ) cubitIndex = 5*size*size - 12*size + 8 + (size-1-row)*size;
584
      else
585
        {
586
        if( row==size-1 ) cubitIndex = size*size + 4*(size-2-col)*(size-1);
587
        else              cubitIndex = size*size + 4*(size-2-col)*(size-1) + size + 2*(size-2-row);
588
        }
589

    
590
      color = getCubitFaceColorIndex(cubitIndex,BACK);
591
      objectString.append(FACE_NAMES[color]);
592
      }
593

    
594
    return objectString.toString();
595
    }
596
}
(2-2/10)