Project

General

Profile

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

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

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

    
10
package org.distorted.objectlib.scrambling;
11

    
12
import java.util.ArrayList;
13

    
14
///////////////////////////////////////////////////////////////////////////////////////////////////
15
// producer of the ScrambleStateGraph - but only for a single Twisty Puzzle, the 'Square-1'.
16

    
17
public class ScrambleStateSquare1
18
{
19
  private static final int INVALID_MOVE = -1;
20
  private static final int NUM_MOVES = 23;
21

    
22
  private final int mDist;
23
  private boolean mFresh;
24
  private long mID;
25
  private final long[] mMoves;
26

    
27
  private final int[][] mPermittedAngles;
28
  private final int[] mCornerQuat, mTmp;
29

    
30
  // QUATS[i]*QUATS[j] = QUATS[QUAT_MULT[i][j]]
31
  static final int[][] QUAT_MULT = new int[][]
32
    {
33
      {  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,},
34
      {  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11,  0, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 12,},
35
      {  2,  3,  4,  5,  6,  7,  8,  9, 10, 11,  0,  1, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 12, 13,},
36
      {  3,  4,  5,  6,  7,  8,  9, 10, 11,  0,  1,  2, 15, 16, 17, 18, 19, 20, 21, 22, 23, 12, 13, 14,},
37
      {  4,  5,  6,  7,  8,  9, 10, 11,  0,  1,  2,  3, 16, 17, 18, 19, 20, 21, 22, 23, 12, 13, 14, 15,},
38
      {  5,  6,  7,  8,  9, 10, 11,  0,  1,  2,  3,  4, 17, 18, 19, 20, 21, 22, 23, 12, 13, 14, 15, 16,},
39
      {  6,  7,  8,  9, 10, 11,  0,  1,  2,  3,  4,  5, 18, 19, 20, 21, 22, 23, 12, 13, 14, 15, 16, 17,},
40
      {  7,  8,  9, 10, 11,  0,  1,  2,  3,  4,  5,  6, 19, 20, 21, 22, 23, 12, 13, 14, 15, 16, 17, 18,},
41
      {  8,  9, 10, 11,  0,  1,  2,  3,  4,  5,  6,  7, 20, 21, 22, 23, 12, 13, 14, 15, 16, 17, 18, 19,},
42
      {  9, 10, 11,  0,  1,  2,  3,  4,  5,  6,  7,  8, 21, 22, 23, 12, 13, 14, 15, 16, 17, 18, 19, 20,},
43
      { 10, 11,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 22, 23, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,},
44
      { 11,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 23, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,},
45
      { 12, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13,  0, 11, 10,  9,  8,  7,  6,  5,  4,  3,  2,  1,},
46
      { 13, 12, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14,  1,  0, 11, 10,  9,  8,  7,  6,  5,  4,  3,  2,},
47
      { 14, 13, 12, 23, 22, 21, 20, 19, 18, 17, 16, 15,  2,  1,  0, 11, 10,  9,  8,  7,  6,  5,  4,  3,},
48
      { 15, 14, 13, 12, 23, 22, 21, 20, 19, 18, 17, 16,  3,  2,  1,  0, 11, 10,  9,  8,  7,  6,  5,  4,},
49
      { 16, 15, 14, 13, 12, 23, 22, 21, 20, 19, 18, 17,  4,  3,  2,  1,  0, 11, 10,  9,  8,  7,  6,  5,},
50
      { 17, 16, 15, 14, 13, 12, 23, 22, 21, 20, 19, 18,  5,  4,  3,  2,  1,  0, 11, 10,  9,  8,  7,  6,},
51
      { 18, 17, 16, 15, 14, 13, 12, 23, 22, 21, 20, 19,  6,  5,  4,  3,  2,  1,  0, 11, 10,  9,  8,  7,},
52
      { 19, 18, 17, 16, 15, 14, 13, 12, 23, 22, 21, 20,  7,  6,  5,  4,  3,  2,  1,  0, 11, 10,  9,  8,},
53
      { 20, 19, 18, 17, 16, 15, 14, 13, 12, 23, 22, 21,  8,  7,  6,  5,  4,  3,  2,  1,  0, 11, 10,  9,},
54
      { 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 23, 22,  9,  8,  7,  6,  5,  4,  3,  2,  1,  0, 11, 10,},
55
      { 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 23, 10,  9,  8,  7,  6,  5,  4,  3,  2,  1,  0, 11,},
56
      { 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10,  9,  8,  7,  6,  5,  4,  3,  2,  1,  0,}
57
    };
58

    
59
  // quat indices that make corner cubits bandage the puzzle.
60
  private static final int[][] BAD_CORNER_QUATS = new int[][]
61
    {
62
      { 2, 8,17,23},
63
      { 5,11,14,20},
64
    };
65

    
66
///////////////////////////////////////////////////////////////////////////////////////////////////
67

    
68
  public ScrambleStateSquare1(long id, int dist)
69
    {
70
    mCornerQuat = new int[8];
71
    mTmp        = new int[8];
72
    mPermittedAngles = new int[2][12];
73

    
74
    mDist = dist;
75
    mFresh = true;
76
    mID = id;
77
    mMoves = createMoves(mID);
78
    }
79

    
80
///////////////////////////////////////////////////////////////////////////////////////////////////
81

    
82
  private void setNotFresh()
83
    {
84
    mFresh = false;
85
    }
86

    
87
///////////////////////////////////////////////////////////////////////////////////////////////////
88

    
89
  private boolean isFresh()
90
    {
91
    return mFresh;
92
    }
93

    
94
///////////////////////////////////////////////////////////////////////////////////////////////////
95

    
96
  public static void computeGraph()
97
    {
98
    ArrayList<ScrambleStateSquare1> graph;
99

    
100
    ScrambleStateSquare1 bsg = new ScrambleStateSquare1(0,0);
101
    graph = new ArrayList<>();
102
    graph.add(bsg);
103

    
104
android.util.Log.e("D", "INSERTING");
105

    
106
    insertChildren(graph,0);
107

    
108
//android.util.Log.e("D", "PRUNING "+graph.size());
109

    
110
//    pruneGraph(graph);
111

    
112
android.util.Log.e("D", "REMAPPING "+graph.size());
113

    
114
    remapGraph(graph);
115

    
116
    int num = graph.size();
117
    android.util.Log.e("D", "\n"+num+" states\n");
118

    
119
    for(int i=0; i<num; i++)
120
      {
121
      bsg = graph.get(i);
122
      android.util.Log.e("D", formatMoves(bsg));
123
      }
124
    }
125

    
126
///////////////////////////////////////////////////////////////////////////////////////////////////
127

    
128
  private static void insertChildren(ArrayList<ScrambleStateSquare1> list, long id)
129
    {
130
    ScrambleStateSquare1 bsg = findState(list,id);
131

    
132
    if( bsg==null )
133
      {
134
      android.util.Log.e("D", "error: "+id+" doesn't exist");
135
      return;
136
      }
137

    
138
    int dist = bsg.mDist;
139
    if( dist>6 ) return;
140

    
141
    for(int i=0; i<NUM_MOVES; i++)
142
      {
143
      long moveID = bsg.getMoveID(i);
144

    
145
      if( moveID!=INVALID_MOVE )
146
        {
147
        ScrambleStateSquare1 tmp = findState(list,moveID);
148

    
149
        if( tmp==null )
150
          {
151
          tmp = new ScrambleStateSquare1(moveID,dist+1);
152
          list.add(tmp);
153
          }
154
        }
155
      }
156

    
157
    for(int i=0; i<NUM_MOVES; i++)
158
      {
159
      long moveID = bsg.getMoveID(i);
160

    
161
      if( moveID!=INVALID_MOVE )
162
        {
163
        ScrambleStateSquare1 tmp = findState(list,moveID);
164

    
165
        if( tmp.isFresh() )
166
          {
167
          tmp.setNotFresh();
168
          insertChildren(list,moveID);
169
          }
170
        }
171
      }
172
    }
173

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

    
176
  private static void pruneGraph(ArrayList<ScrambleStateSquare1> list)
177
    {
178
    int num = list.size(), numAxis;
179
    boolean pruned = false;
180
    ScrambleStateSquare1 bsg;
181

    
182
    for(int i=0; i<num; i++)
183
      {
184
      bsg = list.get(i);
185
      numAxis = bsg.numAxis();
186

    
187
      if( numAxis<2 )
188
        {
189
        list.remove(i);
190
        long id = bsg.getID();
191
        pruned = true;
192
        remapID(list,id,INVALID_MOVE);
193
        break;
194
        }
195
      }
196

    
197
    if( pruned ) pruneGraph(list);
198
    }
199

    
200
///////////////////////////////////////////////////////////////////////////////////////////////////
201

    
202
  private static void remapGraph(ArrayList<ScrambleStateSquare1> list)
203
    {
204
    long id;
205
    int num = list.size();
206
    ScrambleStateSquare1 bsg;
207

    
208
    for(int i=0; i<num; i++ )
209
      {
210
      bsg = list.get(i);
211
      id = bsg.getID();
212
      bsg.setID(i);
213
      remapID(list,id,i);
214
      }
215
    }
216

    
217
///////////////////////////////////////////////////////////////////////////////////////////////////
218

    
219
  private static void remapID(ArrayList<ScrambleStateSquare1> list, long id, long newId)
220
    {
221
    ScrambleStateSquare1 bsg;
222
    int size = list.size();
223

    
224
    for(int i=0; i<size; i++)
225
      {
226
      bsg = list.get(i);
227

    
228
      for(int j=0; j<NUM_MOVES; j++)
229
        {
230
        if( bsg.getMoveID(j)==id ) bsg.setMoveID(j,newId);
231
        }
232
      }
233
    }
234

    
235
///////////////////////////////////////////////////////////////////////////////////////////////////
236

    
237
  private static ScrambleStateSquare1 findState(ArrayList<ScrambleStateSquare1> list, long id)
238
    {
239
    ScrambleStateSquare1 bsg;
240
    int num = list.size();
241

    
242
    for(int i=0; i<num; i++)
243
      {
244
      bsg= list.get(i);
245
      if( bsg.getID() == id ) return bsg;
246
      }
247

    
248
    return null;
249
    }
250

    
251
///////////////////////////////////////////////////////////////////////////////////////////////////
252

    
253
  private static String formatMoves(ScrambleStateSquare1 bsg)
254
    {
255
    String x = getTable(bsg,0);
256
    String y = getTable(bsg,11);
257
    String z = getTable(bsg,12);
258

    
259
    //return "    new ScrambleStateGraph( new int[][] { "+x+", "+y+", "+z+" } ),";
260

    
261
    long id = bsg.getID();
262

    
263
    return id+" "+x+" , "+y+" , "+z;
264
    }
265

    
266
///////////////////////////////////////////////////////////////////////////////////////////////////
267

    
268
  private static String getTable(ScrambleStateSquare1 sc, int index)
269
    {
270
    String ret = "";
271
    long m;
272
    int half = (NUM_MOVES)/2;
273

    
274
    if( index==11 )
275
      {
276
      m = sc.getMoveID(index);
277
      if( m==INVALID_MOVE ) return formatL("{}");
278
      ret += formatRet(ret,0,1,m);
279
      }
280
    else
281
      {
282
      for(int i=0; i<half; i++)
283
        {
284
        m = sc.getMoveID(index+i);
285
        int row = index==0 ? 0:2;
286
        int angle = i+1;
287
        if( m!=INVALID_MOVE ) ret += formatRet(ret,row,angle,m);
288
        }
289
      }
290

    
291
    return formatL("{" + ret + "}");
292
    }
293

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

    
296
  private static String formatRet(String str, int row, int angle, long id)
297
    {
298
    String ret = str.length()!=0 ? "  ,":"  ";
299

    
300
    ret += row;
301
    ret += ",";
302
    ret += angle;
303

    
304
         if( id< 10 ) ret += (",  "+id);
305
    else if( id<100 ) ret += (", " +id);
306
    else              ret += (","  +id);
307

    
308
    return ret;
309
    }
310

    
311
///////////////////////////////////////////////////////////////////////////////////////////////////
312

    
313
  private static final int LENGTH = 28;
314

    
315
  private static String formatL(String input)
316
    {
317
    int len = input.length();
318
    String ret = input;
319
    for(int i=0 ;i<LENGTH-len; i++) ret += " ";
320
    return ret;
321
    }
322

    
323
///////////////////////////////////////////////////////////////////////////////////////////////////
324

    
325
  private long getID()
326
    {
327
    return mID;
328
    }
329

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

    
332
  private void setID(long id)
333
    {
334
    mID = id;
335
    }
336

    
337
///////////////////////////////////////////////////////////////////////////////////////////////////
338

    
339
  private long getMoveID(int index)
340
    {
341
    return (index>=0 && index<NUM_MOVES) ? mMoves[index] : -1;
342
    }
343

    
344
///////////////////////////////////////////////////////////////////////////////////////////////////
345

    
346
  private void setMoveID(int index, long newID)
347
    {
348
    if( index>=0 && index<NUM_MOVES ) mMoves[index] = newID;
349
    }
350

    
351
///////////////////////////////////////////////////////////////////////////////////////////////////
352

    
353
  private int numAxis()
354
    {
355
    int num = 0;
356
    int half = (NUM_MOVES)/2;
357

    
358
    for(int i=0; i<half; i++)
359
      {
360
      if( mMoves[i]!=INVALID_MOVE )
361
        {
362
        num++;
363
        break;
364
        }
365
      }
366

    
367
    for(int i=half; i<NUM_MOVES-1; i++)
368
      {
369
      if( mMoves[i]!=INVALID_MOVE )
370
        {
371
        num++;
372
        break;
373
        }
374
      }
375

    
376
    if( mMoves[NUM_MOVES-1]!=INVALID_MOVE ) num++;
377

    
378
    return num;
379
    }
380

    
381
///////////////////////////////////////////////////////////////////////////////////////////////////
382

    
383
  private long[] createMoves(long id)
384
    {
385
    long[] ret = new long[NUM_MOVES];
386
    fillCornerQuat(id);
387
    computePermittedAngles();
388

    
389
    generateUMoves(ret, 0);
390
    generateSMoves(ret,11);
391
    generateLMoves(ret,12);
392

    
393
    return ret;
394
    }
395

    
396
///////////////////////////////////////////////////////////////////////////////////////////////////
397

    
398
  private void generateUMoves(long[] table, int index)
399
    {
400
    for(int angle=1; angle<12; angle++)
401
      {
402
      table[index+angle-1] = mPermittedAngles[1][angle]==1 ? updateCornerQuats(0,2,angle) : INVALID_MOVE;
403
      }
404
    }
405

    
406
///////////////////////////////////////////////////////////////////////////////////////////////////
407

    
408
  private void generateLMoves(long[] table, int index)
409
    {
410
    for(int angle=1; angle<12; angle++)
411
      {
412
      table[index+angle-1] = mPermittedAngles[0][angle]==1 ? updateCornerQuats(0,0,angle) : INVALID_MOVE;
413
      }
414
    }
415

    
416
///////////////////////////////////////////////////////////////////////////////////////////////////
417

    
418
  private void generateSMoves(long[] table, int index)
419
    {
420
    table[index] = updateCornerQuats(1,1,1);
421
    }
422

    
423
///////////////////////////////////////////////////////////////////////////////////////////////////
424

    
425
  private void fillCornerQuat(long id)
426
    {
427
    int NUM_QUATS = 24;
428

    
429
    for(int i=0; i<8; i++)
430
      {
431
      mCornerQuat[i] = (int)(id%NUM_QUATS);
432
      id/=NUM_QUATS;
433
      }
434
    }
435

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

    
438
  private static long returnID(int[] cornerQuat)
439
    {
440
    int NUM_QUATS = 24;
441
    long mult=1,ret=0;
442

    
443
    for(int i=0; i<8; i++)
444
      {
445
      ret += mult*cornerQuat[i];
446
      mult*=NUM_QUATS;
447
      }
448

    
449
    return ret;
450
    }
451

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

    
454
  private boolean cornerIsUp(int index)
455
    {
456
    return ((index<4) ^ (mCornerQuat[index]>=12));
457
    }
458

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

    
461
  private boolean cornerIsLeft(int index)
462
    {
463
    int q = mCornerQuat[index];
464

    
465
    switch(index)
466
      {
467
      case 0:
468
      case 4: return ((q>=3 && q<= 7) || (q>=18 && q<=22));
469
      case 1:
470
      case 5: return ((q>=6 && q<=10) || (q>=15 && q<=19));
471
      case 2:
472
      case 6: return ((q==0 || q==1 || (q>=9 && q<=11)) || (q>=12 && q<=16));
473
      case 3:
474
      case 7: return ((q>=0 && q<=4) || (q==12 || q==13 || (q>=21 && q<=23)));
475
      }
476

    
477
    return false;
478
    }
479

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

    
482
  private int makeQuat(int axis,int index)
483
    {
484
    if( axis==1 ) return 13;
485
    if( index<0 ) index+=12;
486
    return index;
487
    }
488

    
489
///////////////////////////////////////////////////////////////////////////////////////////////////
490

    
491
  private boolean cornerBelongs(int index, int axis, int layer)
492
    {
493
    if( axis==0 )
494
      {
495
      boolean up = cornerIsUp(index);
496
      return ((up && layer==2) || (!up && layer==0));
497
      }
498
    else
499
      {
500
      boolean le = cornerIsLeft(index);
501
      return ((le && layer==0) || (!le && layer==1));
502
      }
503
    }
504

    
505
///////////////////////////////////////////////////////////////////////////////////////////////////
506

    
507
  private long updateCornerQuats(int axis, int layer, int index)
508
    {
509
    int quat = makeQuat(axis,index);
510

    
511
    for(int corner=0; corner<8; corner++)
512
      {
513
      if( cornerBelongs(corner,axis,layer) )
514
        {
515
        int curr = mCornerQuat[corner];
516
        mTmp[corner] = QUAT_MULT[quat][curr];
517
        }
518
      else
519
        {
520
        mTmp[corner] = mCornerQuat[corner];
521
        }
522
      }
523

    
524
    return returnID(mTmp);
525
    }
526

    
527
///////////////////////////////////////////////////////////////////////////////////////////////////
528

    
529
  private boolean quatIsBad(int quatIndex, int corner)
530
    {
531
    int index = (corner%2);
532

    
533
    return ( quatIndex==BAD_CORNER_QUATS[index][0] ||
534
             quatIndex==BAD_CORNER_QUATS[index][1] ||
535
             quatIndex==BAD_CORNER_QUATS[index][2] ||
536
             quatIndex==BAD_CORNER_QUATS[index][3]  );
537
    }
538

    
539
///////////////////////////////////////////////////////////////////////////////////////////////////
540

    
541
  private int isPermittedDo(int angle)
542
    {
543
    for(int corner=0; corner<8; corner++)
544
      {
545
      if( !cornerIsUp(corner) )
546
        {
547
        int currQuat = mCornerQuat[corner];
548
        int finalQuat= QUAT_MULT[angle][currQuat];
549
        if( quatIsBad(finalQuat,corner) ) return 0;
550
        }
551
      }
552

    
553
    return 1;
554
    }
555

    
556
///////////////////////////////////////////////////////////////////////////////////////////////////
557

    
558
  private int isPermittedUp(int angle)
559
    {
560
    for(int corner=0; corner<8; corner++)
561
      {
562
      if( cornerIsUp(corner) )
563
        {
564
        int currQuat = mCornerQuat[corner];
565
        int finalQuat= QUAT_MULT[angle][currQuat];
566
        if( quatIsBad(finalQuat,corner) ) return 0;
567
        }
568
      }
569

    
570
    return 1;
571
    }
572

    
573
///////////////////////////////////////////////////////////////////////////////////////////////////
574

    
575
  private void computePermittedAngles()
576
    {
577
    for(int angle=0; angle<12; angle++)
578
      {
579
      mPermittedAngles[0][angle] = isPermittedDo(angle);
580
      mPermittedAngles[1][angle] = isPermittedUp(angle);
581
      }
582
    }
583
}
(7-7/7)