Project

General

Profile

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

distorted-objectlib / src / main / java / org / distorted / objectlib / scrambling / ScrambleStateBandaged3x3.java @ 6777e712

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
    return numXMoves()+numYMoves()+numZMoves();
154
    }
155

    
156
///////////////////////////////////////////////////////////////////////////////////////////////////
157

    
158
  public int getNthMove(int n, int excludedAxis)
159
    {
160
    int num = 0;
161

    
162
    for(int m=0; m<NUM_MOVES; m++)
163
      {
164
      if( (m/9)!=excludedAxis && mMoves[m]!=INVALID_MOVE)
165
        {
166
        if( num==n ) return m;
167
        num++;
168
        }
169
      }
170

    
171
    return -1;
172
    }
173

    
174
///////////////////////////////////////////////////////////////////////////////////////////////////
175

    
176
  public void removeMoves(long signature)
177
    {
178
    for(int m=0; m<NUM_MOVES; m++)
179
      if( signature==mMoves[m] ) mMoves[m]=INVALID_MOVE;
180
    }
181

    
182
///////////////////////////////////////////////////////////////////////////////////////////////////
183

    
184
  public String formatMoves()
185
    {
186
    String x = getTable( 0);
187
    String y = getTable( 9);
188
    String z = getTable(18);
189

    
190
    return mID+"\n"+x+"\n"+y+"\n"+z;
191
    }
192

    
193
///////////////////////////////////////////////////////////////////////////////////////////////////
194

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

    
207
    String ret = "";
208

    
209
    if( m0!=INVALID_MOVE ) ret += formatRet(ret,0,-1,m0);
210
    if( m1!=INVALID_MOVE ) ret += formatRet(ret,0, 2,m1);
211
    if( m2!=INVALID_MOVE ) ret += formatRet(ret,0, 1,m2);
212
    if( m3!=INVALID_MOVE ) ret += formatRet(ret,1,-1,m3);
213
    if( m4!=INVALID_MOVE ) ret += formatRet(ret,1, 2,m4);
214
    if( m5!=INVALID_MOVE ) ret += formatRet(ret,1, 1,m5);
215
    if( m6!=INVALID_MOVE ) ret += formatRet(ret,2,-1,m6);
216
    if( m7!=INVALID_MOVE ) ret += formatRet(ret,2, 2,m7);
217
    if( m8!=INVALID_MOVE ) ret += formatRet(ret,2, 1,m8);
218

    
219
    return formatL("{" + ret + "}");
220
    }
221

    
222
///////////////////////////////////////////////////////////////////////////////////////////////////
223

    
224
  private int[] getMoves(int index)
225
    {
226
    int numValid = 0;
227
    for(int i=index; i<index+9; i++) if( mMoves[i]!=INVALID_MOVE ) numValid++;
228

    
229
    int[] ret = new int[3*numValid];
230

    
231
    long m0 = getMove(index  );
232
    long m1 = getMove(index+1);
233
    long m2 = getMove(index+2);
234
    long m3 = getMove(index+3);
235
    long m4 = getMove(index+4);
236
    long m5 = getMove(index+5);
237
    long m6 = getMove(index+6);
238
    long m7 = getMove(index+7);
239
    long m8 = getMove(index+8);
240

    
241
    int pointer=0;
242

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

    
253
    return ret;
254
    }
255

    
256
///////////////////////////////////////////////////////////////////////////////////////////////////
257
// broken when we were converting to the new format of ScrambleState.
258

    
259
  private ScrambleState produceScrambleState()
260
    {
261
    return null;
262
    }
263

    
264
///////////////////////////////////////////////////////////////////////////////////////////////////
265
// STATIC STUFF
266
///////////////////////////////////////////////////////////////////////////////////////////////////
267

    
268
  public static ScrambleState[] computeGraph(long id)
269
    {
270
    ScrambleStateBandaged3x3 bsg = new ScrambleStateBandaged3x3(id);
271
    Map<Long, ScrambleStateBandaged3x3> graph = new LinkedHashMap<>();
272
    graph.put(id,bsg);
273

    
274
    insertChildren(graph,id);
275
    // if there's only one state, do not prune moves which point to itself
276
    if(graph.size()>1) pruneGraph(graph,id);
277
    computeDistance(graph,id,0);
278
    removeDisconnectedParts(graph);
279
    remapGraph(graph);
280

    
281
    int num = graph.size();
282
    ScrambleState[] ret = new ScrambleState[num];
283

    
284
    for (Map.Entry<Long, ScrambleStateBandaged3x3> entry : graph.entrySet())
285
      {
286
      ScrambleStateBandaged3x3 value = entry.getValue();
287
      int mid = (int)value.mID;
288
      ret[mid] = value.produceScrambleState();
289
      }
290

    
291
    return ret;
292
    }
