Project

General

Profile

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

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

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_X = 0;
32
  public static final int AXIS_Y = 1;
33
  public static final int AXIS_Z = 2;
34

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

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

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

    
46
///////////////////////////////////////////////////////////////////////////////////////////////////
47

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

    
55
///////////////////////////////////////////////////////////////////////////////////////////////////
56

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

    
62
///////////////////////////////////////////////////////////////////////////////////////////////////
63

    
64
  public long getMove(int index)
65
    {
66
    return (index>=0 && index<NUM_MOVES) ? mMoves[index] : INVALID_MOVE;
67
    }
68

    
69
///////////////////////////////////////////////////////////////////////////////////////////////////
70

    
71
  public int numAxis()
72
    {
73
    int num = 0;
74

    
75
    if( mMoves[ 0]!=INVALID_MOVE || mMoves[ 1]!=INVALID_MOVE || mMoves[ 2]!=INVALID_MOVE ||
76
        mMoves[ 3]!=INVALID_MOVE || mMoves[ 4]!=INVALID_MOVE || mMoves[ 5]!=INVALID_MOVE ||
77
        mMoves[ 6]!=INVALID_MOVE || mMoves[ 7]!=INVALID_MOVE || mMoves[ 8]!=INVALID_MOVE   ) num++;
78

    
79
    if( mMoves[ 9]!=INVALID_MOVE || mMoves[10]!=INVALID_MOVE || mMoves[11]!=INVALID_MOVE ||
80
        mMoves[12]!=INVALID_MOVE || mMoves[13]!=INVALID_MOVE || mMoves[14]!=INVALID_MOVE ||
81
        mMoves[15]!=INVALID_MOVE || mMoves[16]!=INVALID_MOVE || mMoves[17]!=INVALID_MOVE   ) num++;
82

    
83
    if( mMoves[18]!=INVALID_MOVE || mMoves[19]!=INVALID_MOVE || mMoves[20]!=INVALID_MOVE ||
84
        mMoves[21]!=INVALID_MOVE || mMoves[22]!=INVALID_MOVE || mMoves[23]!=INVALID_MOVE ||
85
        mMoves[24]!=INVALID_MOVE || mMoves[25]!=INVALID_MOVE || mMoves[26]!=INVALID_MOVE   ) num++;
86

    
87
    return num;
88
    }
89

    
90
///////////////////////////////////////////////////////////////////////////////////////////////////
91

    
92
  private int numXMoves()
93
    {
94
    int num=0;
95

    
96
    if( mMoves[ 0]!=INVALID_MOVE ) num++;
97
    if( mMoves[ 1]!=INVALID_MOVE ) num++;
98
    if( mMoves[ 2]!=INVALID_MOVE ) num++;
99
    if( mMoves[ 3]!=INVALID_MOVE ) num++;
100
    if( mMoves[ 4]!=INVALID_MOVE ) num++;
101
    if( mMoves[ 5]!=INVALID_MOVE ) num++;
102
    if( mMoves[ 6]!=INVALID_MOVE ) num++;
103
    if( mMoves[ 7]!=INVALID_MOVE ) num++;
104
    if( mMoves[ 8]!=INVALID_MOVE ) num++;
105

    
106
    return num;
107
    }
108

    
109
///////////////////////////////////////////////////////////////////////////////////////////////////
110

    
111
  private int numYMoves()
112
    {
113
    int num=0;
114

    
115
    if( mMoves[ 9]!=INVALID_MOVE ) num++;
116
    if( mMoves[10]!=INVALID_MOVE ) num++;
117
    if( mMoves[11]!=INVALID_MOVE ) num++;
118
    if( mMoves[12]!=INVALID_MOVE ) num++;
119
    if( mMoves[13]!=INVALID_MOVE ) num++;
120
    if( mMoves[14]!=INVALID_MOVE ) num++;
121
    if( mMoves[15]!=INVALID_MOVE ) num++;
122
    if( mMoves[16]!=INVALID_MOVE ) num++;
123
    if( mMoves[17]!=INVALID_MOVE ) num++;
124

    
125
    return num;
126
    }
127

    
128
///////////////////////////////////////////////////////////////////////////////////////////////////
129

    
130
  private int numZMoves()
