Project

General

Profile

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

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

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
  private static final long INVALID_MOVE = -1;
32
  private static final int NUM_MOVES = 27;
33

    
34
  private static final int AXIS_X = 0;
35
  private static final int AXIS_Y = 1;
36
  private static final int AXIS_Z = 2;
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
  private ScrambleStateBandaged3x3(long id)
49
    {
50
    mDistance = -1;
51
    mID = id;
52
    mMoves = createMoves(mID);
53
    }
54

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

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

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

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

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

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

    
76
///////////////////////////////////////////////////////////////////////////////////////////////////
77

    
78
  private int numAxis()
79
    {
80
    int num = 0;
81

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

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

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

    
94
    return num;
95
    }
96

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

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

    
104
///////////////////////////////////////////////////////////////////////////////////////////////////
105

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

    
112
    return x+"  "+y+"  "+z;
113
    }
114

    
115
///////////////////////////////////////////////////////////////////////////////////////////////////
116

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

    
129
    String ret = "";
130

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

    
141
    return formatL("{" + ret + "}");
142
    }
143

    
144
///////////////////////////////////////////////////////////////////////////////////////////////////
145

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

    
151
    int[] ret = new int[3*numValid];
152

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

    
163
    int pointer=0;
164

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

    
175
    return ret;
176
    }
177

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

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

    
186
    int[][] moves = { xMoves,yMoves,zMoves };
187

    
188
    return new ScrambleState( moves );
189
    }
190

    
191
///////////////////////////////////////////////////////////////////////////////////////////////////
192
// STATIC STUFF
193
///////////////////////////////////////////////////////////////////////////////////////////////////
194

    
195
  public static ScrambleState[] computeGraph(long id)
196
    {
197
    ScrambleStateBandaged3x3 bsg = new ScrambleStateBandaged3x3(id);
198
    Map<Long,ScrambleStateBandaged3x3> graph = new LinkedHashMap<>();
199
    graph.put(id,bsg);
200

    
201
long t1 = System.currentTimeMillis();
202

    
203
    insertChildren(graph,id);
204

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

    
208
    // if there's only one single state, do not prune moves which point to itself
209
    if(graph.size()>1)
210
      {
211
      pruneGraph(graph,id);
212
      }
213

    
214
long t3 = System.currentTimeMillis();
215
android.util.Log.e("D", "pruning graph: "+(t3-t2));
216

    
217
    computeDistance(graph,id,0);
218

    
219
long t4 = System.currentTimeMillis();
220
android.util.Log.e("D", "computing distance: "+(t4-t3));
221

    
222
    removeDisconnectedParts(graph);
223

    
224
long t5 = System.currentTimeMillis();
225
android.util.Log.e("D", "removing disconnected parts: "+(t5-t4));
226

    
227
    remapGraph(graph);
228

    
229
long t6 = System.currentTimeMillis();
230
android.util.Log.e("D", "remapping graph: "+(t6-t5));
231

    
232
    int num = graph.size();
233
    ScrambleState[] ret = new ScrambleState[num];
234

    
235
    for (Map.Entry<Long,ScrambleStateBandaged3x3> entry : graph.entrySet())
236
      {
237
      ScrambleStateBandaged3x3 value = entry.getValue();
238
      int mid = (int)value.mID;
239
      ret[mid] = value.produceScrambleState();
240
      }
241

    
242
//printGraph(graph);
243

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

    
247
    return ret;
248
    }
249

    
250
///////////////////////////////////////////////////////////////////////////////////////////////////
251

    
252
  private static void insertChildren(Map<Long,ScrambleStateBandaged3x3> map, long id)
253
    {
254
    ScrambleStateBandaged3x3 bsg = findState(map,id);
255

    
256
    if( bsg==null )
257
      {
258
      android.util.Log.e("D", "error: "+id+" doesn't exist");
259
      return;
260
      }
261

    
262
    for(int i=0; i<NUM_MOVES; i++)
263
      {
264
      long move = bsg.getMove(i);
265

    
266
      if( move!=INVALID_MOVE )
267
        {
268
        ScrambleStateBandaged3x3 tmp = findState(map,move);
269

    
270
        if( tmp==null )
271
          {
272
          tmp = new ScrambleStateBandaged3x3(move);
273
          map.put(move,tmp);
274
          insertChildren(map,move);
275
          }
276
        }
277
      }
278
    }