293

    
294
///////////////////////////////////////////////////////////////////////////////////////////////////
295

    
296
  private static void insertChildren(Map<Long, ScrambleStateBandaged3x3> map, long id)
297
    {
298
    ScrambleStateBandaged3x3 bsg = findState(map,id);
299

    
300
    if( bsg==null )
301
      {
302
      android.util.Log.e("D", "error: "+id+" doesn't exist");
303
      return;
304
      }
305

    
306
    for(int i=0; i<NUM_MOVES; i++)
307
      {
308
      long move = bsg.getMove(i);
309

    
310
      if( move!=INVALID_MOVE )
311
        {
312
        ScrambleStateBandaged3x3 tmp = findState(map,move);
313

    
314
        if( tmp==null )
315
          {
316
          tmp = new ScrambleStateBandaged3x3(move);
317
          map.put(move,tmp);
318
          insertChildren(map,move);
319
          }
320
        }
321
      }
322
    }
323

    
324
///////////////////////////////////////////////////////////////////////////////////////////////////
325

    
326
  private static void pruneGraph(Map<Long, ScrambleStateBandaged3x3> map, long startingID)
327
    {
328
    boolean pruned = false;
329
    boolean startingIsSingle = false;
330

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

    
333
    while (it.hasNext())
334
      {
335
      Map.Entry<Long, ScrambleStateBandaged3x3> entry = it.next();
336
      ScrambleStateBandaged3x3 value = entry.getValue();
337

    
338
      if( value.numAxis()<2 )
339
        {
340
        long prunedID = value.getID();
341

    
342
        if( prunedID!=startingID ) // do not remove the starting point, even if it does have only 1 axis
343
          {
344
          it.remove();
345
          pruned = true;
346
          }
347
        else
348
          {
349
          startingIsSingle = true;
350
          }
351
        }
352
      }
353

    
354
    for (Map.Entry<Long, ScrambleStateBandaged3x3> entry : map.entrySet() )
355
      {
356
      ScrambleStateBandaged3x3 value = entry.getValue();
357

    
358
      for(int m=0; m<NUM_MOVES; m++)
359
        {
360
        long move = value.mMoves[m];
361
        ScrambleStateBandaged3x3 tmp = findState(map,move);
362

    
363
        if( tmp==null || (startingIsSingle && move==startingID) )
364
          {
365
          value.mMoves[m]=INVALID_MOVE;
366
          }
367
        }
368
      }
369

    
370
    if( pruned ) pruneGraph(map,startingID);
371
    }
372

    
373
///////////////////////////////////////////////////////////////////////////////////////////////////
374

    
375
  private static void remapGraph(Map<Long, ScrambleStateBandaged3x3> map)
376
    {
377
    int id=0;
378

    
379
    for (Map.Entry<Long, ScrambleStateBandaged3x3> entry : map.entrySet())
380
      {
381
      ScrambleStateBandaged3x3 value = entry.getValue();
382
      value.mID = id++;
383
      }
384

    
385
    for (Map.Entry<Long, ScrambleStateBandaged3x3> entry : map.entrySet())
386
      {
387
      ScrambleStateBandaged3x3 value = entry.getValue();
388

    
389
      for(int m=0; m<NUM_MOVES; m++)
390
        {
391
        long move = value.mMoves[m];
392

    
393
        if( move!=INVALID_MOVE )
394
          {
395
          ScrambleStateBandaged3x3 tmp = map.get(move);
396
          if( tmp!=null ) value.mMoves[m] = tmp.mID;
397
          else            android.util.Log.e("D", "ERROR in remapGraph");
398
          }
399
        }
400
      }
401
    }
402

    
403
///////////////////////////////////////////////////////////////////////////////////////////////////
404

    
405
  private static void computeDistance(Map<Long, ScrambleStateBandaged3x3> map, long id, int distance)