131
    {
132
    int num=0;
133

    
134
    if( mMoves[18]!=INVALID_MOVE ) num++;
135
    if( mMoves[19]!=INVALID_MOVE ) num++;
136
    if( mMoves[20]!=INVALID_MOVE ) num++;
137
    if( mMoves[21]!=INVALID_MOVE ) num++;
138
    if( mMoves[22]!=INVALID_MOVE ) num++;
139
    if( mMoves[23]!=INVALID_MOVE ) num++;
140
    if( mMoves[24]!=INVALID_MOVE ) num++;
141
    if( mMoves[25]!=INVALID_MOVE ) num++;
142
    if( mMoves[26]!=INVALID_MOVE ) num++;
143

    
144
    return num;
145
    }
146

    
147
///////////////////////////////////////////////////////////////////////////////////////////////////
148

    
149
  public int numMoves()
150
    {
151
    return numXMoves()+numYMoves()+numZMoves();
152
    }
153

    
154
///////////////////////////////////////////////////////////////////////////////////////////////////
155

    
156
  public int numMoves(int excludedAxis)
157
    {
158
    switch(excludedAxis)
159
      {
160
      case AXIS_X: return numYMoves()+numZMoves();
161
      case AXIS_Y: return numXMoves()+numZMoves();
162
      case AXIS_Z: return numXMoves()+numYMoves();
163
      }
164

    
165
    int ret= numXMoves()+numYMoves()+numZMoves();
166

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

    
169
    return ret;
170
    }
171

    
172
///////////////////////////////////////////////////////////////////////////////////////////////////
173

    
174
  public int getNthMove(int n, int excludedAxis)
175
    {
176
    int num = 0;
177

    
178
    for(int m=0; m<NUM_MOVES; m++)
179
      {
180
      if( (m/9)!=excludedAxis && mMoves[m]!=INVALID_MOVE)
181
        {
182
        if( num==n ) return m;
183
        num++;
184
        }
185
      }
186

    
187
    return -1;
188
    }
189

    
190
///////////////////////////////////////////////////////////////////////////////////////////////////
191

    
192
  public void removeMoves(long signature)
193
    {
194
    for(int m=0; m<NUM_MOVES; m++)
195
      if( signature==mMoves[m] ) mMoves[m]=INVALID_MOVE;
196
    }
197

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

    
200
  public String formatMoves()
201
    {
202
    String x = getTable( 0);
203
    String y = getTable( 9);
204
    String z = getTable(18);
205

    
206
    return mID+"\n"+x+"\n"+y+"\n"+z;
207
    }
208

    
209
///////////////////////////////////////////////////////////////////////////////////////////////////
210

    
211
  private String getTable(int index)
212
    {
213
    long m0 = getMove(index  );
214
    long m1 = getMove(index+1);
215
    long m2 = getMove(index+2);
216
    long m3 = getMove(index+3);
217
    long m4 = getMove(index+4);
218
    long m5 = getMove(index+5);
219
    long m6 = getMove(index+6);
220
    long m7 = getMove(index+7);
221
    long m8 = getMove(index+8);
222

    
223
    String ret = "";
224

    
225
    if( m0!=INVALID_MOVE ) ret += formatRet(ret,0,-1,m0);
226
    if( m1!=INVALID_MOVE ) ret += formatRet(ret,0, 2,m1);
227
    if( m2!=INVALID_MOVE ) ret += formatRet(ret,0, 1,m2);
228
    if( m3!=INVALID_MOVE ) ret += formatRet(ret,1,-1,m3);
229
    if( m4!=INVALID_MOVE ) ret += formatRet(ret,1, 2,m4);
230
    if( m5!=INVALID_MOVE ) ret += formatRet(ret,1, 1,m5);
231
    if( m6!=INVALID_MOVE ) ret += formatRet(ret,2,-1,m6);
232
    if( m7!=INVALID_MOVE ) ret += formatRet(ret,2, 2,m7);
233
    if( m8!=INVALID_MOVE ) ret += formatRet(ret,2, 1,m8);
234

    
235
    return formatL("{" + ret + "}");
236
    }
