Project

General

Profile

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

distorted-objectlib / src / main / java / org / distorted / objectlib / scrambling / ScrambleStateBandaged3x3.java @ 9c7d220a

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

    
8
package org.distorted.objectlib.scrambling;
9

    
10
import java.util.LinkedHashMap;
11
import java.util.Iterator;
12
import java.util.Map;
13

    
14
///////////////////////////////////////////////////////////////////////////////////////////////////
15
// Producer of the ScrambleStateGraph for any bandaged 3x3x3.
16

    
17
public class ScrambleStateBandaged3x3
18
{
19
  public static final int AXIS_X = 0;
20
  public static final int AXIS_Y = 1;
21
  public static final int AXIS_Z = 2;
22

    
23
  private static final long INVALID_MOVE = -1;
24
  private static final int NUM_MOVES = 27;
25

    
26
  private static final int LAYER_L = 0;
27
  private static final int LAYER_M = 1;
28
  private static final int LAYER_R = 2;
29

    
30
  private long mID;
31
  private int mDistance;
32
  private final long[] mMoves;
33

    
34
///////////////////////////////////////////////////////////////////////////////////////////////////
35

    
36
  public ScrambleStateBandaged3x3(long id)
37
    {
38
    mDistance = -1;
39
    mID = id;
40
    mMoves = createMoves(mID);
41
    }
42

    
43
///////////////////////////////////////////////////////////////////////////////////////////////////
44

    
45
  public long getID()
46
    {
47
    return mID;
48
    }
49

    
50
///////////////////////////////////////////////////////////////////////////////////////////////////
51

    
52
  public long getMove(int index)
53
    {
54
    return (index>=0 && index<NUM_MOVES) ? mMoves[index] : INVALID_MOVE;
55
    }
56

    
57
///////////////////////////////////////////////////////////////////////////////////////////////////
58

    
59
  public int numAxis()
60
    {
61
    int num = 0;
62

    
63
    if( mMoves[ 0]!=INVALID_MOVE || mMoves[ 1]!=INVALID_MOVE || mMoves[ 2]!=INVALID_MOVE ||
64
        mMoves[ 3]!=INVALID_MOVE || mMoves[ 4]!=INVALID_MOVE || mMoves[ 5]!=INVALID_MOVE ||
65
        mMoves[ 6]!=INVALID_MOVE || mMoves[ 7]!=INVALID_MOVE || mMoves[ 8]!=INVALID_MOVE   ) num++;
66

    
67
    if( mMoves[ 9]!=INVALID_MOVE || mMoves[10]!=INVALID_MOVE || mMoves[11]!=INVALID_MOVE ||
68
        mMoves[12]!=INVALID_MOVE || mMoves[13]!=INVALID_MOVE || mMoves[14]!=INVALID_MOVE ||
69
        mMoves[15]!=INVALID_MOVE || mMoves[16]!=INVALID_MOVE || mMoves[17]!=INVALID_MOVE   ) num++;
70

    
71
    if( mMoves[18]!=INVALID_MOVE || mMoves[19]!=INVALID_MOVE || mMoves[20]!=INVALID_MOVE ||
72
        mMoves[21]!=INVALID_MOVE || mMoves[22]!=INVALID_MOVE || mMoves[23]!=INVALID_MOVE ||
73
        mMoves[24]!=INVALID_MOVE || mMoves[25]!=INVALID_MOVE || mMoves[26]!=INVALID_MOVE   ) num++;
74

    
75
    return num;
76
    }
77

    
78
///////////////////////////////////////////////////////////////////////////////////////////////////
79

    
80
  private int numXMoves()
81
    {
82
    int num=0;
83

    
84
    if( mMoves[ 0]!=INVALID_MOVE ) num++;
85
    if( mMoves[ 1]!=INVALID_MOVE ) num++;
86
    if( mMoves[ 2]!=INVALID_MOVE ) num++;
87
    if( mMoves[ 3]!=INVALID_MOVE ) num++;
88
    if( mMoves[ 4]!=INVALID_MOVE ) num++;
89
    if( mMoves[ 5]!=INVALID_MOVE ) num++;
90
    if( mMoves[ 6]!=INVALID_MOVE ) num++;
91
    if( mMoves[ 7]!=INVALID_MOVE ) num++;
92
    if( mMoves[ 8]!=INVALID_MOVE ) num++;
93

    
94
    return num;
95
    }
96

    
97
///////////////////////////////////////////////////////////////////////////////////////////////////
98

    
99
  private int numYMoves()
100
    {
101
    int num=0;
102

    
103
    if( mMoves[ 9]!=INVALID_MOVE ) num++;
104
    if( mMoves[10]!=INVALID_MOVE ) num++;
105
    if( mMoves[11]!=INVALID_MOVE ) num++;
106
    if( mMoves[12]!=INVALID_MOVE ) num++;
107
    if( mMoves[13]!=INVALID_MOVE ) num++;
108
    if( mMoves[14]!=INVALID_MOVE ) num++;
109
    if( mMoves[15]!=INVALID_MOVE ) num++;
110
    if( mMoves[16]!=INVALID_MOVE ) num++;
111
    if( mMoves[17]!=INVALID_MOVE ) num++;
112

    
113
    return num;
114
    }
115

    
116
///////////////////////////////////////////////////////////////////////////////////////////////////
117

    
118
  private int numZMoves()
119
    {
120
    int num=0;
121

    
122
    if( mMoves[18]!=INVALID_MOVE ) num++;
123
    if( mMoves[19]!=INVALID_MOVE ) num++;
124
    if( mMoves[20]!=INVALID_MOVE ) num++;
125
    if( mMoves[21]!=INVALID_MOVE ) num++;
126
    if( mMoves[22]!=INVALID_MOVE ) num++;
127
    if( mMoves[23]!=INVALID_MOVE ) num++;
128
    if( mMoves[24]!=INVALID_MOVE ) num++;
129
    if( mMoves[25]!=INVALID_MOVE ) num++;
130
    if( mMoves[26]!=INVALID_MOVE ) num++;
131

    
132
    return num;
133
    }
134

    
135
///////////////////////////////////////////////////////////////////////////////////////////////////
136

    
137
  public int numMoves()
138
    {
139
    return numXMoves()+numYMoves()+numZMoves();
140
    }
141

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

    
144
  public int numMoves(int excludedAxis)
145
    {
146
    switch(excludedAxis)
147
      {
148
      case AXIS_X: return numYMoves()+numZMoves();
149
      case AXIS_Y: return numXMoves()+numZMoves();
150
      case AXIS_Z: return numXMoves()+numYMoves();
151
      }
152

    
153
    int ret= numXMoves()+numYMoves()+numZMoves();
154

    
155
    //android.util.Log.e("D", "numMoves returning "+ret+" "+formatMoves() );
156

    
157
    return ret;
158
    }
159

    
160
///////////////////////////////////////////////////////////////////////////////////////////////////
161

    
162
  public int getNthMove(int n, int excludedAxis)
163
    {
164
    int num = 0;
165

    
166
    for(int m=0; m<NUM_MOVES; m++)
167
      {
168
      if( (m/9)!=excludedAxis && mMoves[m]!=INVALID_MOVE)
169
        {
170
        if( num==n ) return m;
171
        num++;
172
        }
173
      }
174

    
175
    return -1;
176
    }
177

    
178
///////////////////////////////////////////////////////////////////////////////////////////////////
179

    
180
  public void removeMoves(long signature)
181
    {
182
    for(int m=0; m<NUM_MOVES; m++)
183
      if( signature==mMoves[m] ) mMoves[m]=INVALID_MOVE;
184
    }
185

    
186
///////////////////////////////////////////////////////////////////////////////////////////////////
187

    
188
  public String formatMoves()
189
    {
190
    String x = getTable( 0);
191
    String y = getTable( 9);
192
    String z = getTable(18);
193

    
194
    return mID+"\n"+x+"\n"+y+"\n"+z;
195
    }
196

    
197
///////////////////////////////////////////////////////////////////////////////////////////////////
198

    
199
  private String getTable(int index)
200
    {
201
    long m0 = getMove(index  );
202
    long m1 = getMove(index+1);
203
    long m2 = getMove(index+2);
204
    long m3 = getMove(index+3);
205
    long m4 = getMove(index+4);
206
    long m5 = getMove(index+5);
207
    long m6 = getMove(index+6);
208
    long m7 = getMove(index+7);
209
    long m8 = getMove(index+8);
210

    
211
    String ret = "";
212

    
213
    if( m0!=INVALID_MOVE ) ret += formatRet(ret,0,-1,m0);
214
    if( m1!=INVALID_MOVE ) ret += formatRet(ret,0, 2,m1);
215
    if( m2!=INVALID_MOVE ) ret += formatRet(ret,0, 1,m2);
216
    if( m3!=INVALID_MOVE ) ret += formatRet(ret,1,-1,m3);
217
    if( m4!=INVALID_MOVE ) ret += formatRet(ret,1, 2,m4);
218
    if( m5!=INVALID_MOVE ) ret += formatRet(ret,1, 1,m5);
219
    if( m6!=INVALID_MOVE ) ret += formatRet(ret,2,-1,m6);
220
    if( m7!=INVALID_MOVE ) ret += formatRet(ret,2, 2,m7);
221
    if( m8!=INVALID_MOVE ) ret += formatRet(ret,2, 1,m8);
222

    
223
    return formatL("{" + ret + "}");
224
    }
225

    
226
///////////////////////////////////////////////////////////////////////////////////////////////////
227

    
228
  private int[] getMoves(int index)
229
    {
230
    int numValid = 0;
231
    for(int i=index; i<index+9; i++) if( mMoves[i]!=INVALID_MOVE ) numValid++;
232

    
233
    int[] ret = new int[3*numValid];
234

    
235
    long m0 = getMove(index  );
236
    long m1 = getMove(index+1);
237
    long m2 = getMove(index+2);
238
    long m3 = getMove(index+3);
239
    long m4 = getMove(index+4);
240
    long m5 = getMove(index+5);
241
    long m6 = getMove(index+6);
242
    long m7 = getMove(index+7);
243
    long m8 = getMove(index+8);
244

    
245
    int pointer=0;
246

    
247
    if( m0!=INVALID_MOVE ) { ret[pointer]=0; ret[pointer+1]=-1; ret[pointer+2]= (int)m0; pointer+=3; }
248
    if( m1!=INVALID_MOVE ) { ret[pointer]=0; ret[pointer+1]= 2; ret[pointer+2]= (int)m1; pointer+=3; }
249
    if( m2!=INVALID_MOVE ) { ret[pointer]=0; ret[pointer+1]= 1; ret[pointer+2]= (int)m2; pointer+=3; }
250
    if( m3!=INVALID_MOVE ) { ret[pointer]=1; ret[pointer+1]=-1; ret[pointer+2]= (int)m3; pointer+=3; }
251
    if( m4!=INVALID_MOVE ) { ret[pointer]=1; ret[pointer+1]= 2; ret[pointer+2]= (int)m4; pointer+=3; }
252
    if( m5!=INVALID_MOVE ) { ret[pointer]=1; ret[pointer+1]= 1; ret[pointer+2]= (int)m5; pointer+=3; }
253
    if( m6!=INVALID_MOVE ) { ret[pointer]=2; ret[pointer+1]=-1; ret[pointer+2]= (int)m6; pointer+=3; }
254
    if( m7!=INVALID_MOVE ) { ret[pointer]=2; ret[pointer+1]= 2; ret[pointer+2]= (int)m7; pointer+=3; }
255
    if( m8!=INVALID_MOVE ) { ret[pointer]=2; ret[pointer+1]= 1; ret[pointer+2]= (int)m8; pointer+=3; }
256

    
257
    return ret;
258
    }
259

    
260
///////////////////////////////////////////////////////////////////////////////////////////////////
261
// broken when we were converting to the new format of ScrambleState.
262

    
263
  private ScrambleState produceScrambleState()
264
    {
265
    /*
266
    int[] xMoves = getMoves(0);
267
    int[] yMoves = getMoves(9);
268
    int[] zMoves = getMoves(18);
269

    
270
    int[][] moves = { xMoves,yMoves,zMoves };
271

    
272
    return new ScrambleState( moves );
273
    */
274

    
275
    return null;
276
    }
277

    
278
///////////////////////////////////////////////////////////////////////////////////////////////////
279
// STATIC STUFF
280
///////////////////////////////////////////////////////////////////////////////////////////////////
281

    
282
  public static ScrambleState[] computeGraph(long id)
283
    {
284
    ScrambleStateBandaged3x3 bsg = new ScrambleStateBandaged3x3(id);
285
    Map<Long, ScrambleStateBandaged3x3> graph = new LinkedHashMap<>();
286
    graph.put(id,bsg);
287

    
288
    insertChildren(graph,id);
289
    // if there's only one state, do not prune moves which point to itself
290
    if(graph.size()>1) pruneGraph(graph,id);
291
    computeDistance(graph,id,0);
292
    removeDisconnectedParts(graph);
293
    remapGraph(graph);
294

    
295
    int num = graph.size();
296
    ScrambleState[] ret = new ScrambleState[num];
297

    
298
    for (Map.Entry<Long, ScrambleStateBandaged3x3> entry : graph.entrySet())
299
      {
300
      ScrambleStateBandaged3x3 value = entry.getValue();
301
      int mid = (int)value.mID;
302
      ret[mid] = value.produceScrambleState();
303
      }
304

    
305
    return ret;
306
    }
307

    
308
///////////////////////////////////////////////////////////////////////////////////////////////////
309

    
310
  private static void insertChildren(Map<Long, ScrambleStateBandaged3x3> map, long id)
311
    {
312
    ScrambleStateBandaged3x3 bsg = findState(map,id);
313

    
314
    if( bsg==null )
315
      {
316
      android.util.Log.e("D", "error: "+id+" doesn't exist");
317
      return;
318
      }
319

    
320
    for(int i=0; i<NUM_MOVES; i++)
321
      {
322
      long move = bsg.getMove(i);
323

    
324
      if( move!=INVALID_MOVE )
325
        {
326
        ScrambleStateBandaged3x3 tmp = findState(map,move);
327

    
328
        if( tmp==null )
329
          {
330
          tmp = new ScrambleStateBandaged3x3(move);
331
          map.put(move,tmp);
332
          insertChildren(map,move);
333
          }
334
        }
335
      }
336
    }
337

    
338
///////////////////////////////////////////////////////////////////////////////////////////////////
339

    
340
  private static void pruneGraph(Map<Long, ScrambleStateBandaged3x3> map, long startingID)
341
    {
342
    boolean pruned = false;
343
    boolean startingIsSingle = false;
344

    
345
    Iterator<Map.Entry<Long, ScrambleStateBandaged3x3>> it = map.entrySet().iterator();
346

    
347
    while (it.hasNext())
348
      {
349
      Map.Entry<Long, ScrambleStateBandaged3x3> entry = it.next();
350
      ScrambleStateBandaged3x3 value = entry.getValue();
351

    
352
      if( value.numAxis()<2 )
353
        {
354
        long prunedID = value.getID();
355

    
356
        if( prunedID!=startingID ) // do not remove the starting point, even if it does have only 1 axis
357
          {
358
          it.remove();
359
          pruned = true;
360
          }
361
        else
362
          {
363
          startingIsSingle = true;
364
          }
365
        }
366
      }
367

    
368
    for (Map.Entry<Long, ScrambleStateBandaged3x3> entry : map.entrySet() )
369
      {
370
      ScrambleStateBandaged3x3 value = entry.getValue();
371

    
372
      for(int m=0; m<NUM_MOVES; m++)
373
        {
374
        long move = value.mMoves[m];
375
        ScrambleStateBandaged3x3 tmp = findState(map,move);
376

    
377
        if( tmp==null || (startingIsSingle && move==startingID) )
378
          {
379
          value.mMoves[m]=INVALID_MOVE;
380
          }
381
        }
382
      }
383

    
384
    if( pruned ) pruneGraph(map,startingID);
385
    }
386

    
387
///////////////////////////////////////////////////////////////////////////////////////////////////
388

    
389
  private static void remapGraph(Map<Long, ScrambleStateBandaged3x3> map)
390
    {
391
    int id=0;
392

    
393
    for (Map.Entry<Long, ScrambleStateBandaged3x3> entry : map.entrySet())
394
      {
395
      ScrambleStateBandaged3x3 value = entry.getValue();
396
      value.mID = id++;
397
      }
398

    
399
    for (Map.Entry<Long, ScrambleStateBandaged3x3> entry : map.entrySet())
400
      {
401
      ScrambleStateBandaged3x3 value = entry.getValue();
402

    
403
      for(int m=0; m<NUM_MOVES; m++)
404
        {
405
        long move = value.mMoves[m];
406

    
407
        if( move!=INVALID_MOVE )
408
          {
409
          ScrambleStateBandaged3x3 tmp = map.get(move);
410
          if( tmp!=null ) value.mMoves[m] = tmp.mID;
411
          else            android.util.Log.e("D", "ERROR in remapGraph");
412
          }
413
        }
414
      }
415
    }
416

    
417
///////////////////////////////////////////////////////////////////////////////////////////////////
418

    
419
  private static void computeDistance(Map<Long, ScrambleStateBandaged3x3> map, long id, int distance)
420
    {
421
    ScrambleStateBandaged3x3 state = findState(map,id);
422

    
423
    if( state==null )
424
      {
425
      android.util.Log.e("D", "error: "+id+" doesn't exist");
426
      return;
427
      }
428

    
429
    if( state.mDistance<0 )
430
      {
431
      state.mDistance = distance;
432

    
433
      for(int i=0; i<NUM_MOVES; i++)
434
        {
435
        long move = state.getMove(i);
436

    
437
        if( move!=INVALID_MOVE )
438
          {
439
          computeDistance(map,move,distance+1);
440
          }
441
        }
442
      }
443
    }
444

    
445
///////////////////////////////////////////////////////////////////////////////////////////////////
446

    
447
  private static void removeDisconnectedParts(Map<Long, ScrambleStateBandaged3x3> map)
448
    {
449
    Iterator<Map.Entry<Long, ScrambleStateBandaged3x3>> it = map.entrySet().iterator();
450

    
451
    while (it.hasNext())
452
      {
453
      Map.Entry<Long, ScrambleStateBandaged3x3> entry = it.next();
454
      ScrambleStateBandaged3x3 value = entry.getValue();
455
      if( value.mDistance<0 ) it.remove();
456
      }
457
    }
458

    
459
///////////////////////////////////////////////////////////////////////////////////////////////////
460

    
461
  private static ScrambleStateBandaged3x3 findState(Map<Long, ScrambleStateBandaged3x3> map, long id)
462
    {
463
    return map.get(id);
464
    }
465

    
466
///////////////////////////////////////////////////////////////////////////////////////////////////
467

    
468
  private static String formatRet(String str, int row, int angle, long id)
469
    {
470
    String ret = str.length()!=0 ? ",":"";
471

    
472
    ret += row;
473
    ret += angle<0 ? "," : ", ";
474
    ret += angle;
475

    
476
         if( id< 10 ) ret += (",  "+id);
477
    else if( id<100 ) ret += (", " +id);
478
    else              ret += (","  +id);
479

    
480
    return ret;
481
    }
482

    
483
///////////////////////////////////////////////////////////////////////////////////////////////////
484

    
485
  private static final int LENGTH = 28;
486

    
487
  private static String formatL(String input)
488
    {
489
    int len = input.length();
490
    String ret = input;
491
    for(int i=0 ;i<LENGTH-len; i++) ret += " ";
492
    return ret;
493
    }
494

    
495
///////////////////////////////////////////////////////////////////////////////////////////////////
496

    
497
  private static long[] createMoves(long id)
498
    {
499
    long[] ret = new long[NUM_MOVES];
500
    int index = 0;
501

    
502
    for(int axis=0; axis<3; axis++)
503
      for(int layer=0; layer<3; layer++)
504
        {
505
        long x1 = turn(id,axis,layer);
506

    
507
        if( x1!=INVALID_MOVE )
508
          {
509
          long x2 = turn(x1,axis,layer);
510
          long x3 = turn(x2,axis,layer);
511

    
512
          ret[index  ] = x1;
513
          ret[index+1] = x2;
514
          ret[index+2] = x3;
515
          }
516
        else
517
          {
518
          ret[index  ] = INVALID_MOVE;
519
          ret[index+1] = INVALID_MOVE;
520
          ret[index+2] = INVALID_MOVE;
521
          }
522

    
523
        index+=3;
524
        }
525

    
526
    return ret;
527
    }
528

    
529
///////////////////////////////////////////////////////////////////////////////////////////////////
530
// Definition of the id: it's an 'Andreas signature' of a bandaged cube.
531
// https://twistypuzzles.com/forum/viewtopic.php?t=24452&sid=f3b4ac0c611c4713e4d7840f1aabbb0b&start=350
532

    
533
  private static long turn(long id, int axis, int layer)
534
    {
535
    switch(axis)
536
      {
537
      case AXIS_X: switch(layer)
538
                     {
539
                     case LAYER_L: if( getBit(id, 1)==1 || getBit(id, 6)==1 || getBit(id,11)==1 ||
540
                                       getBit(id,22)==1 || getBit(id,27)==1 || getBit(id,32)==1 ||
541
                                       getBit(id,43)==1 || getBit(id,48)==1 || getBit(id,53)==1  ) return INVALID_MOVE;
542

    
543
                                   long x1 = cycle(id,9,14,46,41);
544
                                   long x2 = cycle(x1,4,35,51,20);
545
                                   return    cycle(x2,17,25,38,30);
546

    
547
                     case LAYER_M: if( getBit(id, 1)==1 || getBit(id, 6)==1 || getBit(id,11)==1 ||
548
                                       getBit(id,22)==1 || getBit(id,27)==1 || getBit(id,32)==1 ||
549
                                       getBit(id,43)==1 || getBit(id,48)==1 || getBit(id,53)==1 ||
550
                                       getBit(id, 0)==1 || getBit(id, 5)==1 || getBit(id,10)==1 ||
551
                                       getBit(id,21)==1 || getBit(id,26)==1 || getBit(id,31)==1 ||
552
                                       getBit(id,42)==1 || getBit(id,47)==1 || getBit(id,52)==1  ) return INVALID_MOVE;
553

    
554
                                   long x4 = cycle(id,8,13,45,40);
555
                                   long x5 = cycle(x4,3,34,50,19);
556
                                   return    cycle(x5,16,24,37,29);
557

    
558
                     case LAYER_R: if( getBit(id, 0)==1 || getBit(id, 5)==1 || getBit(id,10)==1 ||
559
                                       getBit(id,21)==1 || getBit(id,26)==1 || getBit(id,31)==1 ||
560
                                       getBit(id,42)==1 || getBit(id,47)==1 || getBit(id,52)==1  ) return INVALID_MOVE;
561

    
562
                                   long x7 = cycle(id,7,12,44,39);
563
                                   long x8 = cycle(x7,2,33,49,18);
564
                                   return    cycle(x8,15,23,36,28);
565
                     }
566

    
567
      case AXIS_Y: switch(layer)
568
                     {
569
                     case LAYER_L: if( getBit(id,12)==1 || getBit(id,13)==1 || getBit(id,14)==1 ||
570
                                       getBit(id,15)==1 || getBit(id,16)==1 || getBit(id,17)==1 ||
571
                                       getBit(id,18)==1 || getBit(id,19)==1 || getBit(id,20)==1  ) return INVALID_MOVE;
572

    
573
                                   long y1 = cycle(id,1,9,10,2);
574
                                   long y2 = cycle(y1,0,4,11,7);
575
                                   return    cycle(y2,3,6,8,5);
576

    
577
                     case LAYER_M: if( getBit(id,12)==1 || getBit(id,13)==1 || getBit(id,14)==1 ||
578
                                       getBit(id,15)==1 || getBit(id,16)==1 || getBit(id,17)==1 ||
579
                                       getBit(id,18)==1 || getBit(id,19)==1 || getBit(id,20)==1 ||
580
                                       getBit(id,33)==1 || getBit(id,34)==1 || getBit(id,35)==1 ||
581
                                       getBit(id,36)==1 || getBit(id,37)==1 || getBit(id,38)==1 ||
582
                                       getBit(id,39)==1 || getBit(id,40)==1 || getBit(id,41)==1  ) return INVALID_MOVE;
583

    
584
                                   long y4 = cycle(id,21,25,32,28);
585
                                   long y5 = cycle(y4,22,30,31,23);
586
                                   return    cycle(y5,24,27,29,26);
587

    
588
                     case LAYER_R: if( getBit(id,33)==1 || getBit(id,34)==1 || getBit(id,35)==1 ||
589
                                       getBit(id,36)==1 || getBit(id,37)==1 || getBit(id,38)==1 ||
590
                                       getBit(id,39)==1 || getBit(id,40)==1 || getBit(id,41)==1  ) return INVALID_MOVE;
591

    
592
                                   long y7 = cycle(id,42,46,53,49);
593
                                   long y8 = cycle(y7,43,51,52,44);
594
                                   return    cycle(y8,45,48,50,47);
595
                     }
596

    
597
      case AXIS_Z: switch(layer)
598
                     {
599
                     case LAYER_L: if( getBit(id, 7)==1 || getBit(id, 8)==1 || getBit(id, 9)==1 ||
600
                                       getBit(id,28)==1 || getBit(id,29)==1 || getBit(id,30)==1 ||
601
                                       getBit(id,49)==1 || getBit(id,50)==1 || getBit(id,51)==1  ) return INVALID_MOVE;
602

    
603
                                   long z1 = cycle(id,10,20,53,39);
604
                                   long z2 = cycle(z1,11,41,52,18);
605
                                   return    cycle(z2,19,32,40,31);
606

    
607
                     case LAYER_M: if( getBit(id, 7)==1 || getBit(id, 8)==1 || getBit(id, 9)==1 ||
608
                                       getBit(id,28)==1 || getBit(id,29)==1 || getBit(id,30)==1 ||
609
                                       getBit(id,49)==1 || getBit(id,50)==1 || getBit(id,51)==1 ||
610
                                       getBit(id, 2)==1 || getBit(id, 3)==1 || getBit(id, 4)==1 ||
611
                                       getBit(id,23)==1 || getBit(id,24)==1 || getBit(id,25)==1 ||
612
                                       getBit(id,44)==1 || getBit(id,45)==1 || getBit(id,46)==1  ) return INVALID_MOVE;
613

    
614
                                   long z4 = cycle(id,5,17,48,36);
615
                                   long z5 = cycle(z4,6,38,47,15);
616
                                   return    cycle(z5,16,27,37,26);
617

    
618
                     case LAYER_R: if( getBit(id, 2)==1 || getBit(id, 3)==1 || getBit(id, 4)==1 ||
619
                                       getBit(id,23)==1 || getBit(id,24)==1 || getBit(id,25)==1 ||
620
                                       getBit(id,44)==1 || getBit(id,45)==1 || getBit(id,46)==1  ) return INVALID_MOVE;
621

    
622
                                   long z7 = cycle(id,0,14,43,33);
623
                                   long z8 = cycle(z7,1,35,42,12);
624
                                   return    cycle(z8,13,22,34,21);
625
                     }
626
      }
627

    
628
    return 0;
629
    }
630

    
631
///////////////////////////////////////////////////////////////////////////////////////////////////
632
// bit b1 in place of b2 etc.
633

    
634
  private static long cycle(long id, int b1, int b2, int b3, int b4)
635
    {
636
    long bit1 = getBit(id,b1);
637
    long bit2 = getBit(id,b2);
638
    long bit3 = getBit(id,b3);
639
    long bit4 = getBit(id,b4);
640

    
641
    long i1 = setBit(id,b2,bit1);
642
    long i2 = setBit(i1,b3,bit2);
643
    long i3 = setBit(i2,b4,bit3);
644
    return    setBit(i3,b1,bit4);
645
    }
646

    
647
///////////////////////////////////////////////////////////////////////////////////////////////////
648

    
649
  private static long getBit(long id, int bit)
650
    {
651
    return (id>>bit)&0x1;
652
    }
653

    
654
///////////////////////////////////////////////////////////////////////////////////////////////////
655

    
656
  private static long setBit(long id, int bit, long value)
657
    {
658
    long old = getBit(id,bit);
659

    
660
    if( old!=value )
661
      {
662
      long diff = (1L<<bit);
663
      id += (value==0 ? -diff : diff);
664
      }
665

    
666
    return id;
667
    }
668

    
669
///////////////////////////////////////////////////////////////////////////////////////////////////
670

    
671
  private void printMoves()
672
    {
673
    String moves = "";
674

    
675
    for(int i=0; i<NUM_MOVES; i++)
676
      {
677
      moves += (" " + mMoves[i]);
678
      }
679

    
680
    android.util.Log.e("D", moves);
681
    }
682

    
683
///////////////////////////////////////////////////////////////////////////////////////////////////
684

    
685
  private static String printBits(long id)
686
    {
687
    String ret = "[";
688
    boolean first = true;
689

    
690
    for(int i=0; i<64; i++)
691
      {
692
      if( ( (id>>i)&0x1)==1 )
693
        {
694
        String num = (i<10 ? " "+i : ""+i);
695

    
696
        if( first ) { ret += num; first=false; }
697
        else          ret += (","+num);
698
        }
699
      }
700

    
701
    return ret + "]";
702
    }
703

    
704
///////////////////////////////////////////////////////////////////////////////////////////////////
705

    
706
  private static void printGraph(Map<Long, ScrambleStateBandaged3x3> map)
707
    {
708
    int num = map.size();
709
    android.util.Log.e("D", "\n"+num+" states\n");
710

    
711
    for (Map.Entry<Long, ScrambleStateBandaged3x3> entry : map.entrySet())
712
      {
713
      ScrambleStateBandaged3x3 value = entry.getValue();
714
      android.util.Log.e("D", value.formatMoves());
715
      }
716
    }
717
}
(5-5/7)