406
    {
407
    ScrambleStateBandaged3x3 state = findState(map,id);
408

    
409
    if( state==null )
410
      {
411
      android.util.Log.e("D", "error: "+id+" doesn't exist");
412
      return;
413
      }
414

    
415
    if( state.mDistance<0 )
416
      {
417
      state.mDistance = distance;
418

    
419
      for(int i=0; i<NUM_MOVES; i++)
420
        {
421
        long move = state.getMove(i);
422

    
423
        if( move!=INVALID_MOVE )
424
          {
425
          computeDistance(map,move,distance+1);
426
          }
427
        }
428
      }
429
    }
430

    
431
///////////////////////////////////////////////////////////////////////////////////////////////////
432

    
433
  private static void removeDisconnectedParts(Map<Long, ScrambleStateBandaged3x3> map)
434
    {
435
    Iterator<Map.Entry<Long, ScrambleStateBandaged3x3>> it = map.entrySet().iterator();
436

    
437
    while (it.hasNext())
438
      {
439
      Map.Entry<Long, ScrambleStateBandaged3x3> entry = it.next();
440
      ScrambleStateBandaged3x3 value = entry.getValue();
441
      if( value.mDistance<0 ) it.remove();
442
      }
443
    }
444

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

    
447
  private static ScrambleStateBandaged3x3 findState(Map<Long, ScrambleStateBandaged3x3> map, long id)
448
    {
449
    return map.get(id);
450
    }
451

    
452
///////////////////////////////////////////////////////////////////////////////////////////////////
453

    
454
  private static String formatRet(String str, int row, int angle, long id)
455
    {
456
    String ret = str.length()!=0 ? ",":"";
457

    
458
    ret += row;
459
    ret += angle<0 ? "," : ", ";
460
    ret += angle;
461

    
462
         if( id< 10 ) ret += (",  "+id);
463
    else if( id<100 ) ret += (", " +id);
464
    else              ret += (","  +id);
465

    
466
    return ret;
467
    }
468

    
469
///////////////////////////////////////////////////////////////////////////////////////////////////
470

    
471
  private static final int LENGTH = 28;
472

    
473
  private static String formatL(String input)
474
    {
475
    int len = input.length();
476
    String ret = input;
477
    for(int i=0 ;i<LENGTH-len; i++) ret += " ";
478
    return ret;
479
    }
480

    
481
///////////////////////////////////////////////////////////////////////////////////////////////////
482

    
483
  private static long[] createMoves(long id)
484
    {
485
    long[] ret = new long[NUM_MOVES];
486
    int index = 0;
487

    
488
    for(int axis=0; axis<3; axis++)
489
      for(int layer=0; layer<3; layer++)
490
        {
491
        long x1 = turn(id,axis,layer);
492

    
493
        if( x1!=INVALID_MOVE )
494
          {
495
          long x2 = turn(x1,axis,layer);
496
          long x3 = turn(x2,axis,layer);
497

    
498
          ret[index  ] = x1;
499
          ret[index+1] = x2;
500
          ret[index+2] = x3;
501
          }
502
        else
503
          {
504
          ret[index  ] = INVALID_MOVE;
505
          ret[index+1] = INVALID_MOVE;
506
          ret[index+2] = INVALID_MOVE;
507
          }
508

    
509
        index+=3;
510
        }
511

    
512
    return ret;
513
    }
514

    
515
///////////////////////////////////////////////////////////////////////////////////////////////////
516
// Definition of the id: it's an 'Andreas signature' of a bandaged cube.
517
// https://twistypuzzles.com/forum/viewtopic.php?t=24452&sid=f3b4ac0c611c4713e4d7840f1aabbb0b&start=350
518

    
519
  private static long turn(long id, int axis, int layer)