237

    
238
///////////////////////////////////////////////////////////////////////////////////////////////////
239

    
240
  private int[] getMoves(int index)
241
    {
242
    int numValid = 0;
243
    for(int i=index; i<index+9; i++) if( mMoves[i]!=INVALID_MOVE ) numValid++;
244

    
245
    int[] ret = new int[3*numValid];
246

    
247
    long m0 = getMove(index  );
248
    long m1 = getMove(index+1);
249
    long m2 = getMove(index+2);
250
    long m3 = getMove(index+3);
251
    long m4 = getMove(index+4);
252
    long m5 = getMove(index+5);
253
    long m6 = getMove(index+6);
254
    long m7 = getMove(index+7);
255
    long m8 = getMove(index+8);
256

    
257
    int pointer=0;
258

    
259
    if( m0!=INVALID_MOVE ) { ret[pointer]=0; ret[pointer+1]=-1; ret[pointer+2]= (int)m0; pointer+=3; }
260
    if( m1!=INVALID_MOVE ) { ret[pointer]=0; ret[pointer+1]= 2; ret[pointer+2]= (int)m1; pointer+=3; }
261
    if( m2!=INVALID_MOVE ) { ret[pointer]=0; ret[pointer+1]= 1; ret[pointer+2]= (int)m2; pointer+=3; }
262
    if( m3!=INVALID_MOVE ) { ret[pointer]=1; ret[pointer+1]=-1; ret[pointer+2]= (int)m3; pointer+=3; }
263
    if( m4!=INVALID_MOVE ) { ret[pointer]=1; ret[pointer+1]= 2; ret[pointer+2]= (int)m4; pointer+=3; }
264
    if( m5!=INVALID_MOVE ) { ret[pointer]=1; ret[pointer+1]= 1; ret[pointer+2]= (int)m5; pointer+=3; }
265
    if( m6!=INVALID_MOVE ) { ret[pointer]=2; ret[pointer+1]=-1; ret[pointer+2]= (int)m6; pointer+=3; }
266
    if( m7!=INVALID_MOVE ) { ret[pointer]=2; ret[pointer+1]= 2; ret[pointer+2]= (int)m7; pointer+=3; }
267
    if( m8!=INVALID_MOVE ) { ret[pointer]=2; ret[pointer+1]= 1; ret[pointer+2]= (int)m8; pointer+=3; }
268

    
269
    return ret;
270
    }
271

    
272
///////////////////////////////////////////////////////////////////////////////////////////////////
273

    
274
  private ScrambleState produceScrambleState()
275
    {
276
    int[] xMoves = getMoves(0);
277
    int[] yMoves = getMoves(9);
278
    int[] zMoves = getMoves(18);
279

    
280
    int[][] moves = { xMoves,yMoves,zMoves };
281

    
282
    return new ScrambleState( moves );
283
    }
284

    
285
///////////////////////////////////////////////////////////////////////////////////////////////////
286
// STATIC STUFF
287
///////////////////////////////////////////////////////////////////////////////////////////////////
288

    
289
  public static ScrambleState[] computeGraph(long id)
290
    {
291
    ScrambleStateBandaged3x3 bsg = new ScrambleStateBandaged3x3(id);
292
    Map<Long, ScrambleStateBandaged3x3> graph = new LinkedHashMap<>();
293
    graph.put(id,bsg);
294

    
295
    insertChildren(graph,id);
296
    // if there's only one state, do not prune moves which point to itself
297
    if(graph.size()>1) pruneGraph(graph,id);
298
    computeDistance(graph,id,0);
299
    removeDisconnectedParts(graph);
300
    remapGraph(graph);
301

    
302
    int num = graph.size();
303
    ScrambleState[] ret = new ScrambleState[num];
304

    
305
    for (Map.Entry<Long, ScrambleStateBandaged3x3> entry : graph.entrySet())
306
      {
307
      ScrambleStateBandaged3x3 value = entry.getValue();
308
      int mid = (int)value.mID;
309
      ret[mid] = value.produceScrambleState();
310
      }
311

    
312
    return ret;
313
    }
