Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / RubikCube.java @ e69c7a11

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
// return if the Cubit, when rotated with its own mQuatScramble, would have looked any different
399
// then if it were rotated by quaternion 'quat'.
400
// No it is not so simple as the quats need to be the same - imagine a 4x4x4 cube where the two
401
// middle squares get interchanged. No visible difference!
402
//
403
// So: this is true iff the cubit
404
// a) is a corner or edge and the quaternions are the same
405
// b) is inside one of the faces and after rotations by both quats it ends up on the same face.
406

    
407
  boolean thereIsNoVisibleDifference(Cubit cubit, int quatIndex)
408
    {
409
    if ( cubit.mQuatIndex == quatIndex ) return true;
410

    
411
    int belongsToHowManyFaces = 0;
412
    int size = getSize()-1;
413
    float row;
414
    final float MAX_ERROR = 0.01f;
415

    
416
    for(int i=0; i<NUM_AXIS; i++)
417
      {
418
      row = cubit.mRotationRow[i];
419
      if( (row     <MAX_ERROR && row     >-MAX_ERROR) ||
420
          (row-size<MAX_ERROR && row-size>-MAX_ERROR)  ) belongsToHowManyFaces++;
421
      }
422

    
423
    switch(belongsToHowManyFaces)
424
      {
425
      case 0 : return true ;  // 'inside' cubit that does not lie on any face
426
      case 1 :                // cubit that lies inside one of the faces
427
               Static3D orig = cubit.getOrigPosition();
428
               Static4D quat1 = QUATS[quatIndex];
429
               Static4D quat2 = QUATS[cubit.mQuatIndex];
430

    
431
               Static4D cubitCenter = new Static4D( orig.get0(), orig.get1(), orig.get2(), 0);
432
               Static4D rotated1 = RubikSurfaceView.rotateVectorByQuat( cubitCenter, quat1 );
433
               Static4D rotated2 = RubikSurfaceView.rotateVectorByQuat( cubitCenter, quat2 );
434

    
435
               float row1, row2, row3, row4;
436
               float ax,ay,az;
437
               Static3D axis;
438
               float x1 = rotated1.get0();
439
               float y1 = rotated1.get1();
440
               float z1 = rotated1.get2();
441
               float x2 = rotated2.get0();
442
               float y2 = rotated2.get1();
443
               float z2 = rotated2.get2();
444

    
445
               for(int i=0; i<NUM_AXIS; i++)
446
                 {
447
                 axis = ROTATION_AXIS[i];
448
                 ax = axis.get0();
449
                 ay = axis.get1();
450
                 az = axis.get2();
451

    
452
                 row1 = ((x1*ax + y1*ay + z1*az) - mStart) / mStep;
453
                 row2 = ((x2*ax + y2*ay + z2*az) - mStart) / mStep;
454
                 row3 = row1 - size;
455
                 row4 = row2 - size;
456

    
457
                 if( (row1<MAX_ERROR && row1>-MAX_ERROR && row2<MAX_ERROR && row2>-MAX_ERROR) ||
458
                     (row3<MAX_ERROR && row3>-MAX_ERROR && row4<MAX_ERROR && row4>-MAX_ERROR)  )
459
                   {
460
                   return true;
461
                   }
462
                 }
463
               return false;
464

    
465
      default: return false;  // edge or corner
466
      }
467
    }
468

    
469
///////////////////////////////////////////////////////////////////////////////////////////////////
470
// order: Up --> Right --> Front --> Down --> Left --> Back
471
// (because the first implemented Solver - the two-phase Cube3 one - expects such order)
472
//
473
// Solved 3x3x3 Cube maps to "UUUUUUUUURRRRRRRRRFFFFFFFFFDDDDDDDDDLLLLLLLLLBBBBBBBBB"
474
//
475
// s : size of the cube; let index = a*s + b    (i.e. a,b = row,column)
476
//
477
// Up    :   index --> b<s-1 ? (s-1)*(s+4b)+a : 6*s*s -13*s +8 +a
478
// Right :   index --> 6*s*s - 12*s + 7 - index
479
// Front :   index --> if b==0  : s*s - 1 - index
480
//                     if b==s-1: 6*s*s -11*s +6 - index
481
//                     else
482
//                         a==0: s*s + s-1 + 4*(b-1)*(s-1) + 2*(s-2) + s
483
//                         else: s*s + s-1 + 4*(b-1)*(s-1) + 2*(s-1-a)
484
// Down  :   index --> b==0 ? (s-1-a) : s*s + s-1 + 4*(b-1)*(s-1) - a
485
// Left  :   index --> (s-1-a)*s + b
486
// Back  :   index --> if b==s-1: s*(s-1-a)
487
//                     if b==0  : 5*s*s -12*s + 8 + (s-1-a)*s
488
//                     else
489
//                        if a==s-1: s*s + 4*(s-2-b)*(s-1)
490
//                        else     : s*s + 4*(s-2-b)*(s-1) + s + (s-2-a)*2
491

    
492
  public String retObjectString()