520
    {
521
    switch(axis)
522
      {
523
      case AXIS_X: switch(layer)
524
                     {
525
                     case LAYER_L: if( getBit(id, 1)==1 || getBit(id, 6)==1 || getBit(id,11)==1 ||
526
                                       getBit(id,22)==1 || getBit(id,27)==1 || getBit(id,32)==1 ||
527
                                       getBit(id,43)==1 || getBit(id,48)==1 || getBit(id,53)==1  ) return INVALID_MOVE;
528

    
529
                                   long x1 = cycle(id,9,14,46,41);
530
                                   long x2 = cycle(x1,4,35,51,20);
531
                                   return    cycle(x2,17,25,38,30);
532

    
533
                     case LAYER_M: if( getBit(id, 1)==1 || getBit(id, 6)==1 || getBit(id,11)==1 ||
534
                                       getBit(id,22)==1 || getBit(id,27)==1 || getBit(id,32)==1 ||
535
                                       getBit(id,43)==1 || getBit(id,48)==1 || getBit(id,53)==1 ||
536
                                       getBit(id, 0)==1 || getBit(id, 5)==1 || getBit(id,10)==1 ||
537
                                       getBit(id,21)==1 || getBit(id,26)==1 || getBit(id,31)==1 ||
538
                                       getBit(id,42)==1 || getBit(id,47)==1 || getBit(id,52)==1  ) return INVALID_MOVE;
539

    
540
                                   long x4 = cycle(id,8,13,45,40);
541
                                   long x5 = cycle(x4,3,34,50,19);
542
                                   return    cycle(x5,16,24,37,29);
543

    
544
                     case LAYER_R: if( getBit(id, 0)==1 || getBit(id, 5)==1 || getBit(id,10)==1 ||
545
                                       getBit(id,21)==1 || getBit(id,26)==1 || getBit(id,31)==1 ||
546
                                       getBit(id,42)==1 || getBit(id,47)==1 || getBit(id,52)==1  ) return INVALID_MOVE;
547

    
548
                                   long x7 = cycle(id,7,12,44,39);
549
                                   long x8 = cycle(x7,2,33,49,18);
550
                                   return    cycle(x8,15,23,36,28);
551
                     }
552

    
553
      case AXIS_Y: switch(layer)
554
                     {
555
                     case LAYER_L: if( getBit(id,12)==1 || getBit(id,13)==1 || getBit(id,14)==1 ||
556
                                       getBit(id,15)==1 || getBit(id,16)==1 || getBit(id,17)==1 ||
557
                                       getBit(id,18)==1 || getBit(id,19)==1 || getBit(id,20)==1  ) return INVALID_MOVE;
558

    
559
                                   long y1 = cycle(id,1,9,10,2);
560
                                   long y2 = cycle(y1,0,4,11,7);
561
                                   return    cycle(y2,3,6,8,5);
562

    
563
                     case LAYER_M: if( getBit(id,12)==1 || getBit(id,13)==1 || getBit(id,14)==1 ||
564
                                       getBit(id,15)==1 || getBit(id,16)==1 || getBit(id,17)==1 ||
565
                                       getBit(id,18)==1 || getBit(id,19)==1 || getBit(id,20)==1 ||
566
                                       getBit(id,33)==1 || getBit(id,34)==1 || getBit(id,35)==1 ||
567
                                       getBit(id,36)==1 || getBit(id,37)==1 || getBit(id,38)==1 ||
568
                                       getBit(id,39)==1 || getBit(id,40)==1 || getBit(id,41)==1  ) return INVALID_MOVE;
569

    
570
                                   long y4 = cycle(id,21,25,32,28);
571
                                   long y5 = cycle(y4,22,30,31,23);
572
                                   return    cycle(y5,24,27,29,26);
573

    
574
                     case LAYER_R: if( getBit(id,33)==1 || getBit(id,34)==1 || getBit(id,35)==1 ||
575
                                       getBit(id,36)==1 || getBit(id,37)==1 || getBit(id,38)==1 ||
576
                                       getBit(id,39)==1 || getBit(id,40)==1 || getBit(id,41)==1  ) return INVALID_MOVE;
577

    
578
                                   long y7 = cycle(id,42,46,53,49);
579
                                   long y8 = cycle(y7,43,51,52,44);
580
                                   return    cycle(y8,45,48,50,47);
581
                     }
582

    
583
      case AXIS_Z: switch(layer)
584
                     {
585
                     case LAYER_L: if( getBit(id, 7)==1 || getBit(id, 8)==1 || getBit(id, 9)==1 ||
586
                                       getBit(id,28)==1 || getBit(id,29)==1 || getBit(id,30)==1 ||
587
                                       getBit(id,49)==1 || getBit(id,50)==1 || getBit(id,51)==1  ) return INVALID_MOVE;
588

    
589
                                   long z1 = cycle(id,10,20,53,39);
590
                                   long z2 = cycle(z1,11,41,52,18);
591
                                   return    cycle(z2,19,32,40,31);
592

    
593
                     case LAYER_M: if( getBit(id, 7)==1 || getBit(id, 8)==1 || getBit(id, 9)==1 ||
594
                                       getBit(id,28)==1 || getBit(id,29)==1 || getBit(id,30)==1 ||
595
                                       getBit(id,49)==1 || getBit(id,50)==1 || getBit(id,51)==1 ||
596
                                       getBit(id, 2)==1 || getBit(id, 3)==1 || getBit(id, 4)==1 ||
597
                                       getBit(id,23)==1 || getBit(id,24)==1 || getBit(id,25)==1 ||
598
                                       getBit(id,44)==1 || getBit(id,45)==1 || getBit(id,46)==1  ) return INVALID_MOVE;
599

    
600
                                   long z4 = cycle(id,5,17,48,36);
601
                                   long z5 = cycle(z4,6,38,47,15);
602
                                   return    cycle(z5,16,27,37,26);
603

    
604
                     case LAYER_R: if( getBit(id, 2)==1 || getBit(id, 3)==1 || getBit(id, 4)==1 ||
605
                                       getBit(id,23)==1 || getBit(id,24)==1 || getBit(id,25)==1 ||
606
                                       getBit(id,44)==1 || getBit(id,45)==1 || getBit(id,46)==1  ) return INVALID_MOVE;
607

    
608
                                   long z7 = cycle(id,0,14,43,33);
609
                                   long z8 = cycle(z7,1,35,42,12);
610
                                   return    cycle(z8,13,22,34,21);
611
                     }
612
      }
613

    
614
    return 0;
615
    }