314

    
315
///////////////////////////////////////////////////////////////////////////////////////////////////
316

    
317
  private static void insertChildren(Map<Long, ScrambleStateBandaged3x3> map, long id)
318
    {
319
    ScrambleStateBandaged3x3 bsg = findState(map,id);
320

    
321
    if( bsg==null )
322
      {
323
      android.util.Log.e("D", "error: "+id+" doesn't exist");
324
      return;
325
      }
326

    
327
    for(int i=0; i<NUM_MOVES; i++)
328
      {
329
      long move = bsg.getMove(i);
330

    
331
      if( move!=INVALID_MOVE )
332
        {
333
        ScrambleStateBandaged3x3 tmp = findState(map,move);
334

    
335
        if( tmp==null )
336
          {
337
          tmp = new ScrambleStateBandaged3x3(move);
338
          map.put(move,tmp);
339
          insertChildren(map,move);
340
          }
341
        }
342
      }
343
    }
344

    
345
///////////////////////////////////////////////////////////////////////////////////////////////////
346

    
347
  private static void pruneGraph(Map<Long, ScrambleStateBandaged3x3> map, long startingID)
348
    {
349
    boolean pruned = false;
350
    boolean startingIsSingle = false;
351

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

    
354
    while (it.hasNext())
355
      {
356
      Map.Entry<Long, ScrambleStateBandaged3x3> entry = it.next();
357
      ScrambleStateBandaged3x3 value = entry.getValue();
358

    
359
      if( value.numAxis()<2 )
360
        {
361
        long prunedID = value.getID();
362

    
363
        if( prunedID!=startingID ) // do not remove the starting point, even if it does have only 1 axis
364
          {
365
          it.remove();
366
          pruned = true;
367
          }
368
        else
369
          {
370
          startingIsSingle = true;
371
          }
372
        }
373
      }
374

    
375
    for (Map.Entry<Long, ScrambleStateBandaged3x3> entry : map.entrySet() )
376
      {
377
      ScrambleStateBandaged3x3 value = entry.getValue();
378

    
379
      for(int m=0; m<NUM_MOVES; m++)
380
        {
381
        long move = value.mMoves[m];
382
        ScrambleStateBandaged3x3 tmp = findState(map,move);
383

    
384
        if( tmp==null || (startingIsSingle && move==startingID) )
385
          {
386
          value.mMoves[m]=INVALID_MOVE;
387
          }
388
        }
389
      }
390

    
391
    if( pruned ) pruneGraph(map,startingID);
392
    }
393

    
394
///////////////////////////////////////////////////////////////////////////////////////////////////
395

    
396
  private static void remapGraph(Map<Long, ScrambleStateBandaged3x3> map)
397
    {
398
    int id=0;
399

    
400
    for (Map.Entry<Long, ScrambleStateBandaged3x3> entry : map.entrySet())
401
      {
402
      ScrambleStateBandaged3x3 value = entry.getValue();
403
      value.mID = id++;
404
      }
405

    
406
    for (Map.Entry<Long, ScrambleStateBandaged3x3> entry : map.entrySet())
407
      {
408
      ScrambleStateBandaged3x3 value = entry.getValue();
409

    
410
      for(int m=0; m<NUM_MOVES; m++)
411
        {
412
        long move = value.mMoves[m];
413

    
414
        if( move!=INVALID_MOVE )
415
          {
416
          ScrambleStateBandaged3x3 tmp = map.get(move);
417
          if( tmp!=null ) value.mMoves[m] = tmp.mID;
418
          else            android.util.Log.e("D", "ERROR in remapGraph");
419
          }
420
        }
421
      }
422
    }
423

    
424
///////////////////////////////////////////////////////////////////////////////////////////////////
425

    
426
  private static void computeDistance(Map<Long, ScrambleStateBandaged3x3> map, long id, int distance)
427
    {
428
    ScrambleStateBandaged3x3 state = findState(map,id);
429

    
430
    if( state==null )
431
      {
432
      android.util.Log.e("D", "error: "+id+" doesn't exist");
433
      return;
434
      }
435

    
436
    if( state.mDistance<0 )
437
      {
438
      state.mDistance = distance;
439

    
440
      for(int i=0; i<NUM_MOVES; i++)
441
        {
442
        long move = state.getMove(i);
443

    
444
        if( move!=INVALID_MOVE )
445
          {
446
          computeDistance(map,move,distance+1);
447
          }
448
        }
449
      }
450
    }
