Project

General

Profile

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

distorted-objectlib / src / main / java / org / distorted / objectlib / scrambling / ObjectScrambler.java @ 062efe79

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

    
10
package org.distorted.objectlib.scrambling;
11

    
12
import java.util.ArrayList;
13
import java.util.Random;
14

    
15
import org.distorted.objectlib.helpers.ObjectSignature;
16
import org.distorted.objectlib.tablebases.TablebasesAbstract;
17

    
18
///////////////////////////////////////////////////////////////////////////////////////////////////
19

    
20
public class ObjectScrambler
21
  {
22
  public static final int SCRAMBLING_ALGORITHMS = 0;
23
  public static final int SCRAMBLING_SQUARE1    = 1;
24
  public static final int SCRAMBLING_BANDAGED   = 2;
25

    
26
  private final ScrambleState[] mStates;
27
  private final int mType;
28
  private final int mNumAxis;
29
  private final int[] mNumLayers;
30
  private final int[][] mAlgorithms;
31

    
32
  // type=0, i.e. main
33
  private int mCurrState;
34
  private int mAxisExcluded;
35
  private int[][] mScrambleTable;
36
  private int[] mNumOccurences;
37
  private int[] mResult;
38
  private int mCurrAlgorithm;
39
  private int mCurrStep;
40

    
41
  // type=1, i.e. the exception: Square-1
42
  private static final int BASIC_ANGLE = 12;
43
  private static final int LAST_SL = 0; // automatic rotations: last rot was a 'slash' i.e. along ROT_AXIS[1]
44
  private static final int LAST_UP = 1; // last rot was along ROT_AXIS[0], upper layer and forelast was a slash
45
  private static final int LAST_LO = 2; // last rot was along ROT_AXIS[0], lower layer and forelast was a slash
46
  private static final int LAST_UL = 3; // two last rots were along ROT_AXIS[0] (so the next must be a slash)
47

    
48
  private int[][] mPermittedAngles;
49
  private int[] mCornerQuat;
50
  private int mPermittedUp, mPermittedDo;
51
  private int[][] mBadCornerQuats;
52
  private int mLastRot;
53
  private int[][] mQuatMult;
54

    
55
  // type=2 , i.e. locally created bandaged cuboids
56
  private ArrayList<ScrambleStateBandagedCuboid> mStatesHistory;
57
  private BlacklistedSignatures mBlacklisted;
58

    
59
  // type==3 (tablebases)
60
  private final TablebasesAbstract mTablebase;
61

    
62
///////////////////////////////////////////////////////////////////////////////////////////////////
63

    
64
  public ObjectScrambler(int type, int numAxis, int[] numLayers, int[][] algorithms, int[][] edges, TablebasesAbstract tablebase)
65
    {
66
    mType       = type;
67
    mNumAxis    = numAxis;
68
    mNumLayers  = numLayers;
69
    mAlgorithms = algorithms;
70

    
71
    if( mType==0 )
72
      {
73
      mResult = new int[2];
74
      }
75

    
76
    if( edges!=null )
77
      {
78
      int numEdges = edges.length;
79
      mStates = new ScrambleState[numEdges];
80
      for(int i=0; i<numEdges; i++) mStates[i] = new ScrambleState(edges[i],algorithms);
81
      }
82
    else mStates = null;
83

    
84
    if( mType==1 )
85
      {
86
      mPermittedAngles = new int[2][BASIC_ANGLE];
87
      mCornerQuat = new int[8];
88
      mLastRot = LAST_SL;
89
      }
90

    
91
    mTablebase = ((tablebase!=null && tablebase.useForScrambling()) ? tablebase : null);
92
    }
93

    
94
///////////////////////////////////////////////////////////////////////////////////////////////////
95

    
96
  private void initializeScrambling()
97
    {
98
    if( mScrambleTable==null )
99
      {
100
      mScrambleTable = new int[mNumAxis][];
101
      }
102
    if( mNumOccurences==null )
103
      {
104
      int max=0;
105

    
106
      for (ScrambleState mState : mStates)
107
        {
108
        int tmp = mState.getTotal();
109
        if (max < tmp) max = tmp;
110
        }
111

    
112
      mNumOccurences = new int[max];
113
      }
114

    
115
    for(int i=0; i<mNumAxis; i++)
116
      {
117
      int len = mNumLayers[i];
118
      mScrambleTable[i] = new int[len];
119
      for(int j=0; j<len; j++) mScrambleTable[i][j] = 0;
120
      }
121
    }
122

    
123
///////////////////////////////////////////////////////////////////////////////////////////////////
124
// PUBLIC API
125

    
126
  private void randomizeNewScramble0(int[][] scramble, Random rnd, int curr)
127
    {
128
    if( curr==0 )
129
      {
130
      mCurrStep     = 100000;
131
      mCurrState    = 0;
132
      mAxisExcluded =-1;
133
      initializeScrambling();
134
      }
135

    
136
    if( mCurrStep+6 <= mAlgorithms[mCurrAlgorithm].length )
137
      {
138
      mCurrStep += 3;
139
      }
140
    else
141
      {
142
      mStates[mCurrState].getRandom(rnd, mAlgorithms, mAxisExcluded, mScrambleTable, mNumOccurences, mResult);
143
      mCurrAlgorithm = mResult[0];
144
      mCurrState     = mResult[1];
145
      mCurrStep      = 0;
146
      }
147

    
148
    int[] algorithm = mAlgorithms[mCurrAlgorithm];
149
    scramble[curr][0] = algorithm[mCurrStep  ];
150
    scramble[curr][1] = (1<<algorithm[mCurrStep+1]);
151
    scramble[curr][2] = algorithm[mCurrStep+2];
152

    
153
    mAxisExcluded = algorithm[0];
154
    }
155

    
156
///////////////////////////////////////////////////////////////////////////////////////////////////
157
// TYPE 1
158
///////////////////////////////////////////////////////////////////////////////////////////////////
159
// QUATS[i]*QUATS[j] = QUATS[QUAT_MULT[i][j]]
160
///////////////////////////////////////////////////////////////////////////////////////////////////
161

    
162
  void initializeQuatMult()
163
    {
164
    mQuatMult = new int[][]
165
      {
166
        {  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,},
167
        {  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11,  0, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 12,},
168
        {  2,  3,  4,  5,  6,  7,  8,  9, 10, 11,  0,  1, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 12, 13,},
169
        {  3,  4,  5,  6,  7,  8,  9, 10, 11,  0,  1,  2, 15, 16, 17, 18, 19, 20, 21, 22, 23, 12, 13, 14,},
170
        {  4,  5,  6,  7,  8,  9, 10, 11,  0,  1,  2,  3, 16, 17, 18, 19, 20, 21, 22, 23, 12, 13, 14, 15,},
171
        {  5,  6,  7,  8,  9, 10, 11,  0,  1,  2,  3,  4, 17, 18, 19, 20, 21, 22, 23, 12, 13, 14, 15, 16,},
172
        {  6,  7,  8,  9, 10, 11,  0,  1,  2,  3,  4,  5, 18, 19, 20, 21, 22, 23, 12, 13, 14, 15, 16, 17,},
173
        {  7,  8,  9, 10, 11,  0,  1,  2,  3,  4,  5,  6, 19, 20, 21, 22, 23, 12, 13, 14, 15, 16, 17, 18,},
174
        {  8,  9, 10, 11,  0,  1,  2,  3,  4,  5,  6,  7, 20, 21, 22, 23, 12, 13, 14, 15, 16, 17, 18, 19,},
175
        {  9, 10, 11,  0,  1,  2,  3,  4,  5,  6,  7,  8, 21, 22, 23, 12, 13, 14, 15, 16, 17, 18, 19, 20,},
176
        { 10, 11,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 22, 23, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,},
177
        { 11,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 23, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,},
178
        { 12, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13,  0, 11, 10,  9,  8,  7,  6,  5,  4,  3,  2,  1,},
179
        { 13, 12, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14,  1,  0, 11, 10,  9,  8,  7,  6,  5,  4,  3,  2,},
180
        { 14, 13, 12, 23, 22, 21, 20, 19, 18, 17, 16, 15,  2,  1,  0, 11, 10,  9,  8,  7,  6,  5,  4,  3,},
181
        { 15, 14, 13, 12, 23, 22, 21, 20, 19, 18, 17, 16,  3,  2,  1,  0, 11, 10,  9,  8,  7,  6,  5,  4,},
182
        { 16, 15, 14, 13, 12, 23, 22, 21, 20, 19, 18, 17,  4,  3,  2,  1,  0, 11, 10,  9,  8,  7,  6,  5,},
183
        { 17, 16, 15, 14, 13, 12, 23, 22, 21, 20, 19, 18,  5,  4,  3,  2,  1,  0, 11, 10,  9,  8,  7,  6,},
184
        { 18, 17, 16, 15, 14, 13, 12, 23, 22, 21, 20, 19,  6,  5,  4,  3,  2,  1,  0, 11, 10,  9,  8,  7,},
185
        { 19, 18, 17, 16, 15, 14, 13, 12, 23, 22, 21, 20,  7,  6,  5,  4,  3,  2,  1,  0, 11, 10,  9,  8,},
186
        { 20, 19, 18, 17, 16, 15, 14, 13, 12, 23, 22, 21,  8,  7,  6,  5,  4,  3,  2,  1,  0, 11, 10,  9,},
187
        { 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 23, 22,  9,  8,  7,  6,  5,  4,  3,  2,  1,  0, 11, 10,},
188
        { 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 23, 10,  9,  8,  7,  6,  5,  4,  3,  2,  1,  0, 11,},
189
        { 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10,  9,  8,  7,  6,  5,  4,  3,  2,  1,  0,}
190
      };
191
    }
192

    
193
///////////////////////////////////////////////////////////////////////////////////////////////////
194
// TYPE 1
195

    
196
  private boolean cornerIsUp(int index)
197
    {
198
    return ((index<4) ^ (mCornerQuat[index]>=12));
199
    }
200

    
201
///////////////////////////////////////////////////////////////////////////////////////////////////
202
// TYPE 1
203

    
204
  private boolean cornerIsLeft(int index)
205
    {
206
    int q = mCornerQuat[index];
207

    
208
    switch(index)
209
      {
210
      case 0:
211
      case 4: return ((q>=3 && q<= 7) || (q>=18 && q<=22));
212
      case 1:
213
      case 5: return ((q>=6 && q<=10) || (q>=15 && q<=19));
214
      case 2:
215
      case 6: return ((q==0 || q==1 || (q>=9 && q<=11)) || (q>=12 && q<=16));
216
      case 3:
217
      case 7: return ((q>=0 && q<=4) || (q==12 || q==13 || (q>=21 && q<=23)));
218
      }
219

    
220
    return false;
221
    }
222

    
223
///////////////////////////////////////////////////////////////////////////////////////////////////
224
// TYPE 1
225

    
226
  private boolean quatIsBad(int quatIndex, int corner)
227
    {
228
    if( mBadCornerQuats ==null )
229
      {
230
      // quat indices that make corner cubits bandage the puzzle.
231
      mBadCornerQuats = new int[][] { { 2, 8,17,23}, { 5,11,14,20} };
232
      }
233

    
234
    int index = (corner%2);
235

    
236
    return ( quatIndex== mBadCornerQuats[index][0] ||
237
             quatIndex== mBadCornerQuats[index][1] ||
238
             quatIndex== mBadCornerQuats[index][2] ||
239
             quatIndex== mBadCornerQuats[index][3]  );
240
    }
241

    
242
///////////////////////////////////////////////////////////////////////////////////////////////////
243
// TYPE 1
244

    
245
  private boolean isPermittedDo(int angle)
246
    {
247
    if( mQuatMult==null ) initializeQuatMult();
248

    
249
    for(int corner=0; corner<8; corner++)
250
      {
251
      if( !cornerIsUp(corner) )
252
        {
253
        int currQuat = mCornerQuat[corner];
254
        int finalQuat= mQuatMult[angle][currQuat];
255
        if( quatIsBad(finalQuat,corner) ) return false;
256
        }
257
      }
258

    
259
    return true;
260
    }
261

    
262
///////////////////////////////////////////////////////////////////////////////////////////////////
263
// TYPE 1
264

    
265
  private boolean isPermittedUp(int angle)
266
    {
267
    if( mQuatMult==null ) initializeQuatMult();
268

    
269
    for(int corner=0; corner<8; corner++)
270
      {
271
      if( cornerIsUp(corner) )
272
        {
273
        int currQuat = mCornerQuat[corner];
274
        int finalQuat= mQuatMult[angle][currQuat];
275
        if( quatIsBad(finalQuat,corner) ) return false;
276
        }
277
      }
278

    
279
    return true;
280
    }
281

    
282
///////////////////////////////////////////////////////////////////////////////////////////////////
283
// TYPE 1
284

    
285
  private void computePermittedAngles()
286
    {
287
    mPermittedDo = 0;
288

    
289
    for(int angle=0; angle<BASIC_ANGLE; angle++)
290
      {
291
      if( isPermittedDo(angle ) ) mPermittedAngles[0][mPermittedDo++] = angle;
292
      }
293

    
294
    mPermittedUp = 0;
295

    
296
    for(int angle=0; angle<BASIC_ANGLE; angle++)
297
      {
298
      if( isPermittedUp(angle ) ) mPermittedAngles[1][mPermittedUp++] = angle;
299
      }
300
    }
301

    
302
///////////////////////////////////////////////////////////////////////////////////////////////////
303
// TYPE 1
304

    
305
  private int getNextAngle(Random rnd, int layer)
306
    {
307
    int num = layer==0 ? mPermittedDo:mPermittedUp;
308
    int index = rnd.nextInt(num);
309
    int angle = mPermittedAngles[layer][index];
310
    return angle<BASIC_ANGLE/2 ? -angle : BASIC_ANGLE-angle;
311
    }
312

    
313
///////////////////////////////////////////////////////////////////////////////////////////////////
314
// TYPE 1
315

    
316
  private int getNextAngleNotZero(Random rnd, int layer)
317
    {
318
    int num = layer==0 ? mPermittedDo:mPermittedUp;
319
    int index = rnd.nextInt(num-1);
320
    int angle = mPermittedAngles[layer][index+1];
321
    return angle<BASIC_ANGLE/2 ? -angle : BASIC_ANGLE-angle;
322
    }
323

    
324
///////////////////////////////////////////////////////////////////////////////////////////////////
325
// TYPE 1
326

    
327
  private int makeQuat(int axis,int index)
328
    {
329
    if( axis==1 ) return 13;
330
    if( index<0 ) index+=12;
331
    return index;
332
    }
333

    
334
///////////////////////////////////////////////////////////////////////////////////////////////////
335
// TYPE 1
336

    
337
  private boolean cornerBelongs(int index, int axis, int layer)
338
    {
339
    if( axis==0 )
340
      {
341
      boolean up = cornerIsUp(index);
342
      return ((up && layer==2) || (!up && layer==0));
343
      }
344
    else
345
      {
346
      boolean le = cornerIsLeft(index);
347
      return ((le && layer==0) || (!le && layer==1));
348
      }
349
    }
350

    
351
///////////////////////////////////////////////////////////////////////////////////////////////////
352
// TYPE 1
353

    
354
  private void updateCornerQuats(int[] rotInfo)
355
    {
356
    if( mQuatMult==null ) initializeQuatMult();
357

    
358
    int axis = rotInfo[0];
359
    int layer= rotInfo[1];
360
    int index=-rotInfo[2];
361

    
362
    int quat = makeQuat(axis,index);
363

    
364
    for(int corner=0; corner<8; corner++)
365
      {
366
      if( cornerBelongs(corner,axis,layer) )
367
        {
368
        int curr = mCornerQuat[corner];
369
        mCornerQuat[corner] = mQuatMult[quat][curr];
370
        }
371
      }
372
    }
373

    
374
///////////////////////////////////////////////////////////////////////////////////////////////////
375
// TYPE 1
376

    
377
  private void randomizeNewScramble1(int[][] scramble, Random rnd, int curr)
378
    {
379
    int layer, nextAngle;
380

    
381
    if( curr==0 )
382
      {
383
      for(int corner=0; corner<8; corner++) mCornerQuat[corner] = 0;
384
      mLastRot = rnd.nextInt(4);
385
      computePermittedAngles();
386
      }
387

    
388
    switch(mLastRot)
389
      {
390
      case LAST_SL: layer = rnd.nextInt(2);
391
                    nextAngle = getNextAngle(rnd,layer);
392

    
393
                    if( nextAngle==0 )
394
                      {
395
                      layer = 1-layer;
396
                      nextAngle = getNextAngleNotZero(rnd,layer);
397
                      }
398

    
399
                    scramble[curr][0] = 0;
400
                    scramble[curr][1] = 2*layer;
401
                    scramble[curr][2] = nextAngle;
402
                    mLastRot = layer==0 ? LAST_LO : LAST_UP;
403
                    updateCornerQuats(scramble[curr]);
404
                    scramble[curr][1] = (1<<scramble[curr][1]);
405
                    break;
406
      case LAST_LO:
407
      case LAST_UP: layer = mLastRot==LAST_LO ? 1:0;
408
                    nextAngle = getNextAngle(rnd,layer);
409

    
410
                    if( nextAngle!=0 )
411
                      {
412
                      scramble[curr][0] = 0;
413
                      scramble[curr][1] = 2*layer;
414
                      scramble[curr][2] = nextAngle;
415
                      updateCornerQuats(scramble[curr]);
416
                      scramble[curr][1] = (1<<scramble[curr][1]);
417
                      mLastRot = LAST_UL;
418
                      }
419
                    else
420
                      {
421
                      scramble[curr][0] = 1;
422
                      scramble[curr][1] = rnd.nextInt(2);
423
                      scramble[curr][2] = 1;
424
                      mLastRot = LAST_SL;
425
                      updateCornerQuats(scramble[curr]);
426
                      scramble[curr][1] = (1<<scramble[curr][1]);
427
                      computePermittedAngles();
428
                      }
429

    
430
                    break;
431
      case LAST_UL: scramble[curr][0] = 1;
432
                    scramble[curr][1] = rnd.nextInt(2);
433
                    scramble[curr][2] = 1;
434
                    mLastRot = LAST_SL;
435
                    updateCornerQuats(scramble[curr]);
436
                    computePermittedAngles();
437
                    scramble[curr][1] = (1<<scramble[curr][1]);
438
                    break;
439
      }
440
    }
441

    
442
///////////////////////////////////////////////////////////////////////////////////////////////////
443
// TYPE 2
444

    
445
  private void buildMoveForced(int[][] scramble, Random rnd, int curr)
446
    {
447
    ScrambleStateBandagedCuboid currState = mStatesHistory.get(curr);
448
    int indexExcluded = curr>0 ? scramble[curr-1][0] : ScrambleStateBandagedCuboid.AXIS_NONE;
449
    int numMoves = currState.numMoves(indexExcluded);
450
    ObjectSignature signature;
451

    
452
    if( numMoves==0 )
453
      {
454
      indexExcluded = ScrambleStateBandagedCuboid.AXIS_NONE;
455
      numMoves = currState.numMoves(indexExcluded);
456
      }
457

    
458
    if( numMoves==0 )
459
      {
460
      scramble[curr][0] = 0;
461
      scramble[curr][1] = 0;
462
      scramble[curr][2] = 0;
463
      signature = currState.getSignature();
464
      }
465
    else
466
      {
467
      int randMove = rnd.nextInt(numMoves);
468
      int moveIndex = currState.getNthMove(randMove,indexExcluded);
469
      signature = currState.getMove(moveIndex);
470
      currState.fillOutScramble(scramble[curr],moveIndex);
471
      }
472

    
473
    ScrambleStateBandagedCuboid nextState = new ScrambleStateBandagedCuboid(mNumLayers[0], mNumLayers[1], mNumLayers[2], signature, mBlacklisted);
474
    mStatesHistory.add(nextState);
475
    }
476

    
477

    
478
///////////////////////////////////////////////////////////////////////////////////////////////////
479
// TYPE 2
480

    
481
  private boolean buildMove2Cons(int[][] scramble, Random rnd, int curr)
482
    {
483
    ScrambleStateBandagedCuboid currState = mStatesHistory.get(curr);
484
    boolean lock= (curr>=2 && scramble[curr-2][0]==scramble[curr-1][0] );
485
    int axisExcluded = lock ? scramble[curr-1][0] : ScrambleStateBandagedCuboid.AXIS_NONE;
486
    int layerExcluded= !lock && curr>=1 ? scramble[curr-1][1] : -1;
487
    int numMoves = currState.numMoves(axisExcluded,layerExcluded);
488

    
489
    while( numMoves==0 )
490
      {
491
      if( curr>0 )
492
        {
493
        mStatesHistory.remove(curr);
494
        ScrambleStateBandagedCuboid prevState = mStatesHistory.get(curr-1);
495
        ObjectSignature signature = currState.getSignature();
496
        prevState.removeMoves(signature);
497
        mBlacklisted.add(signature);
498
        boolean result = buildMove2Cons(scramble,rnd,curr-1);
499
        if( !result ) return false;
500
        currState = mStatesHistory.get(curr);
501
        lock= (curr>=2 && scramble[curr-2][0]==scramble[curr-1][0] );
502
        axisExcluded = lock ? scramble[curr-1][0] : ScrambleStateBandagedCuboid.AXIS_NONE;
503
        layerExcluded= lock ? -1 : scramble[curr-1][1];
504
        numMoves = currState.numMoves(axisExcluded,layerExcluded);
505
        }
506
      else return false;
507
      }
508

    
509
    int randMove = rnd.nextInt(numMoves);
510
    int moveIndex = currState.getNthMove(randMove,axisExcluded,layerExcluded);
511
    ObjectSignature signature = currState.getMove(moveIndex);
512
    currState.fillOutScramble(scramble[curr],moveIndex);
513

    
514
    ScrambleStateBandagedCuboid nextState = new ScrambleStateBandagedCuboid(mNumLayers[0], mNumLayers[1], mNumLayers[2], signature, mBlacklisted);
515
    mStatesHistory.add(nextState);
516

    
517
    return true;
518
    }
519

    
520
///////////////////////////////////////////////////////////////////////////////////////////////////
521
// TYPE 2
522

    
523
  private boolean buildMove1Cons(int[][] scramble, Random rnd, int curr)
524
    {
525
    ScrambleStateBandagedCuboid currState = mStatesHistory.get(curr);
526
    int axisExcluded = curr>=1 ? scramble[curr-1][0] : ScrambleStateBandagedCuboid.AXIS_NONE;
527
    int numMoves = currState.numMoves(axisExcluded);
528

    
529
    while( numMoves==0 )
530
      {
531
      if( curr>0 )
532
        {
533
        mStatesHistory.remove(curr);
534
        ScrambleStateBandagedCuboid prevState = mStatesHistory.get(curr-1);
535
        ObjectSignature signature = currState.getSignature();
536
        prevState.removeMoves(signature);
537
        mBlacklisted.add(signature);
538
        boolean result = buildMove1Cons(scramble,rnd,curr-1);
539
        if( !result ) return false;
540
        currState = mStatesHistory.get(curr);
541
        axisExcluded = scramble[curr-1][0];
542
        numMoves = currState.numMoves(axisExcluded);
543
        }
544
      else
545
        {
546
        return false;
547
        }
548
      }
549

    
550
    int randMove = rnd.nextInt(numMoves);
551
    int moveIndex = currState.getNthMove(randMove,axisExcluded);
552
    ObjectSignature signature = currState.getMove(moveIndex);
553
    currState.fillOutScramble(scramble[curr],moveIndex);
554

    
555
    ScrambleStateBandagedCuboid nextState = new ScrambleStateBandagedCuboid(mNumLayers[0], mNumLayers[1], mNumLayers[2], signature, mBlacklisted);
556
    mStatesHistory.add(nextState);
557

    
558
    return true;
559
    }
560

    
561
///////////////////////////////////////////////////////////////////////////////////////////////////
562
// TYPE 2
563

    
564
  private void initializeType2Scrambling(int[][] scramble, Random rnd, int total, ObjectSignature signature)
565
    {
566
    if( mStatesHistory==null ) mStatesHistory = new ArrayList<>();
567
    else                       mStatesHistory.clear();
568

    
569
    if( mBlacklisted==null ) mBlacklisted = BlacklistedSignatures.getInstance();
570
    else                     mBlacklisted.clear();
571

    
572
    ScrambleStateBandagedCuboid state = new ScrambleStateBandagedCuboid(mNumLayers[0], mNumLayers[1], mNumLayers[2], signature, mBlacklisted);
573
    mStatesHistory.add(state);
574
    boolean success = true;
575

    
576
    for(int curr=0; curr<total; curr++)
577
      {
578
      boolean result = buildMove1Cons(scramble,rnd,curr);
579
      if( !result )
580
        {
581
        success = false;
582
        break;
583
        }
584
      }
585

    
586
    if( !success )
587
      {
588
      success = true;
589
      mStatesHistory.clear();
590
      mBlacklisted.clear();
591
      state = new ScrambleStateBandagedCuboid(mNumLayers[0], mNumLayers[1], mNumLayers[2], signature, mBlacklisted);
592
      mStatesHistory.add(state);
593

    
594
      for(int curr=0; curr<total; curr++)
595
        {
596
        boolean result = buildMove2Cons(scramble,rnd,curr);
597
        if( !result )
598
          {
599
          success = false;
600
          break;
601
          }
602
        }
603
      }
604

    
605
    if( !success )
606
      {
607
      mStatesHistory.clear();
608
      mBlacklisted.clear();
609
      state = new ScrambleStateBandagedCuboid(mNumLayers[0], mNumLayers[1], mNumLayers[2], signature, mBlacklisted);
610
      mStatesHistory.add(state);
611

    
612
      for(int curr=0; curr<total; curr++)
613
        {
614
        buildMoveForced(scramble,rnd,curr);
615
        }
616
      }
617
    }
618

    
619
///////////////////////////////////////////////////////////////////////////////////////////////////
620
// TYPE 2   (locally-created bandaged cuboids)
621

    
622
  private void randomizeNewScramble2(int[][] scramble, Random rnd, int curr, int total, ObjectSignature signature)
623
    {
624
    if( curr==0 )
625
      {
626
      initializeType2Scrambling(scramble,rnd,total,signature);
627
      int len = scramble.length;
628
      for(int i=0; i<len; i++) scramble[i][1] = (1<<scramble[i][1]);
629
      }
630
    }
631

    
632
///////////////////////////////////////////////////////////////////////////////////////////////////
633
// PUBLIC API
634

    
635
  public void randomizeNewScramble(int[][] scramble, Random rnd, int curr, int total, ObjectSignature signature)
636
    {
637
    if( mTablebase!=null )
638
      {
639
      if( curr==0 ) mTablebase.scramble(rnd,total,scramble);
640
      }
641
    else
642
      {
643
      switch(mType)
644
        {
645
        case SCRAMBLING_ALGORITHMS: randomizeNewScramble0(scramble, rnd, curr); break;
646
        case SCRAMBLING_SQUARE1   : randomizeNewScramble1(scramble, rnd, curr); break;
647
        case SCRAMBLING_BANDAGED  : randomizeNewScramble2(scramble, rnd, curr, total, signature); break;
648
        }
649
      }
650
    }
651
  }
(2-2/7)