616

    
617
///////////////////////////////////////////////////////////////////////////////////////////////////
618
// bit b1 in place of b2 etc.
619

    
620
  private static long cycle(long id, int b1, int b2, int b3, int b4)
621
    {
622
    long bit1 = getBit(id,b1);
623
    long bit2 = getBit(id,b2);
624
    long bit3 = getBit(id,b3);
625
    long bit4 = getBit(id,b4);
626

    
627
    long i1 = setBit(id,b2,bit1);
628
    long i2 = setBit(i1,b3,bit2);
629
    long i3 = setBit(i2,b4,bit3);
630
    return    setBit(i3,b1,bit4);
631
    }
632

    
633
///////////////////////////////////////////////////////////////////////////////////////////////////
634

    
635
  private static long getBit(long id, int bit)
636
    {
637
    return (id>>bit)&0x1;
638
    }
639

    
640
///////////////////////////////////////////////////////////////////////////////////////////////////
641

    
642
  private static long setBit(long id, int bit, long value)
643
    {
644
    long old = getBit(id,bit);
645

    
646
    if( old!=value )
647
      {
648
      long diff = (1L<<bit);
649
      id += (value==0 ? -diff : diff);
650
      }
651

    
652
    return id;
653
    }
654

    
655
///////////////////////////////////////////////////////////////////////////////////////////////////
656

    
657
  private void printMoves()
658
    {
659
    String moves = "";
660

    
661
    for(int i=0; i<NUM_MOVES; i++)
662
      {
663
      moves += (" " + mMoves[i]);
664
      }
665

    
666
    android.util.Log.e("D", moves);
667
    }
668

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

    
671
  private static String printBits(long id)
672
    {
673
    String ret = "[";
674
    boolean first = true;
675

    
676
    for(int i=0; i<64; i++)
677
      {
678
      if( ( (id>>i)&0x1)==1 )
679
        {
680
        String num = (i<10 ? " "+i : ""+i);
681

    
682
        if( first ) { ret += num; first=false; }
683
        else          ret += (","+num);
684
        }
685
      }
686

    
687
    return ret + "]";
688
    }
689

    
690
///////////////////////////////////////////////////////////////////////////////////////////////////
691

    
692
  private static void printGraph(Map<Long, ScrambleStateBandaged3x3> map)
693
    {
694
    int num = map.size();
695
    android.util.Log.e("D", "\n"+num+" states\n");
696

    
697
    for (Map.Entry<Long, ScrambleStateBandaged3x3> entry : map.entrySet())
698
      {
699
      ScrambleStateBandaged3x3 value = entry.getValue();
700
      android.util.Log.e("D", value.formatMoves());
701
      }
702
    }
703
}
(5-5/7)