451

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

    
454
  private static void removeDisconnectedParts(Map<Long, ScrambleStateBandaged3x3> map)
455
    {
456
    Iterator<Map.Entry<Long, ScrambleStateBandaged3x3>> it = map.entrySet().iterator();
457

    
458
    while (it.hasNext())
459
      {
460
      Map.Entry<Long, ScrambleStateBandaged3x3> entry = it.next();
461
      ScrambleStateBandaged3x3 value = entry.getValue();
462
      if( value.mDistance<0 ) it.remove();
463
      }
464
    }
465

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

    
468
  private static ScrambleStateBandaged3x3 findState(Map<Long, ScrambleStateBandaged3x3> map, long id)
469
    {
470
    return map.get(id);
471
    }
472

    
473
///////////////////////////////////////////////////////////////////////////////////////////////////
474

    
475
  private static String formatRet(String str, int row, int angle, long id)
476
    {
477
    String ret = str.length()!=0 ? ",":"";
478

    
479
    ret += row;
480
    ret += angle<0 ? "," : ", ";
481
    ret += angle;
482

    
483
         if( id< 10 ) ret += (",  "+id);
484
    else if( id<100 ) ret += (", " +id);
485
    else              ret += (","  +id);
486

    
487
    return ret;
488
    }
489

    
490
///////////////////////////////////////////////////////////////////////////////////////////////////
491

    
492
  private static final int LENGTH = 28;
493

    
494
  private static String formatL(String input)
495
    {
496
    int len = input.length();
497
    String ret = input;
498
    for(int i=0 ;i<LENGTH-len; i++) ret += " ";
499
    return ret;
500
    }
501

    
502
///////////////////////////////////////////////////////////////////////////////////////////////////
503

    
504
  private static long[] createMoves(long id)
505
    {
506
    long[] ret = new long[NUM_MOVES];
507
    int index = 0;
508

    
509
    for(int axis=0; axis<3; axis++)
510
      for(int layer=0; layer<3; layer++)
511
        {
512
        long x1 = turn(id,axis,layer);
513

    
514
        if( x1!=INVALID_MOVE )
515
          {
516
          long x2 = turn(x1,axis,layer);
517
          long x3 = turn(x2,axis,layer);
518

    
519
          ret[index  ] = x1;
520
          ret[index+1] = x2;
521
          ret[index+2] = x3;
522
          }
523
        else
524
          {
525
          ret[index  ] = INVALID_MOVE;
526
          ret[index+1] = INVALID_MOVE;
527
          ret[index+2] = INVALID_MOVE;
528
          }
529

    
530
        index+=3;
531
        }
532

    
533
    return ret;
534
    }
535

    
536
///////////////////////////////////////////////////////////////////////////////////////////////////
537
// Definition of the id: it's an 'Andreas signature' of a bandaged cube.
538
// https://twistypuzzles.com/forum/viewtopic.php?t=24452&sid=f3b4ac0c611c4713e4d7840f1aabbb0b&start=350
539

    
540
  private static long turn(long id, int axis, int layer)