279

    
280
///////////////////////////////////////////////////////////////////////////////////////////////////
281

    
282
  private static void pruneGraph(Map<Long,ScrambleStateBandaged3x3> map, long startingID)
283
    {
284
    boolean pruned = false;
285
    boolean startingIsSingle = false;
286

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

    
289
    while (it.hasNext())
290
      {
291
      Map.Entry<Long,ScrambleStateBandaged3x3> entry = it.next();
292
      ScrambleStateBandaged3x3 value = entry.getValue();
293

    
294
      if( value.numAxis()<2 )
295
        {
296
        long prunedID = value.getID();
297

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

    
310
    for (Map.Entry<Long,ScrambleStateBandaged3x3> entry : map.entrySet() )
311
      {
312
      ScrambleStateBandaged3x3 value = entry.getValue();
313

    
314
      for(int m=0; m<NUM_MOVES; m++)
315
        {
316
        long move = value.mMoves[m];
317
        ScrambleStateBandaged3x3 tmp = findState(map,move);
318

    
319
        if( tmp==null || (startingIsSingle && move==startingID) )
320
          {
321
          value.mMoves[m]=INVALID_MOVE;
322
          }
323
        }
324
      }
325

    
326
    if( pruned ) pruneGraph(map,startingID);
327
    }
328

    
329
///////////////////////////////////////////////////////////////////////////////////////////////////
330

    
331
  private static void remapGraph(Map<Long,ScrambleStateBandaged3x3> map)
332
    {
333
    int id=0;
334

    
335
    for (Map.Entry<Long,ScrambleStateBandaged3x3> entry : map.entrySet())
336
      {
337
      ScrambleStateBandaged3x3 value = entry.getValue();
338
      value.mID = id++;
339
      }
340

    
341
    for (Map.Entry<Long,ScrambleStateBandaged3x3> entry : map.entrySet())
342
      {
343
      ScrambleStateBandaged3x3 value = entry.getValue();
344

    
345
      for(int m=0; m<NUM_MOVES; m++)
346
        {
347
        long move = value.mMoves[m];
348

    
349
        if( move!=INVALID_MOVE )
350
          {
351
          ScrambleStateBandaged3x3 tmp = map.get(move);
352
          value.mMoves[m] = tmp.mID;
353
          }
354
        }
355
      }
356
    }
357

    
358
///////////////////////////////////////////////////////////////////////////////////////////////////
359

    
360
  private static void computeDistance(Map<Long,ScrambleStateBandaged3x3> map, long id, int distance)
361
    {
362
    ScrambleStateBandaged3x3 state = findState(map,id);
363

    
364
    if( state==null )
365
      {
366
      android.util.Log.e("D", "error: "+id+" doesn't exist");
367
      return;
368
      }
369

    
370
    if( state.mDistance<0 )
371
      {
372
      state.mDistance = distance;
373

    
374
      for(int i=0; i<NUM_MOVES; i++)
375
        {
376
        long move = state.getMove(i);
377

    
378
        if( move!=INVALID_MOVE )
379
          {
380
          computeDistance(map,move,distance+1);
381
          }
382
        }
383
      }
384
    }
385

    
386
///////////////////////////////////////////////////////////////////////////////////////////////////
387

    
388
  private static void removeDisconnectedParts(Map<Long,ScrambleStateBandaged3x3> map)
389
    {
390
    Iterator<Map.Entry<Long,ScrambleStateBandaged3x3>> it = map.entrySet().iterator();
391

    
392
    while (it.hasNext())
393
      {
394
      Map.Entry<Long,ScrambleStateBandaged3x3> entry = it.next();
395
      ScrambleStateBandaged3x3 value = entry.getValue();
396
      if( value.mDistance<0 ) it.remove();
397
      }
398
    }
399

    
400
///////////////////////////////////////////////////////////////////////////////////////////////////
401

    
402
  private static ScrambleStateBandaged3x3 findState(Map<Long,ScrambleStateBandaged3x3> map, long id)
403
    {
404
    return map.get(id);
405
    }
406

    
407
///////////////////////////////////////////////////////////////////////////////////////////////////
408

    
409
  private static String formatRet(String str, int row, int angle, long id)
410
    {
411
    String ret = str.length()!=0 ? ",":"";
412

    
413
    ret += row;
414
    ret += angle<0 ? "," : ", ";
415
    ret += angle;
416

    
417
         if( id< 10 ) ret += (",  "+id);
418
    else if( id<100 ) ret += (", " +id);
419
    else              ret += (","  +id);
420

    
421
    return ret;
422
    }
423

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

    
426
  private static final int LENGTH = 28;
427

    
428
  private static String formatL(String input)
429
    {
430
    int len = input.length();
431
    String ret = input;
432
    for(int i=0 ;i<LENGTH-len; i++) ret += " ";
433
    return ret;
434
    }
435

    
436
///////////////////////////////////////////////////////////////////////////////////////////////////
437

    
438
  private static long[] createMoves(long id)
439
    {
440
    long[] ret = new long[NUM_MOVES];
441
    int index = 0;
442

    
443
    for(int axis=0; axis<3; axis++)
444
      for(int layer=0; layer<3; layer++)
445
        {
446
        long x1 = turn(id,axis,layer);
447

    
448
        if( x1!=INVALID_MOVE )
449
          {
450
          long x2 = turn(x1,axis,layer);
451
          long x3 = turn(x2,axis,layer);
452

    
453
          ret[index  ] = x1;
454
          ret[index+1] = x2;
455
          ret[index+2] = x3;
456
          }
457
        else
458
          {
459
          ret[index  ] = INVALID_MOVE;
460
          ret[index+1] = INVALID_MOVE;
461
          ret[index+2] = INVALID_MOVE;
462
          }
463

    
464
        index+=3;
465
        }
466

    
467
    return ret;
468
    }
469

    
470
///////////////////////////////////////////////////////////////////////////////////////////////////
471
// Definition of the id: it's an 'Andreas signature' of a bandaged cube.
472
// https://twistypuzzles.com/forum/viewtopic.php?t=24452&sid=f3b4ac0c611c4713e4d7840f1aabbb0b&start=350
473

    
474
  private static long turn(long id, int axis, int layer)
475
    {
476
    switch(axis)
477
      {
478
      case AXIS_X: switch(layer)
479
                     {
480
                     case LAYER_L: if( getBit(id, 1)==1 || getBit(id, 6)==1 || getBit(id,11)==1 ||
481
                                       getBit(id,22)==1 || getBit(id,27)==1 || getBit(id,32)==1 ||
482
                                       getBit(id,43)==1 || getBit(id,48)==1 || getBit(id,53)==1  ) return INVALID_MOVE;
483

    
484
                                   long x1 = cycle(id,9,14,46,41);
485
                                   long x2 = cycle(x1,4,35,51,20);
486
                                   return    cycle(x2,17,25,38,30);
487

    
488
                     case LAYER_M: if( getBit(id, 1)==1 || getBit(id, 6)==1 || getBit(id,11)==1 ||
489
                                       getBit(id,22)==1 || getBit(id,27)==1 || getBit(id,32)==1 ||
490
                                       getBit(id,43)==1 || getBit(id,48)==1 || getBit(id,53)==1 ||
491
                                       getBit(id, 0)==1 || getBit(id, 5)==1 || getBit(id,10)==1 ||
492
                                       getBit(id,21)==1 || getBit(id,26)==1 || getBit(id,31)==1 ||
493
                                       getBit(id,42)==1 || getBit(id,47)==1 || getBit(id,52)==1  ) return INVALID_MOVE;
494

    
495
                                   long x4 = cycle(id,8,13,45,40);
496
                                   long x5 = cycle(x4,3,34,50,19);
497
                                   return    cycle(x5,16,24,37,29);
498

    
499
                     case LAYER_R: if( getBit(id, 0)==1 || getBit(id, 5)==1 || getBit(id,10)==1 ||
500
                                       getBit(id,21)==1 || getBit(id,26)==1 || getBit(id,31)==1 ||
501
                                       getBit(id,42)==1 || getBit(id,47)==1 || getBit(id,52)==1  ) return INVALID_MOVE;
502

    
503
                                   long x7 = cycle(id,7,12,44,39);
504
                                   long x8 = cycle(x7,2,33,49,18);
505
                                   return    cycle(x8,15,23,36,28);
506
                     }
507

    
508
      case AXIS_Y: switch(layer)
509
                     {
510
                     case LAYER_L: if( getBit(id,12)==1 || getBit(id,13)==1 || getBit(id,14)==1 ||
511
                                       getBit(id,15)==1 || getBit(id,16)==1 || getBit(id,17)==1 ||
512
                                       getBit(id,18)==1 || getBit(id,19)==1 || getBit(id,20)==1  ) return INVALID_MOVE;
513

    
514
                                   long y1 = cycle(id,1,9,10,2);
515
                                   long y2 = cycle(y1,0,4,11,7);
516
                                   return    cycle(y2,3,6,8,5);
517

    
518
                     case LAYER_M: if( getBit(id,12)==1 || getBit(id,13)==1 || getBit(id,14)==1 ||
519
                                       getBit(id,15)==1 || getBit(id,16)==1 || getBit(id,17)==1 ||
520
                                       getBit(id,18)==1 || getBit(id,19)==1 || getBit(id,20)==1 ||
521
                                       getBit(id,33)==1 || getBit(id,34)==1 || getBit(id,35)==1 ||
522
                                       getBit(id,36)==1 || getBit(id,37)==1 || getBit(id,38)==1 ||
523
                                       getBit(id,39)==1 || getBit(id,40)==1 || getBit(id,41)==1  ) return INVALID_MOVE;
524

    
525
                                   long y4 = cycle(id,21,25,32,28);
526
                                   long y5 = cycle(y4,22,30,31,23);
527
                                   return    cycle(y5,24,27,29,26);
528

    
529
                     case LAYER_R: if( getBit(id,33)==1 || getBit(id,34)==1 || getBit(id,35)==1 ||
530
                                       getBit(id,36)==1 || getBit(id,37)==1 || getBit(id,38)==1 ||
531
                                       getBit(id,39)==1 || getBit(id,40)==1 || getBit(id,41)==1  ) return INVALID_MOVE;
532

    
533
                                   long y7 = cycle(id,42,46,53,49);
534
                                   long y8 = cycle(y7,43,51,52,44);
535
                                   return    cycle(y8,45,48,50,47);
536
                     }
537

    
538
      case AXIS_Z: switch(layer)
539
                     {
540
                     case LAYER_L: if( getBit(id, 7)==1 || getBit(id, 8)==1 || getBit(id, 9)==1 ||
541
                                       getBit(id,28)==1 || getBit(id,29)==1 || getBit(id,30)==1 ||
542
                                       getBit(id,49)==1 || getBit(id,50)==1 || getBit(id,51)==1  ) return INVALID_MOVE;
543

    
544
                                   long z1 = cycle(id,10,20,53,39);
545
                                   long z2 = cycle(z1,11,41,52,18);
546
                                   return    cycle(z2,19,32,40,31);
547

    
548
                     case LAYER_M: if( getBit(id, 7)==1 || getBit(id, 8)==1 || getBit(id, 9)==1 ||
549
                                       getBit(id,28)==1 || getBit(id,29)==1 || getBit(id,30)==1 ||
550
                                       getBit(id,49)==1 || getBit(id,50)==1 || getBit(id,51)==1 ||
551
                                       getBit(id, 2)==1 || getBit(id, 3)==1 || getBit(id, 4)==1 ||
552
                                       getBit(id,23)==1 || getBit(id,24)==1 || getBit(id,25)==1 ||
553
                                       getBit(id,44)==1 || getBit(id,45)==1 || getBit(id,46)==1  ) return INVALID_MOVE;
554

    
555
                                   long z4 = cycle(id,5,17,48,36);
556
                                   long z5 = cycle(z4,6,38,47,15);
557
                                   return    cycle(z5,16,27,37,26);
558

    
559
                     case LAYER_R: if( getBit(id, 2)==1 || getBit(id, 3)==1 || getBit(id, 4)==1 ||
560
                                       getBit(id,23)==1 || getBit(id,24)==1 || getBit(id,25)==1 ||
561
                                       getBit(id,44)==1 || getBit(id,45)==1 || getBit(id,46)==1  ) return INVALID_MOVE;
562

    
563
                                   long z7 = cycle(id,0,14,43,33);
564
                                   long z8 = cycle(z7,1,35,42,12);
565
                                   return    cycle(z8,13,22,34,21);
566
                     }
567
      }
568

    
569
    return 0;
570
    }
571

    
572
///////////////////////////////////////////////////////////////////////////////////////////////////
573
// bit b1 in place of b2 etc.
574

    
575
  private static long cycle(long id, int b1, int b2, int b3, int b4)
576
    {
577
    long bit1 = getBit(id,b1);
578
    long bit2 = getBit(id,b2);
579
    long bit3 = getBit(id,b3);
580
    long bit4 = getBit(id,b4);
581

    
582
    long i1 = setBit(id,b2,bit1);
583
    long i2 = setBit(i1,b3,bit2);
584
    long i3 = setBit(i2,b4,bit3);
585
    return    setBit(i3,b1,bit4);
586
    }
587

    
588
///////////////////////////////////////////////////////////////////////////////////////////////////
589

    
590
  private static long getBit(long id, int bit)
591
    {
592
    return (id>>bit)&0x1;
593
    }
594

    
595
///////////////////////////////////////////////////////////////////////////////////////////////////
596

    
597
  private static long setBit(long id, int bit, long value)
598
    {
599
    long old = getBit(id,bit);
600

    
601
    if( old!=value )
602
      {
603
      long diff = (1L<<bit);
604
      id += (value==0 ? -diff : diff);
605
      }
606

    
607
    return id;
608
    }
609

    
610
///////////////////////////////////////////////////////////////////////////////////////////////////
611

    
612
  private void printMoves()
613
    {
614
    String moves = "";
615

    
616
    for(int i=0; i<NUM_MOVES; i++)
617
      {
618
      moves += (" " + mMoves[i]);
619
      }
620

    
621
    android.util.Log.e("D", moves);
622
    }
623

    
624
///////////////////////////////////////////////////////////////////////////////////////////////////
625

    
626
  private static String printBits(long id)
627
    {
628
    String ret = "[";
629
    boolean first = true;
630

    
631
    for(int i=0; i<64; i++)
632
      {
633
      if( ( (id>>i)&0x1)==1 )
634
        {
635
        String num = (i<10 ? " "+i : ""+i);
636

    
637
        if( first ) { ret += num; first=false; }
638
        else          ret += (","+num);
639
        }
640
      }
641

    
642
    return ret + "]";
643
    }
644

    
645
///////////////////////////////////////////////////////////////////////////////////////////////////
646

    
647
  private static void printGraph(Map<Long,ScrambleStateBandaged3x3> map)
648
    {
649
    int num = map.size();
650
    android.util.Log.e("D", "\n"+num+" states\n");
651

    
652
    for (Map.Entry<Long,ScrambleStateBandaged3x3> entry : map.entrySet())
653
      {
654
      ScrambleStateBandaged3x3 value = entry.getValue();
655
      android.util.Log.e("D", value.formatMoves());
656
      }
657
    }
658
}
(3-3/4)