493
    {
494
    StringBuilder objectString = new StringBuilder();
495
    int size = getSize();
496
    int len = size*size;
497
    int cubitIndex, row, col;
498
    int color;
499

    
500
    final int RIGHT= 0;
501
    final int LEFT = 1;
502
    final int UP   = 2;
503
    final int DOWN = 3;
504
    final int FRONT= 4;
505
    final int BACK = 5;
506

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

    
509
    for(int i=0; i<len; i++)
510
      {
511
      row = i/size;
512
      col = i%size;
513

    
514
      cubitIndex = col<size-1 ? (size-1)*(size+4*col) + row : 6*size*size - 13*size + 8 + row;
515
      color = getCubitFaceColorIndex(cubitIndex,UP);
516
      objectString.append(FACE_NAMES[color]);
517
      }
518

    
519
    for(int i=0; i<len; i++)
520
      {
521
      cubitIndex = 6*size*size - 12*size +7 - i;
522
      color = getCubitFaceColorIndex(cubitIndex,RIGHT);
523
      objectString.append(FACE_NAMES[color]);
524
      }
525

    
526
    for(int i=0; i<len; i++)
527
      {
528
      row = i/size;
529
      col = i%size;
530

    
531
      if( col==size-1 ) cubitIndex = 6*size*size - 11*size + 6 -i;
532
      else if( col==0 ) cubitIndex = size*size - 1 - i;
533
      else
534
        {
535
        if( row==0 ) cubitIndex = size*size + size-1 + 4*(col-1)*(size-1) + 2*(size-2) + size;
536
        else         cubitIndex = size*size + size-1 + 4*(col-1)*(size-1) + 2*(size-1-row);
537
        }
538

    
539
      color = getCubitFaceColorIndex(cubitIndex,FRONT);
540
      objectString.append(FACE_NAMES[color]);
541
      }
542

    
543
    for(int i=0; i<len; i++)
544
      {
545
      row = i/size;
546
      col = i%size;
547

    
548
      cubitIndex = col==0 ? size-1-row : size*size + size-1 + 4*(col-1)*(size-1) - row;
549
      color = getCubitFaceColorIndex(cubitIndex,DOWN);
550
      objectString.append(FACE_NAMES[color]);
551
      }
552

    
553
    for(int i=0; i<len; i++)
554
      {
555
      row = i/size;
556
      col = i%size;
557

    
558
      cubitIndex = (size-1-row)*size + col;
559
      color = getCubitFaceColorIndex(cubitIndex,LEFT);
560
      objectString.append(FACE_NAMES[color]);
561
      }
562

    
563
    for(int i=0; i<len; i++)
564
      {
565
      row = i/size;
566
      col = i%size;
567

    
568
      if( col==size-1 ) cubitIndex = size*(size-1-row);
569
      else if( col==0 ) cubitIndex = 5*size*size - 12*size + 8 + (size-1-row)*size;
570
      else
571
        {
572
        if( row==size-1 ) cubitIndex = size*size + 4*(size-2-col)*(size-1);
573
        else              cubitIndex = size*size + 4*(size-2-col)*(size-1) + size + 2*(size-2-row);
574
        }
575

    
576
      color = getCubitFaceColorIndex(cubitIndex,BACK);
577
      objectString.append(FACE_NAMES[color]);
578
      }
579

    
580
    return objectString.toString();
581
    }
582
}
(2-2/10)