Project

General

Profile

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

distorted-objectlib / src / main / java / org / distorted / objectlib / scrambling / ScrambleStateBandaged3x3.java @ 39d97e73

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2022 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.objectlib.scrambling;
21

    
22
import java.util.ArrayList;
23

    
24
///////////////////////////////////////////////////////////////////////////////////////////////////
25
// Producer of the ScrambleStateGraph for any bandaged 3x3x3.
26

    
27
public class ScrambleStateBandaged3x3
28
{
29
  private static final long INVALID_MOVE = -1;
30
  private static final int NUM_MOVES = 27;
31

    
32
  private static final int AXIS_X = 0;
33
  private static final int AXIS_Y = 1;
34
  private static final int AXIS_Z = 2;
35

    
36
  private static final int LAYER_L = 0;
37
  private static final int LAYER_M = 1;
38
  private static final int LAYER_R = 2;
39

    
40
  private long mID;
41
  private int mDistance;
42
  private final long[] mMoves;
43

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

    
46
  private ScrambleStateBandaged3x3(long id)
47
    {
48
    mDistance = -1;
49
    mID = id;
50
    mMoves = createMoves(mID);
51
    }
52

    
53
///////////////////////////////////////////////////////////////////////////////////////////////////
54

    
55
  private long getID()
56
    {
57
    return mID;
58
    }
59

    
60
///////////////////////////////////////////////////////////////////////////////////////////////////
61

    
62
  private void setID(long id)
63
    {
64
    mID = id;
65
    }
66

    
67
///////////////////////////////////////////////////////////////////////////////////////////////////
68

    
69
  private long getMove(int index)
70
    {
71
    return (index>=0 && index<NUM_MOVES) ? mMoves[index] : INVALID_MOVE;
72
    }
73

    
74
///////////////////////////////////////////////////////////////////////////////////////////////////
75

    
76
  private int numAxis()
77
    {
78
    int num = 0;
79

    
80
    if( mMoves[ 0]!=INVALID_MOVE || mMoves[ 1]!=INVALID_MOVE || mMoves[ 2]!=INVALID_MOVE ||
81
        mMoves[ 3]!=INVALID_MOVE || mMoves[ 4]!=INVALID_MOVE || mMoves[ 5]!=INVALID_MOVE ||
82
        mMoves[ 6]!=INVALID_MOVE || mMoves[ 7]!=INVALID_MOVE || mMoves[ 8]!=INVALID_MOVE   ) num++;
83

    
84
    if( mMoves[ 9]!=INVALID_MOVE || mMoves[10]!=INVALID_MOVE || mMoves[11]!=INVALID_MOVE ||
85
        mMoves[12]!=INVALID_MOVE || mMoves[13]!=INVALID_MOVE || mMoves[14]!=INVALID_MOVE ||
86
        mMoves[15]!=INVALID_MOVE || mMoves[16]!=INVALID_MOVE || mMoves[17]!=INVALID_MOVE   ) num++;
87

    
88
    if( mMoves[18]!=INVALID_MOVE || mMoves[19]!=INVALID_MOVE || mMoves[20]!=INVALID_MOVE ||
89
        mMoves[21]!=INVALID_MOVE || mMoves[22]!=INVALID_MOVE || mMoves[23]!=INVALID_MOVE ||
90
        mMoves[24]!=INVALID_MOVE || mMoves[25]!=INVALID_MOVE || mMoves[26]!=INVALID_MOVE   ) num++;
91

    
92
    return num;
93
    }
94

    
95
///////////////////////////////////////////////////////////////////////////////////////////////////
96

    
97
  private void setMove(int index, long newMove)
98
    {
99
    if( index>=0 && index<NUM_MOVES ) mMoves[index] = newMove;
100
    }
101

    
102
///////////////////////////////////////////////////////////////////////////////////////////////////
103

    
104
  private String formatMoves()
105
    {
106
    String x = getTable( 0);
107
    String y = getTable( 9);
108
    String z = getTable(18);
109

    
110
    return "    new ScrambleState( new int[][] { "+x+", "+y+", "+z+" } ),";
111
    }
112

    
113
///////////////////////////////////////////////////////////////////////////////////////////////////
114

    
115
  private String getTable(int index)
116
    {
117
    long m0 = getMove(index  );
118
    long m1 = getMove(index+1);
119
    long m2 = getMove(index+2);
120
    long m3 = getMove(index+3);
121
    long m4 = getMove(index+4);
122
    long m5 = getMove(index+5);
123
    long m6 = getMove(index+6);
124
    long m7 = getMove(index+7);
125
    long m8 = getMove(index+8);
126

    
127
    String ret = "";
128

    
129
    if( m0!=INVALID_MOVE ) ret += formatRet(ret,0,-1,m0);
130
    if( m1!=INVALID_MOVE ) ret += formatRet(ret,0, 2,m1);
131
    if( m2!=INVALID_MOVE ) ret += formatRet(ret,0, 1,m2);
132
    if( m3!=INVALID_MOVE ) ret += formatRet(ret,1,-1,m3);
133
    if( m4!=INVALID_MOVE ) ret += formatRet(ret,1, 2,m4);
134
    if( m5!=INVALID_MOVE ) ret += formatRet(ret,1, 1,m5);
135
    if( m6!=INVALID_MOVE ) ret += formatRet(ret,2,-1,m6);
136
    if( m7!=INVALID_MOVE ) ret += formatRet(ret,2, 2,m7);
137
    if( m8!=INVALID_MOVE ) ret += formatRet(ret,2, 1,m8);
138

    
139
    return formatL("{" + ret + "}");
140
    }
141

    
142
///////////////////////////////////////////////////////////////////////////////////////////////////
143

    
144
  private int[] getMoves(int index)
145
    {
146
    int numValid = 0;
147
    for(int i=index; i<index+9; i++) if( mMoves[i]!=INVALID_MOVE ) numValid++;
148

    
149
    int[] ret = new int[3*numValid];
150

    
151
    long m0 = getMove(index  );
152
    long m1 = getMove(index+1);
153
    long m2 = getMove(index+2);
154
    long m3 = getMove(index+3);
155
    long m4 = getMove(index+4);
156
    long m5 = getMove(index+5);
157
    long m6 = getMove(index+6);
158
    long m7 = getMove(index+7);
159
    long m8 = getMove(index+8);
160

    
161
    int pointer=0;
162

    
163
    if( m0!=INVALID_MOVE ) { ret[pointer]=0; ret[pointer+1]=-1; ret[pointer+2]= (int)m0; pointer+=3; }
164
    if( m1!=INVALID_MOVE ) { ret[pointer]=0; ret[pointer+1]= 2; ret[pointer+2]= (int)m1; pointer+=3; }
165
    if( m2!=INVALID_MOVE ) { ret[pointer]=0; ret[pointer+1]= 1; ret[pointer+2]= (int)m2; pointer+=3; }
166
    if( m3!=INVALID_MOVE ) { ret[pointer]=1; ret[pointer+1]=-1; ret[pointer+2]= (int)m3; pointer+=3; }
167
    if( m4!=INVALID_MOVE ) { ret[pointer]=1; ret[pointer+1]= 2; ret[pointer+2]= (int)m4; pointer+=3; }
168
    if( m5!=INVALID_MOVE ) { ret[pointer]=1; ret[pointer+1]= 1; ret[pointer+2]= (int)m5; pointer+=3; }
169
    if( m6!=INVALID_MOVE ) { ret[pointer]=2; ret[pointer+1]=-1; ret[pointer+2]= (int)m6; pointer+=3; }
170
    if( m7!=INVALID_MOVE ) { ret[pointer]=2; ret[pointer+1]= 2; ret[pointer+2]= (int)m7; pointer+=3; }
171
    if( m8!=INVALID_MOVE ) { ret[pointer]=2; ret[pointer+1]= 1; ret[pointer+2]= (int)m8; pointer+=3; }
172

    
173
    return ret;
174
    }
175

    
176
///////////////////////////////////////////////////////////////////////////////////////////////////
177

    
178
  private ScrambleState produceScrambleState()
179
    {
180
    int[] xMoves = getMoves(0);
181
    int[] yMoves = getMoves(9);
182
    int[] zMoves = getMoves(18);
183

    
184
    int[][] moves = { xMoves,yMoves,zMoves };
185

    
186
    return new ScrambleState( moves );
187
    }
188

    
189
///////////////////////////////////////////////////////////////////////////////////////////////////
190
// STATIC STUFF
191
///////////////////////////////////////////////////////////////////////////////////////////////////
192

    
193
  public static ScrambleState[] computeGraph(long id)
194
    {
195
    ScrambleStateBandaged3x3 bsg = new ScrambleStateBandaged3x3(id);
196
    ArrayList<ScrambleStateBandaged3x3> graph = new ArrayList<>();
197
    graph.add(bsg);
198

    
199
long t1 = System.currentTimeMillis();
200

    
201
    insertChildren(graph,id);
202

    
203
long t2 = System.currentTimeMillis();
204
android.util.Log.e("D", "inserting children: "+(t2-t1));
205

    
206
    pruneGraph(graph,id,false);
207

    
208
long t3 = System.currentTimeMillis();
209
android.util.Log.e("D", "pruning graph: "+(t3-t2));
210

    
211
    computeDistance(graph,id,0);
212

    
213
long t4 = System.currentTimeMillis();
214
android.util.Log.e("D", "computing distance: "+(t4-t3));
215

    
216
    removeDisconnectedParts(graph);
217

    
218
long t5 = System.currentTimeMillis();
219
android.util.Log.e("D", "removing disconnected parts: "+(t5-t4));
220

    
221
    remapGraph(graph);
222

    
223
long t6 = System.currentTimeMillis();
224
android.util.Log.e("D", "remapping graph: "+(t6-t5));
225

    
226
    int num = graph.size();
227
    ScrambleState[] ret = new ScrambleState[num];
228

    
229
    for(int i=0; i<num; i++)
230
      {
231
      ScrambleStateBandaged3x3 ssb = graph.get(i);
232
      ret[i] = ssb.produceScrambleState();
233
      }
234

    
235
long t7 = System.currentTimeMillis();
236
android.util.Log.e("D", "producing scramble states: "+(t7-t6)+" graph size: "+graph.size() );
237

    
238
    return ret;
239
    }
240

    
241
///////////////////////////////////////////////////////////////////////////////////////////////////
242

    
243
  private static void insertChildren(ArrayList<ScrambleStateBandaged3x3> list, long id)
244
    {
245
    ScrambleStateBandaged3x3 bsg = findState(list,id);
246

    
247
    if( bsg==null )
248
      {
249
      android.util.Log.e("D", "error: "+id+" doesn't exist");
250
      return;
251
      }
252

    
253
    for(int i=0; i<NUM_MOVES; i++)
254
      {
255
      long move = bsg.getMove(i);
256

    
257
      if( move!=INVALID_MOVE )
258
        {
259
        ScrambleStateBandaged3x3 tmp = findState(list,move);
260

    
261
        if( tmp==null )
262
          {
263
          tmp = new ScrambleStateBandaged3x3(move);
264
          list.add(tmp);
265
          insertChildren(list,move);
266
          }
267
        else if( tmp.mID != move )
268
          {
269
          bsg.setMove(i,tmp.mID);
270
          }
271
        }
272
      }
273
    }
274

    
275
///////////////////////////////////////////////////////////////////////////////////////////////////
276

    
277
  private static void pruneGraph(ArrayList<ScrambleStateBandaged3x3> list, long id, boolean startingPrunedAlready)
278
    {
279
    int num = list.size();
280

    
281
    if( num>1 ) // do not prune moves of an only node leading to itself. Case in point: bandaged 3x3 locked along 2 of its axis.
282
      {
283
      boolean pruned = false;
284
      ScrambleStateBandaged3x3 bsg;
285

    
286
      for(int i=0; i<num; i++)
287
        {
288
        bsg = list.get(i);
289

    
290
        if( bsg.numAxis()<2 )
291
          {
292
          long prunedID = bsg.getID();
293
          if( id!=prunedID || !startingPrunedAlready )
294
            {
295
            startingPrunedAlready = true;
296
            remapID(list,prunedID,INVALID_MOVE);
297
            }
298

    
299
          // do not remove the starting point, even if it does have only 1 axis
300
          if( id!=prunedID )
301
            {
302
            list.remove(i);
303
            pruned = true;
304
            break;
305
            }
306
          }
307
        }
308

    
309
      if( pruned ) pruneGraph(list,id,startingPrunedAlready);
310
      }
311
    }
312

    
313
///////////////////////////////////////////////////////////////////////////////////////////////////
314

    
315
  private static void remapGraph(ArrayList<ScrambleStateBandaged3x3> list)
316
    {
317
    long id;
318
    int num = list.size();
319
    ScrambleStateBandaged3x3 bsg;
320

    
321
    for(int i=0; i<num; i++ )
322
      {
323
      bsg = list.get(i);
324
      id = bsg.getID();
325
      bsg.setID(i);
326
      remapID(list,id,i);
327
      }
328
    }
329

    
330
///////////////////////////////////////////////////////////////////////////////////////////////////
331

    
332
  private static void remapID(ArrayList<ScrambleStateBandaged3x3> list, long id, long newId)
333
    {
334
    ScrambleStateBandaged3x3 bsg;
335
    int size = list.size();
336

    
337
    for(int i=0; i<size; i++)
338
      {
339
      bsg = list.get(i);
340

    
341
      for(int j=0; j<NUM_MOVES; j++)
342
        {
343
        if( bsg.mMoves[j]==id ) bsg.mMoves[j]=newId;
344
        }
345
      }
346
    }
347

    
348
///////////////////////////////////////////////////////////////////////////////////////////////////
349

    
350
  private static void computeDistance(ArrayList<ScrambleStateBandaged3x3> list, long id, int distance)
351
    {
352
    ScrambleStateBandaged3x3 state = findState(list,id);
353

    
354
    if( state==null )
355
      {
356
      android.util.Log.e("D", "error: "+id+" doesn't exist");
357
      return;
358
      }
359

    
360
    if( state.mDistance<0 )
361
      {
362
      state.mDistance = distance;
363

    
364
      for(int i=0; i<NUM_MOVES; i++)
365
        {
366
        long move = state.getMove(i);
367

    
368
        if( move!=INVALID_MOVE )
369
          {
370
          computeDistance(list,move,distance+1);
371
          }
372
        }
373
      }
374
    }
375

    
376
///////////////////////////////////////////////////////////////////////////////////////////////////
377

    
378
  private static void removeDisconnectedParts(ArrayList<ScrambleStateBandaged3x3> list)
379
    {
380
    int num = list.size();
381
    ScrambleStateBandaged3x3 bsg;
382

    
383
    for(int i=0; i<num; i++)
384
      {
385
      bsg = list.get(i);
386

    
387
      if( bsg.mDistance<0 )
388
        {
389
        list.remove(i);
390
        i--;
391
        num--;
392
        }
393
      }
394
    }
395

    
396
///////////////////////////////////////////////////////////////////////////////////////////////////
397

    
398
  private static ScrambleStateBandaged3x3 findState(ArrayList<ScrambleStateBandaged3x3> list, long id)
399
    {
400
    ScrambleStateBandaged3x3 bsg;
401
    int num = list.size();
402

    
403
    for(int i=0; i<num; i++)
404
      {
405
      bsg= list.get(i);
406
      if( bsg.mID==id ) return bsg;
407
      }
408

    
409
    return null;
410
    }
411

    
412
///////////////////////////////////////////////////////////////////////////////////////////////////
413

    
414
  private static String formatRet(String str, int row, int angle, long id)
415
    {
416
    String ret = str.length()!=0 ? ",":"";
417

    
418
    ret += row;
419
    ret += angle<0 ? "," : ", ";
420
    ret += angle;
421

    
422
         if( id< 10 ) ret += (",  "+id);
423
    else if( id<100 ) ret += (", " +id);
424
    else              ret += (","  +id);
425

    
426
    return ret;
427
    }
428

    
429
///////////////////////////////////////////////////////////////////////////////////////////////////
430

    
431
  private static final int LENGTH = 28;
432

    
433
  private static String formatL(String input)
434
    {
435
    int len = input.length();
436
    String ret = input;
437
    for(int i=0 ;i<LENGTH-len; i++) ret += " ";
438
    return ret;
439
    }
440

    
441
///////////////////////////////////////////////////////////////////////////////////////////////////
442

    
443
  private static long[] createMoves(long id)
444
    {
445
    long[] ret = new long[NUM_MOVES];
446
    int index = 0;
447

    
448
    for(int axis=0; axis<3; axis++)
449
      for(int layer=0; layer<3; layer++)
450
        {
451
        long x1 = turn(id,axis,layer);
452

    
453
        if( x1!=INVALID_MOVE )
454
          {
455
          long x2 = turn(x1,axis,layer);
456
          long x3 = turn(x2,axis,layer);
457

    
458
          ret[index  ] = x1;
459
          ret[index+1] = x2;
460
          ret[index+2] = x3;
461
          }
462
        else
463
          {
464
          ret[index  ] = INVALID_MOVE;
465
          ret[index+1] = INVALID_MOVE;
466
          ret[index+2] = INVALID_MOVE;
467
          }
468

    
469
        index+=3;
470
        }
471

    
472
    return ret;
473
    }
474

    
475
///////////////////////////////////////////////////////////////////////////////////////////////////
476
// Definition of the id: it's an 'Andreas signature' of a bandaged cube.
477
// https://twistypuzzles.com/forum/viewtopic.php?t=24452&sid=f3b4ac0c611c4713e4d7840f1aabbb0b&start=350
478

    
479
  private static long turn(long id, int axis, int layer)
480
    {
481
    switch(axis)
482
      {
483
      case AXIS_X: switch(layer)
484
                     {
485
                     case LAYER_L: if( getBit(id, 1)==1 || getBit(id, 6)==1 || getBit(id,11)==1 ||
486
                                       getBit(id,22)==1 || getBit(id,27)==1 || getBit(id,32)==1 ||
487
                                       getBit(id,43)==1 || getBit(id,48)==1 || getBit(id,53)==1  ) return INVALID_MOVE;
488

    
489
                                   long x1 = cycle(id,9,14,46,41);
490
                                   long x2 = cycle(x1,4,35,51,20);
491
                                   return    cycle(x2,17,25,38,30);
492

    
493
                     case LAYER_M: if( getBit(id, 1)==1 || getBit(id, 6)==1 || getBit(id,11)==1 ||
494
                                       getBit(id,22)==1 || getBit(id,27)==1 || getBit(id,32)==1 ||
495
                                       getBit(id,43)==1 || getBit(id,48)==1 || getBit(id,53)==1 ||
496
                                       getBit(id, 0)==1 || getBit(id, 5)==1 || getBit(id,10)==1 ||
497
                                       getBit(id,21)==1 || getBit(id,26)==1 || getBit(id,31)==1 ||
498
                                       getBit(id,42)==1 || getBit(id,47)==1 || getBit(id,52)==1  ) return INVALID_MOVE;
499

    
500
                                   long x4 = cycle(id,8,13,45,40);
501
                                   long x5 = cycle(x4,3,34,50,19);
502
                                   return    cycle(x5,16,24,37,29);
503

    
504
                     case LAYER_R: if( getBit(id, 0)==1 || getBit(id, 5)==1 || getBit(id,10)==1 ||
505
                                       getBit(id,21)==1 || getBit(id,26)==1 || getBit(id,31)==1 ||
506
                                       getBit(id,42)==1 || getBit(id,47)==1 || getBit(id,52)==1  ) return INVALID_MOVE;
507

    
508
                                   long x7 = cycle(id,7,12,44,39);
509
                                   long x8 = cycle(x7,2,33,49,18);
510
                                   return    cycle(x8,15,23,36,28);
511
                     }
512

    
513
      case AXIS_Y: switch(layer)
514
                     {
515
                     case LAYER_L: if( getBit(id,12)==1 || getBit(id,13)==1 || getBit(id,14)==1 ||
516
                                       getBit(id,15)==1 || getBit(id,16)==1 || getBit(id,17)==1 ||
517
                                       getBit(id,18)==1 || getBit(id,19)==1 || getBit(id,20)==1  ) return INVALID_MOVE;
518

    
519
                                   long y1 = cycle(id,1,9,10,2);
520
                                   long y2 = cycle(y1,0,4,11,7);
521
                                   return    cycle(y2,3,6,8,5);
522

    
523
                     case LAYER_M: if( getBit(id,12)==1 || getBit(id,13)==1 || getBit(id,14)==1 ||
524
                                       getBit(id,15)==1 || getBit(id,16)==1 || getBit(id,17)==1 ||
525
                                       getBit(id,18)==1 || getBit(id,19)==1 || getBit(id,20)==1 ||
526
                                       getBit(id,33)==1 || getBit(id,34)==1 || getBit(id,35)==1 ||
527
                                       getBit(id,36)==1 || getBit(id,37)==1 || getBit(id,38)==1 ||
528
                                       getBit(id,39)==1 || getBit(id,40)==1 || getBit(id,41)==1  ) return INVALID_MOVE;
529

    
530
                                   long y4 = cycle(id,21,25,32,28);
531
                                   long y5 = cycle(y4,22,30,31,23);
532
                                   return    cycle(y5,24,27,29,26);
533

    
534
                     case LAYER_R: if( getBit(id,33)==1 || getBit(id,34)==1 || getBit(id,35)==1 ||
535
                                       getBit(id,36)==1 || getBit(id,37)==1 || getBit(id,38)==1 ||
536
                                       getBit(id,39)==1 || getBit(id,40)==1 || getBit(id,41)==1  ) return INVALID_MOVE;
537

    
538
                                   long y7 = cycle(id,42,46,53,49);
539
                                   long y8 = cycle(y7,43,51,52,44);
540
                                   return    cycle(y8,45,48,50,47);
541
                     }
542

    
543
      case AXIS_Z: switch(layer)
544
                     {
545
                     case LAYER_L: if( getBit(id, 7)==1 || getBit(id, 8)==1 || getBit(id, 9)==1 ||
546
                                       getBit(id,28)==1 || getBit(id,29)==1 || getBit(id,30)==1 ||
547
                                       getBit(id,49)==1 || getBit(id,50)==1 || getBit(id,51)==1  ) return INVALID_MOVE;
548

    
549
                                   long z1 = cycle(id,10,20,53,39);
550
                                   long z2 = cycle(z1,11,41,52,18);
551
                                   return    cycle(z2,19,32,40,31);
552

    
553
                     case LAYER_M: if( getBit(id, 7)==1 || getBit(id, 8)==1 || getBit(id, 9)==1 ||
554
                                       getBit(id,28)==1 || getBit(id,29)==1 || getBit(id,30)==1 ||
555
                                       getBit(id,49)==1 || getBit(id,50)==1 || getBit(id,51)==1 ||
556
                                       getBit(id, 2)==1 || getBit(id, 3)==1 || getBit(id, 4)==1 ||
557
                                       getBit(id,23)==1 || getBit(id,24)==1 || getBit(id,25)==1 ||
558
                                       getBit(id,44)==1 || getBit(id,45)==1 || getBit(id,46)==1  ) return INVALID_MOVE;
559

    
560
                                   long z4 = cycle(id,5,17,48,36);
561
                                   long z5 = cycle(z4,6,38,47,15);
562
                                   return    cycle(z5,16,27,37,26);
563

    
564
                     case LAYER_R: if( getBit(id, 2)==1 || getBit(id, 3)==1 || getBit(id, 4)==1 ||
565
                                       getBit(id,23)==1 || getBit(id,24)==1 || getBit(id,25)==1 ||
566
                                       getBit(id,44)==1 || getBit(id,45)==1 || getBit(id,46)==1  ) return INVALID_MOVE;
567

    
568
                                   long z7 = cycle(id,0,14,43,33);
569
                                   long z8 = cycle(z7,1,35,42,12);
570
                                   return    cycle(z8,13,22,34,21);
571
                     }
572
      }
573

    
574
    return 0;
575
    }
576

    
577
///////////////////////////////////////////////////////////////////////////////////////////////////
578
// bit b1 in place of b2 etc.
579

    
580
  private static long cycle(long id, int b1, int b2, int b3, int b4)
581
    {
582
    long bit1 = getBit(id,b1);
583
    long bit2 = getBit(id,b2);
584
    long bit3 = getBit(id,b3);
585
    long bit4 = getBit(id,b4);
586

    
587
    long i1 = setBit(id,b2,bit1);
588
    long i2 = setBit(i1,b3,bit2);
589
    long i3 = setBit(i2,b4,bit3);
590
    return    setBit(i3,b1,bit4);
591
    }
592

    
593
///////////////////////////////////////////////////////////////////////////////////////////////////
594

    
595
  private static long getBit(long id, int bit)
596
    {
597
    return (id>>bit)&0x1;
598
    }
599

    
600
///////////////////////////////////////////////////////////////////////////////////////////////////
601

    
602
  private static long setBit(long id, int bit, long value)
603
    {
604
    long old = getBit(id,bit);
605

    
606
    if( old!=value )
607
      {
608
      long diff = (1L<<bit);
609
      id += (value==0 ? -diff : diff);
610
      }
611

    
612
    return id;
613
    }
614

    
615
///////////////////////////////////////////////////////////////////////////////////////////////////
616

    
617
  private void printMoves()
618
    {
619
    String moves = "";
620

    
621
    for(int i=0; i<NUM_MOVES; i++)
622
      {
623
      moves += (" " + mMoves[i]);
624
      }
625

    
626
    android.util.Log.e("D", moves);
627
    }
628

    
629
///////////////////////////////////////////////////////////////////////////////////////////////////
630

    
631
  private static String printBits(long id)
632
    {
633
    String ret = "[";
634
    boolean first = true;
635

    
636
    for(int i=0; i<64; i++)
637
      {
638
      if( ( (id>>i)&0x1)==1 )
639
        {
640
        String num = (i<10 ? " "+i : ""+i);
641

    
642
        if( first ) { ret += num; first=false; }
643
        else          ret += (","+num);
644
        }
645
      }
646

    
647
    return ret + "]";
648
    }
649

    
650
///////////////////////////////////////////////////////////////////////////////////////////////////
651

    
652
  private static void printGraph(ArrayList<ScrambleStateBandaged3x3> graph)
653
    {
654
    int num = graph.size();
655
    android.util.Log.e("D", "\n"+num+" states\n");
656

    
657
    for(int i=0; i<num; i++)
658
      {
659
      ScrambleStateBandaged3x3 bsg = graph.get(i);
660
      android.util.Log.e("D", bsg.formatMoves());
661
      }
662
    }
663
}
(3-3/4)