541
    {
542
    switch(axis)
543
      {
544
      case AXIS_X: switch(layer)
545
                     {
546
                     case LAYER_L: if( getBit(id, 1)==1 || getBit(id, 6)==1 || getBit(id,11)==1 ||
547
                                       getBit(id,22)==1 || getBit(id,27)==1 || getBit(id,32)==1 ||
548
                                       getBit(id,43)==1 || getBit(id,48)==1 || getBit(id,53)==1  ) return INVALID_MOVE;
549

    
550
                                   long x1 = cycle(id,9,14,46,41);
551
                                   long x2 = cycle(x1,4,35,51,20);
552
                                   return    cycle(x2,17,25,38,30);
553

    
554
                     case LAYER_M: if( getBit(id, 1)==1 || getBit(id, 6)==1 || getBit(id,11)==1 ||
555
                                       getBit(id,22)==1 || getBit(id,27)==1 || getBit(id,32)==1 ||
556
                                       getBit(id,43)==1 || getBit(id,48)==1 || getBit(id,53)==1 ||
557
                                       getBit(id, 0)==1 || getBit(id, 5)==1 || getBit(id,10)==1 ||
558
                                       getBit(id,21)==1 || getBit(id,26)==1 || getBit(id,31)==1 ||
559
                                       getBit(id,42)==1 || getBit(id,47)==1 || getBit(id,52)==1  ) return INVALID_MOVE;
560

    
561
                                   long x4 = cycle(id,8,13,45,40);
562
                                   long x5 = cycle(x4,3,34,50,19);
563
                                   return    cycle(x5,16,24,37,29);
564

    
565
                     case LAYER_R: if( getBit(id, 0)==1 || getBit(id, 5)==1 || getBit(id,10)==1 ||
566
                                       getBit(id,21)==1 || getBit(id,26)==1 || getBit(id,31)==1 ||
567
                                       getBit(id,42)==1 || getBit(id,47)==1 || getBit(id,52)==1  ) return INVALID_MOVE;
568

    
569
                                   long x7 = cycle(id,7,12,44,39);
570
                                   long x8 = cycle(x7,2,33,49,18);
571
                                   return    cycle(x8,15,23,36,28);
572
                     }
573

    
574
      case AXIS_Y: switch(layer)
575
                     {
576
                     case LAYER_L: if( getBit(id,12)==1 || getBit(id,13)==1 || getBit(id,14)==1 ||
577
                                       getBit(id,15)==1 || getBit(id,16)==1 || getBit(id,17)==1 ||
578
                                       getBit(id,18)==1 || getBit(id,19)==1 || getBit(id,20)==1  ) return INVALID_MOVE;
579

    
580
                                   long y1 = cycle(id,1,9,10,2);
581
                                   long y2 = cycle(y1,0,4,11,7);
582
                                   return    cycle(y2,3,6,8,5);
583

    
584
                     case LAYER_M: if( getBit(id,12)==1 || getBit(id,13)==1 || getBit(id,14)==1 ||
585
                                       getBit(id,15)==1 || getBit(id,16)==1 || getBit(id,17)==1 ||
586
                                       getBit(id,18)==1 || getBit(id,19)==1 || getBit(id,20)==1 ||
587
                                       getBit(id,33)==1 || getBit(id,34)==1 || getBit(id,35)==1 ||
588
                                       getBit(id,36)==1 || getBit(id,37)==1 || getBit(id,38)==1 ||
589
                                       getBit(id,39)==1 || getBit(id,40)==1 || getBit(id,41)==1  ) return INVALID_MOVE;
590

    
591
                                   long y4 = cycle(id,21,25,32,28);
592
                                   long y5 = cycle(y4,22,30,31,23);
593
                                   return    cycle(y5,24,27,29,26);
594

    
595
                     case LAYER_R: if( getBit(id,33)==1 || getBit(id,34)==1 || getBit(id,35)==1 ||
596
                                       getBit(id,36)==1 || getBit(id,37)==1 || getBit(id,38)==1 ||
597
                                       getBit(id,39)==1 || getBit(id,40)==1 || getBit(id,41)==1  ) return INVALID_MOVE;
598

    
599
                                   long y7 = cycle(id,42,46,53,49);
600
                                   long y8 = cycle(y7,43,51,52,44);
601
                                   return    cycle(y8,45,48,50,47);
602
                     }
603

    
604
      case AXIS_Z: switch(layer)
605
                     {
606
                     case LAYER_L: if( getBit(id, 7)==1 || getBit(id, 8)==1 || getBit(id, 9)==1 ||
607
                                       getBit(id,28)==1 || getBit(id,29)==1 || getBit(id,30)==1 ||
608
                                       getBit(id,49)==1 || getBit(id,50)==1 || getBit(id,51)==1  ) return INVALID_MOVE;
609

    
610
                                   long z1 = cycle(id,10,20,53,39);
611
                                   long z2 = cycle(z1,11,41,52,18);
612
                                   return    cycle(z2,19,32,40,31);
613

    
614
                     case LAYER_M: if( getBit(id, 7)==1 || getBit(id, 8)==1 || getBit(id, 9)==1 ||
615
                                       getBit(id,28)==1 || getBit(id,29)==1 || getBit(id,30)==1 ||
616
                                       getBit(id,49)==1 || getBit(id,50)==1 || getBit(id,51)==1 ||
617
                                       getBit(id, 2)==1 || getBit(id, 3)==1 || getBit(id, 4)==1 ||
618
                                       getBit(id,23)==1 || getBit(id,24)==1 || getBit(id,25)==1 ||
619
                                       getBit(id,44)==1 || getBit(id,45)==1 || getBit(id,46)==1  ) return INVALID_MOVE;
620

    
621
                                   long z4 = cycle(id,5,17,48,36);
622
                                   long z5 = cycle(z4,6,38,47,15);
623
                                   return    cycle(z5,16,27,37,26);
624

    
625
                     case LAYER_R: if( getBit(id, 2)==1 || getBit(id, 3)==1 || getBit(id, 4)==1 ||
626
                                       getBit(id,23)==1 || getBit(id,24)==1 || getBit(id,25)==1 ||
627
                                       getBit(id,44)==1 || getBit(id,45)==1 || getBit(id,46)==1  ) return INVALID_MOVE;
628

    
629
                                   long z7 = cycle(id,0,14,43,33);
630
                                   long z8 = cycle(z7,1,35,42,12);
631
                                   return    cycle(z8,13,22,34,21);
632
                     }
633
      }
634

    
635
    return 0;
636
    }
