Project

General

Profile

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

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

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.LinkedHashMap;
23
import java.util.Iterator;
24
import java.util.Map;
25

    
26
///////////////////////////////////////////////////////////////////////////////////////////////////
27
// Producer of the ScrambleStateGraph for any bandaged 3x3x3.
28

    
29
public class ScrambleStateBandaged3x3
30
{
31
  public static final int AXIS_NONE = -1;
32
  public static final int AXIS_X = 0;
33
  public static final int AXIS_Y = 1;
34
  public static final int AXIS_Z = 2;
35

    
36
  private static final long INVALID_MOVE = -1;
37
  private static final int NUM_MOVES = 27;
38

    
39
  private static final int LAYER_L = 0;
40
  private static final int LAYER_M = 1;
41
  private static final int LAYER_R = 2;
42

    
43
  private long mID;
44
  private int mDistance;
45
  private final long[] mMoves;
46

    
47
///////////////////////////////////////////////////////////////////////////////////////////////////
48

    
49
  public ScrambleStateBandaged3x3(long id)
50
    {
51
    mDistance = -1;
52
    mID = id;
53
    mMoves = createMoves(mID);
54
    }
55

    
56
///////////////////////////////////////////////////////////////////////////////////////////////////
57

    
58
  public long getID()
59
    {
60
    return mID;
61
    }
62

    
63
///////////////////////////////////////////////////////////////////////////////////////////////////
64

    
65
  private void setID(long id)
66
    {
67
    mID = id;
68
    }
69

    
70
///////////////////////////////////////////////////////////////////////////////////////////////////
71

    
72
  public long getMove(int index)
73
    {
74
    return (index>=0 && index<NUM_MOVES) ? mMoves[index] : INVALID_MOVE;
75
    }
76

    
77
///////////////////////////////////////////////////////////////////////////////////////////////////
78

    
79
  public int numAxis()
80
    {
81
    int num = 0;
82

    
83
    if( mMoves[ 0]!=INVALID_MOVE || mMoves[ 1]!=INVALID_MOVE || mMoves[ 2]!=INVALID_MOVE ||
84
        mMoves[ 3]!=INVALID_MOVE || mMoves[ 4]!=INVALID_MOVE || mMoves[ 5]!=INVALID_MOVE ||
85
        mMoves[ 6]!=INVALID_MOVE || mMoves[ 7]!=INVALID_MOVE || mMoves[ 8]!=INVALID_MOVE   ) num++;
86

    
87
    if( mMoves[ 9]!=INVALID_MOVE || mMoves[10]!=INVALID_MOVE || mMoves[11]!=INVALID_MOVE ||
88
        mMoves[12]!=INVALID_MOVE || mMoves[13]!=INVALID_MOVE || mMoves[14]!=INVALID_MOVE ||
89
        mMoves[15]!=INVALID_MOVE || mMoves[16]!=INVALID_MOVE || mMoves[17]!=INVALID_MOVE   ) num++;
90

    
91
    if( mMoves[18]!=INVALID_MOVE || mMoves[19]!=INVALID_MOVE || mMoves[20]!=INVALID_MOVE ||
92
        mMoves[21]!=INVALID_MOVE || mMoves[22]!=INVALID_MOVE || mMoves[23]!=INVALID_MOVE ||
93
        mMoves[24]!=INVALID_MOVE || mMoves[25]!=INVALID_MOVE || mMoves[26]!=INVALID_MOVE   ) num++;
94

    
95
    return num;
96
    }
97

    
98
///////////////////////////////////////////////////////////////////////////////////////////////////
99

    
100
  private int numXMoves()
101
    {
102
    int num=0;
103

    
104
    if( mMoves[ 0]!=INVALID_MOVE ) num++;
105
    if( mMoves[ 1]!=INVALID_MOVE ) num++;
106
    if( mMoves[ 2]!=INVALID_MOVE ) num++;
107
    if( mMoves[ 3]!=INVALID_MOVE ) num++;
108
    if( mMoves[ 4]!=INVALID_MOVE ) num++;
109
    if( mMoves[ 5]!=INVALID_MOVE ) num++;
110
    if( mMoves[ 6]!=INVALID_MOVE ) num++;
111
    if( mMoves[ 7]!=INVALID_MOVE ) num++;
112
    if( mMoves[ 8]!=INVALID_MOVE ) num++;
113

    
114
    return num;
115
    }
116

    
117
///////////////////////////////////////////////////////////////////////////////////////////////////
118

    
119
  private int numYMoves()
120
    {
121
    int num=0;
122

    
123
    if( mMoves[ 9]!=INVALID_MOVE ) num++;
124
    if( mMoves[10]!=INVALID_MOVE ) num++;
125
    if( mMoves[11]!=INVALID_MOVE ) num++;
126
    if( mMoves[12]!=INVALID_MOVE ) num++;
127
    if( mMoves[13]!=INVALID_MOVE ) num++;
128
    if( mMoves[14]!=INVALID_MOVE ) num++;
129
    if( mMoves[15]!=INVALID_MOVE ) num++;
130
    if( mMoves[16]!=INVALID_MOVE ) num++;
131
    if( mMoves[17]!=INVALID_MOVE ) num++;
132

    
133
    return num;
134
    }
135

    
136
///////////////////////////////////////////////////////////////////////////////////////////////////
137

    
138
  private int numZMoves()
139
    {
140
    int num=0;
141

    
142
    if( mMoves[18]!=INVALID_MOVE ) num++;
143
    if( mMoves[19]!=INVALID_MOVE ) num++;
144
    if( mMoves[20]!=INVALID_MOVE ) num++;
145
    if( mMoves[21]!=INVALID_MOVE ) num++;
146
    if( mMoves[22]!=INVALID_MOVE ) num++;
147
    if( mMoves[23]!=INVALID_MOVE ) num++;
148
    if( mMoves[24]!=INVALID_MOVE ) num++;
149
    if( mMoves[25]!=INVALID_MOVE ) num++;
150
    if( mMoves[26]!=INVALID_MOVE ) num++;
151

    
152
    return num;
153
    }
154

    
155
///////////////////////////////////////////////////////////////////////////////////////////////////
156

    
157
  public int numMoves()
158
    {
159
    return numXMoves()+numYMoves()+numZMoves();
160
    }
161

    
162
///////////////////////////////////////////////////////////////////////////////////////////////////
163

    
164
  public int numMoves(int excludedAxis)
165
    {
166
    switch(excludedAxis)
167
      {
168
      case AXIS_X: return numYMoves()+numZMoves();
169
      case AXIS_Y: return numXMoves()+numZMoves();
170
      case AXIS_Z: return numXMoves()+numYMoves();
171
      }
172

    
173
    int ret= numXMoves()+numYMoves()+numZMoves();
174

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

    
177
    return ret;
178
    }
179

    
180
///////////////////////////////////////////////////////////////////////////////////////////////////
181

    
182
  public int getNthMove(int n, int excludedAxis)
183
    {
184
    int num = 0;
185

    
186
    for(int m=0; m<NUM_MOVES; m++)
187
      {
188
      if( (m/9)!=excludedAxis && mMoves[m]!=INVALID_MOVE)
189
        {
190
        if( num==n ) return m;
191
        num++;
192
        }
193
      }
194

    
195
    return -1;
196
    }
197

    
198
///////////////////////////////////////////////////////////////////////////////////////////////////
199

    
200
  public void removeMoves(long signature)
201
    {
202
    for(int m=0; m<NUM_MOVES; m++)
203
      if( signature==mMoves[m] ) mMoves[m]=INVALID_MOVE;
204
    }
205

    
206
///////////////////////////////////////////////////////////////////////////////////////////////////
207

    
208
  private void setMove(int index, long newMove)
209
    {
210
    if( index>=0 && index<NUM_MOVES ) mMoves[index] = newMove;
211
    }
212

    
213
///////////////////////////////////////////////////////////////////////////////////////////////////
214

    
215
  public String formatMoves()
216
    {
217
    String x = getTable( 0);
218
    String y = getTable( 9);
219
    String z = getTable(18);
220

    
221
    return mID+"\n"+x+"\n"+y+"\n"+z;
222
    }
223

    
224
///////////////////////////////////////////////////////////////////////////////////////////////////
225

    
226
  private String getTable(int index)
227
    {
228
    long m0 = getMove(index  );
229
    long m1 = getMove(index+1);
230
    long m2 = getMove(index+2);
231
    long m3 = getMove(index+3);
232
    long m4 = getMove(index+4);
233
    long m5 = getMove(index+5);
234
    long m6 = getMove(index+6);
235
    long m7 = getMove(index+7);
236
    long m8 = getMove(index+8);
237

    
238
    String ret = "";
239

    
240
    if( m0!=INVALID_MOVE ) ret += formatRet(ret,0,-1,m0);
241
    if( m1!=INVALID_MOVE ) ret += formatRet(ret,0, 2,m1);
242
    if( m2!=INVALID_MOVE ) ret += formatRet(ret,0, 1,m2);
243
    if( m3!=INVALID_MOVE ) ret += formatRet(ret,1,-1,m3);
244
    if( m4!=INVALID_MOVE ) ret += formatRet(ret,1, 2,m4);
245
    if( m5!=INVALID_MOVE ) ret += formatRet(ret,1, 1,m5);
246
    if( m6!=INVALID_MOVE ) ret += formatRet(ret,2,-1,m6);
247
    if( m7!=INVALID_MOVE ) ret += formatRet(ret,2, 2,m7);
248
    if( m8!=INVALID_MOVE ) ret += formatRet(ret,2, 1,m8);
249

    
250
    return formatL("{" + ret + "}");
251
    }
252

    
253
///////////////////////////////////////////////////////////////////////////////////////////////////
254

    
255
  private int[] getMoves(int index)
256
    {
257
    int numValid = 0;
258
    for(int i=index; i<index+9; i++) if( mMoves[i]!=INVALID_MOVE ) numValid++;
259

    
260
    int[] ret = new int[3*numValid];
261

    
262
    long m0 = getMove(index  );
263
    long m1 = getMove(index+1);
264
    long m2 = getMove(index+2);
265
    long m3 = getMove(index+3);
266
    long m4 = getMove(index+4);
267
    long m5 = getMove(index+5);
268
    long m6 = getMove(index+6);
269
    long m7 = getMove(index+7);
270
    long m8 = getMove(index+8);
271

    
272
    int pointer=0;
273

    
274
    if( m0!=INVALID_MOVE ) { ret[pointer]=0; ret[pointer+1]=-1; ret[pointer+2]= (int)m0; pointer+=3; }
275
    if( m1!=INVALID_MOVE ) { ret[pointer]=0; ret[pointer+1]= 2; ret[pointer+2]= (int)m1; pointer+=3; }
276
    if( m2!=INVALID_MOVE ) { ret[pointer]=0; ret[pointer+1]= 1; ret[pointer+2]= (int)m2; pointer+=3; }
277
    if( m3!=INVALID_MOVE ) { ret[pointer]=1; ret[pointer+1]=-1; ret[pointer+2]= (int)m3; pointer+=3; }
278
    if( m4!=INVALID_MOVE ) { ret[pointer]=1; ret[pointer+1]= 2; ret[pointer+2]= (int)m4; pointer+=3; }
279
    if( m5!=INVALID_MOVE ) { ret[pointer]=1; ret[pointer+1]= 1; ret[pointer+2]= (int)m5; pointer+=3; }
280
    if( m6!=INVALID_MOVE ) { ret[pointer]=2; ret[pointer+1]=-1; ret[pointer+2]= (int)m6; pointer+=3; }
281
    if( m7!=INVALID_MOVE ) { ret[pointer]=2; ret[pointer+1]= 2; ret[pointer+2]= (int)m7; pointer+=3; }
282
    if( m8!=INVALID_MOVE ) { ret[pointer]=2; ret[pointer+1]= 1; ret[pointer+2]= (int)m8; pointer+=3; }
283

    
284
    return ret;
285
    }
286

    
287
///////////////////////////////////////////////////////////////////////////////////////////////////
288

    
289
  private ScrambleState produceScrambleState()
290
    {
291
    int[] xMoves = getMoves(0);
292
    int[] yMoves = getMoves(9);
293
    int[] zMoves = getMoves(18);
294

    
295
    int[][] moves = { xMoves,yMoves,zMoves };
296

    
297
    return new ScrambleState( moves );
298
    }
299

    
300
///////////////////////////////////////////////////////////////////////////////////////////////////
301
// STATIC STUFF
302
///////////////////////////////////////////////////////////////////////////////////////////////////
303

    
304
  public static ScrambleState[] computeGraph(long id)
305
    {
306
    ScrambleStateBandaged3x3 bsg = new ScrambleStateBandaged3x3(id);
307
    Map<Long,ScrambleStateBandaged3x3> graph = new LinkedHashMap<>();
308
    graph.put(id,bsg);
309

    
310
    insertChildren(graph,id);
311
    // if there's only one state, do not prune moves which point to itself
312
    if(graph.size()>1) pruneGraph(graph,id);
313
    computeDistance(graph,id,0);
314
    removeDisconnectedParts(graph);
315
    remapGraph(graph);
316

    
317
    int num = graph.size();
318
    ScrambleState[] ret = new ScrambleState[num];
319

    
320
    for (Map.Entry<Long,ScrambleStateBandaged3x3> entry : graph.entrySet())
321
      {
322
      ScrambleStateBandaged3x3 value = entry.getValue();
323
      int mid = (int)value.mID;
324
      ret[mid] = value.produceScrambleState();
325
      }
326

    
327
    return ret;
328
    }
329

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

    
332
  private static void insertChildren(Map<Long,ScrambleStateBandaged3x3> map, long id)
333
    {
334
    ScrambleStateBandaged3x3 bsg = findState(map,id);
335

    
336
    if( bsg==null )
337
      {
338
      android.util.Log.e("D", "error: "+id+" doesn't exist");
339
      return;
340
      }
341

    
342
    for(int i=0; i<NUM_MOVES; i++)
343
      {
344
      long move = bsg.getMove(i);
345

    
346
      if( move!=INVALID_MOVE )
347
        {
348
        ScrambleStateBandaged3x3 tmp = findState(map,move);
349

    
350
        if( tmp==null )
351
          {
352
          tmp = new ScrambleStateBandaged3x3(move);
353
          map.put(move,tmp);
354
          insertChildren(map,move);
355
          }
356
        }
357
      }
358
    }
359

    
360
///////////////////////////////////////////////////////////////////////////////////////////////////
361

    
362
  private static void pruneGraph(Map<Long,ScrambleStateBandaged3x3> map, long startingID)
363
    {
364
    boolean pruned = false;
365
    boolean startingIsSingle = false;
366

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

    
369
    while (it.hasNext())
370
      {
371
      Map.Entry<Long,ScrambleStateBandaged3x3> entry = it.next();
372
      ScrambleStateBandaged3x3 value = entry.getValue();
373

    
374
      if( value.numAxis()<2 )
375
        {
376
        long prunedID = value.getID();
377

    
378
        if( prunedID!=startingID ) // do not remove the starting point, even if it does have only 1 axis
379
          {
380
          it.remove();
381
          pruned = true;
382
          }
383
        else
384
          {
385
          startingIsSingle = true;
386
          }
387
        }
388
      }
389

    
390
    for (Map.Entry<Long,ScrambleStateBandaged3x3> entry : map.entrySet() )
391
      {
392
      ScrambleStateBandaged3x3 value = entry.getValue();
393

    
394
      for(int m=0; m<NUM_MOVES; m++)
395
        {
396
        long move = value.mMoves[m];
397
        ScrambleStateBandaged3x3 tmp = findState(map,move);
398

    
399
        if( tmp==null || (startingIsSingle && move==startingID) )
400
          {
401
          value.mMoves[m]=INVALID_MOVE;
402
          }
403
        }
404
      }
405

    
406
    if( pruned ) pruneGraph(map,startingID);
407
    }
408

    
409
///////////////////////////////////////////////////////////////////////////////////////////////////
410

    
411
  private static void remapGraph(Map<Long,ScrambleStateBandaged3x3> map)
412
    {
413
    int id=0;
414

    
415
    for (Map.Entry<Long,ScrambleStateBandaged3x3> entry : map.entrySet())
416
      {
417
      ScrambleStateBandaged3x3 value = entry.getValue();
418
      value.mID = id++;
419
      }
420

    
421
    for (Map.Entry<Long,ScrambleStateBandaged3x3> entry : map.entrySet())
422
      {
423
      ScrambleStateBandaged3x3 value = entry.getValue();
424

    
425
      for(int m=0; m<NUM_MOVES; m++)
426
        {
427
        long move = value.mMoves[m];
428

    
429
        if( move!=INVALID_MOVE )
430
          {
431
          ScrambleStateBandaged3x3 tmp = map.get(move);
432
          value.mMoves[m] = tmp.mID;
433
          }
434
        }
435
      }
436
    }
437

    
438
///////////////////////////////////////////////////////////////////////////////////////////////////
439

    
440
  private static void computeDistance(Map<Long,ScrambleStateBandaged3x3> map, long id, int distance)
441
    {
442
    ScrambleStateBandaged3x3 state = findState(map,id);
443

    
444
    if( state==null )
445
      {
446
      android.util.Log.e("D", "error: "+id+" doesn't exist");
447
      return;
448
      }
449

    
450
    if( state.mDistance<0 )
451
      {
452
      state.mDistance = distance;
453

    
454
      for(int i=0; i<NUM_MOVES; i++)
455
        {
456
        long move = state.getMove(i);
457

    
458
        if( move!=INVALID_MOVE )
459
          {
460
          computeDistance(map,move,distance+1);
461
          }
462
        }
463
      }
464
    }
465

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

    
468
  private static void removeDisconnectedParts(Map<Long,ScrambleStateBandaged3x3> map)
469
    {
470
    Iterator<Map.Entry<Long,ScrambleStateBandaged3x3>> it = map.entrySet().iterator();
471

    
472
    while (it.hasNext())
473
      {
474
      Map.Entry<Long,ScrambleStateBandaged3x3> entry = it.next();
475
      ScrambleStateBandaged3x3 value = entry.getValue();
476
      if( value.mDistance<0 ) it.remove();
477
      }
478
    }
479

    
480
///////////////////////////////////////////////////////////////////////////////////////////////////
481

    
482
  private static ScrambleStateBandaged3x3 findState(Map<Long,ScrambleStateBandaged3x3> map, long id)
483
    {
484
    return map.get(id);
485
    }
486

    
487
///////////////////////////////////////////////////////////////////////////////////////////////////
488

    
489
  private static String formatRet(String str, int row, int angle, long id)
490
    {
491
    String ret = str.length()!=0 ? ",":"";
492

    
493
    ret += row;
494
    ret += angle<0 ? "," : ", ";
495
    ret += angle;
496

    
497
         if( id< 10 ) ret += (",  "+id);
498
    else if( id<100 ) ret += (", " +id);
499
    else              ret += (","  +id);
500

    
501
    return ret;
502
    }
503

    
504
///////////////////////////////////////////////////////////////////////////////////////////////////
505

    
506
  private static final int LENGTH = 28;
507

    
508
  private static String formatL(String input)
509
    {
510
    int len = input.length();
511
    String ret = input;
512
    for(int i=0 ;i<LENGTH-len; i++) ret += " ";
513
    return ret;
514
    }
515

    
516
///////////////////////////////////////////////////////////////////////////////////////////////////
517

    
518
  private static long[] createMoves(long id)
519
    {
520
    long[] ret = new long[NUM_MOVES];
521
    int index = 0;
522

    
523
    for(int axis=0; axis<3; axis++)
524
      for(int layer=0; layer<3; layer++)
525
        {
526
        long x1 = turn(id,axis,layer);
527

    
528
        if( x1!=INVALID_MOVE )
529
          {
530
          long x2 = turn(x1,axis,layer);
531
          long x3 = turn(x2,axis,layer);
532

    
533
          ret[index  ] = x1;
534
          ret[index+1] = x2;
535
          ret[index+2] = x3;
536
          }
537
        else
538
          {
539
          ret[index  ] = INVALID_MOVE;
540
          ret[index+1] = INVALID_MOVE;
541
          ret[index+2] = INVALID_MOVE;
542
          }
543

    
544
        index+=3;
545
        }
546

    
547
    return ret;
548
    }
549

    
550
///////////////////////////////////////////////////////////////////////////////////////////////////
551
// Definition of the id: it's an 'Andreas signature' of a bandaged cube.
552
// https://twistypuzzles.com/forum/viewtopic.php?t=24452&sid=f3b4ac0c611c4713e4d7840f1aabbb0b&start=350
553

    
554
  private static long turn(long id, int axis, int layer)
555
    {
556
    switch(axis)
557
      {
558
      case AXIS_X: switch(layer)
559
                     {
560
                     case LAYER_L: if( getBit(id, 1)==1 || getBit(id, 6)==1 || getBit(id,11)==1 ||
561
                                       getBit(id,22)==1 || getBit(id,27)==1 || getBit(id,32)==1 ||
562
                                       getBit(id,43)==1 || getBit(id,48)==1 || getBit(id,53)==1  ) return INVALID_MOVE;
563

    
564
                                   long x1 = cycle(id,9,14,46,41);
565
                                   long x2 = cycle(x1,4,35,51,20);
566
                                   return    cycle(x2,17,25,38,30);
567

    
568
                     case LAYER_M: if( getBit(id, 1)==1 || getBit(id, 6)==1 || getBit(id,11)==1 ||
569
                                       getBit(id,22)==1 || getBit(id,27)==1 || getBit(id,32)==1 ||
570
                                       getBit(id,43)==1 || getBit(id,48)==1 || getBit(id,53)==1 ||
571
                                       getBit(id, 0)==1 || getBit(id, 5)==1 || getBit(id,10)==1 ||
572
                                       getBit(id,21)==1 || getBit(id,26)==1 || getBit(id,31)==1 ||
573
                                       getBit(id,42)==1 || getBit(id,47)==1 || getBit(id,52)==1  ) return INVALID_MOVE;
574

    
575
                                   long x4 = cycle(id,8,13,45,40);
576
                                   long x5 = cycle(x4,3,34,50,19);
577
                                   return    cycle(x5,16,24,37,29);
578

    
579
                     case LAYER_R: if( getBit(id, 0)==1 || getBit(id, 5)==1 || getBit(id,10)==1 ||
580
                                       getBit(id,21)==1 || getBit(id,26)==1 || getBit(id,31)==1 ||
581
                                       getBit(id,42)==1 || getBit(id,47)==1 || getBit(id,52)==1  ) return INVALID_MOVE;
582

    
583
                                   long x7 = cycle(id,7,12,44,39);
584
                                   long x8 = cycle(x7,2,33,49,18);
585
                                   return    cycle(x8,15,23,36,28);
586
                     }
587

    
588
      case AXIS_Y: switch(layer)
589
                     {
590
                     case LAYER_L: if( getBit(id,12)==1 || getBit(id,13)==1 || getBit(id,14)==1 ||
591
                                       getBit(id,15)==1 || getBit(id,16)==1 || getBit(id,17)==1 ||
592
                                       getBit(id,18)==1 || getBit(id,19)==1 || getBit(id,20)==1  ) return INVALID_MOVE;
593

    
594
                                   long y1 = cycle(id,1,9,10,2);
595
                                   long y2 = cycle(y1,0,4,11,7);
596
                                   return    cycle(y2,3,6,8,5);
597

    
598
                     case LAYER_M: if( getBit(id,12)==1 || getBit(id,13)==1 || getBit(id,14)==1 ||
599
                                       getBit(id,15)==1 || getBit(id,16)==1 || getBit(id,17)==1 ||
600
                                       getBit(id,18)==1 || getBit(id,19)==1 || getBit(id,20)==1 ||
601
                                       getBit(id,33)==1 || getBit(id,34)==1 || getBit(id,35)==1 ||
602
                                       getBit(id,36)==1 || getBit(id,37)==1 || getBit(id,38)==1 ||
603
                                       getBit(id,39)==1 || getBit(id,40)==1 || getBit(id,41)==1  ) return INVALID_MOVE;
604

    
605
                                   long y4 = cycle(id,21,25,32,28);
606
                                   long y5 = cycle(y4,22,30,31,23);
607
                                   return    cycle(y5,24,27,29,26);
608

    
609
                     case LAYER_R: if( getBit(id,33)==1 || getBit(id,34)==1 || getBit(id,35)==1 ||
610
                                       getBit(id,36)==1 || getBit(id,37)==1 || getBit(id,38)==1 ||
611
                                       getBit(id,39)==1 || getBit(id,40)==1 || getBit(id,41)==1  ) return INVALID_MOVE;
612

    
613
                                   long y7 = cycle(id,42,46,53,49);
614
                                   long y8 = cycle(y7,43,51,52,44);
615
                                   return    cycle(y8,45,48,50,47);
616
                     }
617

    
618
      case AXIS_Z: switch(layer)
619
                     {
620
                     case LAYER_L: if( getBit(id, 7)==1 || getBit(id, 8)==1 || getBit(id, 9)==1 ||
621
                                       getBit(id,28)==1 || getBit(id,29)==1 || getBit(id,30)==1 ||
622
                                       getBit(id,49)==1 || getBit(id,50)==1 || getBit(id,51)==1  ) return INVALID_MOVE;
623

    
624
                                   long z1 = cycle(id,10,20,53,39);
625
                                   long z2 = cycle(z1,11,41,52,18);
626
                                   return    cycle(z2,19,32,40,31);
627

    
628
                     case LAYER_M: if( getBit(id, 7)==1 || getBit(id, 8)==1 || getBit(id, 9)==1 ||
629
                                       getBit(id,28)==1 || getBit(id,29)==1 || getBit(id,30)==1 ||
630
                                       getBit(id,49)==1 || getBit(id,50)==1 || getBit(id,51)==1 ||
631
                                       getBit(id, 2)==1 || getBit(id, 3)==1 || getBit(id, 4)==1 ||
632
                                       getBit(id,23)==1 || getBit(id,24)==1 || getBit(id,25)==1 ||
633
                                       getBit(id,44)==1 || getBit(id,45)==1 || getBit(id,46)==1  ) return INVALID_MOVE;
634

    
635
                                   long z4 = cycle(id,5,17,48,36);
636
                                   long z5 = cycle(z4,6,38,47,15);
637
                                   return    cycle(z5,16,27,37,26);
638

    
639
                     case LAYER_R: if( getBit(id, 2)==1 || getBit(id, 3)==1 || getBit(id, 4)==1 ||
640
                                       getBit(id,23)==1 || getBit(id,24)==1 || getBit(id,25)==1 ||
641
                                       getBit(id,44)==1 || getBit(id,45)==1 || getBit(id,46)==1  ) return INVALID_MOVE;
642

    
643
                                   long z7 = cycle(id,0,14,43,33);
644
                                   long z8 = cycle(z7,1,35,42,12);
645
                                   return    cycle(z8,13,22,34,21);
646
                     }
647
      }
648

    
649
    return 0;
650
    }
651

    
652
///////////////////////////////////////////////////////////////////////////////////////////////////
653
// bit b1 in place of b2 etc.
654

    
655
  private static long cycle(long id, int b1, int b2, int b3, int b4)
656
    {
657
    long bit1 = getBit(id,b1);
658
    long bit2 = getBit(id,b2);
659
    long bit3 = getBit(id,b3);
660
    long bit4 = getBit(id,b4);
661

    
662
    long i1 = setBit(id,b2,bit1);
663
    long i2 = setBit(i1,b3,bit2);
664
    long i3 = setBit(i2,b4,bit3);
665
    return    setBit(i3,b1,bit4);
666
    }
667

    
668
///////////////////////////////////////////////////////////////////////////////////////////////////
669

    
670
  private static long getBit(long id, int bit)
671
    {
672
    return (id>>bit)&0x1;
673
    }
674

    
675
///////////////////////////////////////////////////////////////////////////////////////////////////
676

    
677
  private static long setBit(long id, int bit, long value)
678
    {
679
    long old = getBit(id,bit);
680

    
681
    if( old!=value )
682
      {
683
      long diff = (1L<<bit);
684
      id += (value==0 ? -diff : diff);
685
      }
686

    
687
    return id;
688
    }
689

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

    
692
  private void printMoves()
693
    {
694
    String moves = "";
695

    
696
    for(int i=0; i<NUM_MOVES; i++)
697
      {
698
      moves += (" " + mMoves[i]);
699
      }
700

    
701
    android.util.Log.e("D", moves);
702
    }
703

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

    
706
  private static String printBits(long id)
707
    {
708
    String ret = "[";
709
    boolean first = true;
710

    
711
    for(int i=0; i<64; i++)
712
      {
713
      if( ( (id>>i)&0x1)==1 )
714
        {
715
        String num = (i<10 ? " "+i : ""+i);
716

    
717
        if( first ) { ret += num; first=false; }
718
        else          ret += (","+num);
719
        }
720
      }
721

    
722
    return ret + "]";
723
    }
724

    
725
///////////////////////////////////////////////////////////////////////////////////////////////////
726

    
727
  private static void printGraph(Map<Long,ScrambleStateBandaged3x3> map)
728
    {
729
    int num = map.size();
730
    android.util.Log.e("D", "\n"+num+" states\n");
731

    
732
    for (Map.Entry<Long,ScrambleStateBandaged3x3> entry : map.entrySet())
733
      {
734
      ScrambleStateBandaged3x3 value = entry.getValue();
735
      android.util.Log.e("D", value.formatMoves());
736
      }
737
    }
738
}
(3-3/4)