Project

General

Profile

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

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

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 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;
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] = 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
                    break;
405
      case LAST_LO:
406
      case LAST_UP: layer = mLastRot==LAST_LO ? 1:0;
407
                    nextAngle = getNextAngle(rnd,layer);
408

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

    
427
                    break;
428
      case LAST_UL: scramble[curr][0] = 1;
429
                    scramble[curr][1] = rnd.nextInt(2);
430
                    scramble[curr][2] = 1;
431
                    mLastRot = LAST_SL;
432
                    updateCornerQuats(scramble[curr]);
433
                    computePermittedAngles();
434
                    break;
435
      }
436
    }
437

    
438
///////////////////////////////////////////////////////////////////////////////////////////////////
439
// TYPE 2
440

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

    
448
    if( numMoves==0 )
449
      {
450
      indexExcluded = ScrambleStateBandagedCuboid.AXIS_NONE;
451
      numMoves = currState.numMoves(indexExcluded);
452
      }
453

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

    
469
    ScrambleStateBandagedCuboid nextState = new ScrambleStateBandagedCuboid(mNumLayers[0], mNumLayers[1], mNumLayers[2], signature, mBlacklisted);
470
    mStatesHistory.add(nextState);
471
    }
472

    
473

    
474
///////////////////////////////////////////////////////////////////////////////////////////////////
475
// TYPE 2
476

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

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

    
505
    int randMove = rnd.nextInt(numMoves);
506
    int moveIndex = currState.getNthMove(randMove,axisExcluded,layerExcluded);
507
    ObjectSignature signature = currState.getMove(moveIndex);
508
    currState.fillOutScramble(scramble[curr],moveIndex);
509

    
510
    ScrambleStateBandagedCuboid nextState = new ScrambleStateBandagedCuboid(mNumLayers[0], mNumLayers[1], mNumLayers[2], signature, mBlacklisted);
511
    mStatesHistory.add(nextState);
512

    
513
    return true;
514
    }
515

    
516
///////////////////////////////////////////////////////////////////////////////////////////////////
517
// TYPE 2
518

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

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

    
546
    int randMove = rnd.nextInt(numMoves);
547
    int moveIndex = currState.getNthMove(randMove,axisExcluded);
548
    ObjectSignature signature = currState.getMove(moveIndex);
549
    currState.fillOutScramble(scramble[curr],moveIndex);
550

    
551
    ScrambleStateBandagedCuboid nextState = new ScrambleStateBandagedCuboid(mNumLayers[0], mNumLayers[1], mNumLayers[2], signature, mBlacklisted);
552
    mStatesHistory.add(nextState);
553

    
554
    return true;
555
    }
556

    
557
///////////////////////////////////////////////////////////////////////////////////////////////////
558
// TYPE 2
559

    
560
  private void initializeType2Scrambling(int[][] scramble, Random rnd, int total, ObjectSignature signature)
561
    {
562
    if( mStatesHistory==null ) mStatesHistory = new ArrayList<>();
563
    else                       mStatesHistory.clear();
564

    
565
    if( mBlacklisted==null ) mBlacklisted = BlacklistedSignatures.getInstance();
566
    else                     mBlacklisted.clear();
567

    
568
    ScrambleStateBandagedCuboid state = new ScrambleStateBandagedCuboid(mNumLayers[0], mNumLayers[1], mNumLayers[2], signature, mBlacklisted);
569
    mStatesHistory.add(state);
570
    boolean success = true;
571

    
572
    for(int curr=0; curr<total; curr++)
573
      {
574
      boolean result = buildMove1Cons(scramble,rnd,curr);
575
      if( !result )
576
        {
577
        success = false;
578
        break;
579
        }
580
      }
581

    
582
    if( !success )
583
      {
584
      success = true;
585
      mStatesHistory.clear();
586
      mBlacklisted.clear();
587
      state = new ScrambleStateBandagedCuboid(mNumLayers[0], mNumLayers[1], mNumLayers[2], signature, mBlacklisted);
588
      mStatesHistory.add(state);
589

    
590
      for(int curr=0; curr<total; curr++)
591
        {
592
        boolean result = buildMove2Cons(scramble,rnd,curr);
593
        if( !result )
594
          {
595
          success = false;
596
          break;
597
          }
598
        }
599
      }
600

    
601
    if( !success )
602
      {
603
      mStatesHistory.clear();
604
      mBlacklisted.clear();
605
      state = new ScrambleStateBandagedCuboid(mNumLayers[0], mNumLayers[1], mNumLayers[2], signature, mBlacklisted);
606
      mStatesHistory.add(state);
607

    
608
      for(int curr=0; curr<total; curr++)
609
        {
610
        buildMoveForced(scramble,rnd,curr);
611
        }
612
      }
613
    }
614

    
615
///////////////////////////////////////////////////////////////////////////////////////////////////
616
// TYPE 2   (locally-created bandaged cuboids)
617

    
618
  private void randomizeNewScramble2(int[][] scramble, Random rnd, int curr, int total, ObjectSignature signature)
619
    {
620
    if( curr==0 ) initializeType2Scrambling(scramble,rnd,total,signature);
621
    }
622

    
623
///////////////////////////////////////////////////////////////////////////////////////////////////
624
// PUBLIC API
625

    
626
  public void randomizeNewScramble(int[][] scramble, Random rnd, int curr, int total, ObjectSignature signature)
627
    {
628
    if( mTablebase!=null )
629
      {
630
      if( curr==0 ) mTablebase.scramble(rnd,total,scramble);
631
      }
632
    else
633
      {
634
      switch(mType)
635
        {
636
        case SCRAMBLING_ALGORITHMS: randomizeNewScramble0(scramble, rnd, curr); break;
637
        case SCRAMBLING_SQUARE1   : randomizeNewScramble1(scramble, rnd, curr); break;
638
        case SCRAMBLING_BANDAGED  : randomizeNewScramble2(scramble, rnd, curr, total, signature); break;
639
        }
640
      }
641
    }
642
  }
(2-2/7)