637

    
638
///////////////////////////////////////////////////////////////////////////////////////////////////
639
// bit b1 in place of b2 etc.
640

    
641
  private static long cycle(long id, int b1, int b2, int b3, int b4)
642
    {
643
    long bit1 = getBit(id,b1);
644
    long bit2 = getBit(id,b2);
645
    long bit3 = getBit(id,b3);
646
    long bit4 = getBit(id,b4);
647

    
648
    long i1 = setBit(id,b2,bit1);
649
    long i2 = setBit(i1,b3,bit2);
650
    long i3 = setBit(i2,b4,bit3);
651
    return    setBit(i3,b1,bit4);
652
    }
653

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

    
656
  private static long getBit(long id, int bit)
657
    {
658
    return (id>>bit)&0x1;
659
    }
660

    
661
///////////////////////////////////////////////////////////////////////////////////////////////////
662

    
663
  private static long setBit(long id, int bit, long value)
664
    {
665
    long old = getBit(id,bit);
666

    
667
    if( old!=value )
668
      {
669
      long diff = (1L<<bit);
670
      id += (value==0 ? -diff : diff);
671
      }
672

    
673
    return id;
674
    }
675

    
676
///////////////////////////////////////////////////////////////////////////////////////////////////
677

    
678
  private void printMoves()
679
    {
680
    String moves = "";
681

    
682
    for(int i=0; i<NUM_MOVES; i++)
683
      {
684
      moves += (" " + mMoves[i]);
685
      }
686

    
687
    android.util.Log.e("D", moves);
688
    }
689

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

    
692
  private static String printBits(long id)
693
    {
694
    String ret = "[";
695
    boolean first = true;
696

    
697
    for(int i=0; i<64; i++)
698
      {
699
      if( ( (id>>i)&0x1)==1 )
700
        {
701
        String num = (i<10 ? " "+i : ""+i);
702

    
703
        if( first ) { ret += num; first=false; }
704
        else          ret += (","+num);
705
        }
706
      }
707

    
708
    return ret + "]";
709
    }
710

    
711
///////////////////////////////////////////////////////////////////////////////////////////////////
712

    
713
  private static void printGraph(Map<Long, ScrambleStateBandaged3x3> map)
714
    {
715
    int num = map.size();
716
    android.util.Log.e("D", "\n"+num+" states\n");
717

    
718
    for (Map.Entry<Long, ScrambleStateBandaged3x3> entry : map.entrySet())
719
      {
720
      ScrambleStateBandaged3x3 value = entry.getValue();
721
      android.util.Log.e("D", value.formatMoves());
722
      }
723
    }
724
}
(3-3/5)